Net-Async-Kubernetes
view release on metacpan or search on metacpan
t/10-dual-crud.t view on Meta::CPAN
is($patched->metadata->labels->{patched_by}, 'perl', 'label applied');
unless (is_live()) {
my $req = MockTransport::last_request();
is($req->{method}, 'PATCH', 'used PATCH method');
like($req->{headers}{'Content-Type'}, qr{strategic-merge-patch},
'strategic merge patch content type');
}
};
subtest 'patch Deployment with merge type' => sub {
unless (is_live()) {
MockTransport::mock_response('PATCH',
"/apis/apps/v1/namespaces/$NS/deployments/demo-nginx", {
kind => 'Deployment', apiVersion => 'apps/v1',
metadata => { name => 'demo-nginx', namespace => $NS,
uid => 'dep-uid-001', resourceVersion => '103',
labels => { app => 'demo-app', patched_by => 'perl' },
annotations => { 'demo.perl/patched' => 'true' } },
spec => {
replicas => 3,
selector => { matchLabels => { app => 'demo-app' } },
template => {
metadata => { labels => { app => 'demo-app' } },
spec => { containers => [{ name => 'nginx', image => 'nginx:1.27-alpine' }] },
},
},
status => {},
});
}
my $patched = $kube->patch('Deployment', 'demo-nginx',
namespace => $NS,
type => 'merge',
patch => {
metadata => { annotations => { 'demo.perl/patched' => 'true' } },
},
)->get;
ok($patched, 'merge patch returned object');
is($patched->metadata->annotations->{'demo.perl/patched'}, 'true', 'annotation applied');
unless (is_live()) {
my $req = MockTransport::last_request();
like($req->{headers}{'Content-Type'}, qr{merge-patch},
'merge patch content type');
}
};
# ============================================================================
# Create Job + CronJob
# ============================================================================
subtest 'create Job' => sub {
unless (is_live()) {
MockTransport::mock_response('POST',
"/apis/batch/v1/namespaces/$NS/jobs", {
kind => 'Job', apiVersion => 'batch/v1',
metadata => { name => 'demo-job', namespace => $NS,
uid => 'job-uid-001', creationTimestamp => '2025-01-01T00:00:00Z' },
spec => { backoffLimit => 2,
template => { spec => { restartPolicy => 'Never',
containers => [{ name => 'worker', image => 'busybox:latest' }] } } },
status => {},
});
}
my $job = $kube->_rest->new_object(Job =>
metadata => { name => 'demo-job', namespace => $NS },
spec => { backoffLimit => 2,
template => { spec => { restartPolicy => 'Never',
containers => [{ name => 'worker', image => 'busybox:latest',
command => ['echo', 'hello'] }] } } },
);
my $created = $kube->create($job)->get;
ok($created, 'Job created');
is($created->metadata->name, 'demo-job', 'name matches');
};
subtest 'create CronJob' => sub {
unless (is_live()) {
MockTransport::mock_response('POST',
"/apis/batch/v1/namespaces/$NS/cronjobs", {
kind => 'CronJob', apiVersion => 'batch/v1',
metadata => { name => 'demo-cronjob', namespace => $NS,
uid => 'cj-uid-001', creationTimestamp => '2025-01-01T00:00:00Z' },
spec => { schedule => '*/5 * * * *',
jobTemplate => { spec => { template => { spec => {
restartPolicy => 'OnFailure',
containers => [{ name => 'cron', image => 'busybox:latest' }] } } } } },
});
}
my $cj = $kube->_rest->new_object(CronJob =>
metadata => { name => 'demo-cronjob', namespace => $NS },
spec => { schedule => '*/5 * * * *',
jobTemplate => { spec => { template => { spec => {
restartPolicy => 'OnFailure',
containers => [{ name => 'cron', image => 'busybox:latest',
command => ['echo', 'tick'] }] } } } } },
);
my $created = $kube->create($cj)->get;
ok($created, 'CronJob created');
is($created->metadata->name, 'demo-cronjob', 'name matches');
};
# ============================================================================
# List resources
# ============================================================================
subtest 'list ConfigMaps in namespace' => sub {
unless (is_live()) {
MockTransport::mock_response('GET',
"/api/v1/namespaces/$NS/configmaps", {
kind => 'ConfigMapList', apiVersion => 'v1',
items => [
{ kind => 'ConfigMap', apiVersion => 'v1',
metadata => { name => 'app-config', namespace => $NS },
data => { 'app.env' => 'staging' } },
],
});
}
my $list = $kube->list('ConfigMap', namespace => $NS)->get;
isa_ok($list, 'IO::K8s::List');
ok(scalar @{$list->items} >= 1, 'got at least 1 configmap');
my @names = map { $_->metadata->name } @{$list->items};
ok(grep({ $_ eq 'app-config' } @names), 'app-config in list');
};
subtest 'list Deployments in namespace' => sub {
unless (is_live()) {
MockTransport::mock_response('GET',
"/apis/apps/v1/namespaces/$NS/deployments", {
kind => 'DeploymentList', apiVersion => 'apps/v1',
items => [
{ kind => 'Deployment', apiVersion => 'apps/v1',
metadata => { name => 'demo-nginx', namespace => $NS },
spec => { replicas => 3,
selector => { matchLabels => { app => 'demo-app' } },
template => { metadata => { labels => { app => 'demo-app' } },
spec => { containers => [{ name => 'nginx', image => 'nginx' }] } } },
status => {} },
],
});
}
my $list = $kube->list('Deployment', namespace => $NS)->get;
ok(scalar @{$list->items} >= 1, 'got at least 1 deployment');
my @names = map { $_->metadata->name } @{$list->items};
ok(grep({ $_ eq 'demo-nginx' } @names), 'demo-nginx in list');
};
# ============================================================================
# Serialization roundtrip
# ============================================================================
subtest 'serialization roundtrip' => sub {
unless (is_live()) {
MockTransport::mock_response('GET',
"/apis/apps/v1/namespaces/$NS/deployments/demo-nginx", {
( run in 1.006 second using v1.01-cache-2.11-cpan-f4a522933cf )