def test_empty(self): obj = self.MyObject() run = agnostic.Runtime() run.create_policy('test') run.register_trigger('p', lambda old, new: obj.increment()) run.insert('p(1)') self.assertEqual(obj.value, 1)
def test_dependency_batch_insert(self): obj = self.MyObject() run = agnostic.Runtime() run.create_policy('test') run.register_trigger('p', lambda old, new: obj.increment()) run.insert('q(1) p(x) :- q(x)') self.assertEqual(obj.value, 1)
def test_positional_args_padding_multiple_atoms(self): """Test positional args padding on a single atom.""" def check(code, correct, msg, no_theory=False): actual = compile.parse1( code).eliminate_column_references_and_pad_positional( {} if no_theory else theories) eq = helper.datalog_same(str(actual), correct) self.assertTrue(eq, msg) run = agnostic.Runtime() run.create_policy('nova') schema = compile.Schema({'q': ('id', 'name', 'status'), 'r': ('id', 'age', 'weight')}) theories = {'nova': self.SchemaWrapper(schema)} # Multiple atoms, no shared variable code = ("p(x) :- nova:q(x, y), nova:r(w)") correct = "p(x) :- nova:q(x, y, z0), nova:r(w, y0, y1)" check(code, correct, 'Multiple atoms') # Multiple atoms, some shared variable code = ("p(x) :- nova:q(x, y), nova:r(x)") correct = "p(x) :- nova:q(x, y, z0), nova:r(x, y0, y1)" check(code, correct, 'Multiple atoms') # Multiple atoms, same table code = ("p(x) :- nova:q(x, y), nova:q(x)") correct = "p(x) :- nova:q(x, y, z0), nova:q(x, w0, w1)" check(code, correct, 'Multiple atoms, same table')
def test_dependency_graph(self): """Test that dependency graph gets updated correctly.""" run = agnostic.Runtime() run.debug_mode() g = run.global_dependency_graph run.create_policy('test') run.insert('p(x) :- q(x), nova:q(x)', target='test') self.assertTrue(g.edge_in('test:p', 'nova:q', False)) self.assertTrue(g.edge_in('test:p', 'test:q', False)) run.insert('p(x) :- s(x)', target='test') self.assertTrue(g.edge_in('test:p', 'nova:q', False)) self.assertTrue(g.edge_in('test:p', 'test:q', False)) self.assertTrue(g.edge_in('test:p', 'test:s', False)) run.insert('q(x) :- nova:r(x)', target='test') self.assertTrue(g.edge_in('test:p', 'nova:q', False)) self.assertTrue(g.edge_in('test:p', 'test:q', False)) self.assertTrue(g.edge_in('test:p', 'test:s', False)) self.assertTrue(g.edge_in('test:q', 'nova:r', False)) run.delete('p(x) :- q(x), nova:q(x)', target='test') self.assertTrue(g.edge_in('test:p', 'test:s', False)) self.assertTrue(g.edge_in('test:q', 'nova:r', False)) run.update([ agnostic.Event(helper.str2form('p(x) :- q(x), nova:q(x)'), target='test') ]) self.assertTrue(g.edge_in('test:p', 'nova:q', False)) self.assertTrue(g.edge_in('test:p', 'test:q', False)) self.assertTrue(g.edge_in('test:p', 'test:s', False)) self.assertTrue(g.edge_in('test:q', 'nova:r', False))
def test_column_references_multiple_atoms(self): """Test column references occurring in multiple atoms in a rule.""" def check(code, correct, msg): actual = compile.parse1(code).eliminate_column_references(theories) eq = helper.datalog_same(str(actual), correct) self.assertTrue(eq, msg) run = agnostic.Runtime() run.create_policy('nova') schema = compile.Schema({ 'q': ('id', 'name', 'status'), 'r': ('id', 'age', 'weight') }) theories = {'nova': self.SchemaWrapper(schema)} # Multiple atoms code = ("p(x) :- nova:q(id=x, 2=y), nova:r(id=x)") correct = "p(x) :- nova:q(x, x0, y), nova:r(x, y0, y1)" check(code, correct, 'Multiple atoms') # Multiple atoms sharing column name but different variables code = ("p(x) :- nova:q(id=x), nova:r(id=y)") correct = "p(x) :- nova:q(x, x0, x1), nova:r(y, y0, y1)" check(code, correct, 'Multiple atoms shared column name') # Multiple atoms, same table code = ("p(x) :- nova:q(id=x, 2=y), nova:q(id=x)") correct = "p(x) :- nova:q(x, x0, y), nova:q(x, y0, y1)" check(code, correct, 'Multiple atoms, same table')
def test_duplicates(self): run = agnostic.Runtime() run.create_policy('test') run.insert('p(x) :- q(x)') run.insert('p(x) :- r(x)') run.insert('q(1)') run.insert('r(1)') self.assertEqual(run.simulate('p(x)', 'test', '', 'test'), 'p(1)')
def test_no_dups(self): run = agnostic.Runtime() run.create_policy('test') run.insert('p(x) :- q(x)') run.insert('p(x) :- r(x)') run.insert('q(1)') run.insert('r(1)') self.assertEqual(run.select('p(x)'), 'p(1)')
def test_atom_deletion(self): run = agnostic.Runtime() run.create_policy('test') run.insert('q(x) :- p(x)') run.delete('p(1)') run.delete('p(1)') # actually just testing that no error is thrown self.assertFalse(run.global_dependency_graph.has_cycle())
def test_monadic(self): run = agnostic.Runtime() run.create_policy('test') run.insert('p(x) :- q(x), not r(x)' 'q(1)' 'q(2)' 'r(2)') self.check(run, 'p(1)', 'p(1)', "Monadic negation") self.check(run, 'p(2)', '', "False monadic negation") self.check(run, 'p(x)', 'p(1)', "Variablized monadic negation")
def test_policy_errors(self): """Test errors for multiple policies.""" # errors run = agnostic.Runtime() run.create_policy('existent') self.assertRaises(KeyError, run.create_policy, 'existent') self.assertRaises(KeyError, run.delete_policy, 'nonexistent') self.assertRaises(KeyError, run.policy_object, 'nonexistent')
def test_rule_noop(self): run = agnostic.Runtime() run.create_policy('test') run.insert('q(1) :- p(1)') run.delete('q(2) :- p(2)') self.assertTrue(run.global_dependency_graph.node_in('test:p')) self.assertTrue(run.global_dependency_graph.node_in('test:q')) self.assertTrue( run.global_dependency_graph.edge_in('test:q', 'test:p', False))
def test_initialize_tables(self): """Test initialize_tables() functionality of agnostic.""" run = agnostic.Runtime() run.create_policy('test') run.insert('p(1) p(2)') facts = [Fact('p', (3, )), Fact('p', (4, ))] run.initialize_tables(['p'], facts) e = helper.datalog_equal(run.select('p(x)'), 'p(3) p(4)') self.assertTrue(e)
def test_mid_rule(self): run = agnostic.Runtime() run.create_policy('test') run.insert('p(x) :- q(x), not s(x), r(x)' 'q(1) q(2) q(3) q(4) q(5) q(6)' 's(1) s(3) s(5)' 'r(2) r(6)') self.check(run, 'p(x)', 'p(2) p(6)', "Multiple answers with monadic negation in middle of rule")
def setUp(self): super(TestRuntimePerformance, self).setUp() self._agnostic = agnostic.Runtime() self._agnostic.create_policy(NREC_THEORY, kind=base.NONRECURSIVE_POLICY_TYPE) self._agnostic.create_policy(DB_THEORY, kind=base.DATABASE_POLICY_TYPE) self._agnostic.debug_mode() self._agnostic.insert('', target=NREC_THEORY)
def test_delete_data(self): obj = self.MyObject() run = agnostic.Runtime() run.create_policy('test') run.register_trigger('p', lambda old, new: obj.increment()) run.insert('p(x) :- q(x, y), equal(y, 1)') run.insert('q(1, 1)') self.assertEqual(obj.value, 1) run.delete('q(1, 1)') self.assertEqual(obj.value, 2)
def test_batch_change(self): obj = self.MyObject() run = agnostic.Runtime() run.create_policy('test') run.register_trigger('p', lambda old, new: obj.increment()) p1 = compile.parse1('p(1)') result = run.update([compile.Event(p1, target='test')]) self.assertTrue(result[0], ("Update failed with errors: " + ";".join(str(x) for x in result[1]))) self.assertEqual(obj.value, 1)
def test_dump_load(self): """Test if dumping/loading theories works properly.""" run = agnostic.Runtime() run.create_policy('test') run.debug_mode() policy = ('p(4,"a","bcdef ghi", 17.1) ' 'p(5,"a","bcdef ghi", 17.1) ' 'p(6,"a","bcdef ghi", 17.1)') run.insert(policy) full_path = os.path.realpath(__file__) path = os.path.dirname(full_path) path = os.path.join(path, "snapshot") run.dump_dir(path) run = agnostic.Runtime() run.load_dir(path) e = helper.datalog_equal(run.theory['test'].content_string(), policy, 'Service theory dump/load') self.assertTrue(e)
def test_modal_with_theory(self): """Test that the modal operators work properly with a theory.""" run = agnostic.Runtime() run.debug_mode() run.create_policy("test") run.insert('execute[nova:p(x)] :- q(x)', 'test') run.insert('q(1)', 'test') self.assertTrue( helper.datalog_equal(run.select('execute[nova:p(x)]', 'test'), 'execute[nova:p(1)]'))
def test_policy_creation_after_ref(self): """Test ability to write rules that span multiple policies.""" # Local table used run = agnostic.Runtime() run.create_policy('test1') run.insert('p(x) :- test2:q(x)', 'test1') run.create_policy('test2') run.insert('q(1)', 'test2') actual = run.select('p(x)', 'test1') e = helper.db_equal(actual, 'p(1)') self.assertTrue(e, "Creation after reference")
def test_multi_policies(self): obj = self.MyObject() run = agnostic.Runtime() run.debug_mode() run.create_policy('alice') run.create_policy('bob') run.register_trigger('p', lambda old, new: obj.increment(), 'alice') run.insert('p(x) :- bob:q(x)', target='alice') run.insert('q(1)', target='bob') self.assertEqual(obj.value, 1) run.delete('q(1)', target='bob') self.assertEqual(obj.value, 2)
def test_external(self): """Test ability to write rules that span multiple policies.""" # External theory run = agnostic.Runtime() run.create_policy('test1') run.insert('q(1)', target='test1') run.insert('q(2)', target='test1') run.create_policy('test2') run.insert('p(x) :- test1:q(x)', target='test2') actual = run.select('p(x)', target='test2') e = helper.db_equal(actual, 'p(1) p(2)') self.assertTrue(e, "Basic")
def test_multipolicy_head(self): """Test SELECT with different policy in the head.""" run = agnostic.Runtime() run.debug_mode() run.create_policy('test1', kind='action') run.create_policy('test2', kind='action') (permitted, errors) = run.insert('test2:p+(x) :- q(x)', 'test1') self.assertTrue(permitted, "modals with policy names must be allowed") run.insert('q(1)', 'test1') run.insert('p(2)', 'test2') actual = run.select('test2:p+(x)', 'test1') e = helper.db_equal(actual, 'test2:p+(1)') self.assertTrue(e, "Policy name in the head")
def test_wrong_arity_index(self): run = agnostic.Runtime() run.create_policy('test1') run.insert('p(x) :- r(x), q(y, x)') run.insert('r(1)') run.insert('q(1,1)') # run query first to build index self.assertTrue(helper.datalog_equal(run.select('p(x)'), 'p(1)')) # next insert causes an exceptionsince the thing we indexed on # doesn't exist self.assertRaises(IndexError, run.insert, 'q(5)') # double-check that the error didn't result in an inconsistent state self.assertEqual(run.select('q(5)'), '')
def test_dependency_batch(self): obj = self.MyObject() run = agnostic.Runtime() run.create_policy('test') run.insert('p(x) :- q(x)') run.register_trigger('p', lambda old, new: obj.increment()) rule = compile.parse1('q(x) :- r(x)') data = compile.parse1('r(1)') run.update([ compile.Event(rule, target='test'), compile.Event(data, target='test') ]) self.assertEqual(obj.value, 1)
def test_unregister(self): obj = self.MyObject() run = agnostic.Runtime() run.create_policy('test') trigger = run.register_trigger('p', lambda old, new: obj.increment()) run.insert('p(1)') self.assertEqual(obj.value, 1) run.unregister_trigger(trigger) self.assertEqual(obj.value, 1) run.insert('p(2)') self.assertEqual(obj.value, 1) self.assertRaises(KeyError, run.unregister_trigger, trigger) self.assertEqual(obj.value, 1)
def test_local(self): """Test ability to write rules that span multiple policies.""" # Local table used run = agnostic.Runtime() run.create_policy('test1') run.insert('q(1)', target='test1') run.insert('q(2)', target='test1') run.create_policy('test2') run.insert('p(x) :- test1:q(x), q(x)', target='test2') run.insert('q(2)', 'test2') actual = run.select('p(x)', target='test2') e = helper.db_equal(actual, 'p(2)') self.assertTrue(e, "Local table used")
def test_negation(self): obj = self.MyObject() run = agnostic.Runtime() run.create_policy('test') run.insert('p(x) :- q(x), not r(x)') run.insert('q(1)') run.insert('q(2)') run.insert('r(2)') run.register_trigger('p', lambda old, new: obj.increment()) run.insert('r(1)') self.assertEqual(obj.value, 1) run.register_trigger('p', lambda old, new: obj.increment()) run.delete('r(1)') self.assertEqual(obj.value, 3)
def prep_runtime(self, code=None, msg=None, target=None): # compile source if msg is not None: LOG.debug(msg) if code is None: code = "" if target is None: target = NREC_THEORY run = agnostic.Runtime() run.create_policy(NREC_THEORY, kind=NONRECURSIVE_POLICY_TYPE) run.create_policy(DB_THEORY, kind=DATABASE_POLICY_TYPE) run.debug_mode() run.insert(code, target=target) return run
def prep_runtime(self, code=None, msg=None, target=None, theories=None): if code is None: code = "" if target is None: target = self.DEFAULT_THEORY run = agnostic.Runtime() run.create_policy(self.DEFAULT_THEORY, abbr='default') run.create_policy(self.ACTION_THEORY, abbr='action', kind='action') if theories: for theory in theories: run.create_policy(theory) run.debug_mode() run.insert(code, target=target) return run
def test_multi_external(self): """Test multiple rules that span multiple policies.""" run = agnostic.Runtime() run.debug_mode() run.create_policy('test1') run.create_policy('test2') run.create_policy('test3') run.insert('p(x) :- test2:p(x)', target='test1') run.insert('p(x) :- test3:p(x)', target='test1') run.insert('p(1)', target='test2') run.insert('p(2)', target='test3') actual = run.select('p(x)', target='test1') e = helper.db_equal(actual, 'p(1) p(2)') self.assertTrue(e, "Multiple external rules with multiple policies")