From e4156e3ffd163e4093b4f2b9625f1bead48274af Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 13 Dec 2019 15:57:18 +0300 Subject: [PATCH] test for HTTPClientBuilder client mocking feature --- core/http_client_builder_test.go | 154 +++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/core/http_client_builder_test.go b/core/http_client_builder_test.go index f374d89..292c1d9 100644 --- a/core/http_client_builder_test.go +++ b/core/http_client_builder_test.go @@ -1,7 +1,15 @@ package core import ( + "context" + "fmt" + "io" + "io/ioutil" + "log" + "net" "net/http" + "os" + "strings" "testing" "time" @@ -159,6 +167,152 @@ func (t *HTTPClientBuilderTest) Test_RestoreDefault() { assert.Equal(t.T(), http.DefaultTransport, DefaultTransport) } +// Test_ClientMocksWorking is supposed to test mocking functionality of generated client. +// Using real HTTP requests and server doesn't look good obviously, but mocking something to check how +// mocks are working doesn't look that good too. +// In this case we are trying to test this in just-like-real environment, without mocks or etc. +// Fake "real" environment is easiest way to do this. +// You know how to make this test better? Let us know. +func (t *HTTPClientBuilderTest) Test_ClientMocksWorking() { + mockProto := "https://" + mockServerAddr := getOutboundIP().String() + ":27717" + mockDomainAddr := "example.com" + certFileData := `-----BEGIN CERTIFICATE----- +MIIC+TCCAeGgAwIBAgIJAPb0Qm9aV+93MA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV +BAMMCGFwaV9tb2NrMB4XDTE5MTAxNzE0NDMzMloXDTI5MTAxNDE0NDMzMlowEzER +MA8GA1UEAwwIYXBpX21vY2swggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCtxUg6aUBcZLjEYEgzzE+B8wAsyK6dT9fbbDfO/5n9PhHjxQLnjTYrs9xAAl7R +Caj8nUg0RzfX38jD1TGwkFrC1u1pjOf74OVMXsw2xa7gmZlnJeeL+QozXQX1rDPk +wO5QqomKAIwM3ab+i6k1tLBfDIOHGLhTEFQZ9cmKVuNdTlkeqBh+bKduRIr7DYhQ +Dsci/PacGJlt0W+r2YuRmm1KGearbS4HabPOkC0c6KbVD+bUyF+F7DxtJ8vg7O4W +SWAXlwoEHonIyJG8H7TQxL2g5w/4UQhp6awAzFNLhqtf/6pw6gPfI9joS+Z/Pxvz +Bry41s4LV7KP8v0GqRK3KH2rAgMBAAGjUDBOMB0GA1UdDgQWBBTEiHl+R8N0kLwH +1RTsKYe8joAwxzAfBgNVHSMEGDAWgBTEiHl+R8N0kLwH1RTsKYe8joAwxzAMBgNV +HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAo/XBUFlrl5yuQ+5eFQjMmbn4T +9qVg4NVRy5qnTKzcOR21X3fB394TvfBiGstW0YQCOCtNakv94UAbZozYktQaYOtP +x5porosgI2RgOTTwmiYOcYQTS2650jYydHhK16Gu2b3UKernO16mAWXNDWfvS2bk +1ufbRWpuUXs0SIR6e/mgSwrBMBvq6fan4EVdEkx4Catjna15DgmBGRL215t5K4aq +nAI2GL2ACEdOCyRvgq16AycJJYU7nYQ+t9aveefx0uhbYYIVeYub9NxmCfD3MojI +saG/63vo0ng851n90DVoMRWx9n1CjEvss/vvz+jXIl9njaCtizN3WUf1NwUB +-----END CERTIFICATE-----` + keyFileData := `-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEArcVIOmlAXGS4xGBIM8xPgfMALMiunU/X22w3zv+Z/T4R48UC +5402K7PcQAJe0Qmo/J1INEc319/Iw9UxsJBawtbtaYzn++DlTF7MNsWu4JmZZyXn +i/kKM10F9awz5MDuUKqJigCMDN2m/oupNbSwXwyDhxi4UxBUGfXJilbjXU5ZHqgY +fmynbkSK+w2IUA7HIvz2nBiZbdFvq9mLkZptShnmq20uB2mzzpAtHOim1Q/m1Mhf +hew8bSfL4OzuFklgF5cKBB6JyMiRvB+00MS9oOcP+FEIaemsAMxTS4arX/+qcOoD +3yPY6Evmfz8b8wa8uNbOC1eyj/L9BqkStyh9qwIDAQABAoIBAG/jNUyW9KAJIocf +T546kX8kzhoH5ZbZEC3ykkSwg6Bx1OcJtYMOg7DEEK8OV6rVQ3/Ubedra+ON7iFa +JrJ/YFFQPnHWDpE6D6qK54bk5mMrw4CNAXg5FH5aCTpUdN139HrwM7st+v9VwO7p +UjyIaX/p+M6F9jlVrDFC91Ah/ifW+DzWS27IsQ/396HTvTUNgD/Lj9pKtC6eW3AQ +aTpLk/cVrkxxT1qc4rx8NRPe9/670CQDQYMvaNJtC54kRUzH87mn06IEy5fuLeI4 +WwYgEIkh1YjQsJhg3Z788JGKR5iKuzjXpw7aD6QESISoWPW1Dh/5PJO1zkKxZril +xUepcgECgYEA5MLP4oCiuloShhaMc+UMYgH8YuglXegGbF5/iG9d7kgaiz4KiXuD +ObwaHegLDFNSxtVSiH6AsXErzd7HHojzTm6B3O5qtBl+QgpW9hiTyJnCxkdzxK7y +cVan8Jp3g/ojcYBY+QgZlR81QHQIwSUrAbMC0fjYlrKb5zJfExgFv4ECgYEAwnY7 +MUoLsHs2eXVOekvb42ReCq7HKVz8TETlSEPN4B5XzOKCnXxCUUvF5iWjWj0XAMSU +yF6LJmmfFmOaVHpXDHhF9MmNKxYiIISS+ZM6B2DXP+hS/DXXuy5hGmYO6p4JC08d +qulIIR7JSJmHyI+5Ref40WTObJvJQDXi2p5a0ysCgYBjdONG2aBmHrUBARqtZH7e +uXhOVBmy2ya3xNnzql+PMl//+8g+/6kM1+AO8oyjHjLV6XcJit5OxyJBTkMJ3obR +qa/iKvHPPWosMiyesA7IXzlUVUpaz6juZ7t6Gt4tTfpM5X1JQCFHORtA23HW717k +TTzDp0obMqofeUHmnkIZgQKBgFBaGktblUjvIKs/VZYjElD7gABaB+GHkpjRPwyF +N+SLpSv7zIzWc3C0Jqnak40OARtIH1JL/qN4sUvHDFYr1xxH9mAXiEVtd9yH61NF +Co1R7p9xmBivBt1JZMZLtY4sjwAlSNT+X9ePqQxepESzXpMMLzwWs1UdaiMmIP7E +wDLRAoGAM/Cz7B+J7KcKI8VqXAsX5nMklIKvACScKU6oIPwNYXyxUfm7jsNaBqXG +weywTxDl/OD5ybNkZIRKsIXciFYG1VCGO2HNGN9qJcV+nJ63kyrIBauwUkuEhiN5 +uf/TQPpjrGW5nxOf94qn6FzV2WSype9BcM5MD7z7rk202Fs7Zqc= +-----END RSA PRIVATE KEY-----` + + certFile, err := ioutil.TempFile("/tmp", "cert_") + require.NoError(t.T(), err, "cannot create temp cert file") + keyFile, err := ioutil.TempFile("/tmp", "key_") + require.NoError(t.T(), err, "cannot create temp key file") + + _, err = certFile.WriteString(certFileData) + require.NoError(t.T(), err, "cannot write temp cert file") + _, err = keyFile.WriteString(keyFileData) + require.NoError(t.T(), err, "cannot write temp key file") + require.NoError(t.T(), + ErrorCollector(certFile.Sync(), certFile.Close()), "cannot sync and close temp cert file") + require.NoError(t.T(), + ErrorCollector(keyFile.Sync(), keyFile.Close()), "cannot sync and close temp key file") + + mux := &http.ServeMux{} + srv := &http.Server{Addr: mockServerAddr, Handler: mux} + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusCreated) + _, err := io.WriteString(w, "ok") + require.NoError(t.T(), err, "cannot response properly") + }) + + testSkipChan := make(chan error, 1) + go func(skip chan error) { + if err := srv.ListenAndServeTLS(certFile.Name(), keyFile.Name()); err != nil && err != http.ErrServerClosed { + skip <- fmt.Errorf("skipping test because server won't start: %s", err.Error()) + } + }(testSkipChan) + + select { + case errStartup := <-testSkipChan: + t.T().Skip(errStartup) + return + case <-time.After(time.Second): + t.T().Log("test server started") + } + + defer func() { + if err := srv.Shutdown(context.TODO()); err != nil { + t.T().Log("warning > cannot shutdown server gracefully: ", err) + } else { + t.T().Log("test server stopped") + } + + if err := os.Remove(certFile.Name()); err != nil { + t.T().Log("warning > cannot remove temp cert file properly: ", err) + } + + if err := os.Remove(keyFile.Name()); err != nil { + t.T().Log("warning > cannot remove temp key file properly: ", err) + } + }() + + client, err := NewHTTPClientBuilder(). + SetLogging(true). + SetMockAddress(mockServerAddr). + SetMockedDomains([]string{mockDomainAddr}). + SetTimeout(time.Second). + SetSSLVerification(false). + Build() + require.NoError(t.T(), err, "cannot build client") + + resp, err := client.Get(mockProto + mockDomainAddr) + if err != nil && strings.Contains(err.Error(), "connection refused") { + t.T().Skip("connection refused - skipping test: ", err) + } + require.NoError(t.T(), err, "error while making request") + + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + require.NoError(t.T(), err, "error while reading body") + + assert.Equal(t.T(), http.StatusCreated, resp.StatusCode, "invalid status code") + assert.Equal(t.T(), "ok", string(data), "invalid body contents") +} + +// taken from https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go +func getOutboundIP() net.IP { + conn, err := net.Dial("udp", "8.8.8.8:80") + if err != nil { + log.Fatal(err) + } + defer conn.Close() + + localAddr := conn.LocalAddr().(*net.UDPAddr) + + return localAddr.IP +} + func Test_HTTPClientBuilder(t *testing.T) { suite.Run(t, new(HTTPClientBuilderTest)) }