1+ using System ;
2+ using FluentAssertions ;
3+ using Halibut ;
4+ using Octopus . Tentacle . Client ;
5+ using Octopus . Tentacle . Client . Scripts . Models ;
6+ using Octopus . Tentacle . Client . Scripts . Models . Builders ;
7+ using Octopus . Tentacle . CommonTestUtils ;
8+ using Octopus . Tentacle . CommonTestUtils . Diagnostics ;
9+ using Octopus . Tentacle . Contracts ;
10+ using Octopus . Tentacle . Contracts . ClientServices ;
11+ using Octopus . Tentacle . Kubernetes . Tests . Integration . Setup ;
12+ using Octopus . Tentacle . Kubernetes . Tests . Integration . Util ;
13+ using Octopus . Tentacle . Tests . Integration . Common . Builders . Decorators ;
14+ using Octopus . Tentacle . Tests . Integration . Common . Builders . Decorators . Proxies ;
15+ using Octopus . Tentacle . Tests . Integration . Common . Logging ;
16+
17+ namespace Octopus . Tentacle . Kubernetes . Tests . Integration ;
18+
19+ [ TestFixture ]
20+ public class KubernetesClientCompatibilityTests
21+ {
22+ static readonly object [ ] TestClusterVersions =
23+ [
24+ new object [ ] { new ClusterVersion ( 1 , 31 ) } ,
25+ new object [ ] { new ClusterVersion ( 1 , 30 ) } ,
26+ new object [ ] { new ClusterVersion ( 1 , 29 ) } ,
27+ new object [ ] { new ClusterVersion ( 1 , 28 ) } ,
28+ ] ;
29+
30+ KubernetesTestsGlobalContext ? testContext ;
31+ ILogger logger = null ! ;
32+ TemporaryDirectory toolsTemporaryDirectory ;
33+ string kindExePath ;
34+ string helmExePath ;
35+ string kubeCtlPath ;
36+ KubernetesClusterInstaller ? clusterInstaller ;
37+ KubernetesAgentInstaller ? kubernetesAgentInstaller ;
38+ HalibutRuntime serverHalibutRuntime = null ! ;
39+ string ? agentThumbprint ;
40+ TraceLogFileLogger ? traceLogFileLogger ;
41+ CancellationToken cancellationToken ;
42+ CancellationTokenSource ? cancellationTokenSource ;
43+ TentacleClient tentacleClient = null ! ;
44+ IRecordedMethodUsages recordedMethodUsages = null ! ;
45+
46+ [ OneTimeSetUp ]
47+ public async Task OneTimeSetup ( )
48+ {
49+ logger = new SerilogLoggerBuilder ( ) . Build ( ) ;
50+ toolsTemporaryDirectory = new TemporaryDirectory ( ) ;
51+ var toolDownloader = new RequiredToolDownloader ( toolsTemporaryDirectory , logger ) ;
52+ ( kindExePath , helmExePath , kubeCtlPath ) = await toolDownloader . DownloadRequiredTools ( CancellationToken . None ) ;
53+ }
54+
55+ [ OneTimeTearDown ]
56+ public void OneTimeTearDown ( )
57+ {
58+ toolsTemporaryDirectory . Dispose ( ) ;
59+ }
60+
61+ [ TearDown ]
62+ public async Task TearDown ( )
63+ {
64+ if ( traceLogFileLogger is not null ) await traceLogFileLogger . DisposeAsync ( ) ;
65+ if ( cancellationTokenSource is not null )
66+ {
67+ await cancellationTokenSource . CancelAsync ( ) ;
68+ cancellationTokenSource . Dispose ( ) ;
69+ }
70+ clusterInstaller ? . Dispose ( ) ;
71+ testContext ? . Dispose ( ) ;
72+
73+ traceLogFileLogger = null ;
74+ cancellationTokenSource = null ;
75+ clusterInstaller = null ;
76+ testContext = null ;
77+ }
78+
79+ [ Test ]
80+ [ TestCaseSource ( nameof ( TestClusterVersions ) ) ]
81+ public async Task RunSimpleScript ( ClusterVersion clusterVersion )
82+ {
83+ await SetUp ( clusterVersion ) ;
84+
85+ // Arrange
86+ var logs = new List < ProcessOutput > ( ) ;
87+ var scriptCompleted = false ;
88+
89+ var builder = new ExecuteKubernetesScriptCommandBuilder ( LoggingUtils . CurrentTestHash ( ) )
90+ . WithScriptBody ( script => script
91+ . Print ( "Hello World" )
92+ . PrintNTimesWithDelay ( "Yep" , 30 , TimeSpan . FromMilliseconds ( 100 ) ) ) ;
93+
94+ var command = builder . Build ( ) ;
95+
96+ // Act
97+ var result = await tentacleClient . ExecuteScript ( command , StatusReceived , ScriptCompleted , new InMemoryLog ( ) , cancellationToken ) ;
98+
99+ // Assert
100+ logs . Should ( ) . Contain ( po => po . Text . StartsWith ( "[POD EVENT]" ) ) ; // Verify that we are receiving some pod events
101+ logs . Should ( ) . Contain ( po => po . Source == ProcessOutputSource . StdOut && po . Text == "Hello World" ) ;
102+ scriptCompleted . Should ( ) . BeTrue ( ) ;
103+ result . ExitCode . Should ( ) . Be ( 0 ) ;
104+ result . State . Should ( ) . Be ( ProcessState . Complete ) ;
105+
106+ recordedMethodUsages . For ( nameof ( IAsyncClientKubernetesScriptServiceV1 . StartScriptAsync ) ) . Started . Should ( ) . Be ( 1 ) ;
107+ recordedMethodUsages . For ( nameof ( IAsyncClientKubernetesScriptServiceV1 . GetStatusAsync ) ) . Started . Should ( ) . BeGreaterThan ( 1 ) ;
108+ recordedMethodUsages . For ( nameof ( IAsyncClientKubernetesScriptServiceV1 . CompleteScriptAsync ) ) . Started . Should ( ) . Be ( 1 ) ;
109+ recordedMethodUsages . For ( nameof ( IAsyncClientKubernetesScriptServiceV1 . CancelScriptAsync ) ) . Started . Should ( ) . Be ( 0 ) ;
110+
111+ return ;
112+
113+ void StatusReceived ( ScriptExecutionStatus status )
114+ {
115+ logs . AddRange ( status . Logs ) ;
116+ }
117+
118+ Task ScriptCompleted ( CancellationToken ct )
119+ {
120+ scriptCompleted = true ;
121+ return Task . CompletedTask ;
122+ }
123+ }
124+
125+ async Task SetUp ( ClusterVersion clusterVersion )
126+ {
127+ testContext = new KubernetesTestsGlobalContext ( logger ) ;
128+
129+ await SetupCluster ( clusterVersion ) ;
130+
131+ kubernetesAgentInstaller = new KubernetesAgentInstaller (
132+ testContext . TemporaryDirectory ,
133+ testContext . HelmExePath ,
134+ testContext . KubeCtlExePath ,
135+ testContext . KubeConfigPath ,
136+ testContext . Logger ) ;
137+
138+ //create a new server halibut runtime
139+ serverHalibutRuntime = SetupHelpers . BuildServerHalibutRuntime ( ) ;
140+ var listeningPort = serverHalibutRuntime . Listen ( ) ;
141+
142+ agentThumbprint = await kubernetesAgentInstaller . InstallAgent ( listeningPort , testContext . TentacleImageAndTag , new Dictionary < string , string > ( ) ) ;
143+
144+ //trust the generated cert thumbprint
145+ serverHalibutRuntime . Trust ( agentThumbprint ) ;
146+
147+ traceLogFileLogger = new TraceLogFileLogger ( LoggingUtils . CurrentTestHash ( ) ) ;
148+ logger = new SerilogLoggerBuilder ( )
149+ . SetTraceLogFileLogger ( traceLogFileLogger )
150+ . Build ( )
151+ . ForContext ( GetType ( ) ) ;
152+
153+ cancellationTokenSource = new CancellationTokenSource ( ) ;
154+ cancellationTokenSource . CancelAfter ( TimeSpan . FromMinutes ( 5 ) ) ;
155+ cancellationToken = cancellationTokenSource . Token ;
156+
157+ tentacleClient = SetupHelpers . BuildTentacleClient ( kubernetesAgentInstaller . SubscriptionId , agentThumbprint , serverHalibutRuntime , builder =>
158+ {
159+ builder . RecordMethodUsages < IAsyncClientKubernetesScriptServiceV1 > ( out var recordedUsages ) ;
160+ recordedMethodUsages = recordedUsages ;
161+ } ) ;
162+ }
163+
164+ async Task SetupCluster ( ClusterVersion clusterVersion )
165+ {
166+ clusterInstaller = new KubernetesClusterInstaller ( testContext . TemporaryDirectory , kindExePath , helmExePath , kubeCtlPath , testContext . Logger ) ;
167+ await clusterInstaller . Install ( clusterVersion ) ;
168+
169+ testContext . TentacleImageAndTag = SetupHelpers . GetTentacleImageAndTag ( kindExePath , clusterInstaller ) ;
170+ testContext . SetToolExePaths ( helmExePath , kubeCtlPath ) ;
171+ testContext . KubeConfigPath = clusterInstaller . KubeConfigPath ;
172+ }
173+ }
0 commit comments