From 9f66925676bf11a321de2015476cb459464c22ed Mon Sep 17 00:00:00 2001 From: Ben Marini Date: Mon, 6 Nov 2017 09:53:44 -0800 Subject: [PATCH] fix(test): fix flakey tests due to race conditions --- dsl/broker_test.go | 56 ++++++++++++++++++++++++++------------------- dsl/pact_test.go | 11 +++++---- dsl/publish_test.go | 19 ++++++++------- 3 files changed, 49 insertions(+), 37 deletions(-) diff --git a/dsl/broker_test.go b/dsl/broker_test.go index 456755289..5e59823ef 100644 --- a/dsl/broker_test.go +++ b/dsl/broker_test.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "net/http" + "net/http/httptest" "testing" "github.com/pact-foundation/pact-go/types" @@ -11,9 +12,10 @@ import ( ) func TestPact_findConsumersNoTags(t *testing.T) { - port := setupMockBroker(false) + s := setupMockBroker(false) + defer s.Close() request := types.VerifyRequest{ - BrokerURL: fmt.Sprintf("http://localhost:%d", port), + BrokerURL: s.URL, } err := findConsumers("bobby", &request) if err != nil { @@ -24,17 +26,18 @@ func TestPact_findConsumersNoTags(t *testing.T) { t.Fatalf("Expected 2 PactURLs but got: %d", len(request.PactURLs)) } - pactURL := fmt.Sprintf("http://localhost:%d/pacts/provider/bobby/consumer/jessica/version/2.0.0", port) + pactURL := fmt.Sprintf("%s/pacts/provider/bobby/consumer/jessica/version/2.0.0", s.URL) if request.PactURLs[0] != pactURL && request.PactURLs[1] != pactURL { t.Fatalf("Expected '%s', but got '%s'", pactURL, request.PactURLs[0]) } } func TestPact_findConsumersWithTags(t *testing.T) { - port := setupMockBroker(false) + s := setupMockBroker(false) + defer s.Close() request := types.VerifyRequest{ Tags: []string{"dev", "prod"}, - BrokerURL: fmt.Sprintf("http://localhost:%d", port), + BrokerURL: s.URL, } err := findConsumers("bobby", &request) if err != nil { @@ -45,7 +48,7 @@ func TestPact_findConsumersWithTags(t *testing.T) { t.Fatalf("Expected 2 PactURLs but got: %d", len(request.PactURLs)) } - pactURL := fmt.Sprintf("http://localhost:%d/pacts/provider/bobby/consumer/billy/version/1.0.1", port) + pactURL := fmt.Sprintf("%s/pacts/provider/bobby/consumer/billy/version/1.0.1", s.URL) if request.PactURLs[0] != pactURL && request.PactURLs[1] != pactURL { t.Fatalf("Expected '%s', but got '%s'", pactURL, request.PactURLs[0]) } @@ -65,10 +68,11 @@ func TestPact_findConsumersBrokerDown(t *testing.T) { } func TestPact_findConsumersInvalidResponse(t *testing.T) { - port := setupMockBroker(false) + s := setupMockBroker(false) + defer s.Close() request := types.VerifyRequest{ Tags: []string{"broken"}, - BrokerURL: fmt.Sprintf("http://localhost:%d", port), + BrokerURL: s.URL, } err := findConsumers("bobby", &request) @@ -89,10 +93,11 @@ func TestPact_findConsumersInvalidURL(t *testing.T) { } func TestPact_findConsumersErrorResponse(t *testing.T) { - port := setupMockBroker(false) + s := setupMockBroker(false) + defer s.Close() request := types.VerifyRequest{ Tags: []string{"dev"}, - BrokerURL: fmt.Sprintf("http://localhost:%d", port), + BrokerURL: s.URL, } err := findConsumers("broken", &request) @@ -102,10 +107,11 @@ func TestPact_findConsumersErrorResponse(t *testing.T) { } func TestPact_findConsumersNoConsumers(t *testing.T) { - port := setupMockBroker(false) + s := setupMockBroker(false) + defer s.Close() request := types.VerifyRequest{ Tags: []string{"dev", "prod"}, - BrokerURL: fmt.Sprintf("http://localhost:%d", port), + BrokerURL: s.URL, } err := findConsumers("idontexist", &request) if err == nil { @@ -114,10 +120,11 @@ func TestPact_findConsumersNoConsumers(t *testing.T) { } func TestPact_findConsumersAuthenticated(t *testing.T) { - port := setupMockBroker(true) + s := setupMockBroker(true) + defer s.Close() request := types.VerifyRequest{ Tags: []string{"dev", "prod"}, - BrokerURL: fmt.Sprintf("http://localhost:%d", port), + BrokerURL: s.URL, BrokerUsername: "foo", BrokerPassword: "bar", } @@ -128,10 +135,11 @@ func TestPact_findConsumersAuthenticated(t *testing.T) { } func TestPact_findConsumersAuthenticatedFail(t *testing.T) { - port := setupMockBroker(true) + s := setupMockBroker(true) + defer s.Close() request := types.VerifyRequest{ Tags: []string{"dev", "prod"}, - BrokerURL: fmt.Sprintf("http://localhost:%d", port), + BrokerURL: s.URL, } err := findConsumers("bobby", &request) @@ -143,8 +151,7 @@ func TestPact_findConsumersAuthenticatedFail(t *testing.T) { } // Pretend to be a Broker for fetching Pacts -func setupMockBroker(auth bool) int { - port, _ := utils.GetFreePort() +func setupMockBroker(auth bool) *httptest.Server { mux := http.NewServeMux() var authFunc func(inner http.HandlerFunc) http.HandlerFunc @@ -173,11 +180,13 @@ func setupMockBroker(auth bool) int { } } + server := httptest.NewServer(mux) + // Find latest 'bobby' consumers (no tag) // curl --user pactuser:pact -H "accept: application/hal+json" "http://pact.onegeek.com.au/pacts/provider/bobby/latest" mux.HandleFunc("/pacts/provider/bobby/latest", authFunc(func(w http.ResponseWriter, req *http.Request) { log.Println("[DEBUG] get pacts for provider 'bobby'") - fmt.Fprintf(w, `{"_links":{"self":{"href":"http://localhost:%d/pacts/provider/bobby/latest","title":"Latest pact versions for the provider bobby"},"provider":{"href":"http://localhost:%d/pacticipants/bobby","title":"bobby"},"pacts":[{"href":"http://localhost:%d/pacts/provider/bobby/consumer/jessica/version/2.0.0","title":"Pact between jessica (v2.0.0) and bobby","name":"jessica"},{"href":"http://localhost:%d/pacts/provider/bobby/consumer/billy/version/1.0.0","title":"Pact between billy (v1.0.0) and bobby","name":"billy"}]}}`, port, port, port, port) + fmt.Fprintf(w, `{"_links":{"self":{"href":"%s/pacts/provider/bobby/latest","title":"Latest pact versions for the provider bobby"},"provider":{"href":"%s/pacticipants/bobby","title":"bobby"},"pacts":[{"href":"%s/pacts/provider/bobby/consumer/jessica/version/2.0.0","title":"Pact between jessica (v2.0.0) and bobby","name":"jessica"},{"href":"%s/pacts/provider/bobby/consumer/billy/version/1.0.0","title":"Pact between billy (v1.0.0) and bobby","name":"billy"}]}}`, server.URL, server.URL, server.URL, server.URL) w.Header().Add("Content-Type", "application/hal+json") })) @@ -185,7 +194,7 @@ func setupMockBroker(auth bool) int { // curl --user pactuser:pact -H "accept: application/hal+json" "http://pact.onegeek.com.au/pacts/provider/bobby/latest/sit4" mux.Handle("/pacts/provider/bobby/latest/prod", authFunc(func(w http.ResponseWriter, req *http.Request) { log.Println("[DEBUG] get all pacts for provider 'bobby' where the tag 'prod' exists") - fmt.Fprintf(w, `{"_links":{"self":{"href":"http://localhost:%d/pacts/provider/bobby/latest/dev","title":"Latest pact versions for the provider bobby with tag 'dev'"},"provider":{"href":"http://localhost:%d/pacticipants/bobby","title":"bobby"},"pacts":[{"href":"http://localhost:%d/pacts/provider/bobby/consumer/billy/version/1.0.0","title":"Pact between billy (v1.0.0) and bobby","name":"billy"}]}}`, port, port, port) + fmt.Fprintf(w, `{"_links":{"self":{"href":"%s/pacts/provider/bobby/latest/dev","title":"Latest pact versions for the provider bobby with tag 'dev'"},"provider":{"href":"%s/pacticipants/bobby","title":"bobby"},"pacts":[{"href":"%s/pacts/provider/bobby/consumer/billy/version/1.0.0","title":"Pact between billy (v1.0.0) and bobby","name":"billy"}]}}`, server.URL, server.URL, server.URL) w.Header().Add("Content-Type", "application/hal+json") })) @@ -208,7 +217,7 @@ func setupMockBroker(auth bool) int { // curl --user pactuser:pact -H "accept: application/hal+json" "http://pact.onegeek.com.au/pacts/provider/bobby/latest/sit4" mux.Handle("/pacts/provider/bobby/latest/dev", authFunc(func(w http.ResponseWriter, req *http.Request) { log.Println("[DEBUG] get all pacts for provider 'bobby' where the tag 'dev' exists") - fmt.Fprintf(w, `{"_links":{"self":{"href":"http://localhost:%d/pacts/provider/bobby/latest/dev","title":"Latest pact versions for the provider bobby with tag 'dev'"},"provider":{"href":"http://localhost:%d/pacticipants/bobby","title":"bobby"},"pacts":[{"href":"http://localhost:%d/pacts/provider/bobby/consumer/billy/version/1.0.1","title":"Pact between billy (v1.0.1) and bobby","name":"billy"}]}}`, port, port, port) + fmt.Fprintf(w, `{"_links":{"self":{"href":"%s/pacts/provider/bobby/latest/dev","title":"Latest pact versions for the provider bobby with tag 'dev'"},"provider":{"href":"%s/pacticipants/bobby","title":"bobby"},"pacts":[{"href":"%s/pacts/provider/bobby/consumer/billy/version/1.0.1","title":"Pact between billy (v1.0.1) and bobby","name":"billy"}]}}`, server.URL, server.URL, server.URL) w.Header().Add("Content-Type", "application/hal+json") })) @@ -216,10 +225,9 @@ func setupMockBroker(auth bool) int { // curl -v --user pactuser:pact -H "accept: application/json" http://pact.onegeek.com.au/pacts/provider/bobby/consumer/billy/version/1.0.0 mux.Handle("/pacts/provider/bobby/consumer/billy/version/", authFunc(func(w http.ResponseWriter, req *http.Request) { log.Println("[DEBUG] get all pacts for provider 'bobby' where any tag exists") - fmt.Fprintf(w, `{"consumer":{"name":"billy"},"provider":{"name":"bobby"},"interactions":[{"description":"Some name for the test","provider_state":"Some state","request":{"method":"GET","path":"/foobar"},"response":{"status":200,"headers":{"Content-Type":"application/json"}}},{"description":"Some name for the test","provider_state":"Some state2","request":{"method":"GET","path":"/bazbat"},"response":{"status":200,"headers":{},"body":[[{"colour":"red","size":10,"tag":[["jumper","shirt"],["jumper","shirt"]]}]],"matchingRules":{"$.body":{"min":1},"$.body[*].*":{"match":"type"},"$.body[*]":{"min":1},"$.body[*][*].*":{"match":"type"},"$.body[*][*].colour":{"match":"regex","regex":"red|green|blue"},"$.body[*][*].size":{"match":"type"},"$.body[*][*].tag":{"min":2},"$.body[*][*].tag[*].*":{"match":"type"},"$.body[*][*].tag[*][0]":{"match":"type"},"$.body[*][*].tag[*][1]":{"match":"type"}}}}],"metadata":{"pactSpecificationVersion":"2.0.0"},"updatedAt":"2016-06-11T13:11:33+00:00","createdAt":"2016-06-09T12:46:42+00:00","_links":{"self":{"title":"Pact","name":"Pact between billy (v1.0.0) and bobby","href":"http://localhost:%d/pacts/provider/bobby/consumer/billy/version/1.0.0"},"pb:consumer":{"title":"Consumer","name":"billy","href":"http://localhost:%d/pacticipants/billy"},"pb:provider":{"title":"Provider","name":"bobby","href":"http://localhost:%d/pacticipants/bobby"},"pb:latest-pact-version":{"title":"Pact","name":"Latest version of this pact","href":"http://localhost:%d/pacts/provider/bobby/consumer/billy/latest"},"pb:previous-distinct":{"title":"Pact","name":"Previous distinct version of this pact","href":"http://localhost:%d/pacts/provider/bobby/consumer/billy/version/1.0.0/previous-distinct"},"pb:diff-previous-distinct":{"title":"Diff","name":"Diff with previous distinct version of this pact","href":"http://localhost:%d/pacts/provider/bobby/consumer/billy/version/1.0.0/diff/previous-distinct"},"pb:pact-webhooks":{"title":"Webhooks for the pact between billy and bobby","href":"http://localhost:%d/webhooks/provider/bobby/consumer/billy"},"pb:tag-prod-version":{"title":"Tag this version as 'production'","href":"http://localhost:%d/pacticipants/billy/versions/1.0.0/tags/prod"},"pb:tag-version":{"title":"Tag version","href":"http://localhost:%d/pacticipants/billy/versions/1.0.0/tags/{tag}"},"curies":[{"name":"pb","href":"http://localhost:%d/doc/{rel}","templated":true}]}}`, port, port, port, port, port, port, port, port, port, port) + fmt.Fprintf(w, `{"consumer":{"name":"billy"},"provider":{"name":"bobby"},"interactions":[{"description":"Some name for the test","provider_state":"Some state","request":{"method":"GET","path":"/foobar"},"response":{"status":200,"headers":{"Content-Type":"application/json"}}},{"description":"Some name for the test","provider_state":"Some state2","request":{"method":"GET","path":"/bazbat"},"response":{"status":200,"headers":{},"body":[[{"colour":"red","size":10,"tag":[["jumper","shirt"],["jumper","shirt"]]}]],"matchingRules":{"$.body":{"min":1},"$.body[*].*":{"match":"type"},"$.body[*]":{"min":1},"$.body[*][*].*":{"match":"type"},"$.body[*][*].colour":{"match":"regex","regex":"red|green|blue"},"$.body[*][*].size":{"match":"type"},"$.body[*][*].tag":{"min":2},"$.body[*][*].tag[*].*":{"match":"type"},"$.body[*][*].tag[*][0]":{"match":"type"},"$.body[*][*].tag[*][1]":{"match":"type"}}}}],"metadata":{"pactSpecificationVersion":"2.0.0"},"updatedAt":"2016-06-11T13:11:33+00:00","createdAt":"2016-06-09T12:46:42+00:00","_links":{"self":{"title":"Pact","name":"Pact between billy (v1.0.0) and bobby","href":"%s/pacts/provider/bobby/consumer/billy/version/1.0.0"},"pb:consumer":{"title":"Consumer","name":"billy","href":"%s/pacticipants/billy"},"pb:provider":{"title":"Provider","name":"bobby","href":"%s/pacticipants/bobby"},"pb:latest-pact-version":{"title":"Pact","name":"Latest version of this pact","href":"%s/pacts/provider/bobby/consumer/billy/latest"},"pb:previous-distinct":{"title":"Pact","name":"Previous distinct version of this pact","href":"%s/pacts/provider/bobby/consumer/billy/version/1.0.0/previous-distinct"},"pb:diff-previous-distinct":{"title":"Diff","name":"Diff with previous distinct version of this pact","href":"%s/pacts/provider/bobby/consumer/billy/version/1.0.0/diff/previous-distinct"},"pb:pact-webhooks":{"title":"Webhooks for the pact between billy and bobby","href":"%s/webhooks/provider/bobby/consumer/billy"},"pb:tag-prod-version":{"title":"Tag this version as 'production'","href":"%s/pacticipants/billy/versions/1.0.0/tags/prod"},"pb:tag-version":{"title":"Tag version","href":"%s/pacticipants/billy/versions/1.0.0/tags/{tag}"},"curies":[{"name":"pb","href":"%s/doc/{rel}","templated":true}]}}`, server.URL, server.URL, server.URL, server.URL, server.URL, server.URL, server.URL, server.URL, server.URL, server.URL) w.Header().Add("Content-Type", "application/hal+json") })) - go http.ListenAndServe(fmt.Sprintf(":%d", port), mux) - return port + return server } diff --git a/dsl/pact_test.go b/dsl/pact_test.go index b1fcfa92f..b5d73f991 100644 --- a/dsl/pact_test.go +++ b/dsl/pact_test.go @@ -1,7 +1,6 @@ package dsl import ( - "fmt" "io/ioutil" "log" "os" @@ -283,7 +282,8 @@ func TestPact_VerifyProvider(t *testing.T) { } func TestPact_VerifyProviderBroker(t *testing.T) { - brokerPort := setupMockBroker(false) + s := setupMockBroker(false) + defer s.Close() old := waitForPort defer func() { waitForPort = old }() waitForPort = func(int, string, string, string) error { @@ -296,7 +296,7 @@ func TestPact_VerifyProviderBroker(t *testing.T) { pact := &Pact{Port: port, LogLevel: "DEBUG", pactClient: &PactClient{Port: port}, Provider: "bobby"} err := pact.VerifyProvider(types.VerifyRequest{ ProviderBaseURL: "http://www.foo.com", - BrokerURL: fmt.Sprintf("http://localhost:%d", brokerPort), + BrokerURL: s.URL, PublishVerificationResults: true, ProviderVersion: "1.0.0", }) @@ -307,7 +307,8 @@ func TestPact_VerifyProviderBroker(t *testing.T) { } func TestPact_VerifyProviderBrokerNoConsumers(t *testing.T) { - brokerPort := setupMockBroker(false) + s := setupMockBroker(false) + defer s.Close() old := waitForPort defer func() { waitForPort = old }() waitForPort = func(int, string, string, string) error { @@ -320,7 +321,7 @@ func TestPact_VerifyProviderBrokerNoConsumers(t *testing.T) { pact := &Pact{Port: port, LogLevel: "DEBUG", pactClient: &PactClient{Port: port}, Provider: "providernotexist"} err := pact.VerifyProvider(types.VerifyRequest{ ProviderBaseURL: "http://www.foo.com", - BrokerURL: fmt.Sprintf("http://localhost:%d", brokerPort), + BrokerURL: s.URL, }) if err == nil { diff --git a/dsl/publish_test.go b/dsl/publish_test.go index 27945e149..836b7b212 100644 --- a/dsl/publish_test.go +++ b/dsl/publish_test.go @@ -16,14 +16,13 @@ import ( "github.com/pact-foundation/pact-go/utils" ) -func createMockRemoteServer(valid bool) string { +func createMockRemoteServer(valid bool) (*httptest.Server, string) { file := createSimplePact(valid) dir := filepath.Dir(file.Name()) path := filepath.Base(file.Name()) - port, _ := utils.GetFreePort() - go http.ListenAndServe(fmt.Sprintf(":%d", port), http.FileServer(http.Dir(dir))) + server := httptest.NewServer(http.FileServer(http.Dir(dir))) - return fmt.Sprintf("http://localhost:%d/%s", port, path) + return server, fmt.Sprintf("%s/%s", server.URL, path) } func createSimplePact(valid bool) *os.File { @@ -250,7 +249,8 @@ func TestPublish_readLocalPactFileFail(t *testing.T) { func TestPublish_readRemotePactFile(t *testing.T) { p := &Publisher{request: types.PublishRequest{}} - url := createMockRemoteServer(true) + s, url := createMockRemoteServer(true) + defer s.Close() f, _, err := p.readRemotePactFile(url) @@ -269,7 +269,8 @@ func TestPublish_readRemotePactFile(t *testing.T) { func TestPublish_readRemotePactFileFail(t *testing.T) { p := &Publisher{request: types.PublishRequest{}} - url := createMockRemoteServer(false) + s, url := createMockRemoteServer(false) + defer s.Close() _, _, err := p.readRemotePactFile(url) @@ -285,7 +286,8 @@ func TestPublish_readRemotePactFileFail(t *testing.T) { func TestPublish_readPactFile(t *testing.T) { p := &Publisher{request: types.PublishRequest{}} - url := createMockRemoteServer(true) + s, url := createMockRemoteServer(true) + defer s.Close() f, _, err := p.readPactFile(url) @@ -319,7 +321,8 @@ func TestPublish_readPactFile(t *testing.T) { func TestPublish_readPactFileFail(t *testing.T) { p := &Publisher{request: types.PublishRequest{}} - url := createMockRemoteServer(false) + s, url := createMockRemoteServer(false) + defer s.Close() _, _, err := p.readPactFile(url)