From e66b38ea9a35418e49585927d65b875161808561 Mon Sep 17 00:00:00 2001 From: Eric K Date: Thu, 19 Jan 2017 19:58:08 -0800 Subject: [PATCH] Update and add haht rule test cases for locking Conflicting* rules sent to different PE's immediately rejected without wait. Also allow unofficial support for sqlite /w replicated_policy_engine *duplicate, recursion, schema mismatch Change-Id: I9c634db3c2eddb374914f34dc53a2574f0880461 --- congress/db/api.py | 2 +- congress/server/congress_server.py | 14 +- congress/tests/etc/congress.conf.test.ha_pe1 | 1 + congress/tests/etc/congress.conf.test.ha_pe2 | 1 + congress/tests/haht/test_congress_haht.py | 127 ++++++++++++------- 5 files changed, 91 insertions(+), 54 deletions(-) diff --git a/congress/db/api.py b/congress/db/api.py index 1f26c1f40..269d8de9d 100644 --- a/congress/db/api.py +++ b/congress/db/api.py @@ -92,7 +92,7 @@ def commit_unlock_tables(session): # unlock if is_mysql(): session.execute('UNLOCK TABLES') - # postgres automatically releases lock at transaction + # postgres automatically releases lock at transaction end def is_mysql(): diff --git a/congress/server/congress_server.py b/congress/server/congress_server.py index 51353a25b..ec2f1d6ed 100644 --- a/congress/server/congress_server.py +++ b/congress/server/congress_server.py @@ -147,10 +147,16 @@ def main(): "the '--config-file' option!") if cfg.CONF.replicated_policy_engine and not ( db_api.is_mysql() or db_api.is_postgres()): - sys.exit("ERROR: replicated_policy_engine option can be used only with" - " MySQL or PostgreSQL database backends. Please set the " - "connection option in [database] section of congress.conf " - "to use a supported backend.") + if db_api.is_sqlite(): + LOG.warning("Deploying replicated policy engine with SQLite " + "backend is not officially supported. Unexpected " + "behavior may occur. Officially supported backends " + "are MySQL and PostgresSQL.") + else: + sys.exit("ERROR: replicated_policy_engine option can be used only " + "with MySQL or PostgreSQL database backends. Please set " + "the connection option in [database] section of " + "congress.conf to use a supported backend.") config.setup_logging() if not (cfg.CONF.api or cfg.CONF.policy_engine or cfg.CONF.datasources): diff --git a/congress/tests/etc/congress.conf.test.ha_pe1 b/congress/tests/etc/congress.conf.test.ha_pe1 index 83da5a270..71619d417 100644 --- a/congress/tests/etc/congress.conf.test.ha_pe1 +++ b/congress/tests/etc/congress.conf.test.ha_pe1 @@ -3,6 +3,7 @@ bind_port = 4001 auth_strategy = noauth datasource_sync_period = 5 debug = True +replicated_policy_engine = True [database] # connection = mysql+pymysql://root:password@127.0.0.1/congress?charset=utf8 diff --git a/congress/tests/etc/congress.conf.test.ha_pe2 b/congress/tests/etc/congress.conf.test.ha_pe2 index 0e8860a0b..40b16a5a6 100644 --- a/congress/tests/etc/congress.conf.test.ha_pe2 +++ b/congress/tests/etc/congress.conf.test.ha_pe2 @@ -3,6 +3,7 @@ bind_port = 4002 auth_strategy = noauth datasource_sync_period = 5 debug = True +replicated_policy_engine = True [database] # connection = mysql+pymysql://root:password@127.0.0.1/congress?charset=utf8 diff --git a/congress/tests/haht/test_congress_haht.py b/congress/tests/haht/test_congress_haht.py index c9ddca55a..031a9c8a4 100644 --- a/congress/tests/haht/test_congress_haht.py +++ b/congress/tests/haht/test_congress_haht.py @@ -24,36 +24,24 @@ from __future__ import print_function from __future__ import division from __future__ import absolute_import -# Note: monkey patch to allow running this test standalone under 'nose' -import eventlet -eventlet.monkey_patch() - -# import mock - -# from oslo_config import cfg -# cfg.CONF.distributed_architecture = True -# import neutronclient.v2_0 -from oslo_log import log as logging - -# from congress.common import config -# from congress.datasources import neutronv2_driver -# from congress.datasources import nova_driver -from congress.db import api as db -from congress.db import db_policy_rules -# from congress import harness -# from congress.tests.api import base as api_base -from congress.tests import base -# from congress.tests.datasources import test_neutron_driver as test_neutron -from congress.tests import helper - -import requests import shutil import subprocess import sys import tempfile -import tenacity import time +# Note: monkey patch to allow running this test standalone under 'nose' +import eventlet +eventlet.monkey_patch() +from oslo_log import log as logging +import requests +import tenacity + +from congress.db import api as db +from congress.db import db_policy_rules +from congress.tests import base +from congress.tests import helper + LOG = logging.getLogger(__name__) @@ -362,10 +350,6 @@ class TestCongressHAHT(base.SqlTestCase): self.assertEqual(self.pe1.delete( suffix='policies/alice/rules/%s' % rule_id).status_code, 200) - # BUG: should be 201 right away not 409 - self.assertEqual(self.pe2.post( - suffix='policies/alice/rules', json=j).status_code, 409) - time.sleep(10) self.assertEqual(self.pe2.post( suffix='policies/alice/rules', json=j).status_code, 201) @@ -380,22 +364,83 @@ class TestCongressHAHT(base.SqlTestCase): suffix='policies', json={'name': 'alice'}).status_code, 201) j = {'rule': 'p(x) :- q(x)', 'name': 'rule1'} - # inconsistent behavior depending on whether duplicate request - # is processed on same or different PE node self.assertEqual(self.pe2.post( suffix='policies/alice/rules', json=j).status_code, 201) + self.assertEqual(self.pe1.post( + suffix='policies/alice/rules', json=j).status_code, 409) + self.assertEqual(self.pe2.post( suffix='policies/alice/rules', json=j).status_code, 409) + self.assertEqual( + self.pe1.get('policies/alice/rules').status_code, 200) + self.assertTrue( + len(self.pe1.get('policies/alice/rules'). + json()['results']) <= 1) + self.assertEqual( + len(self.pe2.get('policies/alice/rules'). + json()['results']), 1) + except Exception: + self.dump_nodes_logs() + raise + + def test_policy_rule_recursion(self): + try: + # create policy alice in PE1 self.assertEqual(self.pe1.post( - suffix='policies/alice/rules', json=j).status_code, 201) + suffix='policies', json={'name': 'alice'}).status_code, 201) + r1 = {'rule': 'p(x) :- q(x)', 'name': 'rule1'} + r2 = {'rule': 'q(x) :- p(x)', 'name': 'rule2'} + + self.assertEqual(self.pe2.post( + suffix='policies/alice/rules', json=r1).status_code, 201) + + self.assertEqual(self.pe1.post( + suffix='policies/alice/rules', json=r2).status_code, 400) + + self.assertEqual(self.pe2.post( + suffix='policies/alice/rules', json=r2).status_code, 400) self.assertEqual( self.pe1.get('policies/alice/rules').status_code, 200) - self.assertEqual( + self.assertTrue( len(self.pe1.get('policies/alice/rules'). - json()['results']), 2) + json()['results']) <= 1) + self.assertEqual( + len(self.pe2.get('policies/alice/rules'). + json()['results']), 1) + except Exception: + self.dump_nodes_logs() + raise + + def test_policy_rule_schema_mismatch(self): + try: + # create policy alice in PE1 + self.assertEqual(self.pe1.post( + suffix='policies', json={'name': 'alice'}).status_code, 201) + r1 = {'rule': 'p(x) :- q(x)', 'name': 'rule1'} + r2 = {'rule': 'p(x) :- q(x, x)', 'name': 'rule2'} + + self.assertEqual(self.pe2.post( + suffix='policies/alice/rules', json=r1).status_code, 201) + + self.assertEqual(self.pe1.post( + suffix='policies/alice/rules', json=r2).status_code, 400) + + self.assertEqual(self.pe2.post( + suffix='policies/alice/rules', json=r2).status_code, 400) + + self.assertEqual( + self.pe1.get('policies/alice/rules').status_code, 200) + self.assertTrue( + len(self.pe1.get('policies/alice/rules'). + json()['results']) <= 1) + self.assertEqual( + self.pe2.get('policies/alice/rules').status_code, 200) + self.assertEqual( + len(self.pe2.get('policies/alice/rules'). + json()['results']), 1) except Exception: self.dump_nodes_logs() raise @@ -424,22 +469,6 @@ class TestCongressHAHT(base.SqlTestCase): self.assertEqual(self.pe2.post( suffix='policies/alice/rules', json=j).status_code, 201) - # time.sleep(6) - # print(self.pe1.get('policies/alice/tables/p/rows').json()) - # print(self.pe2.get('policies/alice/tables/p/rows').json()) - # - # time.sleep(6) - # print(self.pe1.get('policies/alice/tables/p/rows').json()) - # print(self.pe2.get('policies/alice/tables/p/rows').json()) - # - # self.assertEqual(self.pe1.delete( - # suffix='policies/alice/rules/%s' % q1_id).status_code, 200) - # - # time.sleep(6) - # print(self.pe1.get('policies/alice/tables/p/rows').json()) - # print(self.pe2.get('policies/alice/tables/p/rows').json()) - # assert False - # eval on PE1 helper.retry_check_function_return_value_table( lambda: [x['data'] for x in