# See the License for the specific language governing permissions and
# limitations under the License.
# ==================================================================================
+import json
from flask import Response
+from jsonschema import validate
import connexion
-import json
from jsonschema.exceptions import ValidationError
from a1 import get_module_logger
-from a1 import a1rmr, exceptions, utils, data
+from a1 import a1rmr, exceptions, data
logger = get_module_logger(__name__)
-def _get_policy_definition(policy_type_id):
- # Currently we read the manifest on each call, which would seem to allow updating A1 in place. Revisit this?
- manifest = utils.get_ric_manifest()
- for m in manifest["controls"]:
- if m["name"] == policy_type_id:
- return m
-
- raise exceptions.PolicyTypeNotFound()
-
-
-def _get_policy_schema(policy_type_id):
- """
- Get the needed info for a policy
- """
- m = _get_policy_definition(policy_type_id)
- return m["message_receives_payload_schema"] if "message_receives_payload_schema" in m else None
-
-
def _try_func_return(func):
"""
generic caller that returns the apporp http response if exceptions are raised
except ValidationError as exc:
logger.exception(exc)
return "", 400
+ except exceptions.PolicyTypeAlreadyExists as exc:
+ logger.exception(exc)
+ return "", 400
except exceptions.PolicyTypeNotFound as exc:
logger.exception(exc)
return "", 404
return Response(status=500)
-def _put_handler(policy_type_id, policy_instance_id, instance):
- """
- Handles policy put
-
- For now, policy_type_id is used as the message type
- """
- # check for 404
- data.type_is_valid(policy_type_id)
-
- # validate the PUT against the schema, or if there is no shema, make sure the pUT is empty
- schema = _get_policy_schema(policy_type_id)
- if schema:
- utils.validate_json(instance, schema)
- elif instance != {}:
- return "BODY SUPPLIED BUT POLICY HAS NO EXPECTED BODY", 400
-
- # store the instance
- data.store_policy_instance(policy_type_id, policy_instance_id, instance)
-
- body = {
- "operation": "CREATE",
- "policy_type_id": policy_type_id,
- "policy_instance_id": policy_instance_id,
- "payload": instance,
- }
-
- # send rmr (best effort)
- a1rmr.send(json.dumps(body), message_type=policy_type_id)
-
- return "", 201
-
-
-def _get_status_handler(policy_type_id, policy_instance_id):
- """
- Pop trough A1s mailbox, insert the latest status updates into the database, and then return the status vector
-
- NOTE: this is done lazily. Meaning, when someone performs a GET on this API, we pop through a1s mailbox.
- THis may not work in the future if there are "thousands" of policy acknowledgements that hit a1 before this is called,
- because the rmr mailbox may fill. However, in the near term, we do not expect this to happen.
- """
- # check validity to 404 first:
- data.type_is_valid(policy_type_id)
- data.instance_is_valid(policy_type_id, policy_instance_id)
-
- # pop a1s mailbox, looking for policy notifications
- new_messages = a1rmr.dequeue_all_waiting_messages(21024)
-
- # try to parse the messages as responses. Drop those that are malformed
- for msg in new_messages:
- # note, we don't use the parameters "policy_type_id, policy_instance" from above here,
- # because we are popping the whole mailbox, which might include other statuses
- pay = json.loads(msg["payload"])
- if "policy_type_id" in pay and "policy_instance_id" in pay and "handler_id" in pay and "status" in pay:
- data.set_policy_instance_status(
- pay["policy_type_id"], pay["policy_instance_id"], pay["handler_id"], pay["status"]
- )
- else:
- logger.debug("Dropping message")
- logger.debug(pay)
-
- # return the status vector
- return data.get_policy_instance_statuses(policy_type_id, policy_instance_id)
-
-
# Healthcheck
"""
Handles PUT /a1-p/policytypes/policy_type_id
"""
- return "", 501
+
+ def _put_type_handler(policy_type_id, body):
+ data.store_policy_type(policy_type_id, body)
+ return "", 201
+
+ body = connexion.request.json
+ return _try_func_return(lambda: _put_type_handler(policy_type_id, body))
def get_policy_type(policy_type_id):
"""
Handles GET /a1-p/policytypes/policy_type_id
"""
- return "", 501
+ return _try_func_return(lambda: data.get_policy_type(policy_type_id))
def delete_policy_type(policy_type_id):
"""
Handles GET /a1-p/policytypes/polidyid/policies/policy_instance_id
"""
+ # 200 is automatic here
return _try_func_return(lambda: data.get_policy_instance(policy_type_id, policy_instance_id))
"""
Handles GET /a1-p/policytypes/polidyid/policies/policy_instance_id/status
"""
+
+ def _get_status_handler(policy_type_id, policy_instance_id):
+ """
+ Pop trough A1s mailbox, insert the latest status updates into the database, and then return the status vector
+
+ NOTE: this is done lazily. Meaning, when someone performs a GET on this API, we pop through a1s mailbox.
+ THis may not work in the future if there are "thousands" of policy acknowledgements that hit a1 before this is called,
+ because the rmr mailbox may fill. However, in the near term, we do not expect this to happen.
+ """
+ # check validity to 404 first:
+ data.type_is_valid(policy_type_id)
+ data.instance_is_valid(policy_type_id, policy_instance_id)
+
+ # pop a1s mailbox, looking for policy notifications
+ new_messages = a1rmr.dequeue_all_waiting_messages(21024)
+
+ # try to parse the messages as responses. Drop those that are malformed
+ for msg in new_messages:
+ # note, we don't use the parameters "policy_type_id, policy_instance" from above here,
+ # because we are popping the whole mailbox, which might include other statuses
+ pay = json.loads(msg["payload"])
+ if "policy_type_id" in pay and "policy_instance_id" in pay and "handler_id" in pay and "status" in pay:
+ data.set_policy_instance_status(
+ pay["policy_type_id"], pay["policy_instance_id"], pay["handler_id"], pay["status"]
+ )
+ else:
+ logger.debug("Dropping message")
+ logger.debug(pay)
+
+ # return the status vector
+ return data.get_policy_instance_statuses(policy_type_id, policy_instance_id)
+
return _try_func_return(lambda: _get_status_handler(policy_type_id, policy_instance_id))
"""
Handles PUT /a1-p/policytypes/polidyid/policies/policy_instance_id
"""
+
+ def _put_instance_handler(policy_type_id, policy_instance_id, instance):
+ """
+ Handles policy instance put
+
+ For now, policy_type_id is used as the message type
+ """
+ # validate the PUT against the schema
+ schema = data.get_policy_type(policy_type_id)["create_schema"]
+ validate(instance=instance, schema=schema)
+
+ # store the instance
+ data.store_policy_instance(policy_type_id, policy_instance_id, instance)
+
+ body = {
+ "operation": "CREATE",
+ "policy_type_id": policy_type_id,
+ "policy_instance_id": policy_instance_id,
+ "payload": instance,
+ }
+
+ # send rmr (best effort)
+ a1rmr.send(json.dumps(body), message_type=policy_type_id)
+
+ return "", 201
+
instance = connexion.request.json
- return _try_func_return(lambda: _put_handler(policy_type_id, policy_instance_id, instance))
+ return _try_func_return(lambda: _put_instance_handler(policy_type_id, policy_instance_id, instance))
def delete_policy_instance(policy_type_id, policy_instance_id):
For now, the database is in memory.
We use dict data structures (KV) with the expectation of having to move this into Redis
"""
-from a1.exceptions import PolicyTypeNotFound, PolicyInstanceNotFound
+from a1.exceptions import PolicyTypeNotFound, PolicyInstanceNotFound, PolicyTypeAlreadyExists
from a1 import get_module_logger
logger = get_module_logger(__name__)
H = "handlers"
D = "data"
-
-# TODO: REMOVE THIS!! (should be done via PUT)
-POLICY_DATA[20000] = {}
-POLICY_DATA[20000][D] = {"foo": "bar"}
-POLICY_DATA[20000][I] = {}
-POLICY_DATA[20001] = {}
-POLICY_DATA[20001][D] = {"foo": "bar"}
-POLICY_DATA[20001][I] = {}
+# Types
def type_is_valid(policy_type_id):
raise PolicyTypeNotFound()
+def store_policy_type(policy_type_id, body):
+ """
+ store a policy type if it doesn't already exist
+ """
+ if policy_type_id in POLICY_DATA:
+ raise PolicyTypeAlreadyExists()
+
+ POLICY_DATA[policy_type_id] = {}
+ POLICY_DATA[policy_type_id][D] = body
+ POLICY_DATA[policy_type_id][I] = {}
+
+
+def get_policy_type(policy_type_id):
+ """
+ retrieve a type
+ """
+ type_is_valid(policy_type_id)
+ return POLICY_DATA[policy_type_id][D]
+
+
+# Instances
+
+
def instance_is_valid(policy_type_id, policy_instance_id):
"""
check that an instance is valid
"""a policy type instance cannot be found"""
+class PolicyTypeAlreadyExists(BaseException):
+ """a policy type already exists and replace not supported at this time"""
+
+
class MissingRmrString(BaseException):
pass
represents a policy type identifier. Currently this is restricted to an integer range.
type: integer
minimum: 20000
- maximum: 21024
+ maximum: 21023
policy_instance_id:
description: >
# ==================================================================================
from gevent.pywsgi import WSGIServer
from a1 import get_module_logger, app
-from a1 import utils, exceptions
from a1.a1rmr import init_rmr
-import sys
logger = get_module_logger(__name__)
def main():
"""Entrypoint"""
- # Fail fast if we don't have a manifest
- try:
- utils.get_ric_manifest()
- except exceptions.MissingManifest:
- logger.error("Failing fast: no A1 manifest found!")
- sys.exit(1)
-
logger.debug("Initializing rmr")
init_rmr()
logger.debug("Starting gevent server")
- http_server = WSGIServer(('', 10000), app)
+ http_server = WSGIServer(("", 10000), app)
http_server.serve_forever()
+++ /dev/null
-# ==================================================================================
-# Copyright (c) 2019 Nokia
-# Copyright (c) 2018-2019 AT&T Intellectual Property.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# ==================================================================================
-import json
-from jsonschema import validate
-from a1 import get_module_logger
-from a1 import exceptions
-
-
-logger = get_module_logger(__name__)
-
-
-# Public
-
-
-def validate_json(instance, schema):
- """
- validate incoming policy payloads
- """
- validate(instance=instance, schema=schema)
-
-
-def get_ric_manifest():
- """
- Get the ric level manifest
- """
- try:
- with open("/opt/ricmanifest.json", "r") as f:
- content = f.read()
- manifest = json.loads(content)
- return manifest
- except FileNotFoundError:
- logger.error("Missing A1 Manifest!")
- raise exceptions.MissingManifest
# The Jenkins job uses this string for the tag in the image name
# for example nexus3.o-ran-sc.org:10004/my-image-name:my-tag
---
-tag: 0.11.0-NOT_FOR_USE_YET
+tag: 0.12.0-NOT_FOR_USE_YET
* Release 1.0.0 will be the Release A version of A1
+[0.12.0] - 9/19/2019
+::
+
+ * Implement type PUT
+ * Implement type GET
+ * Remove RIC manifest
+ * Read type GET to get schema for instance PUT
+ * Remove Utils (no longer needed)
+ * lots more tests (unit and integration)
+
[0.11.0] - 9/17/2019
::
apiVersion: v1
description: A1 Helm chart for Kubernetes
name: a1mediator
-version: 0.11.0
+version: 0.12.0
rte|20001|delayreceiverrmrservice:4563
rte|21024|{{ .Values.rmrservice.name }}:{{ .Values.rmrservice.port }}
newrt|end
- ricmanifest.json: {{tpl (.Files.Get "files/ricmanifest.json") . | quote}}
containers:
- name: {{ .Chart.Name }}
volumeMounts:
- - name: a1conf
- mountPath: /opt/ricmanifest.json
- subPath: ricmanifest.json
- name: a1conf
mountPath: /opt/route/local.rt
subPath: local.rt
test_name: test admission control
stages:
+ - name: type not there yet
+ request:
+ url: http://localhost:10000/a1-p/policytypes/20000
+ method: GET
+ response:
+ status_code: 404
+
+ - name: put the type
+ request:
+ url: http://localhost:10000/a1-p/policytypes/20000
+ method: PUT
+ json:
+ name: Admission Control
+ description: various parameters to control admission of dual connection
+ policy_type_id: 20000
+ create_schema:
+ "$schema": http://json-schema.org/draft-07/schema#
+ type: object
+ properties:
+ enforce:
+ type: boolean
+ default: true
+ window_length:
+ type: integer
+ default: 1
+ minimum: 1
+ maximum: 60
+ description: Sliding window length (in minutes)
+ blocking_rate:
+ type: number
+ default: 10
+ minimum: 1
+ maximum: 100
+ description: "% Connections to block"
+ trigger_threshold:
+ type: integer
+ default: 10
+ minimum: 1
+ description: Minimum number of events in window to trigger blocking
+ required:
+ - enforce
+ - blocking_rate
+ - trigger_threshold
+ - window_length
+ additionalProperties: false
+
+ - name: type there now
+ request:
+ url: http://localhost:10000/a1-p/policytypes/20000
+ method: GET
+ response:
+ status_code: 200
+
- name: test the admission control policy get not there yet
request:
url: http://localhost:10000/a1-p/policytypes/20000/policies/admission_control_policy
response:
status_code: 404
- - name: test the admission control policy
+ - name: put the admission control policy
request:
url: http://localhost:10000/a1-p/policytypes/20000/policies/admission_control_policy
method: PUT
test_name: test the delay receiver
stages:
- - name: test the delay policy get not there yet
+
+ - name: test the delay policy type not there yet
+ request:
+ url: http://localhost:10000/a1-p/policytypes/20001
+ method: GET
+ response:
+ status_code: 404
+
+ - name: put the type
+ request:
+ url: http://localhost:10000/a1-p/policytypes/20001
+ method: PUT
+ json:
+ name: test policy
+ description: just for testing
+ policy_type_id: 20001
+ create_schema:
+ "$schema": http://json-schema.org/draft-07/schema#
+ type: object
+ properties:
+ test:
+ type: string
+ required:
+ - test
+ additionalProperties: false
+
+ - name: type there now
+ request:
+ url: http://localhost:10000/a1-p/policytypes/20001
+ method: GET
+ response:
+ status_code: 200
+ body:
+ name: test policy
+ description: just for testing
+ policy_type_id: 20001
+ create_schema:
+ "$schema": http://json-schema.org/draft-07/schema#
+ type: object
+ properties:
+ test:
+ type: string
+ required:
+ - test
+ additionalProperties: false
+
+ - name: test the delay policy instance get not there yet
request:
url: http://localhost:10000/a1-p/policytypes/20001/policies/delaytest
method: GET
request:
url: http://localhost:10000/a1-p/policytypes/20001/policies/delaytest
method: PUT
- json: {}
+ json:
+ test: foo
headers:
content-type: application/json
response:
method: GET
response:
status_code: 200
- body: {}
+ body:
+ test: foo
- name: test the admission control policy status get
delay_before: 8 # give it a few seconds for rmr ; delay reciever sleeps for 5 seconds by default
status: OK
-
-
---
test_name: bad_requests
stages:
+ - name: bad type get
+ request:
+ url: http://localhost:10000/a1-p/policytypes/20002
+ method: GET
+ response:
+ status_code: 404
+
+
+ - name: bad instance get
+ request:
+ url: http://localhost:10000/a1-p/policytypes/20000/policies/darkness
+ method: GET
+ response:
+ status_code: 404
+
+ - name: bad int range 1
+ request:
+ url: http://localhost:10000/a1-p/policytypes/19999
+ method: PUT
+ json:
+ name: test policy
+ description: just for testing
+ policy_type_id: 19999
+ create_schema:
+ "$schema": http://json-schema.org/draft-07/schema#
+ type: object
+ response:
+ status_code: 400
+
+ - name: bad int range 2
+ request:
+ url: http://localhost:10000/a1-p/policytypes/21024
+ method: PUT
+ json:
+ name: test policy
+ description: just for testing
+ policy_type_id: 21024
+ create_schema:
+ "$schema": http://json-schema.org/draft-07/schema#
+ type: object
+ response:
+ status_code: 400
+
+
+
+
- name: bad body for admission control policy
request:
url: http://localhost:10000/a1-p/policytypes/20000/policies/admission_control_policy
response:
status_code: 415
- - name: bad body for test policy
+ - name: bad body for delaytest
request:
- url: http://localhost:10000/a1-p/policytypes/20001/policies/test_policy
+ url: http://localhost:10000/a1-p/policytypes/20001/policies/delaytest
method: PUT
json:
not: "welcome"
setup(
name="a1",
- version="0.11.0",
+ version="0.12.0",
packages=find_packages(exclude=["tests.*", "tests"]),
author="Tommy Carpenter",
description="RIC A1 Mediator for policy/intent changes",
--- /dev/null
+import pytest
+
+
+@pytest.fixture
+def adm_type_good():
+ return {
+ "name": "Admission Control",
+ "description": "various parameters to control admission of dual connection",
+ "policy_type_id": 20000,
+ "create_schema": {
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "properties": {
+ "enforce": {"type": "boolean", "default": True},
+ "window_length": {
+ "type": "integer",
+ "default": 1,
+ "minimum": 1,
+ "maximum": 60,
+ "description": "Sliding window length (in minutes)",
+ },
+ "blocking_rate": {
+ "type": "number",
+ "default": 10,
+ "minimum": 1,
+ "maximum": 100,
+ "description": "% Connections to block",
+ },
+ "trigger_threshold": {
+ "type": "integer",
+ "default": 10,
+ "minimum": 1,
+ "description": "Minimum number of events in window to trigger blocking",
+ },
+ },
+ "required": ["enforce", "blocking_rate", "trigger_threshold", "window_length"],
+ "additionalProperties": False,
+ },
+ }
+
+
+@pytest.fixture
+def adm_instance_good():
+ return {"enforce": True, "window_length": 10, "blocking_rate": 20, "trigger_threshold": 10}
+++ /dev/null
-{
- "controls":[
- {
- "name":20000,
- "description":"various parameters to control admission of dual connection",
- "control_state_request_rmr_type":"DC_ADM_GET_POLICY",
- "control_state_request_reply_rmr_type":"DC_ADM_GET_POLICY_ACK",
- "message_receives_rmr_type":"DC_ADM_INT_CONTROL",
- "message_receives_payload_schema":{
- "$schema":"http://json-schema.org/draft-07/schema#",
- "type":"object",
- "properties":{
- "enforce":{
- "type":"boolean",
- "default":true
- },
- "window_length":{
- "type":"integer",
- "default":1,
- "minimum":1,
- "maximum":60,
- "description":"Sliding window length (in minutes)"
- },
- "blocking_rate":{
- "type":"number",
- "default":10,
- "minimum":1,
- "maximum":100,
- "description":"% Connections to block"
- },
- "trigger_threshold":{
- "type":"integer",
- "default":10,
- "minimum":1,
- "description":"Minimum number of events in window to trigger blocking"
- }
- },
- "required":[
- "enforce",
- "blocking_rate",
- "trigger_threshold",
- "window_length"
- ],
- "additionalProperties":false
- },
- "message_sends_rmr_type":"DC_ADM_INT_CONTROL_ACK",
- "message_sends_payload_schema":{
- "$schema":"http://json-schema.org/draft-07/schema#",
- "type":"object",
- "properties":{
- "status":{
- "type":"string",
- "enum":[
- "SUCCESS",
- "FAIL"
- ]
- },
- "message":{
- "type":"string"
- }
- },
- "required":[
- "status"
- ],
- "additionalProperties":false
- }
- },
- {
- "name":20001,
- "description":"for the purposes of testing",
- "message_receives_rmr_type":"TEST_REQ",
- "message_sends_rmr_type":"TEST_ACK",
- "message_sends_payload_schema":{
- "$schema":"http://json-schema.org/draft-07/schema#",
- "type":"object",
- "properties":{
- "status":{
- "type":"string",
- "enum":[
- "SUCCESS",
- "FAIL"
- ]
- }
- }
- }
- }
- ]
-}
from rmr.rmr_mocks import rmr_mocks
from a1 import app
-import testing_helpers
import pytest
ADM_CTRL = "admission_control_policy"
ADM_CTRL_INSTANCE = "/a1-p/policytypes/20000/policies/" + ADM_CTRL
ADM_CTRL_INSTANCE_STATUS = ADM_CTRL_INSTANCE + "/status"
+ADM_CTRL_TYPE = "/a1-p/policytypes/20000"
+TEST_TYPE = "/a1-p/policytypes/20001"
# http://flask.pocoo.org/docs/1.0/testing/
def _test_put_patch(monkeypatch):
- testing_helpers.patch_all(monkeypatch)
+ rmr_mocks.patch_rmr(monkeypatch)
monkeypatch.setattr("rmr.rmr.rmr_send_msg", rmr_mocks.send_mock_generator(0)) # good sends for this whole batch
# we need to repatch alloc (already patched in patch_rmr) to fix the transactionid, alloc is called in send and recieve
# Actual Tests
-# def test_policy_get(client, monkeypatch):
-# """
-# test policy GET
-# """
-# _test_put_patch(monkeypatch)
-# monkeypatch.setattr(
-# "a1.a1rmr.dequeue_all_waiting_messages",
-# _fake_dequeue(monkeypatch, msg_payload={"GET ack": "pretend policy is here"}, msg_type=20003),
-# )
-# res = client.get("/a1-p/policies/admission_control_policy")
-# assert res.status_code == 200
-# assert res.json == {"GET ack": "pretend policy is here"}
-#
-#
-# def test_policy_get_unsupported(client, monkeypatch):
-# """
-# test policy GET
-# """
-# testing_helpers.patch_all(monkeypatch, nofetch=True)
-# res = client.get("/a1-p/policies/admission_control_policy")
-# assert res.status_code == 400
-# assert res.data == b'"POLICY DOES NOT SUPPORT FETCHING"\n'
-#
-#
-def test_xapp_put_good(client, monkeypatch):
+def test_xapp_put_good(client, monkeypatch, adm_type_good, adm_instance_good):
""" test policy put good"""
- # nothing there yet
+ # no type there yet
+ res = client.get(ADM_CTRL_TYPE)
+ assert res.status_code == 404
+
+ # put the type
+ res = client.put(ADM_CTRL_TYPE, json=adm_type_good)
+ assert res.status_code == 201
+
+ # there now
+ res = client.get(ADM_CTRL_TYPE)
+ assert res.status_code == 200
+ assert res.json == adm_type_good
+
+ # no instance there yet
res = client.get(ADM_CTRL_INSTANCE)
assert res.status_code == 404
res = client.get(ADM_CTRL_INSTANCE_STATUS)
# create a good instance
_test_put_patch(monkeypatch)
- res = client.put(ADM_CTRL_INSTANCE, json=testing_helpers.good_payload())
+ res = client.put(ADM_CTRL_INSTANCE, json=adm_instance_good)
assert res.status_code == 201
# get the instance
res = client.get(ADM_CTRL_INSTANCE)
assert res.status_code == 200
- assert res.json == testing_helpers.good_payload()
+ assert res.json == adm_instance_good
# get the instance status
monkeypatch.setattr("a1.a1rmr.dequeue_all_waiting_messages", _fake_dequeue)
# assert that rmr bad states don't cause problems
monkeypatch.setattr("rmr.rmr.rmr_send_msg", rmr_mocks.send_mock_generator(10))
- res = client.put(ADM_CTRL_INSTANCE, json=testing_helpers.good_payload())
+ res = client.put(ADM_CTRL_INSTANCE, json=adm_instance_good)
assert res.status_code == 201
monkeypatch.setattr("rmr.rmr.rmr_send_msg", rmr_mocks.send_mock_generator(5))
- res = client.put(ADM_CTRL_INSTANCE, json=testing_helpers.good_payload())
+ res = client.put(ADM_CTRL_INSTANCE, json=adm_instance_good)
assert res.status_code == 201
-#
-#
# def test_xapp_put_bad(client, monkeypatch):
# """Test policy put fails"""
# _test_put_patch(monkeypatch)
# res = client.put("/a1-p/policies/admission_control_policy", json=testing_helpers.good_payload())
# assert res.status_code == 504
# assert res.data == b"\"A1 was expecting an ACK back but it didn't receive one or didn't recieve the expected ACK\"\n"
-#
-#
-def test_bad_requests(client, monkeypatch):
+
+
+def test_bad_instances(client, monkeypatch, adm_type_good):
"""
Test bad send failures
"""
- testing_helpers.patch_all(monkeypatch)
+ rmr_mocks.patch_rmr(monkeypatch)
+
+ # TODO: reenable this after delete!
+ # put the type
+ # res = client.put(ADM_CTRL_TYPE, json=adm_type_good)
+ # assert res.status_code == 201
+
+ # illegal type range
+ res = client.put("/a1-p/policytypes/19999", json=adm_type_good)
+ assert res.status_code == 400
+ res = client.put("/a1-p/policytypes/21024", json=adm_type_good)
+ assert res.status_code == 400
+
+ # bad body
res = client.put(ADM_CTRL_INSTANCE, json={"not": "expected"})
assert res.status_code == 400
res = client.put(ADM_CTRL_INSTANCE, data="notajson")
assert res.status_code == 415
- # test a PUT body against a poliucy not expecting one
- res = client.put("/a1-p/policytypes/20001/policies/test_policy", json=testing_helpers.good_payload())
- assert res.status_code == 400
- assert res.data == b'"BODY SUPPLIED BUT POLICY HAS NO EXPECTED BODY"\n'
-
-
-# def test_bad_requests(client, monkeypatch):
-# """Test bad requests"""
-# testing_helpers.patch_all(monkeypatch)
-#
-# # test a 404
-# res = client.put("/a1-p/policies/noexist", json=testing_helpers.good_payload())
-# assert res.status_code == 404
-
-
-# def test_missing_manifest(client, monkeypatch):
-# """
-# test that we get a 500 with an approrpiate message on a missing manifest
-# """
-#
-# def f():
-# raise exceptions.MissingManifest()
-#
-# monkeypatch.setattr("a1.utils.get_ric_manifest", f)
-#
-# res = client.put("/a1-p/policies/admission_control_policy", json=testing_helpers.good_payload())
-# assert res.status_code == 500
-# assert res.data == b'"A1 was unable to find the required RIC manifest. report this!"\n'
-#
-#
-
def test_healthcheck(client):
"""
+++ /dev/null
-# ==================================================================================
-# Copyright (c) 2019 Nokia
-# Copyright (c) 2018-2019 AT&T Intellectual Property.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# ==================================================================================
-import pytest
-import jsonschema
-from a1 import utils, exceptions
-import testing_helpers
-
-
-def test_bad_get_ric_manifest(monkeypatch):
- """
- testing missing manifest
- """
-
- def badopen(filename, mode):
- raise FileNotFoundError()
-
- monkeypatch.setattr("builtins.open", badopen)
- with pytest.raises(exceptions.MissingManifest):
- utils.get_ric_manifest()
-
-
-def test_good_get_ric_manifest(monkeypatch):
- """
- test get_ric_manifest
- """
- testing_helpers.patch_all(monkeypatch)
- utils.get_ric_manifest()
-
-
-def test_validate(monkeypatch):
- """
- test json validation wrapper
- """
- testing_helpers.patch_all(monkeypatch)
- ricmanifest = utils.get_ric_manifest()
- schema = ricmanifest["controls"][0]["message_receives_payload_schema"]
- utils.validate_json(testing_helpers.good_payload(), schema)
- with pytest.raises(jsonschema.exceptions.ValidationError):
- utils.validate_json({"dc_admission_start_time": "10:00:00", "dc_admission_end_time": "nevergonnagiveyouup"}, schema)
+++ /dev/null
-# ==================================================================================
-# Copyright (c) 2019 Nokia
-# Copyright (c) 2018-2019 AT&T Intellectual Property.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# ==================================================================================
-import json
-import os
-from rmr.rmr_mocks import rmr_mocks
-
-
-def _get_fixture_path(name):
- cur_dir = os.path.dirname(os.path.realpath(__file__))
- return "{0}/fixtures/{1}".format(cur_dir, name)
-
-
-def patch_all(monkeypatch, nonexisting_rmr=False, nofetch=False):
- rmr_mocks.patch_rmr(monkeypatch)
-
- # patch manifest
- man = json.loads(open(_get_fixture_path("ricmanifest.json"), "r").read())
- if nonexisting_rmr:
- man["controls"][0]["message_receives_rmr_type"] = "DARKNESS"
-
- if nofetch:
- del man["controls"][0]["control_state_request_rmr_type"]
-
- monkeypatch.setattr("a1.utils.get_ric_manifest", lambda: man)
-
-
-def good_payload():
- return {"enforce": True, "window_length": 10, "blocking_rate": 20, "trigger_threshold": 10}
ab
echo
pkill
+ kubectl
passenv = *
deps =
tavern
changedir=integration_tests
commands_pre=
+ echo "WARNING: make sure you're running with latest docker builds!"
+ sleep 5
helm install --devel testreceiver -n testreceiver
- helm install --devel a1mediator/ -n a1
+ helm install --devel a1mediator -n a1
+# wait for helm charts
sleep 20
+ kubectl get pods --all-namespaces
./portforward.sh
sleep 2
commands=
echo "linting"
- helm lint a1mediator/
+ helm lint a1mediator
+ helm lint testreceiver
echo "running tavern"
- pytest
+# run tavern
+ pytest --tavern-beta-new-traceback
echo "running ab"
+# run apache bench
ab -n 100 -c 10 -u putdata -T application/json http://localhost:10000/a1-p/policytypes/20000/policies/admission_control_policy
commands_post=
helm delete testreceiver