Mirror of github.com/gissleh/irc
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
2.6 KiB

  1. package irctest
  2. import (
  3. "bufio"
  4. "net"
  5. "strings"
  6. "sync"
  7. "time"
  8. )
  9. // An Interaction is a "simulated" server that will trigger the
  10. // client.
  11. type Interaction struct {
  12. wg sync.WaitGroup
  13. Strict bool
  14. Lines []InteractionLine
  15. Log []string
  16. Failure *InteractionFailure
  17. }
  18. // Listen listens for a client in a separate goroutine.
  19. func (interaction *Interaction) Listen() (addr string, err error) {
  20. listener, err := net.Listen("tcp", "127.0.0.1:0")
  21. if err != nil {
  22. return "", err
  23. }
  24. lines := make([]InteractionLine, len(interaction.Lines))
  25. copy(lines, interaction.Lines)
  26. go func() {
  27. interaction.wg.Add(1)
  28. defer interaction.wg.Done()
  29. conn, err := listener.Accept()
  30. if err != nil {
  31. interaction.Failure = &InteractionFailure{
  32. Index: -1, NetErr: err,
  33. }
  34. return
  35. }
  36. defer conn.Close()
  37. reader := bufio.NewReader(conn)
  38. for i := 0; i < len(lines); i++ {
  39. line := lines[i]
  40. if line.Server != "" {
  41. _, err := conn.Write(append([]byte(line.Server), '\r', '\n'))
  42. if err != nil {
  43. interaction.Failure = &InteractionFailure{
  44. Index: i, NetErr: err,
  45. }
  46. return
  47. }
  48. } else if line.Client != "" {
  49. conn.SetReadDeadline(time.Now().Add(time.Second * 2))
  50. input, err := reader.ReadString('\n')
  51. if err != nil {
  52. interaction.Failure = &InteractionFailure{
  53. Index: i, NetErr: err,
  54. }
  55. return
  56. }
  57. input = strings.Replace(input, "\r", "", -1)
  58. input = strings.Replace(input, "\n", "", 1)
  59. match := line.Client
  60. success := false
  61. if strings.HasSuffix(match, "*") {
  62. success = strings.HasPrefix(input, match[:len(match)-1])
  63. } else {
  64. success = match == input
  65. }
  66. interaction.Log = append(interaction.Log, input)
  67. if !success {
  68. if !interaction.Strict {
  69. i--
  70. continue
  71. }
  72. interaction.Failure = &InteractionFailure{
  73. Index: i, Result: input,
  74. }
  75. return
  76. }
  77. } else if line.Callback != nil {
  78. err := line.Callback()
  79. if err != nil {
  80. interaction.Failure = &InteractionFailure{
  81. Index: i, CBErr: err,
  82. }
  83. return
  84. }
  85. }
  86. }
  87. }()
  88. return listener.Addr().String(), nil
  89. }
  90. // Wait waits for the setup to be done. It's safe to check
  91. // Failure after that.
  92. func (interaction *Interaction) Wait() {
  93. interaction.wg.Wait()
  94. }
  95. // InteractionFailure signifies a test failure.
  96. type InteractionFailure struct {
  97. Index int
  98. Result string
  99. NetErr error
  100. CBErr error
  101. }
  102. // InteractionLine is part of an interaction, whether it is a line
  103. // that is sent to a client or a line expected from a client.
  104. type InteractionLine struct {
  105. Client string
  106. Server string
  107. Callback func() error
  108. }