Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement integration tests #61

Merged
merged 27 commits into from
Apr 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 56 additions & 52 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ language: go
dist: xenial

services:
- docker
- docker

addons:
apt:
packages:
- docker-ce
- apt-cacher-ng
- docker-ce
- apt-cacher-ng

cache:
directories:
Expand All @@ -21,12 +21,12 @@ cache:
- /var/cache/apt-cacher-ng

os:
- linux
- linux

go:
# When changing, remember to update MAIN_GO_VERSION below.
- "1.13.5"
- master
# When changing, remember to update MAIN_GO_VERSION below.
- "1.13.5"
- master

env:
global:
Expand All @@ -41,60 +41,64 @@ env:
- IMAGE_NAME="iov1/bnsapi:${BUILD_VERSION}"

install:
- wget --quiet https://github.com/tendermint/tendermint/releases/download/${TM_VERSION}/tendermint_${TM_VERSION}_linux_amd64.zip -O tendermint_linux_amd64.zip &&
unzip tendermint_linux_amd64.zip &&
sudo install -D -m 777 -o root tendermint /usr/local/bin
- wget --quiet https://github.com/swaggo/swag/releases/download/v1.6.5/swag_1.6.5_Linux_i386.tar.gz -O swag_linux_amd64.zip &&
tar -xvzf swag_linux_amd64.zip;
sudo install -D -m 777 -o root swag /usr/local/bin
- wget --quiet https://github.com/tendermint/tendermint/releases/download/${TM_VERSION}/tendermint_${TM_VERSION}_linux_amd64.zip -O tendermint_linux_amd64.zip &&
unzip tendermint_linux_amd64.zip &&
sudo install -D -m 777 -o root tendermint /usr/local/bin
- wget --quiet https://github.com/swaggo/swag/releases/download/v1.6.5/swag_1.6.5_Linux_i386.tar.gz -O swag_linux_amd64.zip &&
tar -xvzf swag_linux_amd64.zip;
sudo install -D -m 777 -o root swag /usr/local/bin

script:
- set -eo pipefail
# TODO uncomment when bnsd is imported
# - make protolint
# - make protodocs
- make swaggerdocs
- make install
- make all
# - if [[ "$TRAVIS_GO_VERSION" == "$MAIN_GO_VERSION" ]]; then
# make cover;
# ./coverage/upload.sh;
# fi;
- printenv TRAVIS_COMMIT_MESSAGE > commit.msg
- unset TRAVIS_COMMIT_MESSAGE && printenv | grep -Ev "PATH|path|GEM" > env.list
- export TRAVIS_COMMIT_MESSAGE=`cat commit.msg` && rm -rf commit.msg
# - docker run -it --rm --env-file env.list -v "$(pwd):/usr/src/app" iov1ops/danger:latest > danger.out; cat danger.out
- if [[ "$TRAVIS_GO_VERSION" == "$MAIN_GO_VERSION" && "$TRAVIS_OS_NAME" == "linux" ]]; then
release_latest=$( [[ "$TRAVIS_BRANCH" == "master" && "$TRAVIS_TAG" == "" && "$TRAVIS_PULL_REQUEST_BRANCH" == "" ]] && echo "yes" || echo "no" );
release_tag=$( [[ "$TRAVIS_TAG" != "" ]] && echo "yes" || echo "no" );

if [[ $release_latest == "yes" || $release_tag == "yes" ]]; then
make dist;
fi;
- set -eo pipefail
# TODO uncomment when bnsd is imported
# - make protolint
# - make protodocs
- make swaggerdocs
- make install
- make all
# - if [[ "$TRAVIS_GO_VERSION" == "$MAIN_GO_VERSION" ]]; then
# make cover;
# ./coverage/upload.sh;
# fi;
- printenv TRAVIS_COMMIT_MESSAGE > commit.msg
- unset TRAVIS_COMMIT_MESSAGE && printenv | grep -Ev "PATH|path|GEM" > env.list
- export TRAVIS_COMMIT_MESSAGE=`cat commit.msg` && rm -rf commit.msg
# - docker run -it --rm --env-file env.list -v "$(pwd):/usr/src/app" iov1ops/danger:latest > danger.out; cat danger.out
- if [[ "$TRAVIS_GO_VERSION" == "$MAIN_GO_VERSION" && "$TRAVIS_OS_NAME" == "linux" ]]; then
release_latest=$( [[ "$TRAVIS_BRANCH" == "master" && "$TRAVIS_TAG" == "" && "$TRAVIS_PULL_REQUEST_BRANCH" == "" ]] && echo "yes" || echo "no" );
release_tag=$( [[ "$TRAVIS_TAG" != "" ]] && echo "yes" || echo "no" );

