source: flexoentity/tests/test_id_stress.py@ 2f650ac

Last change on this file since 2f650ac was 2f650ac, checked in by Enrico Schwass <ennoausberlin@…>, 3 months ago

add domain as entity

  • Property mode set to 100644
File size: 3.6 KB
Line 
1"""
2Stress tests for the Flex-O ID lifecycle.
3Focus: collision avoidance, version ceiling, reproducibility.
4"""
5import pytest
6import random
7
8from flexoentity import FlexOID, EntityType, EntityState, Domain
9
10from tests.conftest import DummyEntity
11
12# ──────────────────────────────────────────────────────────────────────────────
13def test_bulk_generation_uniqueness():
14 """Generate 10,000 IDs and assert uniqueness (statistical test)."""
15 domain = Domain(domain="SIG", etype=EntityType.DOMAIN, state=EntityState.DRAFT,
16 fullname="Signal Corps", classification="RESTRICTED", owner="MESE")
17
18 etype = EntityType.QUESTION
19 estate = EntityState.DRAFT
20 seeds = [f"question {i}" for i in range(10_000)]
21
22 ids = [FlexOID.generate(domain, etype, estate, seed) for seed in seeds]
23
24 assert len(ids) == len(set(ids)), "ID collisions detected in bulk generation"
25
26
27def test_disambiguator_trigger():
28 """
29 Generating the same entity twice with same inputs yields identical ID.
30 (No runtime disambiguation; IDs are deterministic by design.)
31 """
32 domain = "AF"
33 etype = EntityType.QUESTION
34 estate = EntityState.DRAFT
35 text = "identical question text"
36 id1 = FlexOID.generate(domain, etype, estate, text)
37 id2 = FlexOID.generate(domain, etype, estate, text)
38 # IDs must be identical, because we now enforce determinism, not randomization
39 assert id1 == id2
40 assert id1.signature == id2.signature
41
42
43def test_id_reproducibility_across_runs():
44 """
45 The same seed on a new process (fresh _seen_hashes)
46 should yield the same base ID (without suffix).
47 """
48 domain = Domain(domain="SIG", etype=EntityType.DOMAIN, state=EntityState.DRAFT,
49 fullname="Signal Corps", classification="RESTRICTED")
50 etype = EntityType.CATALOG
51 estate = EntityState.DRAFT
52 seed = "reproducibility test seed"
53 id1 = FlexOID.generate(domain, etype, estate, seed)
54 # Reset hash cache
55 FlexOID._seen_hashes.clear()
56 id2 = FlexOID.generate(domain, etype, estate, seed)
57 assert id1 == id2
58 assert id1.signature == id2.signature
59
60
61def test_version_ceiling_enforcement():
62 """Simulate approaching @999 to trigger obsolescence guard."""
63 entity = DummyEntity(domain="AF", etype=EntityType.EXAM, state=EntityState.DRAFT, seed="Final Exam 2025")
64 entity.approve()
65 # artificially bump version number to near ceiling
66 entity.flexo_id = FlexOID.from_oid_and_version(entity.flexo_id, 998)
67
68 # 998 → 999 is allowed
69 entity.sign()
70 assert entity.flexo_id.version == 999
71
72 # 999 → 1000 should raise RuntimeError
73 with pytest.raises(RuntimeError):
74 entity.sign()
75
76
77def test_massive_lifecycle_simulation():
78 """
79 Generate 100 random entities, simulate multiple edits and state transitions,
80 ensure all final IDs and fingerprints are unique and valid.
81 """
82 entities = [DummyEntity(domain="AF", etype=EntityType.QUESTION, state=EntityState.DRAFT, seed=f"random question {i}") for i in range(100)]
83
84 for e in entities:
85 # random edit, approval, signing
86 e._seed += " updated"
87 e._update_fingerprint()
88 e.approve()
89 if random.random() > 0.3:
90 e.sign()
91 if random.random() > 0.6:
92 e.publish()
93
94 ids = [e.flexo_id for e in entities]
95 fps = [e.flexo_id.signature for e in entities]
96 assert len(ids) == len(set(ids)), "Duplicate IDs after random lifecycle"
97 assert len(fps) == len(set(fps)), "Duplicate fingerprints after random lifecycle"
Note: See TracBrowser for help on using the repository browser.