Skip to content
This repository has been archived by the owner on Mar 11, 2021. It is now read-only.

Commit

Permalink
contract-tests: Add contract tests for consuming fabric8-auth service. (
Browse files Browse the repository at this point in the history
  • Loading branch information
pmacik authored and MatousJobanek committed May 2, 2019
1 parent 8c48499 commit 959c198
Show file tree
Hide file tree
Showing 11 changed files with 611 additions and 0 deletions.
34 changes: 34 additions & 0 deletions .make/test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,40 @@ test-integration-no-coverage: prebuild-check migrate-database $(SOURCES)
$(eval TEST_PACKAGES:=$(shell go list ./... | grep -v $(ALL_PKGS_EXCLUDE_PATTERN)))
F8_DEVELOPER_MODE_ENABLED=1 F8_RESOURCE_DATABASE=1 F8_RESOURCE_UNIT_TEST=0 F8_POSTGRES_DATABASE=postgres go test $(TEST_FLAGS) $(TEST_PACKAGES)

.PHONY: test-contracts-consumer-no-coverage
## Runs the consumer side of contract tests WITHOUT producing coverage files for each package.
test-contracts-consumer-no-coverage:
$(call log-info,"Running test: $@")
$(eval TEST_PACKAGES:=$(shell go list ./... | grep -e 'contracts/consumer'))
$(eval PACT_DIR=$(TMP_PATH)/test/contracts/pacts)
PACT_DIR=$(PACT_DIR) \
go test $(GO_TEST_VERBOSITY_FLAG) -count=1 $(TEST_PACKAGES)

.PHONY: publish-contract-testing-pacts-to-broker
## Publishes generated Pact file (the contracts) to the Pact broker.
## The following env variables needs to be set in environment:
## - Pact broker for storing pact files
## PACT_BROKER_URL
## PACT_BROKER_USERNAME
## PACT_BROKER_PASSWORD
publish-contract-testing-pacts-to-broker:
$(call log-info,"Publishing pact files to Broker")
$(eval PACT_DIR=$(TMP_PATH)/test/contracts/pacts)
$(eval PACT_FILES:=$(shell find $(PACT_DIR) -name '*.json'))
$(eval PACT_VERSION?=PR-commit)
$(eval PACT_TAGS?=PR-number)
PACT_DIR=$(PACT_DIR) \
go run ./test/contracts/publisher/main.go "$(PACT_FILES)" "$(PACT_VERSION)" "$(PACT_TAGS)"

CLEAN_TARGETS += clean-contract-tests
.PHONY: clean-contract-tests
## Cleans generated pacts and logs from contract tests
clean-contract-tests:
$(call log-info,"Cleaning generated pacts and logs from contract tests")
$(eval PACT_DIR=$(TMP_PATH)/test/contracts/pacts)
$(eval LOGS_TO_BE_CLEANED:=$(shell find $(TMP_PATH)/test/contracts -name '*logs'))
rm -rvf $(PACT_DIR) $(LOGS_TO_BE_CLEANED)

.PHONY: test-remote
## Runs the remote tests and produces coverage files for each package.
test-remote: prebuild-check clean-coverage-remote $(COV_PATH_REMOTE)
Expand Down
5 changes: 5 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ required = [
"github.com/jteeuwen/go-bindata/go-bindata",
"github.com/jstemmer/go-junit-report",
"github.com/wadey/gocovmerge",
"github.com/pact-foundation/pact-go",
]

ignored = [
Expand Down Expand Up @@ -104,6 +105,10 @@ ignored = [
name = "github.com/wadey/gocovmerge"
revision = "master"

[[constraint]]
name = "github.com/pact-foundation/pact-go"
revision = "v1.0.0-beta.3"

[prune]
go-tests = true
unused-packages = true
37 changes: 37 additions & 0 deletions cico_run_contract_tests_consumer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/bash

. cico_setup.sh

CICO_RUN="${CICO_RUN:-true}"
if [ "$CICO_RUN" == "true" ]; then
load_jenkins_vars;
if [ -e "jenkins-env.json" ]; then
eval "$(./env-toolkit load -f jenkins-env.json --regex 'PACT_*')"
fi
install_deps;
fi
make docker-start
make docker-build

DOCKER_CONTAINER_NAME="${BUILD_TAG:-fabric8-tenant-local-build}"

#Ensure Pact CLI is installed
cmd="curl -L -s https://github.com/pact-foundation/pact-ruby-standalone/releases/download/v1.63.0/pact-1.63.0-linux-x86_64.tar.gz -o /tmp/pact-cli.tar.gz \
&& mkdir -p /tmp/pact \
&& tar -xf /tmp/pact-cli.tar.gz --directory /tmp \
&& rm -vf /tmp/pact-cli.tar.gz"
docker exec -t "$DOCKER_CONTAINER_NAME" /bin/bash -ec "$cmd"

# Run the contract tests
cmd="PATH=\$PATH:/tmp/pact/bin GO_TEST_VERBOSITY_FLAG=-v make test-contracts-consumer-no-coverage"
docker exec -t "$DOCKER_CONTAINER_NAME" /bin/bash -ec "$cmd"

# Publish the generated Pact files to Pact broker.
cmd="PATH=\$PATH:/tmp/pact/bin make publish-contract-testing-pacts-to-broker"
docker exec -t \
-e PACT_BROKER_URL=$PACT_BROKER_URL \
-e PACT_BROKER_USERNAME=$PACT_BROKER_USERNAME \
-e PACT_BROKER_PASSWORD=$PACT_BROKER_PASSWORD \
-e PACT_VERSION=${PACT_VERSION:-PR-commit} \
-e PACT_TAGS=${PACT_TAGS:-PR-testing} \
"$DOCKER_CONTAINER_NAME" /bin/bash -ec "$cmd"
4 changes: 4 additions & 0 deletions test/contracts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# For API contract testing
pacts
output
**/*/logs
36 changes: 36 additions & 0 deletions test/contracts/consumer/fabric8auth/api_status_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package fabric8auth_test

import (
"log"
"testing"

contracts_test "github.com/fabric8-services/fabric8-tenant/test/contracts"
consumer_test "github.com/fabric8-services/fabric8-tenant/test/contracts/consumer"
"github.com/pact-foundation/pact-go/dsl"
)

// AuthAPIStatus defines contract of /api/status endpoint
func AuthAPIStatus(t *testing.T, pact *dsl.Pact) {

log.Printf("Invoking AuthAPIStatus now\n")

// Set up our expected interactions.
pact.
AddInteraction().
Given("Auth service is up and running.").
UponReceiving("A request to get status").
WithRequest(dsl.Request{
Method: "GET",
Path: dsl.String("/api/status"),
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/json")},
}).
WillRespondWith(dsl.Response{
Status: 200,
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/vnd.status+json")},
Body: dsl.Match(APIStatusMessage{}),
})

// Verify
err := pact.Verify(consumer_test.SimpleGetInteraction(pact, "/api/status"))
contracts_test.CheckErrorAndCleanPact(t, pact, err) //workaround for https://github.com/pact-foundation/pact-go/issues/108
}
35 changes: 35 additions & 0 deletions test/contracts/consumer/fabric8auth/api_token_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package fabric8auth_test

import (
"log"
"testing"

contracts_test "github.com/fabric8-services/fabric8-tenant/test/contracts"
consumer_test "github.com/fabric8-services/fabric8-tenant/test/contracts/consumer"
"github.com/pact-foundation/pact-go/dsl"
)

// AuthAPITokenKeys defines contract of /api/status endpoint
func AuthAPITokenKeys(t *testing.T, pact *dsl.Pact) {

log.Printf("Invoking AuthAPITokenKeys now\n")

// Set up our expected interactions.
pact.
AddInteraction().
Given("Auth service is up and running.").
UponReceiving("A request to get public keys").
WithRequest(dsl.Request{
Method: "GET",
Path: dsl.String("/api/token/keys"),
}).
WillRespondWith(dsl.Response{
Status: 200,
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/vnd.publickeys+json")},
Body: dsl.Match(TokenKeys{}),
})

// Verify
err := pact.Verify(consumer_test.SimpleGetInteraction(pact, "/api/token/keys"))
contracts_test.CheckErrorAndCleanPact(t, pact, err) //workaround for https://github.com/pact-foundation/pact-go/issues/108
}
166 changes: 166 additions & 0 deletions test/contracts/consumer/fabric8auth/api_user_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package fabric8auth_test

import (
"fmt"
"log"
"testing"

contracts_test "github.com/fabric8-services/fabric8-tenant/test/contracts"
consumer "github.com/fabric8-services/fabric8-tenant/test/contracts/consumer"
"github.com/pact-foundation/pact-go/dsl"
)

// AuthAPIUserByName defines contract of /api/users?filter[username]=<user_name> endpoint
func AuthAPIUserByName(t *testing.T, pact *dsl.Pact, userName string) {

log.Println("Invoking AuthAPIUserByName test interaction now")

// Set up our expected interactions.
pact.
AddInteraction().
Given("User with a given username exists.").
UponReceiving("A request to get user's information by username").
WithRequest(dsl.Request{
Method: "GET",
Path: dsl.String("/api/users"),
Query: dsl.MapMatcher{
"filter[username]": dsl.Term(
userName,
UserNameRegex,
),
},
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/json")},
}).
WillRespondWith(dsl.Response{
Status: 200,
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/vnd.api+json")},
Body: dsl.Match(Users{}),
})

// Verify
err := pact.Verify(consumer.SimpleGetInteraction(pact, fmt.Sprintf("/api/users?filter[username]=%s", userName)))
contracts_test.CheckErrorAndCleanPact(t, pact, err)
}

// AuthAPIUserByID defines contract of /api/users/<user_id> endpoint
func AuthAPIUserByID(t *testing.T, pact *dsl.Pact, userID string) {

log.Printf("Invoking AuthAPIUserByID test interaction now\n")

// Set up our expected interactions.
pact.
AddInteraction().
Given("User with a given ID exists.").
UponReceiving("A request to get user's information by ID").
WithRequest(dsl.Request{
Method: "GET",
Path: dsl.Term(
fmt.Sprintf("/api/users/%s", userID),
fmt.Sprintf("/api/users/%s", UserIDRegex),
),
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/json")},
}).
WillRespondWith(dsl.Response{
Status: 200,
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/vnd.api+json")},
Body: dsl.Match(User{}),
})

// Verify
err := pact.Verify(consumer.SimpleGetInteraction(pact, fmt.Sprintf("/api/users/%s", userID)))
contracts_test.CheckErrorAndCleanPact(t, pact, err) //workaround for https://github.com/pact-foundation/pact-go/issues/108
}

// AuthAPIUserByToken defines contract of /api/user endpoint with valid auth token
// passed as 'Authorization: Bearer ...' header
func AuthAPIUserByToken(t *testing.T, pact *dsl.Pact, userToken string) {

log.Printf("Invoking AuthAPIUserByToken test interaction now\n")

// Pass in test case
// Set up our expected interactions.
pact.
AddInteraction().
Given("A user exists with the given valid token.").
UponReceiving("A request to get user's information with valid auth token ").
WithRequest(dsl.Request{
Method: "GET",
Path: dsl.String("/api/user"),
Headers: dsl.MapMatcher{
"Content-Type": dsl.String("application/json"),
"Authorization": dsl.Term(
fmt.Sprintf("Bearer %s", userToken),
fmt.Sprintf("^Bearer %s$", JWSRegex),
),
},
}).
WillRespondWith(dsl.Response{
Status: 200,
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/vnd.api+json")},
Body: dsl.Match(User{}),
})

// Verify
err := pact.Verify(consumer.SimpleGetInteractionWithToken(pact, "/api/user", userToken))
contracts_test.CheckErrorAndCleanPact(t, pact, err) //workaround for https://github.com/pact-foundation/pact-go/issues/108
}

// AuthAPIUserInvalidToken defines contract of /api/user endpoint with invalid auth token
func AuthAPIUserInvalidToken(t *testing.T, pact *dsl.Pact, invalidToken string) {

log.Printf("Invoking AuthAPIUserInvalidToken test interaction now\n")

// Set up our expected interactions.
pact.
AddInteraction().
Given("No user exists with the given token valid.").
UponReceiving("A request to get user's information with invalid auth token ").
WithRequest(dsl.Request{
Method: "GET",
Path: dsl.String("/api/user"),
Headers: dsl.MapMatcher{
"Content-Type": dsl.String("application/json"),
"Authorization": dsl.Term(
fmt.Sprintf("Bearer %s", invalidToken),
fmt.Sprintf("^Bearer %s$", JWSRegex),
),
},
}).
WillRespondWith(dsl.Response{
Status: 401,
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/vnd.api+json")},
Body: dsl.Match(InvalidTokenMessage{}),
})

// Verify
err := pact.Verify(consumer.SimpleGetInteractionWithToken(pact, "/api/user", invalidToken))
contracts_test.CheckErrorAndCleanPact(t, pact, err) //workaround for https://github.com/pact-foundation/pact-go/issues/108
}

// AuthAPIUserNoToken defines contract of /api/user endpoint with missing auth token
func AuthAPIUserNoToken(t *testing.T, pact *dsl.Pact) {

log.Printf("Invoking AuthAPIUserNoToken test interaction now\n")

// Set up our expected interactions.
pact.
AddInteraction().
Given("Any user exists but no auth token was provided.").
UponReceiving("A request to get user's information with no auth token ").
WithRequest(dsl.Request{
Method: "GET",
Path: dsl.String("/api/user"),
Headers: dsl.MapMatcher{
"Content-Type": dsl.String("application/json"),
},
}).
WillRespondWith(dsl.Response{
Status: 401,
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/vnd.api+json")},
Body: dsl.Match(MissingTokenMessage{}),
})

// Verify
err := pact.Verify(consumer.SimpleGetInteraction(pact, "/api/user"))
contracts_test.CheckErrorAndCleanPact(t, pact, err) //workaround for https://github.com/pact-foundation/pact-go/issues/108
}
Loading

0 comments on commit 959c198

Please sign in to comment.