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.

130 lines
2.7 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. _ = conn.SetWriteDeadline(time.Now().Add(time.Second * 2))
  42. _, err := conn.Write(append([]byte(line.Server), '\r', '\n'))
  43. if err != nil {
  44. interaction.Failure = &InteractionFailure{
  45. Index: i, NetErr: err,
  46. }
  47. return
  48. }
  49. } else if line.Client != "" {
  50. _ = conn.SetReadDeadline(time.Now().Add(time.Second * 2))
  51. input, err := reader.ReadString('\n')
  52. if err != nil {
  53. interaction.Failure = &InteractionFailure{
  54. Index: i, NetErr: err,
  55. }
  56. return
  57. }
  58. input = strings.Replace(input, "\r", "", -1)
  59. input = strings.Replace(input, "\n", "", 1)
  60. match := line.Client
  61. success := false
  62. if strings.HasSuffix(match, "*") {
  63. success = strings.HasPrefix(input, match[:len(match)-1])
  64. } else {
  65. success = match == input
  66. }
  67. interaction.Log = append(interaction.Log, input)
  68. if !success {
  69. if !interaction.Strict {
  70. i--
  71. continue
  72. }
  73. interaction.Failure = &InteractionFailure{
  74. Index: i, Result: input,
  75. }
  76. return
  77. }
  78. } else if line.Callback != nil {
  79. err := line.Callback()
  80. if err != nil {
  81. interaction.Failure = &InteractionFailure{
  82. Index: i, CBErr: err,
  83. }
  84. return
  85. }
  86. }
  87. }
  88. }()
  89. return listener.Addr().String(), nil
  90. }
  91. // Wait waits for the setup to be done. It's safe to check
  92. // Failure after that.
  93. func (interaction *Interaction) Wait() {
  94. interaction.wg.Wait()
  95. }
  96. // InteractionFailure signifies a test failure.
  97. type InteractionFailure struct {
  98. Index int
  99. Result string
  100. NetErr error
  101. CBErr error
  102. }
  103. // InteractionLine is part of an interaction, whether it is a line
  104. // that is sent to a client or a line expected from a client.
  105. type InteractionLine struct {
  106. Client string
  107. Server string
  108. Callback func() error
  109. }