summaryrefslogtreecommitdiffstats
path: root/mod/distributorapi/tests/test_api.py
diff options
context:
space:
mode:
Diffstat (limited to 'mod/distributorapi/tests/test_api.py')
-rw-r--r--mod/distributorapi/tests/test_api.py297
1 files changed, 238 insertions, 59 deletions
diff --git a/mod/distributorapi/tests/test_api.py b/mod/distributorapi/tests/test_api.py
index d7f543e..e943c04 100644
--- a/mod/distributorapi/tests/test_api.py
+++ b/mod/distributorapi/tests/test_api.py
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+# Copyright (c) 2020-2022 AT&T Intellectual Property. All rights reserved.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,103 +14,282 @@
# limitations under the License.
# ============LICENSE_END=========================================================
-from distributor.http import _app as app
-from distributor import config
+"""
+Tests that require a mock requests module, plus a few more
+that didn't fit cleanly elsewhere.
+"""
+
+import copy
+import os
+import re
import pytest
import requests
+from distributor.http import _app as app
+from distributor import config
+from distributor import onboarding_client
+from distributor import utils
+from distributor import errors
+from distributor import data_access
+from distributor import transform
+
class _resp(object):
- def __init__(self, code, json = None):
+ def __init__(self, code, json=None):
self.status_code = code
if json is not None:
self._json = json
-
+
def json(self):
return self._json
def raise_for_status(self):
if self.status_code < 200 or self.status_code >= 300:
- raise Exception('Error response {}'.format(self.status_code))
+ raise Exception("Error response {}".format(self.status_code))
+
class _req(object):
+ # in the test code, you can set
+ # _req.SHOWMATCHES = True
+ # and the match results will be displayed
+ SHOWMATCHES = False
+
def __init__(self, op, url, resp):
self.op = op
- self.url = url;
+ self.url = url
self.resp = resp
def check(self, op, url):
- if op != self.op or url != self.url:
- return None
- return self.resp
+ if _req.SHOWMATCHES:
+ print(f"_req.check(op={op} vs {self.op}, url={url} vs {self.url})")
+ return self.resp if op == self.op and url == self.url else None
+
def _match(answers, op, url):
for choice in answers:
ret = choice.check(op, url)
if ret is not None:
return ret
- message = 'Unexpected request {} {}'.format(op, url)
+ message = "Unexpected request {} {}".format(op, url)
print(message)
raise Exception(message)
+
@pytest.fixture
def mockrequests(monkeypatch):
answers = []
- def get(url, headers = None):
- return _match(answers, 'GET', url)
-
- def post(url, json, headers = None):
- return _match(answers, 'POST', url)
-
- def put(url, json, headers = None):
- return _match(answers, 'PUT', url)
-
- def delete(url, headers = None):
- return _match(answers, 'DELETE', url)
-
- monkeypatch.setattr(requests, 'get', get)
- monkeypatch.setattr(requests, 'post', post)
- monkeypatch.setattr(requests, 'put', put)
- monkeypatch.setattr(requests, 'delete', delete)
+
+ def get(url, headers=None):
+ return _match(answers, "GET", url)
+
+ def post(url, json, headers=None):
+ return _match(answers, "POST", url)
+
+ def put(url, json, headers=None):
+ return _match(answers, "PUT", url)
+
+ def delete(url, headers=None):
+ return _match(answers, "DELETE", url)
+
+ monkeypatch.setattr(requests, "get", get)
+ monkeypatch.setattr(requests, "post", post)
+ monkeypatch.setattr(requests, "put", put)
+ monkeypatch.setattr(requests, "delete", delete)
return answers
+
@pytest.fixture
def client():
- app.config['TESTING'] = True
+ app.config["TESTING"] = True
with app.test_client() as client:
yield client
+
+def isdate(dt):
+ """verify that a string looks like an iso8901 date/time string YYYY-MM-DDTHH:MM:SS.MS"""
+ return re.match(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[.]\d+$", dt)
+
+
+def isuuid(gu):
+ """verify that a string looks like a guid"""
+ return re.match(r"[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}$", gu)
+
+
config.init()
+
def test_api(client, mockrequests):
- dummyflow = {'link': {'href': 'buckets/link1/flows/flow1'}, 'name': 'flowname'}
- mockrequests.extend([
- _req('GET', 'http://nifi-registry:18080/nifi-registry-api/buckets',
- _resp(200, [{'link': {'href':'buckets/link1'}}])),
- _req('GET', 'http://nifi-registry:18080/nifi-registry-api/buckets/link1/flows',
- _resp(200, [dummyflow])),
- _req('POST', 'http://newtarget1/url/api/graph/main',
- _resp(200, {'id':'group1'}))
- ])
+ env_name = "TEST_API_GRAB_ENVIRON"
+ os.environ[env_name] = "xyz"
+ assert config._grab_env(env_name, "foo") == "xyz"
+ assert config._grab_env(env_name) == "xyz"
+ del os.environ[env_name]
+ assert config._grab_env(env_name, "foo") == "foo"
+ try:
+ config._grab_env(env_name)
+ assert not "config._grab_env(env_name) should throw errors.DistributorAPIConfigError"
+ except errors.DistributorAPIConfigError as e:
+ # expected result
+ pass
+
+ dummyflow = {"link": {"href": "buckets/link1/flows/flow1"}, "name": "flowname"}
+
+ nifi_url = "http://nifi-registry:18080/nifi-registry-api"
+ mockrequests.extend(
+ [
+ _req("GET", nifi_url + "/buckets", _resp(200, [{"link": {"href": "buckets/link1"}}])),
+ _req("GET", nifi_url + "/buckets/link1/flows", _resp(200, [dummyflow])),
+ _req("POST", "http://newtarget1/url/api/graph/main", _resp(200, {"id": "group1"})),
+ _req("GET", "/does/not/exist", _resp(404, [{"link": {"href": "does/not/exist"}}])),
+ _req(
+ "GET",
+ "/distributor/distribution-targets/components?name=foo&version=bar",
+ _resp(200, {"id": "groupd", "components": [{"componentUrl": "COMPONENTURL"}]}),
+ ),
+ _req("GET", "COMPONENTURL", _resp(200, {"id": "groupComponentUrl"})),
+ _req(
+ "GET",
+ "/distributor/distribution-targets/components?name=foo&version=bar2",
+ _resp(200, {"id": "groupd", "components": None}),
+ ),
+ ]
+ )
for rule in app.url_map.iter_rules():
- print(rule)
- url = '/distributor/distribution-targets'
- url2 = url + '/notfound'
- url3 = url2 + '/process-groups'
- assert(len(client.get(url).get_json()['distributionTargets']) == 0)
- assert(client.get(url2).status_code == 404)
- assert(client.put(url2, json={'name': 'notfound1', 'runtimeApiUrl': 'http://notfound/url'}).status_code == 404)
- assert(client.delete(url2).status_code == 404)
- assert(client.post(url3, json={'processGroupId': 'group1'}).status_code == 404)
- resp = client.post(url, json={'name': 'target1', 'runtimeApiUrl': 'http://target/url'})
- assert(resp.status_code == 200)
- print(resp.get_json())
- url2 = '/distributor/distribution-targets/' + resp.get_json()['id']
- url3 = url2 + '/process-groups'
- assert(len(client.get(url).get_json()['distributionTargets']) == 1)
- assert(client.get(url2).status_code == 200)
- assert(client.put(url2, json={'name': 'newtarget1', 'runtimeApiUrl': 'http://newtarget1/url'}).status_code == 200)
- assert(client.post(url3, json={'processGroupId': 'group1'}).status_code == 404)
- dummyflow['identifier'] = 'group1'
- assert(client.post(url3, json={'processGroupId': 'group1'}).status_code == 501)
- assert(client.delete(url2).status_code == 200)
- assert(client.delete(url2).status_code == 404)
+ print(rule)
+ url = "/distributor/distribution-targets"
+ url2 = url + "/notfound"
+ url3 = url2 + "/process-groups"
+ assert len(client.get(url).get_json()["distributionTargets"]) == 0
+ assert client.get(url2).status_code == 404
+ assert client.put(url2, json={"name": "notfound1", "runtimeApiUrl": "http://notfound/url"}).status_code == 404
+ assert client.delete(url2).status_code == 404
+ assert client.post(url3, json={"processGroupId": "group1"}).status_code == 404
+ resp = client.post(url, json={"name": "target1", "runtimeApiUrl": "http://target/url"})
+ assert resp.status_code == 200
+
+ # print(resp.get_json())
+ url2 = "/distributor/distribution-targets/" + resp.get_json()["id"]
+ url3 = url2 + "/process-groups"
+ assert len(client.get(url).get_json()["distributionTargets"]) == 1
+
+ assert client.get(url2).status_code == 200
+ assert client.put(url2, json={"name": "newtarget1", "runtimeApiUrl": "http://newtarget1/url"}).status_code == 200
+ assert client.put(url2, json={"name": "newtarget1", "runtimeApiUrl": "http://newtarget1/url"}).status_code == 200
+
+ assert client.post(url3, json={"processGroupId": "group1"}).status_code == 404
+ assert client.post(url3, json={"processGroupId": "group1"}).status_code == 404
+ dummyflow["identifier"] = "group1"
+ assert client.post(url3, json={"processGroupId": "group1"}).status_code == 501
+
+ assert client.delete(url2).status_code == 200
+ assert client.delete(url2).status_code == 404
+ url4 = "/does/not/exist"
+
+ # the following tests do not require an http client but do use requests lib
+
+ # test get_json() exception case
+ try:
+ utils.get_json(url4)
+ assert not "utils.get_json(url4) should throw errors.DistributorAPIError"
+ except errors.DistributorAPIError as e:
+ # expected result
+ pass
+
+ # _req.SHOWMATCHES = True
+ ret = onboarding_client.get_components_indexed(url, [("foo", "bar")])
+ assert ret == {("foo", "bar"): {"id": "groupComponentUrl"}}
+
+ #
+ try:
+ ret = onboarding_client.get_components_indexed(url, [("foo", "bar2")])
+ assert (
+ not "onboarding_client.get_components_indexed(...foo,bar2) should throw errors.DistributorAPIResourceNotFound"
+ )
+ except errors.DistributorAPIResourceNotFound as e:
+ # expected result
+ pass
+
+
+def test_data_access():
+ # various tests for data_access.py
+
+ saved_cache = copy.deepcopy(data_access.get_distribution_targets())
+ ret = data_access.get_distribution_target("ds")
+ assert ret == {}
+
+ # new transform_request()
+ req1 = {"name": "req1", "runtimeApiUrl": "rtau1", "nextDistributionTargetId": "ndti1"}
+ treq1 = data_access.transform_request(req1)
+ assert isdate(treq1["created"])
+ assert isdate(treq1["modified"])
+ assert isuuid(treq1["dt_id"])
+ assert treq1["processGroups"] == []
+
+ # new transform_request()
+ req2 = {"name": "req2", "runtimeApiUrl": "rtau2", "nextDistributionTargetId": "ndti1"}
+ treq2 = data_access.transform_request(req2)
+ assert isdate(treq2["created"])
+ assert isdate(treq2["modified"])
+ assert isuuid(treq2["dt_id"])
+ assert treq2["processGroups"] == []
+
+ # merge_request() should copy certain values from 2nd arg into 1st arg
+ ret = data_access.merge_request(treq1, treq2)
+ assert ret["name"] == treq2["name"]
+ assert ret["runtimeApiUrl"] == treq2["runtimeApiUrl"]
+ assert ret["description"] is None
+ assert ret["nextDistributionTargetId"] == treq2["nextDistributionTargetId"]
+
+ # add_distribution_target() adds to the cache
+ ret = data_access.add_distribution_target({"dt_id": "dt1", "val": "1", "processGroups": []})
+ assert data_access.get_distribution_target("dt1")["val"] == "1"
+
+ # update_distribution_target() updates an existing element of the cache
+ # If the element exists, it returns True
+ ret = data_access.update_distribution_target({"dt_id": "dt1", "val": "1b", "processGroups": []})
+ assert ret
+ assert data_access.get_distribution_target("dt1")["val"] == "1b"
+
+ # update_distribution_target() updates an existing element of the cache
+ # If the element does not exist, it returns False
+ ret = data_access.update_distribution_target({"dt_id": "dt2", "val": "2", "processGroups": []})
+ assert not ret
+
+ # add_process_group adds an element to the processGroups array of the distribution target
+ # if the element exists, returns true, else false
+ assert data_access.add_process_group("dt1", {"processed": "p1"})
+ assert isdate(data_access.get_distribution_target("dt1")["processGroups"][0]["processed"])
+ assert not data_access.add_process_group("dt2", {"processed": "p1"})
+
+ # clean up the cache
+ # if the element exists,
+ assert data_access.delete_distribution_target("dt1")
+ assert not data_access.delete_distribution_target("dt2")
+
+ assert data_access.get_distribution_targets() == saved_cache
+
+
+def test_transform():
+ # various tests for transform.py
+ flow1 = {"flowContents": {"processors": []}}
+ flow2 = {
+ "flowContents": {
+ "processors": [
+ {
+ "bundle": {"artifact": "artifact1", "version": "version1"},
+ }
+ ]
+ }
+ }
+ flow3 = {
+ "flowContents": {
+ "processors": [
+ {
+ "bundle": {"artifact": "artifact1", "version": "version1"},
+ },
+ {"bundle": {"artifact": "artifact2", "version": "version2"}},
+ ]
+ }
+ }
+ assert transform.extract_components_from_flow(flow1) == []
+ assert transform.extract_components_from_flow(flow2) == [("artifact1", "version1")]
+ assert transform.extract_components_from_flow(flow3) == [("artifact1", "version1"), ("artifact2", "version2")]