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  }