github.com/rumpl/bof@v23.0.0-rc.2+incompatible/client/ping_test.go (about)

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