Fix missing 400 impl, update test manifest

Issue-ID: RICPLT-1638
Change-Id: Iff6de7b64a0dd94c6653eff5312ec84c1cf2bced
Signed-off-by: Tommy Carpenter <tommy@research.att.com>
diff --git a/a1/controller.py b/a1/controller.py
index ca9618b..b3bbcdb 100644
--- a/a1/controller.py
+++ b/a1/controller.py
@@ -17,6 +17,7 @@
 from flask import Response
 import connexion
 import json
+from jsonschema.exceptions import ValidationError
 from a1 import get_module_logger
 from a1 import a1rmr, exceptions, utils
 
@@ -47,6 +48,9 @@
     """
     try:
         return func()
+    except ValidationError as exc:
+        logger.exception(exc)
+        return "", 400
     except exceptions.PolicyNotFound as exc:
         logger.exception(exc)
         return "", 404
diff --git a/container-tag.yaml b/container-tag.yaml
index 623599d..d3e22b4 100644
--- a/container-tag.yaml
+++ b/container-tag.yaml
@@ -1,4 +1,4 @@
 # 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.8.3
+tag: 0.8.4
diff --git a/docs/developer-guide.rst b/docs/developer-guide.rst
index 60c1d9a..5209cd3 100644
--- a/docs/developer-guide.rst
+++ b/docs/developer-guide.rst
@@ -45,7 +45,8 @@
 
 Unit Testing
 ============
-Note, this requires rmr to be installed on the system executing the tests. Also, this requires the python packages ``tox`` and ``pytest``.
+Note,  before this will work, for the first time on the machine running the tests, run ``./install_deps.sh``. This is only needed once on the machine.
+Also, this requires the python packages ``tox`` and ``pytest``.
 
 ::
 
@@ -89,8 +90,7 @@
 Running locally
 ===============
 
-1. This requires that RMR is installed on the base system. (the
-   Dockerfile does this when running in Docker)
+1. Before this will work, for the first time on that machine, run ``./install_deps.sh``
 
 2. It also requires rmr-python >= 0.10.1 installed. (The dockerfile also
    does this)
@@ -145,7 +145,7 @@
 ::
 
    curl -v -X PUT -H "Content-Type: application/json" -d '{}' localhost:10000/ric/policies/test_policy
-   curl -v -X PUT -H "Content-Type: application/json" -d '{"dc_admission_start_time": "10:00:00", "dc_admission_end_time": "11:00:00"}' localhost:10000/ric/policies/control_admission_time
+   curl -v -X PUT -H "Content-Type: application/json" -d '{ "enforce":true, "window_length":10, "blocking_rate":20, "trigger_threshold":10 }' localhost:10000/ric/policies/admission_control_policy
 
 Finally, there is a test “bombarder” that will flood A1 with messages
 with good message types but bad transaction IDs, to test A1’s resilience
diff --git a/docs/release-notes.rst b/docs/release-notes.rst
index 8cfeee6..3008efb 100644
--- a/docs/release-notes.rst
+++ b/docs/release-notes.rst
@@ -24,6 +24,16 @@
 and this project adheres to `Semantic
 Versioning <http://semver.org/>`__.
 
+[0.8.4] - 7/16/2019
+-------------------
+
+::
+
+   * Fix the 400, which was in the API, but wasn't actually implemented
+   * Update the test fixture manifests to reflect the latest adm control, paves way for next feature coming which is a policy GET
+
+
+
 [0.8.3] - 6/18/2019
 -------------------
 
diff --git a/install_deps.sh b/install_deps.sh
new file mode 100755
index 0000000..f7b3660
--- /dev/null
+++ b/install_deps.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+git clone https://gerrit.oran-osc.org/r/ric-plt/lib/rmr \
+    && cd rmr \
+    && mkdir .build; cd .build; cmake .. -DPACK_EXTERNALS=1; sudo make install \
+    && cd ../.. \
+    && rm -rf rmr
diff --git a/integration_tests/a1mediator/Chart.yaml b/integration_tests/a1mediator/Chart.yaml
index ab5ee57..17253ae 100644
--- a/integration_tests/a1mediator/Chart.yaml
+++ b/integration_tests/a1mediator/Chart.yaml
@@ -1,4 +1,4 @@
 apiVersion: v1
 description: A1 Helm chart for Kubernetes
 name: a1mediator
-version: 0.8.3
+version: 0.8.4
diff --git a/integration_tests/a1mediator/files/ricmanifest.json b/integration_tests/a1mediator/files/ricmanifest.json
index 211a115..300d7e5 100644
--- a/integration_tests/a1mediator/files/ricmanifest.json
+++ b/integration_tests/a1mediator/files/ricmanifest.json
@@ -1,28 +1,43 @@
 {
   "controls":[
     {
-      "name":"control_admission_time",
-      "description":"time period to allow dual connection",
-      "message_receives_rmr_type":"DC_ADMISSION_INTERVAL_CONTROL",
+      "name":"admission_control_policy",
+      "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":{
-          "dc_admission_start_time":{
-            "type":"string",
-            "pattern":"^[0-9]{2}:[0-9]{2}:[0-9]{2}$"
+          "enforce":{
+            "type":"boolean",
+            "default":true
           },
-          "dc_admission_end_time":{
-            "type":"string",
-            "pattern":"^[0-9]{2}:[0-9]{2}:[0-9]{2}$"
+          "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":[
-          "dc_admission_start_time",
-          "dc_admission_end_time"
-        ]
+        "additionalProperties":false
       },
-      "message_sends_rmr_type":"DC_ADMISSION_INTERVAL_CONTROL_ACK",
+      "message_sends_rmr_type":"DC_ADM_INT_CONTROL_ACK",
       "message_sends_payload_schema":{
         "$schema":"http://json-schema.org/draft-07/schema#",
         "type":"object",
@@ -37,7 +52,11 @@
           "message":{
             "type":"string"
           }
-        }
+        },
+        "required":[
+          "status"
+        ],
+        "additionalProperties":false
       }
     },
     {
diff --git a/integration_tests/a1mediator/files/rmr_string_int_mapping.txt b/integration_tests/a1mediator/files/rmr_string_int_mapping.txt
index ff1479d..1f194b8 100644
--- a/integration_tests/a1mediator/files/rmr_string_int_mapping.txt
+++ b/integration_tests/a1mediator/files/rmr_string_int_mapping.txt
@@ -1,4 +1,4 @@
-DC_ADMISSION_INTERVAL_CONTROL:20000
-DC_ADMISSION_INTERVAL_CONTROL_ACK:20001
+DC_ADM_INT_CONTROL:20000
+DC_ADM_INT_CONTROL_ACK:20001
 TEST_REQ:10000
 TEST_ACK:10001
diff --git a/integration_tests/putdata b/integration_tests/putdata
index 329851c..a2f8d11 100644
--- a/integration_tests/putdata
+++ b/integration_tests/putdata
@@ -1 +1,6 @@
-{"dc_admission_start_time": "10:00:00", "dc_admission_end_time": "11:00:00"}
+{
+    "enforce":true,
+    "window_length":10,
+    "blocking_rate":20,
+    "trigger_threshold":10
+}
diff --git a/integration_tests/test_a1.tavern.yaml b/integration_tests/test_a1.tavern.yaml
index 5ecb69a..8409056 100644
--- a/integration_tests/test_a1.tavern.yaml
+++ b/integration_tests/test_a1.tavern.yaml
@@ -27,11 +27,13 @@
 stages:
   - name: test the admission control policy
     request:
-      url: http://localhost:10000/ric/policies/control_admission_time
+      url: http://localhost:10000/ric/policies/admission_control_policy
       method: PUT
       json:
-        dc_admission_start_time: "10:00:00"
-        dc_admission_end_time: "11:00:00"
+        enforce: true
+        window_length: 10
+        blocking_rate: 20
+        trigger_threshold: 10
       headers:
         content-type: application/json
     response:
@@ -56,15 +58,26 @@
     response:
       status_code: 404
 
+  - name: bad body for admission control policy
+    request:
+      url: http://localhost:10000/ric/policies/admission_control_policy
+      method: PUT
+      json:
+        not: "expected"
+      headers:
+        content-type: application/json
+    response:
+      status_code: 400
+
   - name: not a json
     request:
-      url: http://localhost:10000/ric/policies/control_admission_time
+      url: http://localhost:10000/ric/policies/admission_control_policy
       method: PUT
       data: "asdf"
     response:
       status_code: 415
 
-  - name: body not expected
+  - name: bad body for test policy
     request:
       url: http://localhost:10000/ric/policies/test_policy
       method: PUT
diff --git a/setup.py b/setup.py
index 66be986..b55ab6c 100644
--- a/setup.py
+++ b/setup.py
@@ -18,7 +18,7 @@
 
 setup(
     name="a1",
-    version="0.8.3",
+    version="0.8.4",
     packages=find_packages(exclude=["tests.*", "tests"]),
     author="Tommy Carpenter",
     description="RIC A1 Mediator for policy/intent changes",
diff --git a/tests/fixtures/ricmanifest.json b/tests/fixtures/ricmanifest.json
index 211a115..300d7e5 100644
--- a/tests/fixtures/ricmanifest.json
+++ b/tests/fixtures/ricmanifest.json
@@ -1,28 +1,43 @@
 {
   "controls":[
     {
-      "name":"control_admission_time",
-      "description":"time period to allow dual connection",
-      "message_receives_rmr_type":"DC_ADMISSION_INTERVAL_CONTROL",
+      "name":"admission_control_policy",
+      "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":{
-          "dc_admission_start_time":{
-            "type":"string",
-            "pattern":"^[0-9]{2}:[0-9]{2}:[0-9]{2}$"
+          "enforce":{
+            "type":"boolean",
+            "default":true
           },
-          "dc_admission_end_time":{
-            "type":"string",
-            "pattern":"^[0-9]{2}:[0-9]{2}:[0-9]{2}$"
+          "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":[
-          "dc_admission_start_time",
-          "dc_admission_end_time"
-        ]
+        "additionalProperties":false
       },
-      "message_sends_rmr_type":"DC_ADMISSION_INTERVAL_CONTROL_ACK",
+      "message_sends_rmr_type":"DC_ADM_INT_CONTROL_ACK",
       "message_sends_payload_schema":{
         "$schema":"http://json-schema.org/draft-07/schema#",
         "type":"object",
@@ -37,7 +52,11 @@
           "message":{
             "type":"string"
           }
-        }
+        },
+        "required":[
+          "status"
+        ],
+        "additionalProperties":false
       }
     },
     {
diff --git a/tests/fixtures/rmr_string_int_mapping.txt b/tests/fixtures/rmr_string_int_mapping.txt
index ff1479d..1f194b8 100644
--- a/tests/fixtures/rmr_string_int_mapping.txt
+++ b/tests/fixtures/rmr_string_int_mapping.txt
@@ -1,4 +1,4 @@
-DC_ADMISSION_INTERVAL_CONTROL:20000
-DC_ADMISSION_INTERVAL_CONTROL_ACK:20001
+DC_ADM_INT_CONTROL:20000
+DC_ADM_INT_CONTROL_ACK:20001
 TEST_REQ:10000
 TEST_ACK:10001
diff --git a/tests/test_controller.py b/tests/test_controller.py
index 680f586..5370207 100644
--- a/tests/test_controller.py
+++ b/tests/test_controller.py
@@ -90,6 +90,15 @@
     monkeypatch.setattr("rmr.rmr.generate_and_set_transaction_id", fake_set_transactionid)
 
 
+def test_xapp_put_good(client, monkeypatch):
+    """ test policy put good"""
+    _test_put_patch(monkeypatch)
+    monkeypatch.setattr("a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch))
+    res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
+    assert res.status_code == 200
+    assert res.json == {"status": "SUCCESS", "foo": "bar"}
+
+
 def test_xapp_put_bad(client, monkeypatch):
     """Test policy put fails"""
     _test_put_patch(monkeypatch)
@@ -97,14 +106,14 @@
     monkeypatch.setattr(
         "a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch, msg_payload={"status": "FAIL", "foo": "bar"})
     )
-    res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+    res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
     assert res.status_code == 502
     assert res.json["reason"] == "BAD STATUS"
     assert res.json["return_payload"] == {"status": "FAIL", "foo": "bar"}
 
     # return from policy handler has no status field
     monkeypatch.setattr("a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch, msg_payload={"foo": "bar"}))
-    res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+    res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
     assert res.status_code == 502
     assert res.json["reason"] == "NO STATUS"
     assert res.json["return_payload"] == {"foo": "bar"}
@@ -113,48 +122,41 @@
     monkeypatch.setattr(
         "a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch, msg_payload="booger", jsonb=False)
     )
-    res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+    res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
     assert res.status_code == 502
     assert res.json["reason"] == "NOT JSON"
     assert res.json["return_payload"] == "booger"
 
     # bad type
     monkeypatch.setattr("a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch, msg_type=666))
-    res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+    res = client.put("/ric/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"
 
     # bad state
     monkeypatch.setattr("a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch, msg_state=666))
-    res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+    res = client.put("/ric/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_xapp_put_good(client, monkeypatch):
-    """ test policy put good"""
-    _test_put_patch(monkeypatch)
-
-    # do a good one
-    monkeypatch.setattr("a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch))
-    res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
-    assert res.status_code == 200
-    assert res.json == {"status": "SUCCESS", "foo": "bar"}
-
-
 def test_xapp_put_bad_send(client, monkeypatch):
     """
     Test bad send failures
     """
     testing_helpers.patch_all(monkeypatch)
 
+    monkeypatch.setattr("a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch))
+    res = client.put("/ric/policies/admission_control_policy", json={"not": "expected"})
+    assert res.status_code == 400
+
     monkeypatch.setattr("rmr.rmr.rmr_send_msg", rmr_mocks.send_mock_generator(10))
-    res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+    res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
     assert res.status_code == 504
     assert res.data == b'"A1 was unable to send a needed message to a downstream subscriber"\n'
 
     monkeypatch.setattr("rmr.rmr.rmr_send_msg", rmr_mocks.send_mock_generator(5))
-    res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+    res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
     assert res.status_code == 504
     assert res.data == b'"A1 was unable to send a needed message to a downstream subscriber"\n'
 
@@ -168,7 +170,7 @@
     assert res.status_code == 404
 
     # bad media type
-    res = client.put("/ric/policies/control_admission_time", data="notajson")
+    res = client.put("/ric/policies/admission_control_policy", data="notajson")
     assert res.status_code == 415
 
     # test a PUT body against a poliucy not expecting one
@@ -187,9 +189,7 @@
 
     monkeypatch.setattr("a1.utils.get_ric_manifest", f)
 
-    res = client.put(
-        "/ric/policies/control_admission_time", json=testing_helpers.good_payload(), headers={"Content-Type": "text/plain"}
-    )
+    res = client.put("/ric/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'
 
@@ -199,8 +199,6 @@
     test that we get a 500 with an approrpiate message on a missing rmr rmr_string
     """
     testing_helpers.patch_all(monkeypatch, nonexisting_rmr=True)
