import importlib.util import tempfile import unittest from pathlib import Path SPEC = importlib.util.spec_from_file_location("members_server", Path(__file__).resolve().parents[1] / "services" / "members" / "server.py") server = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(server) UID = "6812345678901234" class ClaimTest(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.addCleanup(self.tmp.cleanup) self.now = 1_790_000_000 self.bio = "" self.found = UID self.registry = server.Registry(Path(self.tmp.name) / "r.sqlite3", clock=lambda: self.now, fetcher=self.fetch) def fetch(self, unique_id): return (self.found, self.bio) def test_code_is_stable_and_per_account(self): code = self.registry.code(UID) self.assertEqual(code, self.registry.code(UID)) self.assertNotEqual(code, self.registry.code("6812345678901235")) self.assertRegex(code, r"^LT-[A-Z2-7]{8}$") def test_bio_with_the_code_gets_the_badge(self): self.assertFalse(self.registry.lookup([UID])["niche"][UID]) self.assertEqual("code_missing", self.registry.claim(UID, "someone")["reason"]) self.bio = "hello " + self.registry.code(UID) + " bye" self.assertTrue(self.registry.claim(UID, "someone")["granted"]) self.assertTrue(self.registry.lookup([UID])["niche"][UID]) def test_someone_elses_profile_is_refused(self): self.found = "999999999" self.bio = self.registry.code(UID) with self.assertRaises(ValueError): self.registry.claim(UID, "someone") def test_nothing_is_issued_after_the_deadline_but_holders_stay(self): self.bio = self.registry.code(UID) self.registry.claim(UID, "someone") self.now = server.CLAIM_DEADLINE + 1 other = "6812345678901299" self.found, self.bio = other, self.registry.code(other) with self.assertRaises(ValueError): self.registry.claim(other, "other") self.assertTrue(self.registry.lookup([UID, other])["niche"][UID]) self.assertFalse(self.registry.lookup([UID, other])["niche"][other]) def test_blocked_accounts_get_nothing(self): with self.registry.connect() as db: db.execute("INSERT INTO blocked(uid) VALUES(?)", (UID,)) self.bio = self.registry.code(UID) with self.assertRaises(ValueError): self.registry.claim(UID, "someone") def test_bad_input_and_unreadable_profiles(self): with self.assertRaises(ValueError): self.registry.claim("abc", "someone") with self.assertRaises(ValueError): self.registry.claim(UID, "bad name!") self.registry.fetcher = lambda u: (_ for _ in ()).throw(OSError("blocked")) with self.assertRaises(ValueError): self.registry.claim(UID, "someone") INSTALLATION = "a" * 64 OTHER_INSTALLATION = "b" * 64 class ShapeTest(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.addCleanup(self.tmp.cleanup) self.now = 1_790_000_000 self.bio = "" self.found = UID self.fetches = 0 self.registry = server.Registry(Path(self.tmp.name) / "r.sqlite3", clock=lambda: self.now, fetcher=self.fetch) def fetch(self, unique_id): self.fetches += 1 return (self.found, self.bio) def publish(self, shape, installation=INSTALLATION, unique_id="someone", uid=UID): return self.registry.shape(uid, installation, shape, unique_id) def test_nothing_is_published_without_the_code_in_the_bio(self): self.assertEqual("code_missing", self.publish("flower")["reason"]) self.assertEqual({}, self.registry.lookup([UID])["shapes"]) self.assertEqual("proof_needed", self.registry.shape(UID, INSTALLATION, "flower")["reason"]) def test_the_code_in_the_bio_publishes_the_shape(self): self.bio = "me " + self.registry.code(UID) self.assertTrue(self.publish("flower")["published"]) self.assertEqual({UID: "flower"}, self.registry.lookup([UID])["shapes"]) def test_the_proven_installation_changes_it_without_another_proof(self): self.bio = self.registry.code(UID) self.publish("flower") fetched = self.fetches self.bio = "" self.assertTrue(self.registry.shape(UID, INSTALLATION, "heart")["published"]) self.assertEqual(fetched, self.fetches) self.assertEqual({UID: "heart"}, self.registry.lookup([UID])["shapes"]) def test_another_installation_must_prove_the_account_itself(self): self.bio = self.registry.code(UID) self.publish("flower") self.bio = "" self.assertFalse(self.publish("hexagon", OTHER_INSTALLATION)["published"]) self.assertEqual({UID: "flower"}, self.registry.lookup([UID])["shapes"]) self.bio = self.registry.code(UID) self.assertTrue(self.publish("hexagon", OTHER_INSTALLATION)["published"]) self.assertEqual({UID: "hexagon"}, self.registry.lookup([UID])["shapes"]) # the first installation lost its right with that self.bio = "" self.assertFalse(self.publish("heart", INSTALLATION)["published"]) def test_circle_withdraws_the_shape(self): self.bio = self.registry.code(UID) self.publish("triangle") self.assertTrue(self.registry.shape(UID, INSTALLATION, "circle")["published"]) self.assertEqual({}, self.registry.lookup([UID])["shapes"]) def test_circle_for_an_account_without_a_shape_needs_nothing(self): self.assertTrue(self.publish("circle")["published"]) self.assertEqual(0, self.fetches) def test_someone_elses_profile_and_blocked_accounts_are_refused(self): self.found = "999999999" self.bio = self.registry.code(UID) with self.assertRaises(ValueError): self.publish("flower") self.found = UID with self.registry.connect() as db: db.execute("INSERT INTO blocked(uid) VALUES(?)", (UID,)) with self.assertRaises(ValueError): self.publish("flower") def test_a_blocked_account_loses_its_shape_in_lookups(self): self.bio = self.registry.code(UID) self.publish("flower") with self.registry.connect() as db: db.execute("INSERT INTO blocked(uid) VALUES(?)", (UID,)) self.assertEqual({}, self.registry.lookup([UID])["shapes"]) def test_bad_input(self): for shape in ("blob", "", None, 5): with self.assertRaises(ValueError): self.publish(shape) with self.assertRaises(ValueError): self.registry.shape("abc", INSTALLATION, "flower", "someone") with self.assertRaises(ValueError): self.registry.shape(UID, "short", "flower", "someone") self.assertEqual("proof_needed", self.registry.shape(UID, INSTALLATION, "flower", "bad name!")["reason"]) if __name__ == "__main__": unittest.main()