if [[ $release_latest == "yes" ]]; then
echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin;
docker tag "iov1/bnsapi:${BUILD_VERSION}" "iov1/bnsapi:latest" ;
docker push "iov1/bnsapi:latest";
docker logout;
fi;
if [[ $release_latest == "yes" || $release_tag == "yes" ]]; then
make dist;
fi;

if [[ $release_tag == "yes" ]]; then
echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin;
docker tag "iov1/bnsapi:${BUILD_VERSION}" "iov1/bnsapi:$TRAVIS_TAG" ;
docker push "iov1/bnsapi:$TRAVIS_TAG";
docker logout;
if [[ -z "$IT_TENDERMINT" ]]; then
(cd cmd/bnsapi; make it-test);
fi;

if [[ $release_latest == "yes" ]]; then
echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin;
docker tag "iov1/bnsapi:${BUILD_VERSION}" "iov1/bnsapi:latest" ;
docker push "iov1/bnsapi:latest";
docker logout;
fi;

if [[ $release_tag == "yes" ]]; then
echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin;
docker tag "iov1/bnsapi:${BUILD_VERSION}" "iov1/bnsapi:$TRAVIS_TAG" ;
docker push "iov1/bnsapi:$TRAVIS_TAG";
docker logout;
fi;
fi;
fi;

notifications:
email: false

# whitelist long living branches to avoid testing feature branches twice (as branch and as pull request)
branches:
only:
- master
- /^v[0-9]+\.[0-9]+\.x$/
- /^v[0-9]+\.[0-9]+\.[0-9]+$/
# milestone releases
- weave-v0.21.x
- master
- /^v[0-9]+\.[0-9]+\.x$/
- /^v[0-9]+\.[0-9]+\.[0-9]+$/
# milestone releases
- weave-v0.21.x
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ test:
# go install -mod=readonly ./cmd/bnscli # TODO uncomment when bnsd/bnscli is imported

go vet -mod=readonly ./...
go test -mod=readonly -race ./...
go test -mod=readonly -race -short ./...

lint:
@go mod vendor
Expand Down
5 changes: 4 additions & 1 deletion cmd/bnsapi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ image:
docker build --pull -t $(IMAGE_NAME) .

test:
go test -mod=readonly -race ./...
go test -mod=readonly -race -short ./...

it-test:
go test -mod=readonly -run Integration ./...

run:
go run .
Expand Down
5 changes: 5 additions & 0 deletions cmd/bnsapi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ To see documentation:
- `go mod vendor`
- `swag init -parseVendor`

## Integration tests

- Set environment value `IT_TENDERMINT` to the address of the network to test against
- run `make it-test`

## Development

Make sure to enable `export GO111MODULE=on`
113 changes: 95 additions & 18 deletions cmd/bnsapi/bnsapitest/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,28 @@ package bnsapitest
import (
"bytes"
"context"
"encoding/hex"
"encoding/binary"
"encoding/json"
"fmt"
"github.com/iov-one/bns/cmd/bnsapi/client"
md "github.com/iov-one/bns/cmd/bnsapi/models"
"github.com/iov-one/bns/cmd/bnsapi/util"
"github.com/iov-one/weave"
"github.com/iov-one/weave/app"
rpctypes "github.com/tendermint/tendermint/rpc/lib/types"
"io"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"strings"
"testing"
)