-    res = client.put(
-        "/ric/policies/control_admission_time", json=testing_helpers.good_payload(), headers={"Content-Type": "text/plain"}
-    )
+    res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
     assert res.status_code == 500
     assert res.data == b'"A1 does not have a mapping for the desired rmr string. report this!"\n'
diff --git a/tests/testing_helpers.py b/tests/testing_helpers.py
index 3cf94e2..b258a85 100644
--- a/tests/testing_helpers.py
+++ b/tests/testing_helpers.py
@@ -39,4 +39,4 @@
 
 
 def good_payload():
-    return {"dc_admission_start_time": "10:00:00", "dc_admission_end_time": "11:00:00"}
+    return {"enforce": True, "window_length": 10, "blocking_rate": 20, "trigger_threshold": 10}
diff --git a/tox-integration.ini b/tox-integration.ini
index b3a9183..aa2ce36 100644
--- a/tox-integration.ini
+++ b/tox-integration.ini
@@ -40,7 +40,7 @@
     echo "running tavern"
     pytest
     echo "running ab"
-    ab -n 100 -c 10 -u putdata -T application/json http://localhost:10000/ric/policies/control_admission_time
+    ab -n 100 -c 10 -u putdata -T application/json http://localhost:10000/ric/policies/admission_control_policy
 commands_post=
     helm delete testreceiver
     helm del --purge testreceiver
diff --git a/tox.ini b/tox.ini
index a89f0a6..976ddc7 100644
--- a/tox.ini
+++ b/tox.ini
@@ -26,7 +26,9 @@
     LD_LIBRARY_PATH = /usr/local/lib/
     RMR_RCV_RETRY_INTERVAL = 1
     RMR_RETRY_TIMES = 2
-commands=pytest --verbose --cov {envsitepackagesdir}/a1  --cov-report html
+commands=
+# Note, before this will work, for the first time on that machine, run ./install_deps.sh
+    pytest --verbose --cov {envsitepackagesdir}/a1  --cov-report html
 
 [testenv:flake8]
 basepython = python3.7