Skip to content
This repository has been archived by the owner on Jan 29, 2025. It is now read-only.

Commit

Permalink
Added in new v3 API tests (to be hooked up in CI later).
Browse files Browse the repository at this point in the history
Updated CircleCI job to run v1 API tests in their new location
  • Loading branch information
chartjes committed Mar 26, 2020
1 parent 9400fdc commit 00df637
Show file tree
Hide file tree
Showing 29 changed files with 773 additions and 38 deletions.
32 changes: 2 additions & 30 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
# Use an in-memory database so that the migrations check doesn't try to access a real database
DATABASE_URL: "sqlite://:memory:"
# Ignore warning and info checks about not applying migrations, and about missing geoip database
DJANGO_SILENCED_SYSTEM_CHECKS: "dockerflow.health.W001,normandy.recipes.I001,normandy.recipes.I002,normandy.recipes.I003,normandy.recipes.E006"
DJANGO_SILENCED_SYSTEM_CHECKS: "dockerflow.health.W001,normandy.recipes.I00,normandy.recipes.I002,normandy.recipes.I003,normandy.recipes.E006"

working_directory: ~/repo

Expand Down Expand Up @@ -193,28 +193,6 @@ jobs:
- store_artifacts:
path: test-reports

js-tests:
docker:
- image: mozilla/cidockerbases:firefox-latest

steps:
- checkout
- run:
name: Install node dependencies
command: yarn install --frozen-lockfile
- run:
name: JS tests
environment:
JUNIT_REPORT_PATH: ./junit/
JUNIT_REPORT_NAME: test-results.xml
command: |
mkdir -p $JUNIT_REPORT_PATH
yarn karma start ./karma.conf.js --single-run
- store_test_results:
path: test-reports
- store_artifacts:
path: test-reports

contract-tests:
docker:
- image: circleci/python:3.7-node-browsers
Expand Down Expand Up @@ -272,7 +250,7 @@ jobs:
name: Contract tests
command: |
mkdir test-reports
py.test contract-tests \
py.test contract-tests/v1_api/ \
--tb=short -vvv \
--junitxml=test-reports/junit.xml \
--server http://localhost:8000
Expand All @@ -292,10 +270,6 @@ workflows:
filters:
tags:
only: /.*/
- js-tests:
filters:
tags:
only: /.*/
- lint:
filters:
tags:
Expand Down Expand Up @@ -335,9 +309,7 @@ workflows:
- docker-image-publish:
requires:
- python-tests
- js-tests
- contract-tests
- js-tests
- lint
- docker-image-build-save
filters:
Expand Down
5 changes: 5 additions & 0 deletions contract-tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# Configuration file for running contract-tests
import os
import pytest
import requests
import sys
import urllib3

# Disable any warnings about SSL connections
urllib3.disable_warnings()

# Fix our path so our tests can see modules inside Normandy
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


