From df32cb92737966233ae5ae870cdd318bec3ea986 Mon Sep 17 00:00:00 2001 From: Stevan Andjelkovic Date: Tue, 19 Jan 2021 13:46:38 +0100 Subject: [PATCH] test(ldfi): separate db loading from sat forumla creation --- src/ldfi/ldfi/__init__.py | 33 +++++++++++++++++++- src/ldfi/setup.py | 2 +- src/ldfi/shell.nix | 2 +- src/ldfi/tests/test_ldfi.py | 60 ++++++++++++++++++++++++++++++++++++- 4 files changed, 93 insertions(+), 4 deletions(-) diff --git a/src/ldfi/ldfi/__init__.py b/src/ldfi/ldfi/__init__.py index 457821ad..b539a563 100644 --- a/src/ldfi/ldfi/__init__.py +++ b/src/ldfi/ldfi/__init__.py @@ -4,7 +4,7 @@ import os import sqlite3 import z3 -from typing import (List, Set) +from typing import (List, Set, Dict) from pkg_resources import get_distribution class Config: @@ -64,6 +64,11 @@ class Storage: def load(self, config: Config) -> Data: pass + def load_previous_faults(self, config: Config) -> List[List[Dict]]: + pass + def load_potential_faults(self, config: Config) -> List[List[Dict]]: + pass + def store(self, event: Event): pass @@ -75,6 +80,32 @@ def __init__(self): self.conn.row_factory = sqlite3.Row self.c = self.conn.cursor() + def load_previous_faults(self, config: Config) -> List[List[Dict]]: + self.c.execute("""SELECT faults FROM faults + WHERE test_id = '%s' + ORDER BY run_id ASC""" % config.test_id) + + return [ json.loads(row["faults"]) for row in self.c.fetchall() ] + + def load_potential_faults(self, config: Config) -> List[List[Dict]]: + potential_faults: List[List[Dict]] = [ [] for _ in range(len(config.run_ids)) ] + self.c.execute("""SELECT run_id,`from`,`to`,at FROM network_trace + WHERE test_id = %d + AND kind <> 'timer' + AND NOT (`from` LIKE 'client:%%') + AND NOT (`to` LIKE 'client:%%') + ORDER BY run_id ASC""" % config.test_id) + i = 0 + run_id = config.run_ids[0] + for row in self.c.fetchall(): + if row["run_id"] != run_id: + run_id = row["run_id"] + i += 1 + potential_faults[i].append( + {"from": row["from"], "to": row["to"], "at": row["at"]}) + + return potential_faults + def load(self, config: Config) -> Data: previous_faults = [] potential_faults = [] diff --git a/src/ldfi/setup.py b/src/ldfi/setup.py index 07323dce..f5e0ffac 100644 --- a/src/ldfi/setup.py +++ b/src/ldfi/setup.py @@ -4,7 +4,7 @@ name='ldfi', use_scm_version=True, description='Lineage-driven fault injection', - url='https://github.com/symbiont-io/symbiont-node', + url='https://github.com/symbiont-io/detsys-testkit/src/ldfi', author='Stevan Andjelkovic', author_email='stevan.andjelkovic@symbiont.io', license='BSD 2-clause', diff --git a/src/ldfi/shell.nix b/src/ldfi/shell.nix index e81084b4..f27357f0 100644 --- a/src/ldfi/shell.nix +++ b/src/ldfi/shell.nix @@ -9,7 +9,7 @@ let pythonPackages = python38Packages; gitignoreSource = gitignoreSource; }; - pythonEnv = python38.withPackages (ps: [ ldfi ]); + pythonEnv = python38.withPackages (ps: [ ldfi ps.pytest ]); in mkShell { diff --git a/src/ldfi/tests/test_ldfi.py b/src/ldfi/tests/test_ldfi.py index d6715e02..c698a5e7 100644 --- a/src/ldfi/tests/test_ldfi.py +++ b/src/ldfi/tests/test_ldfi.py @@ -1,5 +1,9 @@ -import logging +import json import ldfi +import tempfile +import logging +import os +import sqlite3 import z3 from z3 import (And, Or, Not, Bool) @@ -18,6 +22,60 @@ def test_sorted_faults(): def o(f, t, at): return ('{"kind": "omission", "from": "%s", "to": "%s", "at": %d}' % (f, t, at)) +def test_load_previous_faults(): + db = os.path.join(tempfile.gettempdir(), "detsys_pytest.sqlite3") + os.environ["DETSYS_DB"] = db + storage = ldfi.SqliteStorage() + # TODO(stevan): add contract test in db component saying ldfi expects the + # following table and fields. + storage.c.execute("""CREATE TABLE IF NOT EXISTS faults ( + test_id INT NOT NULL, + run_id INT NOT NULL, + faults JSON NOT NULL)""") + storage.conn.commit() + config = ldfi.Config(1, [0, 1], 2, 0) + assert storage.load_previous_faults(config) == [] + + faults1 = '{"faults": [%s]}' % o("A", "B", 1) + faults2 = '{"faults": [%s, %s]}' % (o("A", "B", 1), o("A", "C", 2)) + storage.c.execute("INSERT INTO faults VALUES(?, ?, ?)", (1, 0, faults1)) + storage.c.execute("INSERT INTO faults VALUES(?, ?, ?)", (1, 1, faults2)) + storage.conn.commit() + assert storage.load_previous_faults(config) == [ + {"faults": [{"kind": "omission", "from": "A", "to": "B", "at": 1}]}, + {"faults": [{"kind": "omission", "from": "A", "to": "B", "at": 1}, + {"kind": "omission", "from": "A", "to": "C", "at": 2}]}] + +def test_load_potential_faults(caplog): + caplog.set_level(logging.DEBUG) + db = os.path.join(tempfile.gettempdir(), "detsys_pytest.sqlite3") + os.environ["DETSYS_DB"] = db + storage = ldfi.SqliteStorage() + # TODO(stevan): add contract test in db component saying ldfi expects the + # following table and fields. + storage.c.execute("""CREATE TABLE IF NOT EXISTS network_trace ( + test_id INT NOT NULL, + run_id INT NOT NULL, + kind TEXT NOT NULL, + `from` TEXT NOT NULL, + `to` TEXT NOT NULL, + at INT NOT NULL)""") + storage.conn.commit() + config = ldfi.Config(1, [0, 1], 2, 0) + assert storage.load_potential_faults(config) == [[], []] + + storage.c.execute("INSERT INTO network_trace VALUES(?, ?, ?, ?, ?, ?)", + (1, 0, "message", "A", "B", 1)) + storage.c.execute("INSERT INTO network_trace VALUES(?, ?, ?, ?, ?, ?)", + (1, 0, "message", "A", "C", 1)) + storage.c.execute("INSERT INTO network_trace VALUES(?, ?, ?, ?, ?, ?)", + (1, 1, "message", "A", "C", 2)) + storage.conn.commit() + assert storage.load_potential_faults(config) == [ + [{"from": "A", "to": "B", "at": 1}, + {"from": "A", "to": "C", "at": 1}], + [{"from": "A", "to": "C", "at": 2}]] + def test_create_formula(caplog): caplog.set_level(logging.DEBUG)