11import * as k8s from "@kubernetes/client-node" ;
2- import { setTimeout } from "node:timers/promises" ;
32import { GenericContainer , Network , Wait } from "testcontainers" ;
3+ import { getImage } from "../../../testcontainers/src/utils/test-helper" ;
44import { K3sContainer } from "./k3s-container" ;
55
6- describe ( "K3s" , { timeout : 120_000 } , ( ) => {
7- it ( "should construct" , ( ) => {
8- new K3sContainer ( "rancher/k3s:v1.31.2-k3s1" ) ;
9- } ) ;
6+ const IMAGE = getImage ( __dirname ) ;
107
8+ describe ( "K3s" , { timeout : 120_000 } , ( ) => {
119 // K3sContainer runs as a privileged container
1210 if ( ! process . env [ "CI_ROOTLESS" ] ) {
1311 it ( "should start and have listable node" , async ( ) => {
14- // starting_k3s {
15- await using container = await new K3sContainer ( "rancher/k3s:v1.31.2-k3s1" ) . start ( ) ;
16- // }
17-
18- // connecting_with_client {
19- // obtain a kubeconfig file that allows us to connect to k3s
20- const kubeConfig = container . getKubeConfig ( ) ;
21-
22- const kc = new k8s . KubeConfig ( ) ;
23- kc . loadFromString ( kubeConfig ) ;
12+ // k3sListNodes {
13+ await using container = await new K3sContainer ( IMAGE ) . start ( ) ;
2414
25- const client = kc . makeApiClient ( k8s . CoreV1Api ) ;
15+ const kubeConfig = new k8s . KubeConfig ( ) ;
16+ kubeConfig . loadFromString ( container . getKubeConfig ( ) ) ;
2617
27- // interact with the running K3s server, e.g.:
18+ const client = kubeConfig . makeApiClient ( k8s . CoreV1Api ) ;
2819 const nodeList = await client . listNode ( ) ;
29- // }
3020
3121 expect ( nodeList . items ) . toHaveLength ( 1 ) ;
32- } ) ;
33-
34- it ( "should expose kubeconfig for a network alias" , async ( ) => {
35- await using network = await new Network ( ) . start ( ) ;
36- await using container = await new K3sContainer ( "rancher/k3s:v1.31.2-k3s1" )
37- . withNetwork ( network )
38- . withNetworkAliases ( "k3s" )
39- . start ( ) ;
40-
41- // obtain a kubeconfig that allows us to connect on the custom network
42- const kubeConfig = container . getAliasedKubeConfig ( "k3s" ) ;
43-
44- await using kubectlContainer = await new GenericContainer ( "rancher/kubectl:v1.31.2" )
45- . withNetwork ( network )
46- . withCopyContentToContainer ( [ { content : kubeConfig , target : "/home/kubectl/.kube/config" } ] )
47- . withCommand ( [ "get" , "namespaces" ] )
48- . withWaitStrategy ( Wait . forOneShotStartup ( ) )
49- . withStartupTimeout ( 30_000 )
50- . start ( ) ;
51-
52- const chunks = [ ] ;
53- for await ( const chunk of await kubectlContainer . logs ( ) ) {
54- chunks . push ( chunk ) ;
55- }
56- expect ( chunks ) . toEqual ( expect . arrayContaining ( [ expect . stringContaining ( "kube-system" ) ] ) ) ;
22+ // }
5723 } ) ;
5824
5925 it ( "should start a pod" , async ( ) => {
60- await using container = await new K3sContainer ( "rancher/k3s:v1.31.2-k3s1" ) . start ( ) ;
61- const kc = new k8s . KubeConfig ( ) ;
62- kc . loadFromString ( container . getKubeConfig ( ) ) ;
26+ // k3sStartPod {
27+ await using container = await new K3sContainer ( IMAGE ) . start ( ) ;
28+
29+ const kubeConfig = new k8s . KubeConfig ( ) ;
30+ kubeConfig . loadFromString ( container . getKubeConfig ( ) ) ;
6331
6432 const pod = {
6533 metadata : {
@@ -85,23 +53,37 @@ describe("K3s", { timeout: 120_000 }, () => {
8553 } ,
8654 } ;
8755
88- const client = kc . makeApiClient ( k8s . CoreV1Api ) ;
56+ const client = kubeConfig . makeApiClient ( k8s . CoreV1Api ) ;
8957 await client . createNamespacedPod ( { namespace : "default" , body : pod } ) ;
9058
91- // wait for pod to be ready
92- expect ( await podIsReady ( client , "default" , "helloworld" , 60_000 ) ) . toBe ( true ) ;
59+ await vi . waitFor ( async ( ) => {
60+ const { status } = await client . readNamespacedPodStatus ( { namespace : "default" , name : "helloworld" } ) ;
61+
62+ return (
63+ status ?. phase === "Running" &&
64+ status ?. conditions ?. some ( ( cond ) => cond . type === "Ready" && cond . status === "True" )
65+ ) ;
66+ } , 60_000 ) ;
67+ // }
9368 } ) ;
9469 }
95- } ) ;
9670
97- async function podIsReady ( client : k8s . CoreV1Api , namespace : string , name : string , timeout : number ) : Promise < boolean > {
98- for ( const startTime = Date . now ( ) ; Date . now ( ) - startTime < timeout ; ) {
99- const res = await client . readNamespacedPodStatus ( { namespace, name } ) ;
100- const ready =
101- res . status ?. phase === "Running" &&
102- ! ! res . status ?. conditions ?. some ( ( cond ) => cond . type === "Ready" && cond . status === "True" ) ;
103- if ( ready ) return true ;
104- await setTimeout ( 3_000 ) ;
105- }
106- return false ;
107- }
71+ it ( "should expose kubeconfig for a network alias" , async ( ) => {
72+ // k3sAliasedKubeConfig {
73+ await using network = await new Network ( ) . start ( ) ;
74+ await using container = await new K3sContainer ( IMAGE ) . withNetwork ( network ) . withNetworkAliases ( "k3s" ) . start ( ) ;
75+
76+ const kubeConfig = container . getAliasedKubeConfig ( "k3s" ) ;
77+
78+ await using kubectlContainer = await new GenericContainer ( "rancher/kubectl:v1.31.2" )
79+ . withNetwork ( network )
80+ . withCopyContentToContainer ( [ { content : kubeConfig , target : "/home/kubectl/.kube/config" } ] )
81+ . withCommand ( [ "get" , "namespaces" ] )
82+ . withWaitStrategy ( Wait . forOneShotStartup ( ) )
83+ . start ( ) ;
84+
85+ const chunks = await ( await kubectlContainer . logs ( ) ) . toArray ( ) ;
86+ expect ( chunks ) . toEqual ( expect . arrayContaining ( [ expect . stringContaining ( "kube-system" ) ] ) ) ;
87+ // }
88+ } ) ;
89+ } ) ;
0 commit comments