get.porter.sh/porter@v1.3.0/pkg/porter/generateManifest_test.go (about) 1 package porter 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "path/filepath" 8 "testing" 9 10 "get.porter.sh/porter/pkg/build" 11 "get.porter.sh/porter/pkg/cache" 12 "get.porter.sh/porter/pkg/cnab" 13 cnabtooci "get.porter.sh/porter/pkg/cnab/cnab-to-oci" 14 "get.porter.sh/porter/pkg/config" 15 "get.porter.sh/porter/pkg/experimental" 16 "get.porter.sh/porter/pkg/test" 17 "github.com/docker/docker/api/types/image" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func Test_generateInternalManifest(t *testing.T) { 22 testcases := []struct { 23 name string 24 opts BuildOptions 25 wantErr string 26 wantManifest string 27 }{{ 28 name: "no opts", 29 opts: BuildOptions{}, 30 wantManifest: "expected-result.yaml", 31 }, { 32 name: "preserve tags", 33 opts: BuildOptions{BundleDefinitionOptions: BundleDefinitionOptions{PreserveTags: true}}, 34 wantManifest: "expected-result-preserve-tags.yaml", 35 }, { 36 name: "--file set", 37 opts: BuildOptions{ 38 BundleDefinitionOptions: BundleDefinitionOptions{ 39 File: "alternate.yaml", 40 }, 41 }, 42 wantManifest: "expected-result.yaml", 43 }, { 44 name: "name set", 45 opts: BuildOptions{MetadataOpts: MetadataOpts{Name: "newname"}}, 46 wantManifest: "new-name.yaml", 47 }, { 48 name: "version set", 49 opts: BuildOptions{MetadataOpts: MetadataOpts{Version: "1.0.0"}}, 50 wantManifest: "new-version.yaml", 51 }, { 52 name: "name and value set", 53 opts: BuildOptions{MetadataOpts: MetadataOpts{Name: "newname", Version: "1.0.0"}}, 54 wantManifest: "all-fields.yaml", 55 }, { 56 name: "custom input set", 57 opts: BuildOptions{Customs: []string{"key1=editedValue1", "key2.nestedKey2=editedValue2"}}, 58 wantManifest: "custom-input.yaml", 59 }, { 60 name: "failed to fetch image metadata", 61 opts: BuildOptions{}, 62 wantErr: "failed to fetch image metadata", 63 wantManifest: "expected-result.yaml", 64 }, 65 } 66 67 for _, tc := range testcases { 68 tc := tc 69 t.Run(tc.name, func(t *testing.T) { 70 p := NewTestPorter(t) 71 defer p.Close() 72 73 manifest := config.Name 74 if tc.opts.File != "" { 75 manifest = tc.opts.File 76 } 77 p.TestConfig.TestContext.AddTestFile("testdata/generateManifest/original.yaml", manifest) 78 79 err := tc.opts.Validate(p.Porter) 80 require.NoError(t, err) 81 82 if tc.wantErr == "" { 83 p.TestRegistry.MockGetCachedImage = mockGetCachedImage 84 } else { 85 p.TestRegistry.MockGetImageMetadata = mockGetImageMetadataFailure 86 } 87 88 err = p.generateInternalManifest(context.Background(), tc.opts) 89 if tc.wantErr != "" { 90 require.ErrorContains(t, err, tc.wantErr) 91 return 92 } 93 require.NoError(t, err) 94 95 goldenFile := filepath.Join("testdata/generateManifest", tc.wantManifest) 96 p.TestConfig.TestContext.AddTestFile(goldenFile, tc.wantManifest) 97 got, err := p.FileSystem.ReadFile(build.LOCAL_MANIFEST) 98 require.NoError(t, err) 99 test.CompareGoldenFile(t, goldenFile, string(got)) 100 }) 101 } 102 } 103 104 func mockGetImageMetadataFailure(ctx context.Context, ref cnab.OCIReference, opts cnabtooci.RegistryOptions) (cnabtooci.ImageMetadata, error) { 105 return cnabtooci.ImageMetadata{}, fmt.Errorf("failed to fetch image metadata %s", ref) 106 } 107 108 func mockGetCachedImage(ctx context.Context, ref cnab.OCIReference) (cnabtooci.ImageMetadata, error) { 109 sum := image.InspectResponse{ 110 ID: "test-id", 111 RepoDigests: []string{"test/whalesayd@sha256:8b92b7269f59e3ed824e811a1ff1ee64f0d44c0218efefada57a4bebc2d7ef6f"}, 112 } 113 return cnabtooci.NewImageSummaryFromInspect(ref, sum) 114 } 115 116 func Test_getImageLatestDigest(t *testing.T) { 117 defaultMockGetCachedImage := func(ctx context.Context, ref cnab.OCIReference) (cnabtooci.ImageMetadata, error) { 118 sum := image.InspectResponse{ 119 ID: "test-id", 120 RepoDigests: []string{"test/repo@sha256:8b92b7269f59e3ed824e811a1ff1ee64f0d44c0218efefada57a4bebc2d7ef6f"}, 121 } 122 return cnabtooci.NewImageSummaryFromInspect(ref, sum) 123 } 124 125 testcases := []struct { 126 name string 127 imgRef string 128 mockGetCachedImage func(ctx context.Context, ref cnab.OCIReference) (cnabtooci.ImageMetadata, error) 129 mockGetImageMetadata func(ctx context.Context, ref cnab.OCIReference, opts cnabtooci.RegistryOptions) (cnabtooci.ImageMetadata, error) 130 wantErr string 131 wantDigest string 132 }{{ 133 name: "success", 134 imgRef: "test/repo", 135 wantDigest: "sha256:8b92b7269f59e3ed824e811a1ff1ee64f0d44c0218efefada57a4bebc2d7ef6f", 136 }, { 137 name: "non-default image tag", 138 imgRef: "test/repo:v0.1.0", 139 mockGetCachedImage: func(ctx context.Context, ref cnab.OCIReference) (cnabtooci.ImageMetadata, error) { 140 return cnabtooci.ImageMetadata{}, fmt.Errorf("not in cache") 141 }, 142 mockGetImageMetadata: func(ctx context.Context, ref cnab.OCIReference, opts cnabtooci.RegistryOptions) (cnabtooci.ImageMetadata, error) { 143 require.True(t, ref.HasTag()) 144 require.Equal(t, "v0.1.0", ref.Tag()) 145 return cnabtooci.ImageMetadata{ 146 Reference: ref, 147 RepoDigests: []string{ 148 "test/repo@sha256:d2134b0be91e9e293bc872b719538440e5f933e9828cd96430c85d904afb5aa9", 149 }, 150 }, nil 151 }, 152 wantDigest: "sha256:d2134b0be91e9e293bc872b719538440e5f933e9828cd96430c85d904afb5aa9", 153 }, { 154 name: "failure", 155 imgRef: "test/repo", 156 mockGetCachedImage: func(ctx context.Context, ref cnab.OCIReference) (cnabtooci.ImageMetadata, error) { 157 return cnabtooci.ImageMetadata{}, errors.New("failed to get cached image") 158 }, 159 mockGetImageMetadata: mockGetImageMetadataFailure, 160 wantErr: "failed to fetch image metadata", 161 }, 162 } 163 164 for _, tc := range testcases { 165 tc := tc 166 t.Run(tc.name, func(t *testing.T) { 167 p := NewTestPorter(t) 168 defer p.Close() 169 170 ref, err := cnab.ParseOCIReference(tc.imgRef) 171 require.NoError(t, err) 172 173 if tc.mockGetCachedImage != nil { 174 p.TestRegistry.MockGetCachedImage = tc.mockGetCachedImage 175 } else { 176 p.TestRegistry.MockGetCachedImage = defaultMockGetCachedImage 177 } 178 if tc.mockGetImageMetadata != nil { 179 p.TestRegistry.MockGetImageMetadata = tc.mockGetImageMetadata 180 } 181 182 regOpts := cnabtooci.RegistryOptions{} 183 digest, err := p.getImageDigest(context.Background(), ref, regOpts) 184 if tc.wantErr != "" { 185 require.ErrorContains(t, err, tc.wantErr) 186 return 187 } 188 189 require.Equal(t, tc.wantDigest, digest.String()) 190 }) 191 } 192 } 193 194 func Test_depv2_bundleDigest(t *testing.T) { 195 defaultMockFindBundle := func(ref cnab.OCIReference) (cache.CachedBundle, bool, error) { 196 cachedBundle := cache.CachedBundle{ 197 BundleReference: cnab.BundleReference{ 198 Reference: ref, 199 Digest: "sha256:3abc67269f59e3ed824e811a1ff1ee64f0d44c0218efefada57a4bebc2d7ef6f", 200 }, 201 } 202 203 return cachedBundle, true, nil 204 } 205 206 testcases := []struct { 207 name string 208 originalManifest string 209 wantManifest string 210 wantErr string 211 mockFindBundle func(ref cnab.OCIReference) (cache.CachedBundle, bool, error) 212 mockPullBundle func(ctx context.Context, ref cnab.OCIReference, opts cnabtooci.RegistryOptions) (cnab.BundleReference, error) 213 }{ 214 { 215 name: "use digest in bundle reference", 216 wantManifest: "expected-result-depv2.yaml", 217 originalManifest: "original-depv2.yaml", 218 }, 219 { 220 name: "not found reference", 221 wantManifest: "expected-result-depv2.yaml", 222 originalManifest: "original-depv2.yaml", 223 mockFindBundle: func(ref cnab.OCIReference) (cache.CachedBundle, bool, error) { 224 return cache.CachedBundle{}, false, nil 225 }, 226 mockPullBundle: func(ctx context.Context, ref cnab.OCIReference, opts cnabtooci.RegistryOptions) (cnab.BundleReference, error) { 227 return cnab.BundleReference{}, errors.New("failed to pull bundle") 228 }, 229 wantErr: "failed to pull bundle", 230 }, 231 { 232 name: "no default bundle reference", 233 wantManifest: "expected-result-depv2-no-default-ref.yaml", 234 originalManifest: "original-depv2-no-default-ref.yaml", 235 }, 236 } 237 238 for _, tc := range testcases { 239 t.Run(tc.name, func(t *testing.T) { 240 p := NewTestPorter(t) 241 p.SetExperimentalFlags(experimental.FlagDependenciesV2) 242 defer p.Close() 243 if tc.mockFindBundle != nil { 244 p.TestCache.FindBundleMock = tc.mockFindBundle 245 } else { 246 p.TestCache.FindBundleMock = defaultMockFindBundle 247 } 248 if tc.mockPullBundle != nil { 249 p.TestRegistry.MockPullBundle = tc.mockPullBundle 250 } 251 p.TestConfig.TestContext.AddTestFile(filepath.Join("testdata/generateManifest", tc.originalManifest), config.Name) 252 opts := BuildOptions{} 253 require.NoError(t, opts.Validate(p.Porter)) 254 255 err := p.generateInternalManifest(context.Background(), opts) 256 if tc.wantErr != "" { 257 require.ErrorContains(t, err, tc.wantErr) 258 return 259 } 260 require.NoError(t, err) 261 262 goldenFile := filepath.Join("testdata/generateManifest", tc.wantManifest) 263 p.TestConfig.TestContext.AddTestFile(goldenFile, tc.wantManifest) 264 got, err := p.FileSystem.ReadFile(build.LOCAL_MANIFEST) 265 require.NoError(t, err) 266 test.CompareGoldenFile(t, goldenFile, string(got)) 267 }) 268 } 269 }