def test_events_for_deletion_via_event_type(registry):
    e1 = RawEvent(type=None, object=RawBody(metadata={'name': 'ns1'}))
    e2 = RawEvent(type='DELETED', object=RawBody(metadata={'name': 'ns1'}))
    insights = Insights()
    revise_namespaces(insights=insights, namespaces=['ns*'], raw_events=[e1])
    revise_namespaces(insights=insights, namespaces=['ns*'], raw_events=[e2])
    assert not insights.namespaces
def test_bodies_for_additional_population(registry):
    b1 = RawBody(metadata={'name': 'ns1'})
    b2 = RawBody(metadata={'name': 'ns2'})
    insights = Insights()
    revise_namespaces(insights=insights, namespaces=['ns*'], raw_bodies=[b1])
    revise_namespaces(insights=insights, namespaces=['ns*'], raw_bodies=[b2])
    assert insights.namespaces == {'ns1', 'ns2'}
def test_bodies_for_deletion_via_timestamp(registry):
    b1 = RawBody(metadata={'name': 'ns1'})
    b2 = RawBody(metadata={'name': 'ns1', 'deletionTimestamp': '...'})
    insights = Insights()
    revise_namespaces(insights=insights, namespaces=['ns*'], raw_bodies=[b1])
    revise_namespaces(insights=insights, namespaces=['ns*'], raw_bodies=[b2])
    assert not insights.namespaces
def test_events_for_additional_population(registry):
    e1 = RawEvent(type=None, object=RawBody(metadata={'name': 'ns1'}))
    e2 = RawEvent(type=None, object=RawBody(metadata={'name': 'ns2'}))
    insights = Insights()
    revise_namespaces(insights=insights, namespaces=['ns*'], raw_events=[e1])
    revise_namespaces(insights=insights, namespaces=['ns*'], raw_events=[e2])
    assert insights.namespaces == {'ns1', 'ns2'}
async def test_nonwatchable_resources_are_ignored(settings, registry,
                                                  apis_mock, group1_mock,
                                                  timer, etype, decorator,
                                                  insights):
    @decorator('group1', 'version1', 'plural1')
    def fn(**_):
        ...

    e1 = RawEvent(type=etype, object=RawBody(spec={'group': 'group1'}))

    async def delayed_injection(delay: float):
        await asyncio.sleep(delay)
        await process_discovered_resource_event(insights=insights,
                                                raw_event=e1,
                                                registry=registry,
                                                settings=settings)

    task = asyncio.create_task(delayed_injection(0.1))
    with timer:
        async with insights.revised:
            await insights.revised.wait()
    await task
    assert 0.1 < timer.seconds < 1.0
    assert not insights.watched_resources
    assert apis_mock.called
    assert group1_mock.called
async def test_followups_for_deletion_of_resource(settings, registry,
                                                  apis_mock, group1_empty_mock,
                                                  timer, etype, insights,
                                                  insights_resources):

    e1 = RawEvent(type=etype, object=RawBody(spec={'group': 'group1'}))
    r1 = Resource(group='group1', version='version1', plural='plural1')
    insights_resources.add(r1)

    async def delayed_injection(delay: float):
        await asyncio.sleep(delay)
        await process_discovered_resource_event(insights=insights,
                                                raw_event=e1,
                                                registry=registry,
                                                settings=settings)

    task = asyncio.create_task(delayed_injection(0.1))
    with timer:
        async with insights.revised:
            await insights.revised.wait()
    await task
    assert 0.1 < timer.seconds < 1.0
    assert not insights_resources
    assert apis_mock.called
    assert group1_empty_mock.called
Ejemplo n.º 7
0
    def _build_key(
        self,
        raw_body: bodies.RawBody,
    ) -> str:
        """
        Construct an immutable persistent key of a resource.

        Generally, a uid is sufficient, as it is unique within the cluster.
        But it can be e.g. plural/namespace/name triplet, or anything else,
        even of different types (as long as it satisfies the type checkers).

        But it must be consistent within a single process lifetime.
        """
        return raw_body.get('metadata', {}).get('uid') or ''
async def test_initial_listing_is_ignored():
    insights = Insights()
    e1 = RawEvent(type=None, object=RawBody(metadata={'name': 'ns1'}))

    async def delayed_injection(delay: float):
        await asyncio.sleep(delay)
        await process_discovered_namespace_event(insights=insights,
                                                 raw_event=e1,
                                                 namespaces=['ns*'])

    task = asyncio.create_task(delayed_injection(0))
    with pytest.raises(asyncio.TimeoutError):
        async with insights.revised:
            await asyncio.wait_for(insights.revised.wait(), timeout=0.1)
    await task
    assert not insights.namespaces
Ejemplo n.º 9
0
async def test_followups_for_addition(timer, etype):
    insights = Insights()
    e1 = RawEvent(type=etype, object=RawBody(metadata={'name': 'ns1'}))

    async def delayed_injection(delay: float):
        await asyncio.sleep(delay)
        await process_discovered_namespace_event(insights=insights,
                                                 raw_event=e1,
                                                 namespaces=['ns*'])

    task = asyncio.create_task(delayed_injection(0.1))
    async with timer, async_timeout.timeout(1):
        async with insights.revised:
            await insights.revised.wait()
    await task
    assert 0.1 < timer.seconds < 0.11
    assert insights.namespaces == {'ns1'}