def pytest_addoption(parser):
parser.addoption(
Expand Down
File renamed without changes.
File renamed without changes.
30 changes: 26 additions & 4 deletions contract-tests/v3_api/conftest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
import urllib3

# Disable any warnings about SSL connections
urllib3.disable_warnings()
import pytest
import subprocess

from faker import Faker


@pytest.fixture(scope="session")
def headers():
# Create a test user
fake = Faker()
email = fake.company_email()
user = fake.user_name()

# Add them as a superuser to the system running in Docker
docker_compose = (
subprocess.check_output("which docker-compose", shell=True).decode("ascii").strip("\n")
)
subprocess.call(
"{} run app python manage.py createsuperuser --noinput --email={} --user={}".format(
docker_compose, email, user
),
shell=True,
)

# Return the authorization header that we need
return {"Authorization": "Insecure {}".format(email)}
73 changes: 73 additions & 0 deletions contract-tests/v3_api/support/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import urllib3
import uuid

from faker import Faker
from urllib.parse import urljoin


def approve_approval_request(requests_session, server, approval_id, headers):
return requests_session.post(
urljoin(server, "/api/v3/approval_request/{}/approve/".format(approval_id)),
data={"comment": "r+"},
headers=headers,
)


def create_approval_request(requests_session, server, latest_revision_id, headers):
return requests_session.post(
urljoin(server, "/api/v3/recipe_revision/{}/request_approval/".format(latest_revision_id)),
headers=headers,
)


def create_new_user(requests_session, server, headers):
# Get a list of groups and grab the ID of the first one
response = requests_session.get(urljoin(server, "/api/v3/group/"), headers=headers)
group_id = response.json()["results"][0]["id"]
group_name = response.json()["results"][0]["name"]
fake = Faker()

# Create a user, assigning them to the group we obtained
user_data = {
"first_name": fake.first_name(),
"last_name": fake.last_name(),
"email": fake.company_email(),
"groups": {"id": group_id, "name": group_name},
}
response = requests_session.post(
urljoin(server, "/api/v3/user/"), headers=headers, data=user_data
)

return {
"id": response.json()["id"],
"first_name": response.json()["first_name"],
"last_name": response.json()["last_name"],
"group_id": group_id,
}


def enable_recipe(requests_session, server, recipe_id, headers):
return requests_session.post(
urljoin(server, "/api/v3/recipe/{}/enable/".format(recipe_id)), headers=headers
)


def new_recipe(requests_session, action_id, server, headers):
urllib3.disable_warnings()

# Create a recipe
recipe_data = {
"action_id": action_id,
"arguments": '{"learnMoreMessage":"This field may not be blank.","learnMoreUrl":"This field may not be blank.","message":"This field may not be blank.","postAnswerUrl":"This field may not be blank.","surveyId":"'
+ str(uuid.uuid4())
+ '","thanksMessage":"This field may not be blank."}',
"name": "test recipe",
"extra_filter_expression": "counter == 0",
"enabled": "false",
}

response = requests_session.post(
urljoin(server, "/api/v3/recipe/"), data=recipe_data, headers=headers
)
data = response.json()
return {"id": data["id"], "latest_revision_id": data["latest_revision"]["id"]}
60 changes: 60 additions & 0 deletions contract-tests/v3_api/test_approval_request.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from support.helpers import new_recipe
from support.assertions import assert_valid_schema
from urllib.parse import urljoin


def test_approval_request(conf, requests_session, headers):
# Get a list of actions and pick the first one
action_response = requests_session.get(
urljoin(conf.getoption("server"), "/api/v3/action/"), headers=headers
)
data = action_response.json()
action_id = data["results"][0]["id"]

# Then create an approval request and submit it
recipe_details = new_recipe(requests_session, action_id, conf.getoption("server"), headers)
response = requests_session.post(
urljoin(
conf.getoption("server"),
"/api/v3/recipe_revision/{}/request_approval/".format(
recipe_details["latest_revision_id"]
),
),
headers=headers,
)
data = response.json()
approval_id = data["id"]
approver_email = data["creator"]["email"]
assert response.status_code != 404
assert_valid_schema(response.json())

# Verify that the request was actually created
response = requests_session.get(
urljoin(conf.getoption("server"), "/api/v3/approval_request/{}".format(approval_id))
)
data = response.json()
assert response.status_code != 404
assert_valid_schema(response.json())
assert data["id"] == approval_id
assert data["creator"]["email"] == approver_email

# Approve the approval request
response = requests_session.post(
urljoin(
conf.getoption("server"), "/api/v3/approval_request/{}/approve/".format(approval_id)
),
data={"comment": "r+"},
headers=headers,
)
assert response.status_code != 404
assert_valid_schema(response.json())

# Look at the recipe and make sure that the recipe has been approved and our comment shows up
response = requests_session.get(
urljoin(conf.getoption("server"), "/api/v3/recipe/{}".format(recipe_details["id"]))
)
assert response.status_code not in (404, 500)
assert_valid_schema(response.json())
approval_request = response.json()["latest_revision"]["approval_request"]
assert approval_request["approved"] is True
assert approval_request["comment"] == "r+"
46 changes: 46 additions & 0 deletions contract-tests/v3_api/test_approval_request_close.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from support.assertions import assert_valid_schema
from support.helpers import new_recipe
from urllib.parse import urljoin


def test_approval_request_close(conf, requests_session, headers):
# Get an action we can work with
action_response = requests_session.get(
urljoin(conf.getoption("server"), "/api/v3/action/"), headers=headers
)
data = action_response.json()
action_id = data["results"][0]["id"]

# Create a recipe
recipe_details = new_recipe(requests_session, action_id, conf.getoption("server"), headers)

# Create an approval request
response = requests_session.post(
urljoin(
conf.getoption("server"),
"/api/v3/recipe_revision/{}/request_approval/".format(
recipe_details["latest_revision_id"]
),
),
headers=headers,
)
data = response.json()
approval_id = data["id"]
assert response.status_code != 404
assert_valid_schema(response.json())

# Close the approval request
response = requests_session.post(
urljoin(
conf.getoption("server"), "/api/v3/approval_request/{}/close/".format(approval_id)
),
headers=headers,
)
assert response.status_code == 204

# Verify that is no longer exists
response = requests_session.get(
urljoin(conf.getoption("server"), "/api/v3/approval_request/{}/".format(approval_id)),
headers=headers,
)
assert response.status_code == 404
51 changes: 51 additions & 0 deletions contract-tests/v3_api/test_approval_request_reject.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from support.assertions import assert_valid_schema
from support.helpers import new_recipe
from urllib.parse import urljoin


def test_approval_request_reject(conf, requests_session, headers):
# Get an action we can work with
action_response = requests_session.get(
urljoin(conf.getoption("server"), "/api/v3/action/"), headers=headers
)
data = action_response.json()
action_id = data["results"][0]["id"]

# Create a recipe associated with that action
recipe_details = new_recipe(requests_session, action_id, conf.getoption("server"), headers)

# Create a approval request
response = requests_session.post(
urljoin(
conf.getoption("server"),
"/api/v3/recipe_revision/{}/request_approval/".format(
recipe_details["latest_revision_id"]
),
),
headers=headers,
)
data = response.json()
approval_id = data["id"]
assert response.status_code != 404
assert_valid_schema(response.json())

# Reject the approval
response = requests_session.post(
urljoin(
conf.getoption("server"), "/api/v3/approval_request/{}/reject/".format(approval_id)
),
data={"comment": "r-"},
headers=headers,
)
assert response.status_code == 200
assert_valid_schema(response.json())

# Look at the recipe and make sure it the approval status has been set to False and our comment shows up
response = requests_session.get(
urljoin(conf.getoption("server"), "/api/v3/recipe/{}/".format(recipe_details["id"]))
)
assert response.status_code != 404
assert_valid_schema(response.json())
approval_request = response.json()["latest_revision"]["approval_request"]
assert approval_request["approved"] is False
assert approval_request["comment"] == "r-"
25 changes: 25 additions & 0 deletions contract-tests/v3_api/test_group_create.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import uuid

from support.assertions import assert_valid_schema
from urllib.parse import urljoin


def test_group_create(conf, requests_session, headers):
# Create a new group
data = {"name": str(uuid.uuid4())}
response = requests_session.post(
urljoin(conf.getoption("server"), "/api/v3/group/"), headers=headers, data=data
)
assert response.status_code == 201
assert_valid_schema(response.json())
group_data = response.json()
group_id = group_data["id"]

# Verify group was stored and contains expected data
response = requests_session.get(
urljoin(conf.getoption("server"), "/api/v3/group/{}/".format(group_id)), headers=headers
)
group_data = response.json()
assert response.status_code == 200
assert_valid_schema(response.json())
assert group_data["id"] == group_id
Loading

0 comments on commit 00df637

Please sign in to comment.