github.com/crossplane/upjet@v1.3.0/pkg/migration/plan_generator_test.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package migration
     6  
     7  import (
     8  	"bytes"
     9  	"os"
    10  	"path/filepath"
    11  	"regexp"
    12  	"testing"
    13  
    14  	xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
    15  	"github.com/crossplane/crossplane-runtime/pkg/test"
    16  	v1 "github.com/crossplane/crossplane/apis/apiextensions/v1"
    17  	xpmetav1 "github.com/crossplane/crossplane/apis/pkg/meta/v1"
    18  	xpmetav1alpha1 "github.com/crossplane/crossplane/apis/pkg/meta/v1alpha1"
    19  	xppkgv1 "github.com/crossplane/crossplane/apis/pkg/v1"
    20  	xppkgv1beta1 "github.com/crossplane/crossplane/apis/pkg/v1beta1"
    21  	"github.com/google/go-cmp/cmp"
    22  	"github.com/google/go-cmp/cmp/cmpopts"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    25  	"k8s.io/apimachinery/pkg/runtime"
    26  	"k8s.io/apimachinery/pkg/runtime/schema"
    27  	"k8s.io/apimachinery/pkg/util/yaml"
    28  	k8syaml "sigs.k8s.io/yaml"
    29  
    30  	"github.com/crossplane/upjet/pkg/migration/fake"
    31  )
    32  
    33  func TestGeneratePlan(t *testing.T) {
    34  	type fields struct {
    35  		source   Source
    36  		target   *testTarget
    37  		registry *Registry
    38  		opts     []PlanGeneratorOption
    39  	}
    40  	type want struct {
    41  		err               error
    42  		migrationPlanPath string
    43  		// names of resource files to be loaded
    44  		migratedResourceNames []string
    45  		preProcessResults     map[Category][]string
    46  	}
    47  	tests := map[string]struct {
    48  		fields fields
    49  		want   want
    50  	}{
    51  		"EmptyPlan": {
    52  			fields: fields{
    53  				source:   newTestSource(map[string]Metadata{}),
    54  				target:   newTestTarget(),
    55  				registry: getRegistry(),
    56  			},
    57  			want: want{},
    58  		},
    59  		"PreProcess": {
    60  			fields: fields{
    61  				source: newTestSource(map[string]Metadata{
    62  					"testdata/plan/composition.yaml": {Category: CategoryComposition},
    63  				}),
    64  				target:   newTestTarget(),
    65  				registry: getRegistry(withPreProcessor(CategoryComposition, &preProcessor{})),
    66  			},
    67  			want: want{
    68  				preProcessResults: map[Category][]string{
    69  					CategoryComposition: {"example.compositions.apiextensions.crossplane.io_v1"},
    70  				},
    71  			},
    72  		},
    73  		"PlanWithManagedResourceAndClaim": {
    74  			fields: fields{
    75  				source: newTestSource(map[string]Metadata{
    76  					"testdata/plan/sourcevpc.yaml":   {Category: CategoryManaged},
    77  					"testdata/plan/claim.yaml":       {Category: CategoryClaim},
    78  					"testdata/plan/composition.yaml": {},
    79  					"testdata/plan/xrd.yaml":         {},
    80  					"testdata/plan/xr.yaml":          {Category: CategoryComposite}}),
    81  				target: newTestTarget(),
    82  				registry: getRegistry(
    83  					withPreProcessor(CategoryManaged, &preProcessor{}),
    84  					withDelegatingConverter(fake.MigrationSourceGVK, delegatingConverter{
    85  						rFn: func(mg xpresource.Managed) ([]xpresource.Managed, error) {
    86  							s := mg.(*fake.MigrationSourceObject)
    87  							t := &fake.MigrationTargetObject{}
    88  							if _, err := CopyInto(s, t, fake.MigrationTargetGVK, "spec.forProvider.tags", "mockManaged"); err != nil {
    89  								return nil, err
    90  							}
    91  							t.Spec.ForProvider.Tags = make(map[string]string, len(s.Spec.ForProvider.Tags))
    92  							for _, tag := range s.Spec.ForProvider.Tags {
    93  								v := tag.Value
    94  								t.Spec.ForProvider.Tags[tag.Key] = v
    95  							}
    96  							return []xpresource.Managed{
    97  								t,
    98  							}, nil
    99  						},
   100  						cmpFn: func(_ v1.ComposedTemplate, convertedTemplates ...*v1.ComposedTemplate) error {
   101  							// convert patches in the migration target composed templates
   102  							for i := range convertedTemplates {
   103  								convertedTemplates[i].Patches = append([]v1.Patch{
   104  									{FromFieldPath: ptrFromString("spec.parameters.tagValue"),
   105  										ToFieldPath: ptrFromString(`spec.forProvider.tags["key1"]`),
   106  									}, {
   107  										FromFieldPath: ptrFromString("spec.parameters.tagValue"),
   108  										ToFieldPath:   ptrFromString(`spec.forProvider.tags["key2"]`),
   109  									},
   110  								}, convertedTemplates[i].Patches...)
   111  							}
   112  							return nil
   113  						},
   114  					}),
   115  					withPatchSetConverter(patchSetConverter{
   116  						re:        AllCompositions,
   117  						converter: &testConverter{},
   118  					})),
   119  			},
   120  			want: want{
   121  				migrationPlanPath: "testdata/plan/generated/migration_plan.yaml",
   122  				migratedResourceNames: []string{
   123  					"pause-managed/sample-vpc.vpcs.fakesourceapi.yaml",
   124  					"edit-claims/my-resource.myresources.test.com.yaml",
   125  					"start-managed/sample-vpc.vpcs.faketargetapi.yaml",
   126  					"pause-composites/my-resource-dwjgh.xmyresources.test.com.yaml",
   127  					"edit-composites/my-resource-dwjgh.xmyresources.test.com.yaml",
   128  					"deletion-policy-orphan/sample-vpc.vpcs.fakesourceapi.yaml",
   129  					"remove-finalizers/sample-vpc.vpcs.fakesourceapi.yaml",
   130  					"new-compositions/example-migrated.compositions.apiextensions.crossplane.io.yaml",
   131  					"start-composites/my-resource-dwjgh.xmyresources.test.com.yaml",
   132  					"create-new-managed/sample-vpc.vpcs.faketargetapi.yaml",
   133  				},
   134  				preProcessResults: map[Category][]string{
   135  					CategoryManaged: {"sample-vpc.vpcs.fakesourceapi_v1alpha1"},
   136  				},
   137  			},
   138  		},
   139  		"PlanWithManagedResourceAndClaimForFileSystemMode": {
   140  			fields: fields{
   141  				source: newTestSource(map[string]Metadata{
   142  					"testdata/plan/sourcevpc.yaml":   {Category: CategoryManaged},
   143  					"testdata/plan/claim.yaml":       {Category: CategoryClaim},
   144  					"testdata/plan/composition.yaml": {},
   145  					"testdata/plan/xrd.yaml":         {},
   146  					"testdata/plan/xr.yaml":          {Category: CategoryComposite}}),
   147  				target: newTestTarget(),
   148  				registry: getRegistry(
   149  					withPreProcessor(CategoryManaged, &preProcessor{}),
   150  					withDelegatingConverter(fake.MigrationSourceGVK, delegatingConverter{
   151  						rFn: func(mg xpresource.Managed) ([]xpresource.Managed, error) {
   152  							s := mg.(*fake.MigrationSourceObject)
   153  							t := &fake.MigrationTargetObject{}
   154  							if _, err := CopyInto(s, t, fake.MigrationTargetGVK, "spec.forProvider.tags", "mockManaged"); err != nil {
   155  								return nil, err
   156  							}
   157  							t.Spec.ForProvider.Tags = make(map[string]string, len(s.Spec.ForProvider.Tags))
   158  							for _, tag := range s.Spec.ForProvider.Tags {
   159  								v := tag.Value
   160  								t.Spec.ForProvider.Tags[tag.Key] = v
   161  							}
   162  							return []xpresource.Managed{
   163  								t,
   164  							}, nil
   165  						},
   166  						cmpFn: func(_ v1.ComposedTemplate, convertedTemplates ...*v1.ComposedTemplate) error {
   167  							// convert patches in the migration target composed templates
   168  							for i := range convertedTemplates {
   169  								convertedTemplates[i].Patches = append([]v1.Patch{
   170  									{FromFieldPath: ptrFromString("spec.parameters.tagValue"),
   171  										ToFieldPath: ptrFromString(`spec.forProvider.tags["key1"]`),
   172  									}, {
   173  										FromFieldPath: ptrFromString("spec.parameters.tagValue"),
   174  										ToFieldPath:   ptrFromString(`spec.forProvider.tags["key2"]`),
   175  									},
   176  								}, convertedTemplates[i].Patches...)
   177  							}
   178  							return nil
   179  						},
   180  					}),
   181  					withPatchSetConverter(patchSetConverter{
   182  						re:        AllCompositions,
   183  						converter: &testConverter{},
   184  					})),
   185  				opts: []PlanGeneratorOption{WithEnableOnlyFileSystemAPISteps()},
   186  			},
   187  			want: want{
   188  				migrationPlanPath: "testdata/plan/generated/migration_plan_filesystem.yaml",
   189  				migratedResourceNames: []string{
   190  					"edit-claims/my-resource.myresources.test.com.yaml",
   191  					"start-managed/sample-vpc.vpcs.faketargetapi.yaml",
   192  					"edit-composites/my-resource-dwjgh.xmyresources.test.com.yaml",
   193  					"new-compositions/example-migrated.compositions.apiextensions.crossplane.io.yaml",
   194  					"start-composites/my-resource-dwjgh.xmyresources.test.com.yaml",
   195  					"create-new-managed/sample-vpc.vpcs.faketargetapi.yaml",
   196  				},
   197  				preProcessResults: map[Category][]string{
   198  					CategoryManaged: {"sample-vpc.vpcs.fakesourceapi_v1alpha1"},
   199  				},
   200  			},
   201  		},
   202  		"PlanWithConfigurationMetaV1": {
   203  			fields: fields{
   204  				source: newTestSource(map[string]Metadata{
   205  					"testdata/plan/configurationv1.yaml": {}}),
   206  				target: newTestTarget(),
   207  				registry: getRegistry(
   208  					withConfigurationMetadataConverter(configurationMetadataConverter{
   209  						re:        AllConfigurations,
   210  						converter: &configurationMetaTestConverter{},
   211  					})),
   212  				opts: []PlanGeneratorOption{WithEnableConfigurationMigrationSteps()},
   213  			},
   214  			want: want{
   215  				migrationPlanPath: "testdata/plan/generated/configurationv1_migration_plan.yaml",
   216  				migratedResourceNames: []string{
   217  					"edit-configuration-metadata/platform-ref-aws.configurations.meta.pkg.crossplane.io_v1.yaml",
   218  				},
   219  			},
   220  		},
   221  		"PlanWithConfigurationMetaV1Alpha1": {
   222  			fields: fields{
   223  				source: newTestSource(map[string]Metadata{
   224  					"testdata/plan/configurationv1alpha1.yaml": {}}),
   225  				target: newTestTarget(),
   226  				registry: getRegistry(
   227  					withConfigurationMetadataConverter(configurationMetadataConverter{
   228  						re:        AllConfigurations,
   229  						converter: &configurationMetaTestConverter{},
   230  					})),
   231  				opts: []PlanGeneratorOption{WithEnableConfigurationMigrationSteps()},
   232  			},
   233  			want: want{
   234  				migrationPlanPath: "testdata/plan/generated/configurationv1alpha1_migration_plan.yaml",
   235  				migratedResourceNames: []string{
   236  					"edit-configuration-metadata/platform-ref-aws.configurations.meta.pkg.crossplane.io_v1alpha1.yaml",
   237  				},
   238  			},
   239  		},
   240  		"PlanWithProviderPackageV1": {
   241  			fields: fields{
   242  				source: newTestSource(map[string]Metadata{
   243  					"testdata/plan/providerv1.yaml": {}}),
   244  				target: newTestTarget(),
   245  				registry: getRegistry(
   246  					withProviderPackageConverter(providerPackageConverter{
   247  						re:        regexp.MustCompile(`xpkg.upbound.io/upbound/provider-aws:.+`),
   248  						converter: &monolithProviderToFamilyConfigConverter{},
   249  					}),
   250  					withProviderPackageConverter(providerPackageConverter{
   251  						re:        regexp.MustCompile(`xpkg.upbound.io/upbound/provider-aws:.+`),
   252  						converter: &monolithicProviderToSSOPConverter{},
   253  					})),
   254  				opts: []PlanGeneratorOption{WithEnableConfigurationMigrationSteps()},
   255  			},
   256  			want: want{
   257  				migrationPlanPath: "testdata/plan/generated/providerv1_migration_plan.yaml",
   258  				migratedResourceNames: []string{
   259  					"new-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml",
   260  					"new-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml",
   261  					"new-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml",
   262  					"activate-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml",
   263  					"activate-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml",
   264  					"activate-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml",
   265  				},
   266  			},
   267  		},
   268  		"PlanForConfigurationPackageMigration": {
   269  			fields: fields{
   270  				source: newTestSource(map[string]Metadata{
   271  					"testdata/plan/providerv1.yaml":         {},
   272  					"testdata/plan/configurationv1.yaml":    {},
   273  					"testdata/plan/configurationpkgv1.yaml": {},
   274  					"testdata/plan/lockv1beta1.yaml":        {},
   275  					"testdata/plan/sourcevpc.yaml":          {Category: CategoryManaged},
   276  					"testdata/plan/sourcevpc2.yaml":         {Category: CategoryManaged},
   277  				}),
   278  				target: newTestTarget(),
   279  				registry: getRegistry(
   280  					withConfigurationMetadataConverter(configurationMetadataConverter{
   281  						re:        AllConfigurations,
   282  						converter: &configurationMetaTestConverter{},
   283  					}),
   284  					withConfigurationPackageConverter(configurationPackageConverter{
   285  						re:        regexp.MustCompile(`xpkg.upbound.io/upbound/provider-ref-aws:.+`),
   286  						converter: &configurationPackageTestConverter{},
   287  					}),
   288  					withProviderPackageConverter(providerPackageConverter{
   289  						re:        regexp.MustCompile(`xpkg.upbound.io/upbound/provider-aws:.+`),
   290  						converter: &monolithProviderToFamilyConfigConverter{},
   291  					}),
   292  					withProviderPackageConverter(providerPackageConverter{
   293  						re:        regexp.MustCompile(`xpkg.upbound.io/upbound/provider-aws:.+`),
   294  						converter: &monolithicProviderToSSOPConverter{},
   295  					}),
   296  					withPackageLockConverter(packageLockConverter{
   297  						re:        CrossplaneLockName,
   298  						converter: &lockConverter{},
   299  					}),
   300  				),
   301  				opts: []PlanGeneratorOption{WithEnableConfigurationMigrationSteps()},
   302  			},
   303  			want: want{
   304  				migrationPlanPath: "testdata/plan/generated/configurationv1_pkg_migration_plan.yaml",
   305  				migratedResourceNames: []string{
   306  					"disable-dependency-resolution/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml",
   307  					"edit-configuration-package/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml",
   308  					"enable-dependency-resolution/platform-ref-aws.configurations.pkg.crossplane.io_v1.yaml",
   309  					"edit-configuration-metadata/platform-ref-aws.configurations.meta.pkg.crossplane.io_v1.yaml",
   310  					"new-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml",
   311  					"new-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml",
   312  					"new-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml",
   313  					"activate-ssop/provider-family-aws.providers.pkg.crossplane.io_v1.yaml",
   314  					"activate-ssop/provider-aws-ec2.providers.pkg.crossplane.io_v1.yaml",
   315  					"activate-ssop/provider-aws-eks.providers.pkg.crossplane.io_v1.yaml",
   316  					"edit-package-lock/lock.locks.pkg.crossplane.io_v1beta1.yaml",
   317  					"deletion-policy-orphan/sample-vpc.vpcs.fakesourceapi_v1alpha1.yaml",
   318  					"deletion-policy-delete/sample-vpc.vpcs.fakesourceapi_v1alpha1.yaml",
   319  				},
   320  			},
   321  		},
   322  	}
   323  	for name, tt := range tests {
   324  		t.Run(name, func(t *testing.T) {
   325  			pg := NewPlanGenerator(tt.fields.registry, tt.fields.source, tt.fields.target, tt.fields.opts...)
   326  			err := pg.GeneratePlan()
   327  			// compare error state
   328  			if diff := cmp.Diff(tt.want.err, err, test.EquateErrors()); diff != "" {
   329  				t.Fatalf("GeneratePlan(): -wantError, +gotError: %s", diff)
   330  			}
   331  			if err != nil {
   332  				return
   333  			}
   334  			// compare preprocessor results
   335  			for c, results := range tt.want.preProcessResults {
   336  				pps := tt.fields.registry.unstructuredPreProcessors[c]
   337  				if len(pps) != 1 {
   338  					t.Fatalf("One pre-processor must have been registered for category: %s", c)
   339  				}
   340  				pp := pps[0].(*preProcessor)
   341  				if diff := cmp.Diff(results, pp.results); diff != "" {
   342  					t.Errorf("GeneratePlan(): -wantPreProcessorResults, +gotPreProcessorResults: %s", diff)
   343  				}
   344  			}
   345  			// compare generated plan with the expected plan
   346  			p, err := loadPlan(tt.want.migrationPlanPath)
   347  			if err != nil {
   348  				t.Fatalf("Failed to load plan file from path %s: %v", tt.want.migrationPlanPath, err)
   349  			}
   350  			if diff := cmp.Diff(p, &pg.Plan, cmpopts.IgnoreUnexported(Spec{})); diff != "" {
   351  				t.Errorf("GeneratePlan(): -wantPlan, +gotPlan: %s", diff)
   352  			}
   353  			// compare generated migration files with the expected ones
   354  			for _, name := range tt.want.migratedResourceNames {
   355  				path := filepath.Join("testdata/plan/generated", name)
   356  				buff, err := os.ReadFile(path)
   357  				if err != nil {
   358  					t.Fatalf("Failed to read a generated migration resource from path %s: %v", path, err)
   359  				}
   360  				u := unstructured.Unstructured{}
   361  				if err := k8syaml.Unmarshal(buff, &u); err != nil {
   362  					t.Fatalf("Failed to unmarshal a generated migration resource from path %s: %v", path, err)
   363  				}
   364  				gU, ok := tt.fields.target.targetManifests[name]
   365  				if !ok {
   366  					t.Errorf("GeneratePlan(): Expected generated migration resource file not found: %s", name)
   367  					continue
   368  				}
   369  				removeNilValuedKeys(u.Object)
   370  				if diff := cmp.Diff(u, gU.Object); diff != "" {
   371  					t.Errorf("GeneratePlan(): -wantMigratedResource, +gotMigratedResource with name %q: %s", name, diff)
   372  				}
   373  				delete(tt.fields.target.targetManifests, name)
   374  			}
   375  			// check for unexpected generated migration files
   376  			for name := range tt.fields.target.targetManifests {
   377  				t.Errorf("GeneratePlan(): Unexpected generated migration file: %s", name)
   378  			}
   379  		})
   380  	}
   381  }
   382  
   383  type testSource struct {
   384  	sourceManifests map[string]Metadata
   385  	paths           []string
   386  	index           int
   387  }
   388  
   389  func newTestSource(sourceManifests map[string]Metadata) *testSource {
   390  	result := &testSource{sourceManifests: sourceManifests}
   391  	result.paths = make([]string, 0, len(result.sourceManifests))
   392  	for k := range result.sourceManifests {
   393  		result.paths = append(result.paths, k)
   394  	}
   395  	return result
   396  }
   397  
   398  func (f *testSource) HasNext() (bool, error) {
   399  	return f.index <= len(f.paths)-1, nil
   400  }
   401  
   402  func (f *testSource) Next() (UnstructuredWithMetadata, error) {
   403  	um := UnstructuredWithMetadata{
   404  		Metadata: f.sourceManifests[f.paths[f.index]],
   405  		Object:   unstructured.Unstructured{},
   406  	}
   407  	um.Metadata.Path = f.paths[f.index]
   408  	buff, err := os.ReadFile(f.paths[f.index])
   409  	if err != nil {
   410  		return um, err
   411  	}
   412  	decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(string(buff)), 1024)
   413  	if err := decoder.Decode(&um.Object); err != nil {
   414  		return um, err
   415  	}
   416  	f.index++
   417  	return um, nil
   418  }
   419  
   420  func (f *testSource) Reset() error {
   421  	f.index = 0
   422  	return nil
   423  }
   424  
   425  type testTarget struct {
   426  	targetManifests map[string]UnstructuredWithMetadata
   427  }
   428  
   429  func newTestTarget() *testTarget {
   430  	return &testTarget{
   431  		targetManifests: make(map[string]UnstructuredWithMetadata),
   432  	}
   433  }
   434  
   435  func (f *testTarget) Put(o UnstructuredWithMetadata) error {
   436  	f.targetManifests[o.Metadata.Path] = o
   437  	return nil
   438  }
   439  
   440  func (f *testTarget) Delete(o UnstructuredWithMetadata) error {
   441  	delete(f.targetManifests, o.Metadata.Path)
   442  	return nil
   443  }
   444  
   445  // can be utilized to populate test artifacts
   446  /*func (f *testTarget) dumpFiles(parentDir string) error {
   447  	for f, u := range f.targetManifests {
   448  		path := filepath.Join(parentDir, f)
   449  		buff, err := k8syaml.Marshal(u.Object.Object)
   450  		if err != nil {
   451  			return err
   452  		}
   453  		if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
   454  			return err
   455  		}
   456  		if err := os.WriteFile(path, buff, 0o600); err != nil {
   457  			return err
   458  		}
   459  	}
   460  	return nil
   461  }*/
   462  
   463  type testConverter struct{}
   464  
   465  func (f *testConverter) PatchSets(psMap map[string]*v1.PatchSet) error {
   466  	psMap["ps1"].Patches[0].ToFieldPath = ptrFromString(`spec.forProvider.tags["key3"]`)
   467  	psMap["ps6"].Patches[0].ToFieldPath = ptrFromString(`spec.forProvider.tags["key4"]`)
   468  	return nil
   469  }
   470  
   471  func ptrFromString(s string) *string {
   472  	return &s
   473  }
   474  
   475  type registryOption func(*Registry)
   476  
   477  func withDelegatingConverter(gvk schema.GroupVersionKind, d delegatingConverter) registryOption {
   478  	return func(r *Registry) {
   479  		r.RegisterAPIConversionFunctions(gvk, d.rFn, d.cmpFn, nil)
   480  	}
   481  }
   482  
   483  func withPatchSetConverter(c patchSetConverter) registryOption {
   484  	return func(r *Registry) {
   485  		r.RegisterPatchSetConverter(c.re, c.converter)
   486  	}
   487  }
   488  
   489  func withConfigurationMetadataConverter(c configurationMetadataConverter) registryOption {
   490  	return func(r *Registry) {
   491  		r.RegisterConfigurationMetadataConverter(c.re, c.converter)
   492  	}
   493  }
   494  
   495  func withConfigurationPackageConverter(c configurationPackageConverter) registryOption {
   496  	return func(r *Registry) {
   497  		r.RegisterConfigurationPackageConverter(c.re, c.converter)
   498  	}
   499  }
   500  
   501  func withProviderPackageConverter(c providerPackageConverter) registryOption {
   502  	return func(r *Registry) {
   503  		r.RegisterProviderPackageConverter(c.re, c.converter)
   504  	}
   505  }
   506  
   507  func withPackageLockConverter(c packageLockConverter) registryOption {
   508  	return func(r *Registry) {
   509  		r.RegisterPackageLockConverter(c.re, c.converter)
   510  	}
   511  }
   512  
   513  func withPreProcessor(c Category, pp UnstructuredPreProcessor) registryOption {
   514  	return func(r *Registry) {
   515  		r.RegisterPreProcessor(c, pp)
   516  	}
   517  }
   518  
   519  func getRegistry(opts ...registryOption) *Registry {
   520  	scheme := runtime.NewScheme()
   521  	scheme.AddKnownTypeWithName(fake.MigrationSourceGVK, &fake.MigrationSourceObject{})
   522  	scheme.AddKnownTypeWithName(fake.MigrationTargetGVK, &fake.MigrationTargetObject{})
   523  	r := NewRegistry(scheme)
   524  	for _, o := range opts {
   525  		o(r)
   526  	}
   527  	return r
   528  }
   529  
   530  func loadPlan(planPath string) (*Plan, error) {
   531  	if planPath == "" {
   532  		return emptyPlan(), nil
   533  	}
   534  	buff, err := os.ReadFile(planPath)
   535  	if err != nil {
   536  		return nil, err
   537  	}
   538  	p := &Plan{}
   539  	return p, k8syaml.Unmarshal(buff, p)
   540  }
   541  
   542  func emptyPlan() *Plan {
   543  	return &Plan{
   544  		Version: versionV010,
   545  	}
   546  }
   547  
   548  type configurationPackageTestConverter struct{}
   549  
   550  func (c *configurationPackageTestConverter) ConfigurationPackageV1(pkg *xppkgv1.Configuration) error {
   551  	pkg.Spec.Package = "xpkg.upbound.io/upbound/provider-ref-aws:v0.2.0-ssop"
   552  	return nil
   553  }
   554  
   555  type configurationMetaTestConverter struct{}
   556  
   557  func (cc *configurationMetaTestConverter) ConfigurationMetadataV1(c *xpmetav1.Configuration) error {
   558  	c.Spec.DependsOn = []xpmetav1.Dependency{
   559  		{
   560  			Provider: ptrFromString("xpkg.upbound.io/upbound/provider-aws-eks"),
   561  			Version:  ">=v0.17.0",
   562  		},
   563  	}
   564  	return nil
   565  }
   566  
   567  func (cc *configurationMetaTestConverter) ConfigurationMetadataV1Alpha1(c *xpmetav1alpha1.Configuration) error {
   568  	c.Spec.DependsOn = []xpmetav1alpha1.Dependency{
   569  		{
   570  			Provider: ptrFromString("xpkg.upbound.io/upbound/provider-aws-eks"),
   571  			Version:  ">=v0.17.0",
   572  		},
   573  	}
   574  	return nil
   575  }
   576  
   577  type monolithProviderToFamilyConfigConverter struct{}
   578  
   579  func (c *monolithProviderToFamilyConfigConverter) ProviderPackageV1(_ xppkgv1.Provider) ([]xppkgv1.Provider, error) {
   580  	ap := xppkgv1.ManualActivation
   581  	return []xppkgv1.Provider{
   582  		{
   583  			ObjectMeta: metav1.ObjectMeta{
   584  				Name: "provider-family-aws",
   585  			},
   586  			Spec: xppkgv1.ProviderSpec{
   587  				PackageSpec: xppkgv1.PackageSpec{
   588  					Package:                  "xpkg.upbound.io/upbound/provider-family-aws:v0.37.0",
   589  					RevisionActivationPolicy: &ap,
   590  				},
   591  			},
   592  		},
   593  	}, nil
   594  }
   595  
   596  type monolithicProviderToSSOPConverter struct{}
   597  
   598  func (c *monolithicProviderToSSOPConverter) ProviderPackageV1(_ xppkgv1.Provider) ([]xppkgv1.Provider, error) {
   599  	ap := xppkgv1.ManualActivation
   600  	return []xppkgv1.Provider{
   601  		{
   602  			ObjectMeta: metav1.ObjectMeta{
   603  				Name: "provider-aws-ec2",
   604  			},
   605  			Spec: xppkgv1.ProviderSpec{
   606  				PackageSpec: xppkgv1.PackageSpec{
   607  					Package:                  "xpkg.upbound.io/upbound/provider-aws-ec2:v0.37.0",
   608  					RevisionActivationPolicy: &ap,
   609  				},
   610  			},
   611  		},
   612  		{
   613  			ObjectMeta: metav1.ObjectMeta{
   614  				Name: "provider-aws-eks",
   615  			},
   616  			Spec: xppkgv1.ProviderSpec{
   617  				PackageSpec: xppkgv1.PackageSpec{
   618  					Package:                  "xpkg.upbound.io/upbound/provider-aws-eks:v0.37.0",
   619  					RevisionActivationPolicy: &ap,
   620  				},
   621  			},
   622  		},
   623  	}, nil
   624  }
   625  
   626  type lockConverter struct{}
   627  
   628  func (p *lockConverter) PackageLockV1Beta1(lock *xppkgv1beta1.Lock) error {
   629  	lock.Packages = append(lock.Packages, xppkgv1beta1.LockPackage{
   630  		Name:    "test-provider",
   631  		Type:    xppkgv1beta1.ProviderPackageType,
   632  		Source:  "xpkg.upbound.io/upbound/test-provider",
   633  		Version: "vX.Y.Z",
   634  	})
   635  	return nil
   636  }
   637  
   638  type preProcessor struct {
   639  	results []string
   640  }
   641  
   642  func (pp *preProcessor) PreProcess(u UnstructuredWithMetadata) error {
   643  	pp.results = append(pp.results, getVersionedName(u.Object))
   644  	return nil
   645  }