client_multiline_test.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package ftp
  2. import (
  3. "net"
  4. "net/textproto"
  5. "reflect"
  6. "strings"
  7. "sync"
  8. "testing"
  9. )
  10. type ftpMock struct {
  11. listener net.Listener
  12. commands []string // list of received commands
  13. sync.WaitGroup
  14. }
  15. func newFtpMock(t *testing.T, addresss string) *ftpMock {
  16. var err error
  17. mock := &ftpMock{}
  18. mock.listener, err = net.Listen("tcp", addresss)
  19. if err != nil {
  20. t.Fatal(err)
  21. }
  22. go func() {
  23. // Listen for an incoming connection.
  24. conn, err := mock.listener.Accept()
  25. if err != nil {
  26. t.Fatal(err)
  27. }
  28. mock.Add(1)
  29. defer mock.Done()
  30. defer conn.Close()
  31. proto := textproto.NewConn(conn)
  32. proto.Writer.PrintfLine("220 FTP Server ready.")
  33. for {
  34. command, _ := proto.ReadLine()
  35. // Strip the arguments
  36. if i := strings.Index(command, " "); i > 0 {
  37. command = command[:i]
  38. }
  39. // Append to list of received commands
  40. mock.commands = append(mock.commands, command)
  41. // At least one command must have a multiline response
  42. switch command {
  43. case "FEAT":
  44. proto.Writer.PrintfLine("211-Features:\r\nFEAT\r\nPASV\r\nSIZE\r\n211 End")
  45. case "USER":
  46. proto.Writer.PrintfLine("331 Please send your password")
  47. case "PASS":
  48. proto.Writer.PrintfLine("230-Hey,\r\nWelcome to my FTP\r\n230 Access granted")
  49. case "TYPE":
  50. proto.Writer.PrintfLine("200 Type set ok")
  51. case "QUIT":
  52. proto.Writer.PrintfLine("221 Goodbye.")
  53. return
  54. default:
  55. t.Fatal("unknown command:", command)
  56. }
  57. }
  58. }()
  59. return mock
  60. }
  61. // Closes the listening socket
  62. func (mock *ftpMock) Close() {
  63. mock.listener.Close()
  64. }
  65. // ftp.mozilla.org uses multiline 220 response
  66. func TestMultiline(t *testing.T) {
  67. if testing.Short() {
  68. t.Skip("skipping test in short mode.")
  69. }
  70. address := "localhost:2121"
  71. mock := newFtpMock(t, address)
  72. defer mock.Close()
  73. c, err := Dial(address)
  74. if err != nil {
  75. t.Fatal(err)
  76. }
  77. err = c.Login("anonymous", "anonymous")
  78. if err != nil {
  79. t.Fatal(err)
  80. }
  81. c.Quit()
  82. // Wait for the connection to close
  83. mock.Wait()
  84. expected := []string{"FEAT", "USER", "PASS", "TYPE", "QUIT"}
  85. if !reflect.DeepEqual(mock.commands, expected) {
  86. t.Fatal("unexpected sequence of commands:", mock.commands, "expected:", expected)
  87. }
  88. }