Ejemplo n.º 10
0
async def test_backbone_is_filled(registry, core_mock, corev1_mock, timer,
                                  etype):
    e1 = RawEvent(type=etype, object=RawBody(spec={'group': ''}))
    insights = Insights()

    async def delayed_injection(delay: float):
        await asyncio.sleep(delay)
        await process_discovered_resource_event(insights=insights,
                                                raw_event=e1,
                                                registry=registry)

    task = asyncio.create_task(delayed_injection(0.1))
    async with timer, async_timeout.timeout(1.0):
        await insights.backbone.wait_for(NAMESPACES)
    await task
    assert 0.1 < timer.seconds < 1.0
    assert NAMESPACES in insights.backbone
    assert core_mock.called
    assert corev1_mock.called
Ejemplo n.º 11
0
async def test_initial_listing_is_ignored(registry, apis_mock, group1_mock):
    insights = Insights()
    e1 = RawEvent(type=None, object=RawBody(spec={'group': 'group1'}))

    async def delayed_injection(delay: float):
        await asyncio.sleep(delay)
        await process_discovered_resource_event(insights=insights,
                                                raw_event=e1,
                                                registry=registry)

    task = asyncio.create_task(delayed_injection(0))
    with pytest.raises(asyncio.TimeoutError):
        async with async_timeout.timeout(0.1) as timeout:
            async with insights.revised:
                await insights.revised.wait()
    await task
    assert timeout.expired
    assert not insights.resources
    assert not apis_mock.called
    assert not group1_mock.called
Ejemplo n.º 12
0
async def test_followups_for_addition(registry, apis_mock, group1_mock, timer,
                                      etype):
    e1 = RawEvent(type=etype, object=RawBody(spec={'group': 'group1'}))
    r1 = Resource(group='group1', version='version1', plural='plural1')
    insights = Insights()

    async def delayed_injection(delay: float):
        await asyncio.sleep(delay)
        await process_discovered_resource_event(insights=insights,
                                                raw_event=e1,
                                                registry=registry)

    task = asyncio.create_task(delayed_injection(0.1))
    async with timer, async_timeout.timeout(1.0):
        async with insights.revised:
            await insights.revised.wait()
    await task
    assert 0.1 < timer.seconds < 1.0
    assert insights.resources == {r1}
    assert apis_mock.called
    assert group1_mock.called
async def test_initial_listing_is_ignored(settings, registry, apis_mock,
                                          group1_mock, insights):

    e1 = RawEvent(type=None, object=RawBody(spec={'group': 'group1'}))

    async def delayed_injection(delay: float):
        await asyncio.sleep(delay)
        await process_discovered_resource_event(insights=insights,
                                                raw_event=e1,
                                                registry=registry,
                                                settings=settings)

    task = asyncio.create_task(delayed_injection(0))
    with pytest.raises(asyncio.TimeoutError):
        async with insights.revised:
            await asyncio.wait_for(insights.revised.wait(), timeout=0.1)
    await task
    assert not insights.indexed_resources
    assert not insights.watched_resources
    assert not insights.webhook_resources
    assert not apis_mock.called
    assert not group1_mock.called
Ejemplo n.º 14
0
from kopf._core.actions.execution import cause_var
from kopf._core.actions.invocation import context
from kopf._core.engines.indexing import OperatorIndexers
from kopf._core.intents.causes import ChangingCause, Reason, WatchingCause

OWNER_API_VERSION = 'owner-api-version'
OWNER_NAMESPACE = 'owner-namespace'
OWNER_KIND = 'OwnerKind'
OWNER_NAME = 'owner-name'
OWNER_UID = 'owner-uid'
OWNER_LABELS = {'label-1': 'value-1', 'label-2': 'value-2'}
OWNER = RawBody(
    apiVersion=OWNER_API_VERSION,
    kind=OWNER_KIND,
    metadata=RawMeta(
        namespace=OWNER_NAMESPACE,
        name=OWNER_NAME,
        uid=OWNER_UID,
        labels=OWNER_LABELS,
    ),
)


@pytest.fixture(params=['state-changing-cause', 'event-watching-cause'])
def owner(request, resource):
    body = Body(copy.deepcopy(OWNER))
    if request.param == 'state-changing-cause':
        cause = ChangingCause(
            logger=logging.getLogger('kopf.test.fake.logger'),
            indices=OperatorIndexers().indices,
            resource=resource,
            patch=Patch(),
def test_bodies_ignored_for_mismatching(registry):
    b1 = RawBody(metadata={'name': 'def1'})
    insights = Insights()
    revise_namespaces(insights=insights, namespaces=['ns*'], raw_bodies=[b1])
    assert not insights.namespaces
import asyncio

import aiohttp.web
import pytest

import kopf
from kopf._cogs.structs.bodies import RawBody, RawEvent
from kopf._cogs.structs.references import NAMESPACES, Insights, Resource
from kopf._core.reactor.observation import process_discovered_resource_event

# Implementation awareness: the events only trigger the re-scan, so the fields can be reduced
# to only the group name which is being rescanned. Other fields are ignored in the events.
# The actual data is taken from the API. It is tested elsewhere, so we rely on its correctness here.
GROUP1_EVENT = RawBody(spec={'group': 'group1'})


@pytest.fixture()
def core_mock(resp_mocker, aresponses, hostname):
    mock = resp_mocker(
        return_value=aiohttp.web.json_response({'versions': ['v1']}))
    aresponses.add(hostname, '/api', 'get', mock)
    return mock


@pytest.fixture()
def apis_mock(resp_mocker, aresponses, hostname):
    mock = resp_mocker(return_value=aiohttp.web.json_response({
        'groups': [
            {
                'name': 'group1',
                'preferredVersion': {
def test_events_ignored_for_mismatching(registry):
    e1 = RawEvent(type=None, object=RawBody(metadata={'name': 'def1'}))
    insights = Insights()
    revise_namespaces(insights=insights, namespaces=['ns*'], raw_events=[e1])
    assert not insights.namespaces