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

test: add integration tests #40

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 7 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ language: python
# this ensures that the pipeline is triggered for internal pushes,
# PRs from forks and pushes to existing PRs from forks
if: (type == push) OR (type == pull_request AND fork == true)

branches:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, this is why it didn't trigger a Travis run. Why did you add that? I think we would like to run tests always, for each PR. If you would like for specific tests (like integration tests), you should make use of different stages or a job matrix, then introduce conditions for branches separately for each stage/job. It should also be possible to use conditions on the exact commands, but the syntax is not great and it can quickly become unreadable for more complicated files. In any case, I don't see a good reason why we should not run the Travis CI for all PRs as well, the tests should be fast enough...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(so I would just remove this block again unless there is a convincing reason to keep it)

only:
- master
- dev

stages:
- name: test
Expand All @@ -27,6 +30,9 @@ jobs:
- flake8
- coverage run --source drs_filer -m pytest
- coveralls
- docker-compose up --build -d
- sleep 10
- pytest "${TRAVIS_BUILD_DIR}/tests/integration_tests.py"
- <<: *test
python: 3.7
- <<: *test
Expand Down
174 changes: 174 additions & 0 deletions tests/integration_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import json
import requests

base_url = "http://localhost:8080/ga4gh/drs/v1"
data_objects_path = "data_objects.json"
headers = {
'accept': 'application/json',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be Accept with a capital A: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept

'Content-Type': 'application/json'
}
payload_objects = json.dumps({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can some object from "data_objects.json" perhaps be reused here instead of hardcoding another 50 lines of payload in here?

"name": "Homo_sapiens.GRCh38.dna.chromosome.19.fa.gz",
"size": 16700000,
"created_time": "2021-05-04T11:59:56.400Z",
"updated_time": "2021-05-04T11:59:56.400Z",
"version": "38",
"mime_type": "application/json",
"checksums": [
{
"checksum": "18c2f5517e4ddc02cd57f6c7554b8e88",
"type": "md5"
}
],
"access_methods": [
{
"type": "ftp",
"access_url": {
"url": "ftp://ftp.ensembl.org/pub/release-96/fasta/homo_sapien"
"s/dna//Homo_sapiens.GRCh38.dna.chromosome.19.fa.gz",
"headers": [
"None"
]
},
"region": "us-east-1"
},
{
"type": "ftp",
"access_url": {
"url": "ftp://ftp.ensembl.org/pub/release-96/fasta/homo_sapien"
"s/dna//Homo_sapiens.GRCh38.dna.chromosome.19.fa.gz",
"headers": [
"None"
]
},
"region": "us-east-1"
},
],
"contents": [
{
"name": "Homo_sapiens",
"id": "b001",
"drs_uri": [
"drs://drs.example.org/314159",
"drs://drs.example.org/213512"
],
"contents": []
}
],
"description": "description",
"aliases": [
"alias1"
]
})
payload_service_info = json.dumps({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the payload JSON perhaps be externalized so that it can be easily reused and keep this module cleaner? See here, e.g.: https://github.com/elixir-cloud-aai/trs-filer/blob/dev/tests/mock_data.py

"contactUrl": "mailto:[email protected]",
"createdAt": "2019-06-04T12:58:19Z",
"description": "This service provides...",
"documentationUrl": "https://docs.myservice.example.com",
"environment": "test",
"id": "org.ga4gh.myservice",
"name": "My project",
"organization": {
"name": "My organization",
"url": "https://example.com"
},
"type": {
"artifact": "beacon",
"group": "org.ga4gh",
"version": "1.0.0"
},
"updatedAt": "2019-06-04T12:58:19Z",
"version": "1.0.0"
})
access_id = ""
object_id = ""


def test_post_service_info():
"""Test `POST /service-info` for successfully creating or updating a new
service-info.
"""
endpoint = "/service-info"
response = requests.request("POST", base_url + endpoint, headers=headers,
data=payload_service_info)
assert response.status_code == 201


def test_get_service_info():
"""Test `GET /service-info` for fetching service info."""
endpoint = "/service-info"
response = requests.request("GET", base_url + endpoint, headers=headers)
assert response.status_code == 200
assert json.loads(response.content) == json.loads(payload_service_info)


def test_post_objects():
"""Test `POST /objects` for successfully registering an DrsObject."""
global object_id
endpoint = "/objects"
response = requests.request("POST", base_url + endpoint, headers=headers,
data=payload_objects)
object_id = response.text.replace("\"", "").replace("\n", "")
assert response.status_code == 200


def test_get_objects():
"""Test `GET /objects/{object_id}` for fetching info about DrsObject."""
global access_id
is_expand = "True"
endpoint = "/objects/" + object_id + "?expand=" + is_expand
response = requests.request("GET", base_url + endpoint, headers=headers)
response_content = json.loads(response.text)
access_id = response_content['access_methods'][0]['access_id']
assert response.status_code == 200
assert response_content['name'] == json.loads(payload_objects)['name']


def test_get_objects_access():
"""Test `GET /objects/{object_id}/access/{access_id}` for fetching URL to
fetch the bytes of a DrsObject
"""
endpoint = "/objects/" + object_id + "/access/" + access_id
response = requests.request("GET", base_url + endpoint, headers=headers)
response_content = json.loads(response.text)
assert response.status_code == 200
assert response_content['url'] == \
json.loads(payload_objects)['access_methods'][0]['access_url']['url']


def test_put_objects():
"""Test `PUT /objects/{object_id}` to modify or update a DrsObject"""
global access_id
endpoint = "/objects/" + object_id
object_put_payload = json.loads(payload_objects)
object_put_payload['name'] = "gerp_constrained_elements.tetraodon_" + \
"nigroviridis.bed.gz"
response = requests.request("PUT", base_url + endpoint, headers=headers,
data=json.dumps(object_put_payload))
assert response.status_code == 200
is_expand = "True"
endpoint = "/objects/" + object_id + "?expand=" + is_expand
response = requests.request("GET", base_url + endpoint, headers=headers)
response_content = json.loads(response.text)
access_id = response_content['access_methods'][0]['access_id']
assert response.status_code == 200
assert response_content['name'] == \
"gerp_constrained_elements.tetraodon_nigroviridis.bed.gz"


def test_delete_objects_access():
"""Test `DELETE /objects/{object_id}/access/{access_id}` to delete
DrsObject's access method.
"""
endpoint = "/objects/" + object_id + "/access/" + access_id
response = requests.request("DELETE", base_url + endpoint, headers=headers)
assert response.status_code == 200
assert response.text.replace("\"", "").replace("\n", "") == access_id


def test_delete_objects():
"""Test `DELETE /objects/{object_id}` to delete existing DrsObject"""
endpoint = "/objects/" + object_id
response = requests.request("DELETE", base_url + endpoint, headers=headers)
assert response.status_code == 200
assert response.text.replace("\"", "").replace("\n", "") == object_id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to add test cases for some errors as well, especially 404 and 400. Eventually we should cover 401 and 403 as well, but we can do that once we have a better idea of how controlled access management will look like