Merge pull request #1115 from dod-ccpo/ghost-inspector
Initial set up for Ghost Inspector integration tests.
This commit is contained in:
commit
200fa225cc
@ -135,6 +135,67 @@ jobs:
|
||||
- run: "docker tag ${AZURE_SERVER_NAME}/atat:atat-${CIRCLE_SHA1} ${AZURE_SERVER_NAME}/atat:latest"
|
||||
- run: "docker push ${AZURE_SERVER_NAME}/atat:latest"
|
||||
|
||||
integration-tests:
|
||||
docker:
|
||||
- image: docker:17.05.0-ce-git
|
||||
steps:
|
||||
- setup_remote_docker:
|
||||
version: 18.06.0-ce
|
||||
- checkout
|
||||
- run:
|
||||
name: Set up temporary docker network
|
||||
command: docker network create atat
|
||||
- run:
|
||||
name: Build image
|
||||
command: docker build . -t atat:latest
|
||||
- run:
|
||||
name: Get storage containers
|
||||
command: docker pull postgres:latest && docker pull redis:latest
|
||||
- run:
|
||||
name: Start redis
|
||||
command: docker run -d --network atat --link redis:redis -p 6379:6379 --name redis redis:latest
|
||||
- run:
|
||||
name: Start postgres
|
||||
command: docker run -d --network atat --link postgres:postgres -p 5432:5432 --name postgres postgres:latest
|
||||
- run:
|
||||
name: Start application container
|
||||
command: |
|
||||
docker run -d \
|
||||
-e DISABLE_CRL_CHECK=true \
|
||||
-e PGHOST=postgres \
|
||||
-e REDIS_URI=redis://redis:6379 \
|
||||
-p 8000:8000 \
|
||||
--network atat \
|
||||
--name test-atat \
|
||||
atat:latest \
|
||||
uwsgi \
|
||||
--callable app \
|
||||
--module app \
|
||||
--plugin python3 \
|
||||
--virtualenv /opt/atat/atst/.venv \
|
||||
--http-socket :8000
|
||||
- run:
|
||||
name: Wait for containers
|
||||
command: sleep 3
|
||||
- run:
|
||||
name: Create database
|
||||
command: docker exec postgres createdb -U postgres atat
|
||||
- run:
|
||||
name: Apply migrations
|
||||
command: docker exec test-atat .venv/bin/python .venv/bin/alembic upgrade head
|
||||
- run:
|
||||
name: Execute Ghost Inspector test suite
|
||||
command: |
|
||||
docker pull ghostinspector/test-runner-standalone:latest
|
||||
docker run \
|
||||
-e NGROK_TOKEN=$NGROK_TOKEN \
|
||||
-e GI_API_KEY=$GI_API_KEY \
|
||||
-e GI_SUITE=$GI_SUITE \
|
||||
-e GI_PARAMS_JSON='{}' \
|
||||
-e APP_PORT="test-atat:8000" \
|
||||
--network atat \
|
||||
ghostinspector/test-runner-standalone:latest
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
run-tests:
|
||||
@ -143,9 +204,12 @@ workflows:
|
||||
- test:
|
||||
requires:
|
||||
- app_setup
|
||||
- azure-build-and-push-image:
|
||||
- integration-tests:
|
||||
requires:
|
||||
- test
|
||||
- azure-build-and-push-image:
|
||||
requires:
|
||||
- integration-tests
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
@ -204,7 +268,7 @@ workflows:
|
||||
repo: atat
|
||||
tag: "atat-${CIRCLE_SHA1},latest"
|
||||
requires:
|
||||
- test
|
||||
- integration-tests
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -52,10 +52,12 @@ ssl/client-certs/*.srl
|
||||
# je coverage output
|
||||
coverage
|
||||
|
||||
|
||||
# selenium testing
|
||||
# BrowserStack
|
||||
browserstacklocal
|
||||
|
||||
# decompiled CircleCI yaml
|
||||
local-ci.yml
|
||||
|
||||
# python config
|
||||
.python-version
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
"files": "^.secrets.baseline$",
|
||||
"lines": null
|
||||
},
|
||||
"generated_at": "2019-10-03T14:34:50Z",
|
||||
"generated_at": "2019-10-14T19:14:26Z",
|
||||
"plugins_used": [
|
||||
{
|
||||
"base64_limit": 4.5,
|
||||
@ -40,6 +40,13 @@
|
||||
"is_verified": false,
|
||||
"line_number": 156,
|
||||
"type": "Secret Keyword"
|
||||
},
|
||||
{
|
||||
"hashed_secret": "81b127e2222d9bfc4609053faec85300f7525463",
|
||||
"is_secret": false,
|
||||
"is_verified": false,
|
||||
"line_number": 244,
|
||||
"type": "Secret Keyword"
|
||||
}
|
||||
],
|
||||
"alembic.ini": [
|
||||
@ -153,24 +160,6 @@
|
||||
"type": "Private Key"
|
||||
}
|
||||
],
|
||||
"tests/acceptance/conftest.py": [
|
||||
{
|
||||
"hashed_secret": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f",
|
||||
"is_secret": false,
|
||||
"is_verified": false,
|
||||
"line_number": 48,
|
||||
"type": "Basic Auth Credentials"
|
||||
}
|
||||
],
|
||||
"tests/fixtures/chain/make-chain.sh": [
|
||||
{
|
||||
"hashed_secret": "bad2e396920ce37fe53fc291f90b130d915375fb",
|
||||
"is_secret": false,
|
||||
"is_verified": false,
|
||||
"line_number": 35,
|
||||
"type": "Secret Keyword"
|
||||
}
|
||||
],
|
||||
"tests/forms/test_validators.py": [
|
||||
{
|
||||
"hashed_secret": "260408f687da9094705a841acda9b029563053ee",
|
||||
@ -194,7 +183,7 @@
|
||||
"hashed_secret": "e4f14805dfd1e6af030359090c535e149e6b4207",
|
||||
"is_secret": false,
|
||||
"is_verified": false,
|
||||
"line_number": 651,
|
||||
"line_number": 656,
|
||||
"type": "Hex High Entropy String"
|
||||
}
|
||||
]
|
||||
|
37
README.md
37
README.md
@ -220,30 +220,37 @@ To generate coverage reports for the Javascript tests:
|
||||
|
||||
yarn test:coverage
|
||||
|
||||
### Selenium Tests
|
||||
### Ghost Inspector Tests
|
||||
|
||||
Selenium tests rely on BrowserStack. In order to run the Selenium tests
|
||||
locally, you need BrowserStack credentials. The user email and key can
|
||||
be found on the account settings page. To run the selenium tests:
|
||||
AT-AT uses [Ghost Inpsector](https://app.ghostinspector.com/) for
|
||||
integration testing. These tests do not run locally as part of the
|
||||
regular test suite but do run in CI. To run them locally, you will
|
||||
need the following:
|
||||
|
||||
- [docker](https://docs.docker.com/v17.12/install/)
|
||||
- [circleci CLI tool](https://circleci.com/docs/2.0/local-cli/#installation)
|
||||
- the prerequisite variable information listed [here](https://ghostinspector.com/docs/integration/circle-ci/)
|
||||
|
||||
The version of our CircleCI config (2.1) is incompatible with the
|
||||
`circleci` tool. First run:
|
||||
|
||||
```
|
||||
BROWSERSTACK_TOKEN=<token> BROWSERSTACK_EMAIL=<email> ./script/selenium_test
|
||||
circleci config process .circleci/config.yml > local-ci.yml
|
||||
```
|
||||
|
||||
The selenium tests are in `tests/acceptance`. This directory is ignored by
|
||||
pytest for normal test runs.
|
||||
|
||||
The `selenium_test` script manages the setup of a separate database and
|
||||
launching the BrowserStackLocal client. If you already have the client running
|
||||
locally, you can run the selenium tests with:
|
||||
Then run the job:
|
||||
|
||||
```
|
||||
BROWSERSTACK_TOKEN=<token> BROWSERSTACK_EMAIL=<email> pipenv run pytest tests/acceptance
|
||||
circleci local execute -e GI_SUITE=<SUITE_ID> -e GI_API_KEY=<API KEY> -e NGROK_TOKEN=<NGROK TOKEN> --job integration-tests -c local-ci.yml
|
||||
```
|
||||
|
||||
The BrowserStack email is the one associated with the account. The token is
|
||||
available in the BrowserStack profile information page. Go to the dashboard,
|
||||
then "Account" > "Settings", then the token is under "Local Testing".
|
||||
If the job fails and you want to re-run it, you may receive errors
|
||||
about running docker containers or the network already existing.
|
||||
Some version of the following should reset your local docker state:
|
||||
|
||||
```
|
||||
docker container stop redis postgres test-atat; docker container rm redis postgres test-atat ; docker network rm atat
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
BROWSERSTACK_CONFIG = {
|
||||
"win7_ie10": {
|
||||
"browser": "IE",
|
||||
"browser_version": "10.0",
|
||||
"os": "Windows",
|
||||
"os_version": "7",
|
||||
"resolution": "1024x768",
|
||||
"browserstack.local": True,
|
||||
},
|
||||
"win10_chrome62": {
|
||||
"browser": "Chrome",
|
||||
"browser_version": "62.0",
|
||||
"os": "Windows",
|
||||
"os_version": "10",
|
||||
"resolution": "1024x768",
|
||||
"browserstack.local": True,
|
||||
},
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
import os
|
||||
import pytest
|
||||
import logging
|
||||
from collections import Mapping
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
|
||||
|
||||
from .browsers import BROWSERSTACK_CONFIG
|
||||
|
||||
|
||||
@pytest.fixture(scope="function", autouse=True)
|
||||
def session(db, request):
|
||||
"""
|
||||
Override base test session
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class DriverCollection(Mapping):
|
||||
"""
|
||||
Allows access to drivers with dictionary syntax. Keeps track of which ones
|
||||
have already been initialized. Allows teardown of all existing drivers.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._drivers = {}
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._drivers)
|
||||
|
||||
def __len__(self):
|
||||
return len(self._drivers)
|
||||
|
||||
def __getitem__(self, name):
|
||||
if name in self._drivers:
|
||||
return self._drivers[name]
|
||||
|
||||
elif name in BROWSERSTACK_CONFIG:
|
||||
self._drivers[name] = self._build_driver(name)
|
||||
return self._drivers[name]
|
||||
|
||||
else:
|
||||
raise AttributeError("Driver {} not found".format(name))
|
||||
|
||||
def _build_driver(self, config_key):
|
||||
return webdriver.Remote(
|
||||
command_executor="http://{}:{}@hub.browserstack.com:80/wd/hub".format(
|
||||
os.getenv("BROWSERSTACK_EMAIL"), os.getenv("BROWSERSTACK_TOKEN")
|
||||
),
|
||||
desired_capabilities=BROWSERSTACK_CONFIG.get(config_key),
|
||||
)
|
||||
|
||||
def teardown(self):
|
||||
for driver in self._drivers.values():
|
||||
driver.quit()
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def drivers():
|
||||
driver_collection = DriverCollection()
|
||||
|
||||
yield driver_collection
|
||||
|
||||
driver_collection.teardown()
|
@ -1,50 +0,0 @@
|
||||
import pytest
|
||||
import requests
|
||||
from flask import url_for
|
||||
from urllib.parse import urljoin
|
||||
from .browsers import BROWSERSTACK_CONFIG
|
||||
from atst.domain.users import Users
|
||||
import atst.domain.exceptions as exceptions
|
||||
from atst.routes.dev import _DEV_USERS as DEV_USERS
|
||||
from tests.test_auth import _login
|
||||
|
||||
import cryptography.x509 as x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
|
||||
USER_CERT = "ssl/client-certs/atat.mil.crt"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("browser_type", BROWSERSTACK_CONFIG.keys())
|
||||
@pytest.mark.usefixtures("live_server")
|
||||
def test_can_get_title(browser_type, app, drivers):
|
||||
driver = drivers[browser_type]
|
||||
driver.get(url_for("atst.root", _external=True))
|
||||
assert "JEDI" in driver.title
|
||||
|
||||
|
||||
def _get_common_name(cert_path):
|
||||
with open(USER_CERT, "rb") as cert_file:
|
||||
cert = x509.load_pem_x509_certificate(cert_file.read(), default_backend())
|
||||
common_names = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
|
||||
return common_names[0].value
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def valid_user_from_cert():
|
||||
cn = _get_common_name(USER_CERT)
|
||||
cn_parts = cn.split(".")
|
||||
user_info = {
|
||||
"last_name": cn_parts[0],
|
||||
"first_name": cn_parts[1],
|
||||
"dod_id": cn_parts[-1],
|
||||
"atat_role_name": "developer",
|
||||
}
|
||||
return Users.get_or_create_by_dod_id(**user_info)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("live_server")
|
||||
def test_login(drivers, client, app, valid_user_from_cert):
|
||||
driver = drivers["win7_ie10"]
|
||||
driver.get(url_for("dev.login_dev", _external=True))
|
||||
assert "Sign in" not in driver.title
|
Loading…
x
Reference in New Issue
Block a user