get.porter.sh/porter@v1.3.0/pkg/storage/installation_test.go (about) 1 package storage 2 3 import ( 4 "context" 5 "strings" 6 "testing" 7 "time" 8 9 "get.porter.sh/porter/pkg/cnab" 10 "get.porter.sh/porter/pkg/schema" 11 "get.porter.sh/porter/tests" 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 ) 15 16 func TestNewInstallation(t *testing.T) { 17 inst := NewInstallation("dev", "mybuns") 18 19 assert.Equal(t, "mybuns", inst.Name, "Name was not set") 20 assert.Equal(t, "dev", inst.Namespace, "Namespace was not set") 21 assert.NotEmpty(t, inst.Status.Created, "Created was not set") 22 assert.NotEmpty(t, inst.Status.Modified, "Modified was not set") 23 assert.Equal(t, inst.Status.Created, inst.Status.Modified, "Created and Modified should have the same timestamp") 24 assert.Equal(t, SchemaTypeInstallation, inst.SchemaType, "incorrect SchemaType") 25 assert.Equal(t, DefaultInstallationSchemaVersion, inst.SchemaVersion, "incorrect SchemaVersion") 26 assert.False(t, inst.Uninstalled, "incorrect Uninstalled") 27 } 28 29 func TestInstallation_String(t *testing.T) { 30 t.Parallel() 31 32 i := Installation{InstallationSpec: InstallationSpec{Name: "mybun"}} 33 assert.Equal(t, "/mybun", i.String()) 34 35 i.Namespace = "dev" 36 assert.Equal(t, "dev/mybun", i.String()) 37 } 38 39 func TestOCIReferenceParts_GetBundleReference(t *testing.T) { 40 testcases := []struct { 41 name string 42 repo string 43 digest string 44 version string 45 tag string 46 wantRef string 47 wantErr string 48 }{ 49 {name: "repo missing", wantRef: ""}, 50 {name: "incomplete reference", repo: "ghcr.io/getporter/examples/porter-hello", wantErr: "Invalid bundle reference"}, 51 {name: "version specified", repo: "ghcr.io/getporter/examples/porter-hello", version: "v0.2.0", wantRef: "ghcr.io/getporter/examples/porter-hello:v0.2.0"}, 52 {name: "digest specified", repo: "ghcr.io/getporter/examples/porter-hello", digest: "sha256:a881bbc015bade9f11d95a4244888d8e7fa8800f843b43c74cc07c7b7276b062", wantRef: "ghcr.io/getporter/examples/porter-hello@sha256:a881bbc015bade9f11d95a4244888d8e7fa8800f843b43c74cc07c7b7276b062"}, 53 {name: "tag specified", repo: "ghcr.io/getporter/examples/porter-hello", tag: "latest", wantRef: "ghcr.io/getporter/examples/porter-hello:latest"}, 54 } 55 56 for _, tc := range testcases { 57 t.Run(tc.name, func(t *testing.T) { 58 b := OCIReferenceParts{ 59 Repository: tc.repo, 60 Digest: tc.digest, 61 Version: tc.version, 62 Tag: tc.tag, 63 } 64 65 ref, ok, err := b.GetBundleReference() 66 if tc.wantErr != "" { 67 require.Error(t, err) 68 assert.Contains(t, err.Error(), tc.wantErr) 69 } else if tc.wantRef != "" { 70 require.NoError(t, err) 71 assert.Equal(t, tc.wantRef, ref.String()) 72 } else { 73 require.NoError(t, err) 74 require.False(t, ok) 75 } 76 }) 77 } 78 } 79 80 func TestInstallation_ApplyResult(t *testing.T) { 81 t.Parallel() 82 83 bun := cnab.ExtendedBundle{} 84 t.Run("install failed", func(t *testing.T) { 85 // try to install a bundle and fail 86 inst := NewInstallation("dev", "mybuns") 87 run := inst.NewRun(cnab.ActionInstall, bun) 88 result := run.NewResult(cnab.StatusFailed) 89 90 inst.ApplyResult(run, result) 91 92 assert.False(t, inst.IsInstalled(), "a failed install should not mark the installation as installed") 93 assert.Empty(t, inst.Status.Installed, "the installed timestamp should not be set") 94 }) 95 96 t.Run("install succeeded", func(t *testing.T) { 97 // install a bundle 98 inst := NewInstallation("dev", "mybuns") 99 run := inst.NewRun(cnab.ActionInstall, bun) 100 result := run.NewResult(cnab.StatusSucceeded) 101 102 inst.ApplyResult(run, result) 103 104 assert.True(t, inst.IsInstalled(), "a failed install should not mark the installation as installed") 105 assert.Equal(t, &result.Created, inst.Status.Installed, "the installed timestamp should be set to the result timestamp") 106 }) 107 108 t.Run("uninstall failed", func(t *testing.T) { 109 // Make an installed bundle 110 inst := NewInstallation("dev", "mybuns") 111 inst.Status.Created = now.Add(-time.Second * 10) 112 inst.Status.Installed = &inst.Status.Created 113 114 // try to uninstall it and fail 115 run := inst.NewRun(cnab.ActionUninstall, bun) 116 result := run.NewResult(cnab.StatusFailed) 117 118 inst.ApplyResult(run, result) 119 120 assert.True(t, inst.IsInstalled(), "the installation should still be marked as installed") 121 assert.False(t, inst.IsUninstalled(), "the installation should not be marked as uninstalled") 122 assert.Empty(t, inst.Status.Uninstalled, "the uninstalled timestamp should not be set") 123 }) 124 125 t.Run("uninstall succeeded", func(t *testing.T) { 126 // Make an installed bundle 127 inst := NewInstallation("dev", "mybuns") 128 inst.Status.Created = now.Add(-time.Second * 10) 129 inst.Status.Installed = &inst.Status.Created 130 131 // uninstall it 132 run := inst.NewRun(cnab.ActionUninstall, bun) 133 result := run.NewResult(cnab.StatusSucceeded) 134 135 inst.ApplyResult(run, result) 136 137 assert.False(t, inst.IsInstalled(), "the installation should no longer be considered installed") 138 assert.True(t, inst.IsUninstalled(), "the installation should be marked as uninstalled") 139 assert.Equal(t, &inst.Status.Created, inst.Status.Installed, "the installed timestamp should still be set") 140 assert.Equal(t, &result.Created, inst.Status.Uninstalled, "the uninstalled timestamp should be set") 141 }) 142 143 t.Run("desired state after re-installation and re-unstallation", func(t *testing.T) { 144 // Make an installed bundle 145 inst := NewInstallation("dev", "mybuns") 146 inst.Status.Created = now.Add(-time.Second * 15) 147 inst.Status.Installed = &inst.Status.Created 148 149 // uninstall the bundle 150 run := inst.NewRun(cnab.ActionUninstall, bun) 151 result := run.NewResult(cnab.StatusSucceeded) 152 result.Created = now.Add(-time.Second * 10) 153 154 inst.ApplyResult(run, result) 155 156 assert.False(t, inst.IsInstalled(), "the installation should no longer be considered installed") 157 assert.True(t, inst.IsUninstalled(), "the installation should be marked as uninstalled") 158 assert.Equal(t, &inst.Status.Created, inst.Status.Installed, "the installed timestamp should still be set") 159 assert.Equal(t, &result.Created, inst.Status.Uninstalled, "the uninstalled timestamp should be set") 160 161 // re-install the bundle 162 run = inst.NewRun(cnab.ActionInstall, bun) 163 result = run.NewResult(cnab.StatusSucceeded) 164 result.Created = now.Add(-time.Second * 5) 165 166 inst.ApplyResult(run, result) 167 168 assert.True(t, inst.IsInstalled(), "the installation should be marked as installed") 169 assert.False(t, inst.IsUninstalled(), "the installation should not be marked as uninstalled") 170 assert.Equal(t, &result.Created, inst.Status.Installed, "the installed timestamp should be set to the new install time") 171 assert.NotEmpty(t, inst.Status.Uninstalled, "the uninstalled timestamp should still be be set") 172 173 // re-uninstall the bundle 174 run = inst.NewRun(cnab.ActionUninstall, bun) 175 result = run.NewResult(cnab.StatusSucceeded) 176 177 inst.ApplyResult(run, result) 178 179 assert.False(t, inst.IsInstalled(), "the installation should not be marked as installed") 180 assert.True(t, inst.IsUninstalled(), "the installation should be marked as uninstalled") 181 assert.NotEmpty(t, inst.Status.Installed, "the installed timestamp should still be be set") 182 assert.Equal(t, &result.Created, inst.Status.Uninstalled, "the uninstalled timestamp should be set to the new uninstall time") 183 }) 184 } 185 186 func TestInstallation_Validate(t *testing.T) { 187 t.Parallel() 188 189 testcases := []struct { 190 name string 191 input InstallationSpec 192 wantError string 193 }{ 194 { 195 name: "none", 196 input: InstallationSpec{ 197 SchemaType: "", 198 SchemaVersion: DefaultInstallationSchemaVersion}, 199 wantError: ""}, 200 { 201 name: strings.ToLower(SchemaTypeInstallation), 202 input: InstallationSpec{ 203 SchemaType: "installation", 204 SchemaVersion: DefaultInstallationSchemaVersion}, 205 wantError: ""}, 206 { 207 name: SchemaTypeInstallation, 208 input: InstallationSpec{ 209 SchemaType: SchemaTypeInstallation, 210 SchemaVersion: DefaultInstallationSchemaVersion}, 211 wantError: ""}, 212 { 213 name: strings.ToUpper(SchemaTypeInstallation), 214 input: InstallationSpec{ 215 SchemaType: "INSTALLATION", 216 SchemaVersion: DefaultInstallationSchemaVersion}, 217 wantError: ""}, 218 { 219 name: SchemaTypeCredentialSet, 220 input: InstallationSpec{ 221 SchemaType: SchemaTypeCredentialSet, 222 SchemaVersion: DefaultInstallationSchemaVersion}, 223 wantError: "invalid schemaType CredentialSet, expected Installation"}, 224 } 225 226 for _, tc := range testcases { 227 tc := tc 228 t.Run(tc.name, func(t *testing.T) { 229 t.Parallel() 230 231 ctx := context.Background() 232 err := tc.input.Validate(ctx, schema.CheckStrategyExact) 233 if tc.wantError == "" { 234 require.NoError(t, err) 235 } else { 236 tests.RequireErrorContains(t, err, tc.wantError) 237 } 238 }) 239 } 240 } 241 242 func TestInstallation_Validate_DefaultSchemaType(t *testing.T) { 243 i := NewInstallation("", "mybuns") 244 i.SchemaType = "" 245 require.NoError(t, i.Validate(context.Background(), schema.CheckStrategyExact)) 246 assert.Equal(t, SchemaTypeInstallation, i.SchemaType) 247 }