diff --git a/quorums/quorum_system.py b/quorums/quorum_system.py index acbec6e..9d0600f 100644 --- a/quorums/quorum_system.py +++ b/quorums/quorum_system.py @@ -180,8 +180,8 @@ class QuorumSystem(Generic[T]): read_quorums = self._minimize(read_quorums) write_quorums = self._minimize(write_quorums) - sigma_r = {frozenset(rq): 1 / len(rq) for rq in read_quorums} - sigma_w = {frozenset(wq): 1 / len(wq) for wq in write_quorums} + sigma_r = {frozenset(q): 1 / len(read_quorums) for q in read_quorums} + sigma_w = {frozenset(q): 1 / len(write_quorums) for q in write_quorums} return Strategy(self, sigma_r, sigma_w) def strategy(self, diff --git a/tests/test_quorum_system.py b/tests/test_quorum_system.py new file mode 100644 index 0000000..cf97ba4 --- /dev/null +++ b/tests/test_quorum_system.py @@ -0,0 +1,132 @@ +from quorums import * +from quorums.quorum_system import * +import unittest + +class TestExpr(unittest.TestCase): + def test_init(self): + def quorums(e: Expr['str']) -> FrozenSet[FrozenSet[str]]: + return frozenset(frozenset(q) for q in e.quorums()) + + def assert_equal(x: Expr['str'], y: Expr['str']) -> None: + self.assertEqual(quorums(x), quorums(y)) + + a = Node('a') + b = Node('b') + c = Node('c') + d = Node('d') + + # Specify reads. + qs = QuorumSystem(reads = a + b) + assert_equal(qs.reads, a + b) + assert_equal(qs.writes, a * b) + + # Specify writes. + qs = QuorumSystem(writes = a + b) + assert_equal(qs.reads, a * b) + assert_equal(qs.writes, a + b) + + # Specify neither. + with self.assertRaises(ValueError): + QuorumSystem() + + # Specify both overlapping. + qs = QuorumSystem(reads=a+b, writes=a*b*c) + assert_equal(qs.reads, a+b) + assert_equal(qs.writes, a*b*c) + + # Specify both not overlapping. + with self.assertRaises(ValueError): + QuorumSystem(reads=a+b, writes=a) + + def test_uniform_strategy(self): + a = Node('a') + b = Node('b') + c = Node('c') + d = Node('d') + + sigma = QuorumSystem(reads=a).uniform_strategy() + self.assertEqual(sigma.sigma_r, { + frozenset({'a'}): 1.0, + }) + self.assertEqual(sigma.sigma_w, { + frozenset({'a'}): 1.0, + }) + + sigma = QuorumSystem(reads=a+a).uniform_strategy() + self.assertEqual(sigma.sigma_r, { + frozenset({'a'}): 1.0, + }) + self.assertEqual(sigma.sigma_w, { + frozenset({'a'}): 1.0, + }) + + sigma = QuorumSystem(reads=a*a).uniform_strategy() + self.assertEqual(sigma.sigma_r, { + frozenset({'a'}): 1.0, + }) + self.assertEqual(sigma.sigma_w, { + frozenset({'a'}): 1.0, + }) + + sigma = QuorumSystem(reads=a + a*b).uniform_strategy() + self.assertEqual(sigma.sigma_r, { + frozenset({'a'}): 1.0, + }) + self.assertEqual(sigma.sigma_w, { + frozenset({'a'}): 1.0, + }) + + sigma = QuorumSystem(reads=a + a*b + a*c).uniform_strategy() + self.assertEqual(sigma.sigma_r, { + frozenset({'a'}): 1.0, + }) + self.assertEqual(sigma.sigma_w, { + frozenset({'a'}): 1.0, + }) + + sigma = QuorumSystem(reads=a + b).uniform_strategy() + self.assertEqual(sigma.sigma_r, { + frozenset({'a'}): 1 / 2, + frozenset({'b'}): 1 / 2, + }) + self.assertEqual(sigma.sigma_w, { + frozenset({'a', 'b'}): 1.0, + }) + + sigma = QuorumSystem(reads=a + b + c).uniform_strategy() + self.assertEqual(sigma.sigma_r, { + frozenset({'a'}): 1 / 3, + frozenset({'b'}): 1 / 3, + frozenset({'c'}): 1 / 3, + }) + self.assertEqual(sigma.sigma_w, { + frozenset({'a', 'b', 'c'}): 1.0, + }) + + sigma = QuorumSystem(reads=(a*b)+(c*d)).uniform_strategy() + self.assertEqual(sigma.sigma_r, { + frozenset({'a', 'b'}): 1 / 2, + frozenset({'c', 'd'}): 1 / 2, + }) + self.assertEqual(sigma.sigma_w, { + frozenset({'a', 'c'}): 1 / 4, + frozenset({'a', 'd'}): 1 / 4, + frozenset({'b', 'c'}): 1 / 4, + frozenset({'b', 'd'}): 1 / 4, + }) + + sigma = QuorumSystem(reads=(a*b)+(c*d)+(a*b)+(a*b*c)).uniform_strategy() + self.assertEqual(sigma.sigma_r, { + frozenset({'a', 'b'}): 1 / 2, + frozenset({'c', 'd'}): 1 / 2, + }) + self.assertEqual(sigma.sigma_w, { + frozenset({'a', 'c'}): 1 / 4, + frozenset({'a', 'd'}): 1 / 4, + frozenset({'b', 'c'}): 1 / 4, + frozenset({'b', 'd'}): 1 / 4, + }) + + def test_optimal_strategy(self): + # TODO(mwhittaker): Implement. + pass