func NewAbciQueryResponse(t testing.TB, keys [][]byte, models []weave.Persistent) client.AbciQueryResponse {
func NewAbciQueryResponse(t testing.TB, keys [][]byte, m []weave.Persistent) md.AbciQueryResponse {
t.Helper()
k, v := util.SerializePairs(t, keys, models)
k, v := SerializePairs(t, keys, m)

return client.AbciQueryResponse{
Response: client.AbciQueryResponseResponse{
return md.AbciQueryResponse{
Response: md.AbciQueryResponseResponse{
Key: k,
Value: v,
},
Expand Down Expand Up @@ -72,16 +74,16 @@ func removeTabs(b []byte) []byte {
func TestBnsClientMock(t *testing.T) {
// Just to be sure, test the mock.

result := client.AbciQueryResponse{
Response: client.AbciQueryResponseResponse{
result := md.AbciQueryResponse{
Response: md.AbciQueryResponseResponse{
Key: []byte("foo"),
Value: []byte("bar"),
},
}
bns := BnsClientMock{GetResults: map[string]client.AbciQueryResponse{
bns := BnsClientMock{GetResults: map[string]md.AbciQueryResponse{
"/foo": result,
}}
var response client.AbciQueryResponse
var response md.AbciQueryResponse
if err := bns.Get(context.Background(), "/foo", &response); err != nil {
t.Fatal(err)
}
Expand All @@ -91,8 +93,8 @@ func TestBnsClientMock(t *testing.T) {
}

type BnsClientMock struct {
GetResults map[string]client.AbciQueryResponse
PostResults map[string]map[string]client.AbciQueryResponse
GetResults map[string]md.AbciQueryResponse
PostResults map[string]map[string]md.AbciQueryResponse
Err error
}

Expand All @@ -118,18 +120,31 @@ func (mock *BnsClientMock) Get(ctx context.Context, path string, dest interface{
return mock.Err
}

func (mock *BnsClientMock) Post(ctx context.Context, path string, data []byte, dest interface{}) error {
func (mock *BnsClientMock) Post(ctx context.Context, data []byte, dest interface{}) error {
var req rpctypes.RPCRequest
err := json.Unmarshal(data, &req)
if err != nil {
return err
}

type params struct {
Path string `json:"path"`
Data string `json:"data"`
}

var p params
_ = json.Unmarshal(req.Params, &p)

select {
case <-ctx.Done():
return ctx.Err()
default:
}

hexData := strings.ToUpper(hex.EncodeToString(data))
resp, ok := mock.PostResults[path][hexData]
resp, ok := mock.PostResults[p.Path][p.Data]
if !ok {
raw, _ := url.PathUnescape(path)
return fmt.Errorf("no result declared in mock for %q %q (%q)", path, hexData, raw)
raw, _ := url.PathUnescape(p.Path)
return fmt.Errorf("no result declared in mock for %q %q (%q)", p.Path, p.Data, raw)
}

v := reflect.ValueOf(dest)
Expand All @@ -140,3 +155,65 @@ func (mock *BnsClientMock) Post(ctx context.Context, path string, data []byte, d

return mock.Err
}

func AssertAPIResponseBasic(t testing.TB, want, got io.Reader) {
t.Helper()

var w json.RawMessage
if err := json.NewDecoder(want).Decode(&w); err != nil {
t.Fatalf("cannot decode JSON serialized body: %s", err)
}
var g json.RawMessage
if err := json.NewDecoder(got).Decode(&g); err != nil {
t.Fatalf("cannot decode JSON serialized body: %s", err)
}

w1, _ := json.MarshalIndent(w, "", " ")
g1, _ := json.MarshalIndent(g, "", " ")

if !bytes.Equal(w1, g1) {
t.Logf("want JSON response:\n%s", w1)
t.Logf("got JSON response:\n%s", g1)
t.Fatal("unexpected response")
}
}

func SerializePairs(t testing.TB, keys [][]byte, models []weave.Persistent) ([]byte, []byte) {
t.Helper()

if len(keys) != len(models) {
t.Fatalf("keys and models length must be the same: %d != %d", len(keys), len(models))
}

kset := app.ResultSet{
Results: keys,
}
kraw, err := kset.Marshal()
if err != nil {
t.Fatalf("cannot marshal keys: %s", err)
}

var values [][]byte
for i, m := range models {
raw, err := m.Marshal()
if err != nil {
t.Fatalf("cannot marshal %d model: %s", i, err)
}
values = append(values, raw)
}
vset := app.ResultSet{
Results: values,
}
vraw, err := vset.Marshal()
if err != nil {
t.Fatalf("cannot marshal values: %s", err)
}

return kraw, vraw
}

func SequenceID(n uint64) []byte {
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, n)
return b
}
Loading