Skip to content

Commit

Permalink
test: add test harness and integration tests (#16)
Browse files Browse the repository at this point in the history
* test: add test harness and integration tests

* chore: bump k3s

* chore: switch over to minikube

* chore: use docker

* chore: change command

* chore: change command

* chore: increase wait times and remove old tests

* chore: remove step
  • Loading branch information
kleyow authored Dec 2, 2021
1 parent 6ae9796 commit 683739c
Show file tree
Hide file tree
Showing 47 changed files with 15,416 additions and 148 deletions.
67 changes: 67 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Publish image

on:
# The build will run on all of the following event types. Semver tagged images will be published
# for a release. A long sha image will be published for every push.
release:
types: [published]
push:
branches:
- '**'

jobs:
main:
runs-on: ubuntu-latest
steps:
-
name: Docker meta
id: docker_meta
uses: docker/metadata-action@v3
with:
# Except for Dockerhub, which is the default, tags need to have the registry name in
# them, e.g. ghcr.io for Github container registry, or gcr.io for Google container
# registry.
# Note that the generated tags will look like:
# ghcr.io/{owner}/{repo}:version
images: ghcr.io/${{ github.repository }}
# For a release v1.2.3, we'll produce the following image tags
# v1.2.3
# 1.2.3
# 1.2
# latest
# For non-releases, we'll produce a long sha
flavor: |
latest=${{ github.event_name == 'release' }}
tags: |
type=match,pattern=v\d+\.\d+\.\d+,enable=${{ github.event_name == 'release' }}
type=match,pattern=v(\d+\.\d+\.\d+),enable=${{ github.event_name == 'release' }},group=1
type=match,pattern=v(\d+\.\d+)\.\d+,enable=${{ github.event_name == 'release' }},group=1
type=match,pattern=v(\d+)\.\d+\.\d+,group=1,enable=${{ !startsWith(github.ref, 'refs/tags/v0.') && github.event_name == 'release' }}
type=sha,event=push,value={{sha}},format=long,enable=${{ github.event_name != 'release' }}
labels: |
org.opencontainers.image.source=https://github.com/${{ github.repository }}/tree/${{ github.sha }}
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Login to GitHub Container Registry
if: ${{ github.event_name != 'pull_request' }}
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
-
name: Build and push
id: docker_build
uses: docker/build-push-action@v2.2.1
with:
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
-
name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
109 changes: 109 additions & 0 deletions .github/workflows/integration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: Integration test

on:
push:
branches:
- '**'

jobs:
manifest_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.3.4
- uses: cachix/install-nix-action@v13
with:
nix_path: nixpkgs=https://github.com/NixOS/nixpkgs/archive/8e4fe32876ca15e3d5eb3ecd3ca0b224417f5f17.tar.gz
- name: Install dependencies in environment
run: nix-env -if integration_test/default.nix
- name: Validate integration test manifest
run: kustomize build integration_test | kubeconform -strict -kubernetes-version 1.21.5

integration_test:
timeout-minutes: 45
needs: manifest_check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- uses: cachix/install-nix-action@v13
with:
nix_path: nixpkgs=https://github.com/NixOS/nixpkgs/archive/8e4fe32876ca15e3d5eb3ecd3ca0b224417f5f17.tar.gz

- name: Install dependencies
run: nix-env -if integration_test/default.nix
- name: Install helm
run: sudo snap install helm --classic

- name: Start cluster
run: minikube start --driver=docker --kubernetes-version=v1.21.5

- name: Install Mojaloop Charts
run: helm repo add mojaloop-charts http://docs.mojaloop.io/charts/repo

- name: Install BizOps Backend
run: helm upgrade --install backend mojaloop-charts/backend --devel -f integration_test/chart_values/backend.yaml

- name: Install BizOps Services
run: helm upgrade --install bof mojaloop-charts/bof --devel -f integration_test/chart_values/bof.yaml

- name: Deploy
run: skaffold run -p integration-test

- name: Wait for kube api server to process and create all resources
# This is because the wait step that follows this one does this:
# 1. retrieve list of pods
# 2. wait for list of pods
# Unfortunately, the list of pods might not be complete at step (1), as all pods may not yet
# be created, meaning the list of pods waited on in step (2) is not complete. We therefore
# wait some time here to allow that to finish before we retrieve the list of pods to wait on.
# 30s should be more than enough.
run: sleep 30s

- name: Wait for deployment readiness
# Skaffold is supposed to do this, but for whatever reason, does not. At the time of writing,
# investigating this was not a priority.
run: timeout 900 kubectl wait --for=condition=Ready pod --all --timeout=900s

- name: Migrate Keto
run: kubectl exec --namespace default $(kubectl get pod -l app.kubernetes.io/name=keto -o jsonpath="{.items[0].metadata.name}") -- sh -c "keto migrate up -y --all-namespaces --config /etc/config/keto.yaml"

- name: Port-forward the portal frontend ingress
run: kubectl port-forward -n ingress-nginx --address 0.0.0.0 svc/ingress-nginx-controller 3000:80 &

- name: Install test dependencies
working-directory: integration_test/tests
run: |-
npm ci
- name: Run tests
working-directory: integration_test/tests
run: |-
ROLE_MICROFRONTEND_ENDPOINT="http://localhost:3000" npm run test:headless
- name: Archive test report
if: ${{ always() }}
uses: actions/upload-artifact@v2
with:
name: test-report
path: integration_test/tests/report.html

- name: Print docker containers to check any issues with the cluster
if: ${{ failure() }}
run: docker ps

- name: Print voodoo doll logs
if: ${{ always() }}
run: kubectl logs voodoo-doll

- name: Print resources
if: ${{ always() }}
run: kubectl get svc,deploy,sts,pv,pvc,configmap,job,pod -A

- name: Describe resources
if: ${{ always() }}
run: kubectl describe svc,deploy,sts,pv,pvc,configmap,job,pod -A

- name: Print secret values
if: ${{ always() }}
run: |-
kubectl get secrets -o json | jq -r '.items[] | { name: .metadata.name, data: .data | map_values(@base64d) }'
55 changes: 0 additions & 55 deletions .github/workflows/node.js.yml

This file was deleted.

3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ npm-debug.log
.idea

.editor-config
package-lock.json
yarn-error.log
.env
report.html
4 changes: 4 additions & 0 deletions integration_test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# prevents the result of:
# kustomize build . -o output
# from being committed
output
118 changes: 118 additions & 0 deletions integration_test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
### E2E UI tests

#### Structure
We aim to use page models. These are a simple abstraction of the UI to reduce duplication in the
tests and speed UI and corresponding test refactoring. Not all tests use page models at the time of
writing, but all new tests should. The rule you should use is this: if you find yourself writing a
selector, you should instead use an existing page model (and extend it if necessary), or if none
exists for your current test, create a page model and place your selector there.

References for those unfamiliar with page models:
- https://testcafe.io/documentation/402826/guides/concepts/page-model#why-use-page-model
- https://github.com/SeleniumHQ/selenium/wiki/PageObjects
- https://martinfowler.com/bliki/PageObject.html

### Setup

#### Get a Kubernetes cluster

Kubernetes 1.17 to 1.21 should work. You'll probably want at least four cores and 8gb mem. This is
left as an exercise for the reader. Some suggestions:
1. [Minikube](https://minikube.sigs.k8s.io/docs/)
2. [k3d](https://k3d.io/)
3. [KinD](https://kind.sigs.k8s.io/docs/)
4. [DigitalOcean](https://www.digitalocean.com/products/kubernetes/)

#### Install application dependencies
You have two choices here: [with Nix](#with-nix) and [without Nix](#without-nix). The advantages of
using Nix here are:
1. Exactly the same versions of dependencies as CI, and other developers (except core system things
like the kernel/container runtime).
2. Therefore, no need to track and manage dependency versions, simply run one command to get all
required dependencies at the correct versions, and enter a shell with those dependencies.

##### With Nix
1. Install nix:
```sh
curl -L https://nixos.org/nix/install | sh -s -- --no-daemon
```
(From: https://nixos.org/manual/nix/stable/#sect-single-user-installation)
2. Navigate to the `integration_test` directory of this project
3. Run `nix-shell` to be dropped into a shell containing all necessary dependencies

##### Without Nix
Install the following:
- Google Chrome (it's possible to use another browser, see [run tests with a different browser](#with-a-different-browser))
- Skaffold v1.28.0 or greater: https://github.com/GoogleContainerTools/skaffold/releases
- Kustomize v4.0.5 or greater: https://github.com/kubernetes-sigs/kustomize/releases
- A recent version of kubectl
#### Deploy Mojaloop and dependencies to cluster
In the project root:
```sh
skaffold run -p backend
```
You'll need to wait a few minutes until the wso2is-populate job has completed. You can view its status
with:
```sh
kubectl get jobs
```
When it's completed, it'll look like this:
```
NAME COMPLETIONS DURATION AGE
wso2is-populate 1/1 2m35s 6h26m
```
Specifically, `COMPLETIONS` will be `1/1`

#### Port-forward the ingress and support service
```sh
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 8000:80
kubectl port-forward voodoo-doll 3030
```

#### Build and run the portal
From the project root:
```sh
yarn install
yarn start
```

#### Install integration test npm dependencies
In the `integration_test/tests` directory:
```sh
npm ci
```

### Run tests
In the `integration_test/tests` directory:
```sh
npm run test
```

#### View results
In the `integration_test/tests` directory:
```sh
$BROWSER results.html
```

#### Run a single test
```sh
npm run test -- -t 'name of test'
```
E.g., for one of the login tests:
```sh
npm run test -- -t 'Log in with valid credentials'
```

#### With a different browser
```sh
BROWSER_TCAFE=chromium npm run test
# or
BROWSER_TCAFE=firefox npm run test
```

### Clean up
In the project root:
```sh
skaffold delete -p backend
```
Loading

0 comments on commit 683739c

Please sign in to comment.