package tofumigrate import ( "reflect" "testing" "github.com/opentofu/opentofu/internal/addrs" "github.com/opentofu/opentofu/internal/configs/configload" "github.com/opentofu/opentofu/internal/states" ) func TestMigrateStateProviderAddresses(t *testing.T) { loader, close := configload.NewLoaderForTests(t) defer close() mustParseInstAddr := func(s string) addrs.AbsResourceInstance { addr, err := addrs.ParseAbsResourceInstanceStr(s) if err != nil { t.Fatal(err) } return addr } makeRootProviderAddr := func(s string) addrs.AbsProviderConfig { return addrs.AbsProviderConfig{ Module: addrs.RootModule, Provider: addrs.MustParseProviderSourceString(s), } } type args struct { configDir string state *states.State } tests := []struct { name string args args want *states.State }{ { name: "if there are no code references, migrate", args: args{ configDir: "testdata/nomention", state: states.BuildState(func(s *states.SyncState) { s.SetResourceInstanceCurrent( mustParseInstAddr("random_id.example"), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{}`), }, makeRootProviderAddr("registry.terraform.io/hashicorp/random"), ) s.SetResourceInstanceCurrent( mustParseInstAddr("aws_instance.example"), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{}`), }, makeRootProviderAddr("registry.terraform.io/hashicorp/aws"), ) }), }, want: states.BuildState(func(s *states.SyncState) { s.SetResourceInstanceCurrent( mustParseInstAddr("random_id.example"), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{}`), }, makeRootProviderAddr("registry.opentofu.org/hashicorp/random"), ) s.SetResourceInstanceCurrent( mustParseInstAddr("aws_instance.example"), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{}`), }, makeRootProviderAddr("registry.opentofu.org/hashicorp/aws"), ) }), }, { name: "if there are some full-form references in the code, only migrate the ones not referenced", args: args{ configDir: "testdata/mention", state: states.BuildState(func(s *states.SyncState) { s.SetResourceInstanceCurrent( mustParseInstAddr("random_id.example"), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{}`), }, makeRootProviderAddr("registry.terraform.io/hashicorp/random"), ) s.SetResourceInstanceCurrent( mustParseInstAddr("aws_instance.example"), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{}`), }, makeRootProviderAddr("registry.terraform.io/hashicorp/aws"), ) }), }, want: states.BuildState(func(s *states.SyncState) { s.SetResourceInstanceCurrent( mustParseInstAddr("random_id.example"), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{}`), }, makeRootProviderAddr("registry.opentofu.org/hashicorp/random"), ) s.SetResourceInstanceCurrent( mustParseInstAddr("aws_instance.example"), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{}`), }, makeRootProviderAddr("registry.terraform.io/hashicorp/aws"), ) }), }, { name: "if the state file contains no legacy references, return statefile unchanged", args: args{ configDir: "testdata/nomention", state: states.BuildState(func(s *states.SyncState) { s.SetResourceInstanceCurrent( mustParseInstAddr("random_id.example"), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{}`), }, makeRootProviderAddr("registry.opentofu.org/hashicorp/random"), ) s.SetResourceInstanceCurrent( mustParseInstAddr("aws_instance.example"), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{}`), }, makeRootProviderAddr("registry.opentofu.org/hashicorp/aws"), ) }), }, want: states.BuildState(func(s *states.SyncState) { s.SetResourceInstanceCurrent( mustParseInstAddr("random_id.example"), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{}`), }, makeRootProviderAddr("registry.opentofu.org/hashicorp/random"), ) s.SetResourceInstanceCurrent( mustParseInstAddr("aws_instance.example"), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, AttrsJSON: []byte(`{}`), }, makeRootProviderAddr("registry.opentofu.org/hashicorp/aws"), ) }), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg, hclDiags := loader.LoadConfig(tt.args.configDir) if hclDiags.HasErrors() { t.Fatalf("invalid configuration: %s", hclDiags.Error()) } got, err := MigrateStateProviderAddresses(cfg, tt.args.state) if !reflect.DeepEqual(got, tt.want) { t.Errorf("MigrateStateProviderAddresses() got = %v, want %v", got, tt.want) } if err != nil { t.Errorf("MigrateStateProviderAddresses() err = %v, want %v", err, nil) } }) } }