ping_test.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. package client // import "github.com/docker/docker/client"
  2. import (
  3. "context"
  4. "errors"
  5. "io"
  6. "net/http"
  7. "strings"
  8. "testing"
  9. "github.com/docker/docker/api/types/swarm"
  10. "gotest.tools/v3/assert"
  11. is "gotest.tools/v3/assert/cmp"
  12. )
  13. // TestPingFail tests that when a server sends a non-successful response that we
  14. // can still grab API details, when set.
  15. // Some of this is just exercising the code paths to make sure there are no
  16. // panics.
  17. func TestPingFail(t *testing.T) {
  18. var withHeader bool
  19. client := &Client{
  20. client: newMockClient(func(req *http.Request) (*http.Response, error) {
  21. resp := &http.Response{StatusCode: http.StatusInternalServerError}
  22. if withHeader {
  23. resp.Header = http.Header{}
  24. resp.Header.Set("API-Version", "awesome")
  25. resp.Header.Set("Docker-Experimental", "true")
  26. resp.Header.Set("Swarm", "inactive")
  27. }
  28. resp.Body = io.NopCloser(strings.NewReader("some error with the server"))
  29. return resp, nil
  30. }),
  31. }
  32. ping, err := client.Ping(context.Background())
  33. assert.Check(t, is.ErrorContains(err, "some error with the server"))
  34. assert.Check(t, is.Equal(false, ping.Experimental))
  35. assert.Check(t, is.Equal("", ping.APIVersion))
  36. var si *swarm.Status
  37. assert.Check(t, is.Equal(si, ping.SwarmStatus))
  38. withHeader = true
  39. ping2, err := client.Ping(context.Background())
  40. assert.Check(t, is.ErrorContains(err, "some error with the server"))
  41. assert.Check(t, is.Equal(true, ping2.Experimental))
  42. assert.Check(t, is.Equal("awesome", ping2.APIVersion))
  43. assert.Check(t, is.Equal(swarm.Status{NodeState: "inactive"}, *ping2.SwarmStatus))
  44. }
  45. // TestPingWithError tests the case where there is a protocol error in the ping.
  46. // This test is mostly just testing that there are no panics in this code path.
  47. func TestPingWithError(t *testing.T) {
  48. client := &Client{
  49. client: newMockClient(func(req *http.Request) (*http.Response, error) {
  50. resp := &http.Response{StatusCode: http.StatusInternalServerError}
  51. resp.Header = http.Header{}
  52. resp.Header.Set("API-Version", "awesome")
  53. resp.Header.Set("Docker-Experimental", "true")
  54. resp.Header.Set("Swarm", "active/manager")
  55. resp.Body = io.NopCloser(strings.NewReader("some error with the server"))
  56. return resp, errors.New("some error")
  57. }),
  58. }
  59. ping, err := client.Ping(context.Background())
  60. assert.Check(t, is.ErrorContains(err, "some error"))
  61. assert.Check(t, is.Equal(false, ping.Experimental))
  62. assert.Check(t, is.Equal("", ping.APIVersion))
  63. var si *swarm.Status
  64. assert.Check(t, is.Equal(si, ping.SwarmStatus))
  65. }
  66. // TestPingSuccess tests that we are able to get the expected API headers/ping
  67. // details on success.
  68. func TestPingSuccess(t *testing.T) {
  69. client := &Client{
  70. client: newMockClient(func(req *http.Request) (*http.Response, error) {
  71. resp := &http.Response{StatusCode: http.StatusOK}
  72. resp.Header = http.Header{}
  73. resp.Header.Set("API-Version", "awesome")
  74. resp.Header.Set("Docker-Experimental", "true")
  75. resp.Header.Set("Swarm", "active/manager")
  76. resp.Body = io.NopCloser(strings.NewReader("OK"))
  77. return resp, nil
  78. }),
  79. }
  80. ping, err := client.Ping(context.Background())
  81. assert.NilError(t, err)
  82. assert.Check(t, is.Equal(true, ping.Experimental))
  83. assert.Check(t, is.Equal("awesome", ping.APIVersion))
  84. assert.Check(t, is.Equal(swarm.Status{NodeState: "active", ControlAvailable: true}, *ping.SwarmStatus))
  85. }
  86. // TestPingHeadFallback tests that the client falls back to GET if HEAD fails.
  87. func TestPingHeadFallback(t *testing.T) {
  88. tests := []struct {
  89. status int
  90. expected string
  91. }{
  92. {
  93. status: http.StatusOK,
  94. expected: http.MethodHead,
  95. },
  96. {
  97. status: http.StatusInternalServerError,
  98. expected: http.MethodHead,
  99. },
  100. {
  101. status: http.StatusNotFound,
  102. expected: "HEAD, GET",
  103. },
  104. {
  105. status: http.StatusMethodNotAllowed,
  106. expected: "HEAD, GET",
  107. },
  108. }
  109. for _, tc := range tests {
  110. tc := tc
  111. t.Run(http.StatusText(tc.status), func(t *testing.T) {
  112. var reqs []string
  113. client := &Client{
  114. client: newMockClient(func(req *http.Request) (*http.Response, error) {
  115. reqs = append(reqs, req.Method)
  116. resp := &http.Response{StatusCode: http.StatusOK}
  117. if req.Method == http.MethodHead {
  118. resp.StatusCode = tc.status
  119. }
  120. resp.Header = http.Header{}
  121. resp.Header.Add("API-Version", strings.Join(reqs, ", "))
  122. return resp, nil
  123. }),
  124. }
  125. ping, _ := client.Ping(context.Background())
  126. assert.Check(t, is.Equal(ping.APIVersion, tc.expected))
  127. })
  128. }
  129. }