@@ -4,8 +4,12 @@ import (
44 "testing"
55
66 "github.com/blang/semver"
7+ "github.com/golang/mock/gomock"
78 downstreamtypes "github.com/replicatedhq/kots/pkg/api/downstream/types"
9+ apptypes "github.com/replicatedhq/kots/pkg/app/types"
810 "github.com/replicatedhq/kots/pkg/cursor"
11+ "github.com/replicatedhq/kots/pkg/store"
12+ mock_store "github.com/replicatedhq/kots/pkg/store/mock"
913 kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
1014 "github.com/stretchr/testify/require"
1115)
@@ -287,3 +291,161 @@ func Test_getRequiredAirgapUpdates(t *testing.T) {
287291 })
288292 }
289293}
294+
295+ func TestIsAirgapUpdateDeployable (t * testing.T ) {
296+ tests := []struct {
297+ name string
298+ airgap * kotsv1beta1.Airgap
299+ currentECVersion string
300+ wantDeployable bool
301+ wantCause string
302+ setupStore func (mockStore * mock_store.MockStore )
303+ }{
304+ {
305+ name : "not deployable due to required releases" ,
306+ airgap : & kotsv1beta1.Airgap {
307+ Spec : kotsv1beta1.AirgapSpec {
308+ ChannelID : "test-channel" ,
309+ RequiredReleases : []kotsv1beta1.AirgapReleaseMeta {
310+ {
311+ VersionLabel : "1.0.0" ,
312+ UpdateCursor : "100" ,
313+ },
314+ },
315+ AirgapReleaseMeta : kotsv1beta1.AirgapReleaseMeta {
316+ VersionLabel : "1.1.0" ,
317+ UpdateCursor : "110" ,
318+ EmbeddedClusterVersion : "2.7.4+k8s-1.30" ,
319+ },
320+ },
321+ },
322+ currentECVersion : "2.7.3+k8s-1.29" ,
323+ wantDeployable : false ,
324+ wantCause : "This version cannot be deployed because version 1.0.0 is required and must be deployed first." ,
325+ setupStore : func (mockStore * mock_store.MockStore ) {
326+ s := semver .MustParse ("0.9.0" )
327+ c := cursor .MustParse ("90" )
328+ mockStore .EXPECT ().FindDownstreamVersions ("test-app" , true ).Return (& downstreamtypes.DownstreamVersions {
329+ AllVersions : []* downstreamtypes.DownstreamVersion {
330+ {
331+ ChannelID : "test-channel" ,
332+ VersionLabel : "0.9.0" ,
333+ UpdateCursor : "90" ,
334+ Semver : & s ,
335+ Cursor : & c ,
336+ },
337+ },
338+ }, nil )
339+ },
340+ },
341+ {
342+ name : "deployable when no required updates and compatible EC version" ,
343+ airgap : & kotsv1beta1.Airgap {
344+ Spec : kotsv1beta1.AirgapSpec {
345+ ChannelID : "test-channel" ,
346+ AirgapReleaseMeta : kotsv1beta1.AirgapReleaseMeta {
347+ EmbeddedClusterVersion : "2.7.4+k8s-1.30" ,
348+ },
349+ },
350+ },
351+ currentECVersion : "2.7.3+k8s-1.29" ,
352+ wantDeployable : true ,
353+ wantCause : "" ,
354+ setupStore : func (mockStore * mock_store.MockStore ) {
355+ mockStore .EXPECT ().FindDownstreamVersions ("test-app" , true ).Return (& downstreamtypes.DownstreamVersions {
356+ AllVersions : []* downstreamtypes.DownstreamVersion {},
357+ }, nil )
358+ },
359+ },
360+ {
361+ name : "not deployable due to EC version incompatibility" ,
362+ airgap : & kotsv1beta1.Airgap {
363+ Spec : kotsv1beta1.AirgapSpec {
364+ ChannelID : "test-channel" ,
365+ AirgapReleaseMeta : kotsv1beta1.AirgapReleaseMeta {
366+ EmbeddedClusterVersion : "2.8.0+k8s-1.31" ,
367+ },
368+ },
369+ },
370+ currentECVersion : "2.7.4+k8s-1.29" ,
371+ wantDeployable : false ,
372+ wantCause : "Before you can update to this version, you need to update to an earlier version that includes the required infrastructure update." ,
373+ setupStore : func (mockStore * mock_store.MockStore ) {
374+ mockStore .EXPECT ().FindDownstreamVersions ("test-app" , true ).Return (& downstreamtypes.DownstreamVersions {
375+ AllVersions : []* downstreamtypes.DownstreamVersion {},
376+ }, nil )
377+ },
378+ },
379+ {
380+ name : "deployable when airgap EC version is empty" ,
381+ airgap : & kotsv1beta1.Airgap {
382+ Spec : kotsv1beta1.AirgapSpec {
383+ ChannelID : "test-channel" ,
384+ AirgapReleaseMeta : kotsv1beta1.AirgapReleaseMeta {
385+ EmbeddedClusterVersion : "" ,
386+ },
387+ },
388+ },
389+ currentECVersion : "2.7.3+k8s-1.29" ,
390+ wantDeployable : true ,
391+ wantCause : "" ,
392+ setupStore : func (mockStore * mock_store.MockStore ) {
393+ mockStore .EXPECT ().FindDownstreamVersions ("test-app" , true ).Return (& downstreamtypes.DownstreamVersions {
394+ AllVersions : []* downstreamtypes.DownstreamVersion {},
395+ }, nil )
396+ },
397+ },
398+ {
399+ name : "deployable when current EC version is empty (non-ec installation) even if airgap EC version is set" ,
400+ airgap : & kotsv1beta1.Airgap {
401+ Spec : kotsv1beta1.AirgapSpec {
402+ ChannelID : "test-channel" ,
403+ AirgapReleaseMeta : kotsv1beta1.AirgapReleaseMeta {
404+ EmbeddedClusterVersion : "2.7.5+k8s-1.30" ,
405+ },
406+ },
407+ },
408+ currentECVersion : "" ,
409+ wantDeployable : true ,
410+ wantCause : "" ,
411+ setupStore : func (mockStore * mock_store.MockStore ) {
412+ mockStore .EXPECT ().FindDownstreamVersions ("test-app" , true ).Return (& downstreamtypes.DownstreamVersions {
413+ AllVersions : []* downstreamtypes.DownstreamVersion {},
414+ }, nil )
415+ },
416+ },
417+ }
418+
419+ for _ , tt := range tests {
420+ t .Run (tt .name , func (t * testing.T ) {
421+ ctrl := gomock .NewController (t )
422+ defer ctrl .Finish ()
423+
424+ mockStore := mock_store .NewMockStore (ctrl )
425+ tt .setupStore (mockStore )
426+
427+ store .SetStore (mockStore )
428+ defer store .SetStore (nil )
429+
430+ app := & apptypes.App {
431+ ID : "test-app" ,
432+ SelectedChannelID : "test-channel" ,
433+ License : `apiVersion: kots.io/v1beta1
434+ kind: License
435+ spec:
436+ channelID: test-channel
437+ channels:
438+ - channelID: test-channel
439+ channelName: Test
440+ isDefault: true
441+ isSemverRequired: false` ,
442+ }
443+
444+ deployable , cause , err := IsAirgapUpdateDeployable (app , tt .airgap , tt .currentECVersion )
445+
446+ require .NoError (t , err )
447+ require .Equal (t , tt .wantDeployable , deployable )
448+ require .Equal (t , tt .wantCause , cause )
449+ })
450+ }
451+ }
0 commit comments