about summary refs log tree commit diff
path: root/tests/unit
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit')
-rw-r--r--tests/unit/test_mysqldb.py2
-rw-r--r--tests/unit/test_privileges_checking.py39
-rw-r--r--tests/unit/test_privileges_spec_parsing.py174
3 files changed, 214 insertions, 1 deletions
diff --git a/tests/unit/test_mysqldb.py b/tests/unit/test_mysqldb.py
index df8fd49..d1167f0 100644
--- a/tests/unit/test_mysqldb.py
+++ b/tests/unit/test_mysqldb.py
@@ -21,7 +21,7 @@ def test_database_connection(mock_db_parser, mock_sql):
     mock_sql.Error = Exception
     with database_connection("mysql://guest:4321@localhost/users") as _conn:
         mock_sql.connect.assert_called_with(
-            db="users", user="guest", passwd="4321", host="localhost",
+            database="users", user="guest", password="4321", host="localhost",
             port=3306)
 
 
diff --git a/tests/unit/test_privileges_checking.py b/tests/unit/test_privileges_checking.py
new file mode 100644
index 0000000..05969b1
--- /dev/null
+++ b/tests/unit/test_privileges_checking.py
@@ -0,0 +1,39 @@
+"""Tests to verify the privileges check works."""
+import pytest
+
+from gn_libs.privileges import check
+
+@pytest.mark.unit_test
+@pytest.mark.parametrize(
+    "spec,privileges,expected",
+    (("(AND priv1 priv2 priv3)",
+      ("priv2", "priv4", "priv1", "priv6", "priv3"),
+      True),
+     ("(AND priv1 priv2 priv3)",
+      ("priv1", "priv2", "priv4" "priv6"),
+      False),
+     ("(AND priv1 priv2 priv3)",
+      ("priv1", "priv4" "priv6"),
+      False),
+     ("(AND priv1 priv2 priv3)",
+      ("priv4", "priv5", "priv6"),
+      False),
+     ("(OR priv1 priv2 priv3)",
+      ("priv1", "priv2" "priv3"),
+      True),
+     ("(OR priv1 priv2 priv3)",
+      ("priv1", "priv2" "priv4", "priv5"),
+      True),
+     ("(OR priv1 priv2 priv3)",
+      ("priv1", "priv4", "priv5"),
+      True),
+     ("(OR priv1 priv2 priv3)",
+      ("priv4", "priv5", "priv6"),
+      False)))
+def test_check(spec, privileges, expected):
+    """
+    GIVEN: A privileges-check specification, and a tuple of privileges
+    WHEN: A check is performed
+    THEN: Verify that the check returns the expected value
+    """
+    assert check(spec, privileges) == expected
diff --git a/tests/unit/test_privileges_spec_parsing.py b/tests/unit/test_privileges_spec_parsing.py
new file mode 100644
index 0000000..124f570
--- /dev/null
+++ b/tests/unit/test_privileges_spec_parsing.py
@@ -0,0 +1,174 @@
+"""Tests for parsing the privileges checks specification."""
+import pytest
+
+from gn_libs.privileges import parse, SpecificationValueError
+
+
+## NOTE: Should we limit depth of nesting of checks, e.g. don't do more than
+## 3 levels or so?
+
+
+@pytest.mark.unit_test
+@pytest.mark.parametrize(
+    "spec",
+    ("",
+     "(AND)",
+     "(AND (OR))",
+     "(OR (AND))",
+     "(OR (AND (OR (AND ))))"))
+def test_empty_spec(spec):
+    """
+    GIVEN: An effectively empty specification
+    WHEN: The specification is parsed
+    THEN: Raise a `SpecificationValueError`
+    """
+    with pytest.raises(SpecificationValueError):
+        parse(spec)
+
+
+@pytest.mark.unit_test
+@pytest.mark.parametrize(
+    "spec,expected",
+    (("(AND priv1)", ("AND", ("priv1",))),
+     ("(AND priv1 priv2)", ("AND", ("priv1", "priv2"))),
+     ("(AND priv1 priv2 priv3)", ("AND", ("priv1", "priv2", "priv3"))),
+     ("(and priv1)", ("AND", ("priv1",))),
+     ("(and priv1 priv2)", ("AND", ("priv1", "priv2"))),
+     ("(and priv1 priv2 priv3)", ("AND", ("priv1", "priv2", "priv3"))),
+     ("(and priv1 priv2 (and priv3 priv4))",
+      ("AND", ("priv1", "priv2", "priv3", "priv4")))))
+def test_and(spec, expected):
+    """
+    GIVEN: A simple 'AND' privileges check specification `spec`
+    WHEN: The specification is parsed
+    THEN: Verify the parsed output gives an 'AND' check object
+    """
+    assert parse(spec) == expected
+
+
+@pytest.mark.unit_test
+@pytest.mark.parametrize(
+    "spec,expected",
+    (("(OR priv1)", ("OR", ("priv1",))),
+     ("(OR priv1 priv2)", ("OR", ("priv1", "priv2"))),
+     ("(OR priv1 priv2 priv3)", ("OR", ("priv1", "priv2", "priv3"))),
+     ("(or priv1)", ("OR", ("priv1",))),
+     ("(or priv1 priv2)", ("OR", ("priv1", "priv2"))),
+     ("(or priv1 priv2 priv3)", ("OR", ("priv1", "priv2", "priv3")))))
+def test_or(spec, expected):
+    """
+    GIVEN: A simple 'OR' privileges check specification `spec`
+    WHEN: The specification is parsed
+    THEN: Verify the parsed output gives an 'OR' check object
+    """
+    assert parse(spec) == expected
+
+
+@pytest.mark.unit_test
+@pytest.mark.parametrize(
+    "spec,expected",
+    (("(or priv1 priv2 (or priv3 priv4))",
+      ("OR", ("priv1", "priv2", "priv3", "priv4"))),
+     ("(and priv1 priv2 (and priv3 priv4))",
+      ("AND", ("priv1", "priv2", "priv3", "priv4")))))
+def test_merging(spec, expected):
+    """
+    GIVEN:
+    - A nested specification where 2 or more of subsequent operators are
+    - the same
+    WHEN: The specification is parsed
+    THEN: Verify the parsed output merges the checks into a single object
+    """
+    # NOTE: The "given-when-then" description above does not please me.
+    assert parse(spec) == expected
+
+
+@pytest.mark.unit_test
+@pytest.mark.parametrize(
+    "spec,expected",
+    (("(AND priv1 (or priv2 priv3))",
+      ("AND", ("priv1",), ("OR", ("priv2", "priv3")))),))
+def test_and_or(spec, expected):
+    """
+    GIVEN:
+    - A specification beginning with an "AND" operator followed by an "OR"
+    - operator
+    WHEN: The specification is parsed
+    THEN: Verify the parsed output is correct
+    """
+    assert parse(spec) == expected
+
+
+@pytest.mark.unit_test
+@pytest.mark.parametrize(
+    "spec,expected",
+    (("(OR priv1 priv2 priv3 (and priv4 priv5))",
+      ("OR", ("priv1", "priv2", "priv3"), ("AND", ("priv4", "priv5")))),))
+def test_or_and(spec, expected):
+    """
+    GIVEN:
+    - A specification beginning with an "OR" operator followed by an "AND"
+    - operator
+    WHEN: The specification is parsed
+    THEN: Verify the parsed output is correct
+    """
+    assert parse(spec) == expected
+
+
+@pytest.mark.unit_test
+@pytest.mark.parametrize(
+    "spec",
+    ("()",
+     "this is invalid",
+     "priv1 AND priv2",
+     "(priv1 AND priv2)",
+     "(AND priv1 priv2 priv3"))
+def test_invalid(spec):
+    """
+    GIVEN: An invalid specification
+    WHEN: The specification is parsed
+    THEN: Verify that the `SpecificationValueError` is raised
+    """
+    # NOTE: Maybe use hypothesis to generate random strings?
+    with pytest.raises(SpecificationValueError):
+        assert parse(spec)
+
+
+@pytest.mark.unit_test
+@pytest.mark.parametrize(
+    "spec,expected",
+    (("(AND priv1 (or priv2 priv3) priv4 (and priv5 priv6))",
+      ("AND",
+       ("priv1", "priv4", "priv5", "priv6"),
+       ("OR", ("priv2", "priv3")))),))
+def test_complex(spec, expected):
+    """
+    GIVEN: An valid, but more complex specification
+    WHEN: The specification is parsed
+    THEN: Verify that the specification parses correctly
+    """
+    assert parse(spec) == expected
+
+
+@pytest.mark.unit_test
+@pytest.mark.parametrize(
+    "spec,expected",
+    (
+        # -- We need to be careful about reduction --
+        # -- Please revisit your boolean logic to verify --
+        # -- how to reduce boolean statements. --
+        # ("(AND priv1 (or priv2 priv3) priv4 (or priv5 priv6))",
+        #  ("AND",
+        #   ("priv1", "priv4"),
+        #   ("OR", ("priv2", "priv3", "priv5", "priv6")))),
+        ("(OR priv1 (or priv2 priv3 (or priv4 priv5)) (or priv6 priv7))",
+         ("OR", ("priv1", "priv6", "priv7", "priv2", "priv3", "priv4", "priv5"))),))
+def test_reduction(spec, expected):
+    """
+    GIVEN: A spec that can be reduced
+    WHEN: The specification is parsed
+    THEN:
+    - Verify that after parsing, it is reduced to the minimum number of levels
+    - possible.
+    """
+    assert parse(spec) == expected