-
Jorrit Schaap authoredJorrit Schaap authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
tmss_test_environment_unittest_setup.py 8.45 KiB
#!/usr/bin/env python3
# Copyright (C) 2018 ASTRON (Netherlands Institute for Radio Astronomy)
# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands
#
# This file is part of the LOFAR software suite.
# The LOFAR software suite is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# The LOFAR software suite is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>.
'''
By importing this helper module in your unittest module you get a TMSSTestDatabaseInstance
which is automatically destroyed at the end of the unittest session.
'''
import logging
logger = logging.getLogger(__name__)
# before we import any django modules the DJANGO_SETTINGS_MODULE, TMSS_LDAPCREDENTIALS and TMSS_DBCREDENTIALS need to be known/set.
# import and start an isolated TMSSTestEnvironment (with fresh database and attached django and ldap server on free ports)
# this automagically sets the required DJANGO_SETTINGS_MODULE, TMSS_LDAPCREDENTIALS and TMSS_DBCREDENTIALS envvars.
from lofar.sas.tmss.test.test_utils import TMSSTestEnvironment
tmss_test_env = TMSSTestEnvironment()
try:
tmss_test_env.start()
except:
tmss_test_env.stop()
exit(1)
# tell unittest to stop (and automagically cleanup) the test database once all testing is done.
def tearDownModule():
tmss_test_env.stop()
################################################################################################
# the methods below can be used to to HTTP REST calls to the django server and check the results
################################################################################################
import json
import requests
AUTH = requests.auth.HTTPBasicAuth(tmss_test_env.ldap_server.dbcreds.user, tmss_test_env.ldap_server.dbcreds.password)
BASE_URL = tmss_test_env.django_server.url
OIDC_URL = tmss_test_env.django_server.oidc_url
from lofar.sas.tmss.test.test_utils import assertDataWithUrls
import lofar.sas.tmss.tmss.settings as TMSS_SETTINGS
def _call_API_and_assert_expected_response(test_instance, url, call, data, expected_code, expected_content):
"""
Call API method on the provided url and assert the expected code is returned and the expected content is in the response content
:return: response as dict. This either contains the data of an entry or error details. If JSON cannot be parsed, return string.
"""
if call == 'PUT':
response = requests.put(url, json=data, auth=AUTH)
elif call == 'POST':
response = requests.post(url, json=data, auth=AUTH)
elif call == 'GET':
response = requests.get(url, auth=AUTH)
elif call == 'PATCH':
response = requests.patch(url, json=data, auth=AUTH)
elif call == 'DELETE':
response = requests.delete(url, auth=AUTH)
else:
raise ValueError("The provided call '%s' is not a valid API method choice" % call)
if response.status_code != expected_code:
logger.error("!!! Unexpected: [%s] - %s %s: %s", test_instance.id(), call, url, response.content.decode('utf-8').strip())
test_instance.assertEqual(response.status_code, expected_code)
content = response.content.decode('utf-8')
from django.db import models
if response.status_code in range(200, 300) and expected_content is not None:
r_dict = json.loads(content)
for key, value in expected_content.items():
if key not in r_dict.keys():
logger.error('!!! Missing key: %s in %s', key, r_dict.keys())
test_instance.assertTrue(key in r_dict.keys())
if isinstance(value, models.Model):
value = str(value.pk)
value = value.replace(' ', '%20')
test_instance.assertTrue(str(value) in r_dict[key])
elif type(value) is list:
test_instance.assertEqual(sorted(value), sorted(r_dict[key]), msg="lists differ for key=%s"%key) # compare lists independent of ordering
else:
test_instance.assertEqual(value, r_dict[key])
return r_dict
try:
return json.loads(content)
except:
return content
def PUT_and_assert_expected_response(test_instance, url, data, expected_code, expected_content):
"""
PUT data on url and assert the expected code is returned and the expected content is in the response content
"""
r_dict = _call_API_and_assert_expected_response(test_instance, url, 'PUT', data, expected_code, expected_content)
return r_dict
def POST_and_assert_expected_response(test_instance, url, data, expected_code, expected_content):
"""
POST data on url and assert the expected code is returned and the expected content is in the response content
:return: response dict
"""
r_dict = _call_API_and_assert_expected_response(test_instance, url, 'POST', data, expected_code, expected_content)
return r_dict
def GET_and_assert_equal_expected_code(test_instance, url, expected_code):
"""
GET from url and assert the expected code is returned and the expected content is in the response content
"""
r_dict = _call_API_and_assert_expected_response(test_instance, url, 'GET', {}, expected_code, None)
return r_dict
def GET_and_assert_in_expected_response_result_list(test_instance, url, expected_content, expected_nbr_results):
"""
GET from url and assert the expected code is returned and the expected content is in the response content
Use this check when multiple results (list) are returned
"""
r_dict = _call_API_and_assert_expected_response(test_instance, url, 'GET', {}, 200, None)
page_size = TMSS_SETTINGS.REST_FRAMEWORK.get('PAGE_SIZE')
if page_size is not None and expected_nbr_results > page_size:
logger.warning("Limited result length due to pagination setting (%d)", page_size)
test_instance.assertEqual(page_size, len(r_dict["results"]))
test_instance.assertEqual(page_size, len(r_dict["results"]))
test_instance.assertEqual(expected_nbr_results, r_dict["count"])
test_instance.assertNotEqual(None, r_dict['next'])
url_check = False
else:
test_instance.assertEqual(expected_nbr_results, len(r_dict["results"]))
test_instance.assertEqual(r_dict["count"], len(r_dict["results"]))
test_instance.assertEqual(None, r_dict['next'])
url_check = True
for item in r_dict["results"]:
for key in expected_content.keys():
test_instance.assertIn(key, item.keys())
if url_check:
assertDataWithUrls(test_instance, r_dict['results'][expected_nbr_results-1], expected_content)
return r_dict
def GET_OK_and_assert_equal_expected_response(test_instance, url, expected_content):
"""
GET from url and assert the expected code is returned and the expected content is equal the response content
assertDataWithUrls is already checked in _call_API_and_assert_expected_response
"""
r_dict = _call_API_and_assert_expected_response(test_instance, url, 'GET', {}, 200, expected_content)
# assertDataWithUrls(test_instance, r_dict, expected_content)
return r_dict
def PATCH_and_assert_expected_response(test_instance, url, data, expected_code, expected_content):
"""
POST data on url and assert the provided values have changed based on the server response.
:return: url for new item
"""
r_dict = _call_API_and_assert_expected_response(test_instance, url, 'PATCH', data, expected_code, expected_content)
return r_dict
def DELETE_and_assert_gone(test_instance, url):
"""
DELETE item at provided url and assert that the request was accepted by the server
:return: url for new item
"""
response = requests.delete(url, auth=AUTH)
if response.status_code != 204:
logger.error("!!! Unexpected: [%s] - %s %s: %s", test_instance.id(), 'DELETE', url, response.content)
test_instance.assertEqual(response.status_code, 204)
response = requests.get(url, auth=AUTH)
if response.status_code != 404:
logger.error("!!! Unexpected: [%s] - %s %s: %s", test_instance.id(), 'GET', url, response.content)
test_instance.assertEqual(response.status_code, 404)