Skip to content

Commit 9f4d6c2

Browse files
test: extend and consolidate tag inheritance tests into test_tag_inheritance.py (#14771)
* tag inheritance: add more tests * test: consolidate tag inheritance tests into test_tag_inheritance.py Move all tag-inheritance-related tests into a single file: - InheritedTagsTests, InheritedTagsImportMixin, InheritedTagsImportTestAPI, InheritedTagsImportTestUI from test_tags.py - TestTagInheritanceOnPersist from test_bulk_locations.py - test_tags_signals.py (new unit tests, now absorbed) Add new unit test classes covering tags_signals.py internals: - TestGetProducts — isinstance routing for all model types - TestInheritProductTags — per-product and system-wide flag gating - TestPropagateInheritanceEarlyExit — early-exit short-circuit logic Add class-level docstrings throughout for clarity. Fix SSL redirect in InheritedTagsImportTestAPI/UI setUp. * fix: ruff lint errors in test_tag_inheritance.py * fix: remove unused imports from test_tags.py
1 parent 2c86b42 commit 9f4d6c2

3 files changed

Lines changed: 723 additions & 331 deletions

File tree

unittests/test_bulk_locations.py

Lines changed: 0 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -343,98 +343,6 @@ def test_bulk_fewer_queries_than_locations(self):
343343
self.assertLess(len(ctx.captured_queries), 10)
344344

345345

346-
# ---------------------------------------------------------------------------
347-
# Tag inheritance after bulk persist
348-
# ---------------------------------------------------------------------------
349-
@skip_unless_v3
350-
class TestTagInheritanceOnPersist(DojoTestCase):
351-
352-
def test_locations_inherit_product_tags(self):
353-
"""Locations should inherit tags from their associated product after persist."""
354-
finding = _make_finding()
355-
product = finding.test.engagement.product
356-
# Enable tag inheritance at the product level and add some product tags
357-
product.enable_product_tag_inheritance = True
358-
product.save()
359-
product.tags.add("inherit", "tags", "these")
360-
361-
loc_data = [LocationData(type="url", data={"url": "https://oss-tag-inherit.example.com"})]
362-
mgr = LocationManager(product)
363-
mgr.record_locations_for_finding(finding, loc_data)
364-
mgr.persist()
365-
366-
loc = Location.objects.get(url__host="oss-tag-inherit.example.com")
367-
inherited = sorted(t.name for t in loc.inherited_tags.all())
368-
self.assertEqual(inherited, ["inherit", "tags", "these"])
369-
370-
def test_bulk_inherit_is_no_op_when_already_in_sync(self):
371-
"""Calling persist() again with the same data should not re-inherit (no mutation queries)."""
372-
finding = _make_finding()
373-
product = finding.test.engagement.product
374-
product.enable_product_tag_inheritance = True
375-
product.save()
376-
product.tags.add("a", "b")
377-
378-
loc_data = [LocationData(type="url", data={"url": "https://oss-nosync.example.com"})]
379-
# First import — mutations expected
380-
mgr1 = LocationManager(product)
381-
mgr1.record_locations_for_finding(finding, loc_data)
382-
mgr1.persist()
383-
384-
# Second import — tags already inherited, should be a fast no-op
385-
mgr2 = LocationManager(product)
386-
mgr2.record_locations_for_finding(finding, loc_data)
387-
with CaptureQueriesContext(connection) as ctx:
388-
mgr2.persist()
389-
390-
# Verify no INSERT or UPDATE queries fired in the inheritance path
391-
mutation_queries = [q for q in ctx.captured_queries if q["sql"].startswith(("INSERT", "UPDATE"))]
392-
# There may still be refs check INSERTs if we're creating the LocationFindingReference again,
393-
# but inherited_tags mutation should be absent.
394-
for q in mutation_queries:
395-
self.assertNotIn("inherited_tags", q["sql"].lower(), f"Unexpected inherited_tags mutation: {q['sql']}")
396-
397-
def test_bulk_inherit_already_synced_is_constant_time(self):
398-
"""
399-
The main win from the bulk variant is skipping the per-instance mutation path when
400-
locations are already in sync with their product's tags. This test verifies that
401-
repeated persist() calls don't re-do the expensive tagulous work.
402-
"""
403-
finding = _make_finding()
404-
product = finding.test.engagement.product
405-
product.enable_product_tag_inheritance = True
406-
product.save()
407-
product.tags.add("p-tag-1", "p-tag-2")
408-
409-
loc_data = [
410-
LocationData(type="url", data={"url": f"https://oss-sync-{i}.example.com"})
411-
for i in range(10)
412-
]
413-
# First import to populate inherited_tags
414-
mgr1 = LocationManager(product)
415-
mgr1.record_locations_for_finding(finding, loc_data)
416-
mgr1.persist()
417-
418-
# Second import — same data, already in sync; should do zero mutation queries
419-
mgr2 = LocationManager(product)
420-
mgr2.record_locations_for_finding(finding, loc_data)
421-
with CaptureQueriesContext(connection) as ctx:
422-
mgr2.persist()
423-
424-
# No UPDATEs or INSERTs on inherited_tags / tags through tables should fire
425-
tag_through = Location.tags.through._meta.db_table
426-
inherited_through = Location.inherited_tags.through._meta.db_table
427-
for q in ctx.captured_queries:
428-
sql = q["sql"].lower()
429-
if sql.startswith(("insert", "update", "delete")):
430-
self.assertNotIn(
431-
tag_through.lower(), sql, f"Unexpected tags mutation: {q['sql']}",
432-
)
433-
self.assertNotIn(
434-
inherited_through.lower(), sql, f"Unexpected inherited_tags mutation: {q['sql']}",
435-
)
436-
437-
438346
# ---------------------------------------------------------------------------
439347
# Status update query efficiency
440348
# ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)