Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion kopf/_cogs/structs/references.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,20 @@ def check(self, resource: Resource) -> bool:
"""
# Core v1 events are excluded from EVERYTHING: they are implicitly produced during handling,
# and thus trigger unnecessary handling cycles (even for other resources, not for events).

# For category-based selection, we should include all resources that match the category,
# regardless of version preference. For other selectors, preserve the original behavior.
version_matches = (
self.version == resource.version or
(self.version is None and (
resource.preferred or # Original behavior for non-category selectors
self.category is not None # New: allow all versions for category selectors
))
)

return (
(self.group is None or self.group == resource.group) and
((self.version is None and resource.preferred) or self.version == resource.version) and
version_matches and
(self.kind is None or self.kind == resource.kind) and
(self.plural is None or self.plural == resource.plural) and
(self.singular is None or self.singular == resource.singular) and
Expand Down
106 changes: 106 additions & 0 deletions tests/references/test_category_selector_fix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"""
Test case to verify category selector includes all versions, not just preferred ones.
This test prevents regression of the bug where category selectors only matched
preferred versions of resources.
"""

import pytest
from kopf._cogs.structs.references import Resource, Selector


def test_category_selector_includes_all_versions():
"""
Test that category selectors include all resources with matching categories,
regardless of whether they are the preferred version or not.

This is a regression test for the bug where only preferred versions
were selected when using category-based selectors.
"""

# Create two resources with the same category but different versions
# Only one should be preferred (as would happen in a real cluster)
resource_v1beta1 = Resource(
group='test.com',
version='v1beta1',
plural='rssimples',
kind='Rssimple',
singular='rssimple',
categories=frozenset(['test']),
preferred=False # Not the preferred version
)

resource_v1beta2 = Resource(
group='test.com',
version='v1beta2',
plural='rsmultis',
kind='Rsmulti',
singular='rsmulti',
categories=frozenset(['test']),
preferred=True # This is the preferred version
)

# Create category selector
category_selector = Selector(category='test')

# Test that both resources match individually
assert category_selector.check(resource_v1beta1), \
"Non-preferred resource should match category selector"
assert category_selector.check(resource_v1beta2), \
"Preferred resource should match category selector"

# Test selection from collection - should include BOTH resources
all_resources = [resource_v1beta1, resource_v1beta2]
selected_resources = category_selector.select(all_resources)

assert len(selected_resources) == 2, \
f"Expected 2 resources to be selected, but got {len(selected_resources)}"

# Verify both resources are in the selection
selected_plurals = {r.plural for r in selected_resources}
assert selected_plurals == {'rssimples', 'rsmultis'}, \
f"Expected both resource types, but got {selected_plurals}"


def test_non_category_selector_behavior_unchanged():
"""
Test that non-category selectors still work as expected.
This ensures we didn't break the existing behavior for other selector types.
"""

# Create two resources from the same group with different preferences
resource_v1beta1 = Resource(
group='test.com',
version='v1beta1',
plural='rssimples',
kind='Rssimple',
singular='rssimple',
categories=frozenset(['test']),
preferred=False # Not the preferred version
)

resource_v1beta2 = Resource(
group='test.com',
version='v1beta2',
plural='rsmultis',
kind='Rsmulti',
singular='rsmulti',
categories=frozenset(['test']),
preferred=True # This is the preferred version
)

# Create non-category selector (using kind selector)
kind_selector = Selector(kind='Rsmulti')

# Test selection - should only include the matching resource
all_resources = [resource_v1beta1, resource_v1beta2]
selected_resources = kind_selector.select(all_resources)

assert len(selected_resources) == 1, \
f"Expected 1 matching resource to be selected, but got {len(selected_resources)}"

# Verify only the resource with matching kind is selected
selected_resource = next(iter(selected_resources))
assert selected_resource.kind == 'Rsmulti', \
f"Expected resource with kind 'Rsmulti', but got '{selected_resource.kind}'"
assert selected_resource.plural == 'rsmultis', \
f"Expected resource 'rsmultis', but got '{selected_resource.plural}'"