Kubernetes-REST

 view release on metacpan or  search on metacpan

t/10_watch.t  view on Meta::CPAN

#!/usr/bin/env perl
# Tests for the Kubernetes Watch API using mock data.
#
# Run:
#   prove -l t/10_watch.t

use strict;
use warnings;
use Test::More;
use Test::Exception;
use FindBin;
use lib "$FindBin::Bin/lib";
use lib "$FindBin::Bin/../lib";

use Test::Kubernetes::Mock qw(mock_api);
use Kubernetes::REST;
use Kubernetes::REST::Server;
use Kubernetes::REST::AuthToken;
use Kubernetes::REST::WatchEvent;
use IO::K8s;

my $container = { name => 'nginx', image => 'nginx:1.27' };

# Build a mock API with watch-capable IO
my $mock_io = Test::Kubernetes::Mock::IO->new;

my $api = Kubernetes::REST->new(
    server      => Kubernetes::REST::Server->new(endpoint => 'http://mock.local'),
    credentials => Kubernetes::REST::AuthToken->new(token => 'MockToken'),
    resource_map_from_cluster => 0,
    io          => $mock_io,
);

# === Test 1: Watch with ADDED/MODIFIED/DELETED events ===
subtest 'watch pod events' => sub {
    $mock_io->add_watch_events('/api/v1/namespaces/default/pods', [
        {
            type   => 'ADDED',
            object => {
                apiVersion => 'v1',
                kind       => 'Pod',
                metadata   => {
                    name            => 'nginx-abc',
                    namespace       => 'default',
                    resourceVersion => '100',
                    uid             => 'uid-1',
                },
                spec   => { containers => [$container], nodeName => 'node-1' },
                status => { phase => 'Running' },
            },
        },
        {
            type   => 'MODIFIED',
            object => {
                apiVersion => 'v1',
                kind       => 'Pod',
                metadata   => {
                    name            => 'nginx-abc',
                    namespace       => 'default',
                    resourceVersion => '101',
                    uid             => 'uid-1',
                },
                spec   => { containers => [$container], nodeName => 'node-1' },
                status => { phase => 'Succeeded' },
            },
        },
        {
            type   => 'DELETED',
            object => {
                apiVersion => 'v1',
                kind       => 'Pod',
                metadata   => {
                    name            => 'nginx-abc',
                    namespace       => 'default',
                    resourceVersion => '102',
                    uid             => 'uid-1',
                },
                spec   => { containers => [$container], nodeName => 'node-1' },
                status => { phase => 'Succeeded' },
            },
        },
    ]);

    my @events;
    my $last_rv = $api->watch('Pod',
        namespace => 'default',
        on_event  => sub { push @events, $_[0] },
    );

t/10_watch.t  view on Meta::CPAN

    # Check raw data preserved
    is($events[0]->raw->{metadata}{resourceVersion}, '100', 'raw resourceVersion');
};

# === Test 2: Verify last resourceVersion return ===
subtest 'last resourceVersion returned' => sub {
    $mock_io->add_watch_events('/api/v1/namespaces/kube-system/pods', [
        {
            type   => 'ADDED',
            object => {
                apiVersion => 'v1',
                kind       => 'Pod',
                metadata   => {
                    name            => 'coredns-xyz',
                    namespace       => 'kube-system',
                    resourceVersion => '500',
                },
                spec   => { containers => [$container] },
                status => { phase => 'Running' },
            },
        },
        {
            type   => 'MODIFIED',
            object => {
                apiVersion => 'v1',
                kind       => 'Pod',
                metadata   => {
                    name            => 'coredns-xyz',
                    namespace       => 'kube-system',
                    resourceVersion => '505',
                },
                spec   => { containers => [$container] },
                status => { phase => 'Running' },
            },
        },
    ]);

    my $last_rv = $api->watch('Pod',
        namespace => 'kube-system',
        on_event  => sub {},
    );

    is($last_rv, '505', 'returns last resourceVersion');
};

# === Test 3: Watch without on_event dies ===
subtest 'watch without on_event dies' => sub {
    throws_ok {
        $api->watch('Pod', namespace => 'default');
    } qr/on_event/, 'dies without on_event callback';
};

# === Test 4: Watch CRD class ===
subtest 'watch CRD class' => sub {
    require My::StaticWebSite;

    # Build API with CRD registered
    my $crd_io = Test::Kubernetes::Mock::IO->new;
    my $default_map = IO::K8s->default_resource_map;
    my $crd_api = Kubernetes::REST->new(
        server      => Kubernetes::REST::Server->new(endpoint => 'http://mock.local'),
        credentials => Kubernetes::REST::AuthToken->new(token => 'MockToken'),
        resource_map_from_cluster => 0,
        resource_map => {
            %$default_map,
            StaticWebSite => '+My::StaticWebSite',
        },
        io => $crd_io,
    );

    $crd_io->add_watch_events('/apis/homelab.example.com/v1/namespaces/default/staticwebsites', [
        {
            type   => 'ADDED',
            object => {
                apiVersion => 'homelab.example.com/v1',
                kind       => 'StaticWebSite',
                metadata   => {
                    name            => 'my-blog',
                    namespace       => 'default',
                    resourceVersion => '200',
                },
                spec => {
                    domain   => 'blog.example.com',
                    image    => 'nginx:1.27',
                    replicas => 2,
                },
            },
        },
    ]);

    my @events;
    $crd_api->watch('StaticWebSite',
        namespace => 'default',
        on_event  => sub { push @events, $_[0] },
    );

    is(scalar @events, 1, 'received CRD event');
    is($events[0]->type, 'ADDED', 'CRD event type');
    is($events[0]->object->metadata->name, 'my-blog', 'CRD object name');
    is($events[0]->object->spec->{domain}, 'blog.example.com', 'CRD spec preserved');
};

# === Test 5: ERROR event handling ===
subtest 'ERROR event handling' => sub {
    $mock_io->add_watch_events('/api/v1/namespaces/test/pods', [
        {
            type   => 'ADDED',
            object => {
                apiVersion => 'v1',
                kind       => 'Pod',
                metadata   => {
                    name            => 'test-pod',
                    namespace       => 'test',
                    resourceVersion => '300',
                },
                spec   => { containers => [$container] },
                status => { phase => 'Running' },
            },
        },
        {
            type   => 'ERROR',



( run in 0.491 second using v1.01-cache-2.11-cpan-524268b4103 )