github.com/opentofu/opentofu@v1.7.1/internal/tofumigrate/tofumigrate_test.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package tofumigrate
     7  
     8  import (
     9  	"reflect"
    10  	"testing"
    11  
    12  	"github.com/hashicorp/hcl/v2"
    13  
    14  	"github.com/opentofu/opentofu/internal/addrs"
    15  	"github.com/opentofu/opentofu/internal/configs"
    16  	"github.com/opentofu/opentofu/internal/configs/configload"
    17  	"github.com/opentofu/opentofu/internal/states"
    18  )
    19  
    20  func TestMigrateStateProviderAddresses(t *testing.T) {
    21  	loader, close := configload.NewLoaderForTests(t)
    22  	defer close()
    23  
    24  	mustParseInstAddr := func(s string) addrs.AbsResourceInstance {
    25  		addr, err := addrs.ParseAbsResourceInstanceStr(s)
    26  		if err != nil {
    27  			t.Fatal(err)
    28  		}
    29  		return addr
    30  	}
    31  
    32  	makeRootProviderAddr := func(s string) addrs.AbsProviderConfig {
    33  		return addrs.AbsProviderConfig{
    34  			Module:   addrs.RootModule,
    35  			Provider: addrs.MustParseProviderSourceString(s),
    36  		}
    37  	}
    38  
    39  	type args struct {
    40  		configDir string
    41  		state     *states.State
    42  	}
    43  	tests := []struct {
    44  		name string
    45  		args args
    46  		want *states.State
    47  	}{
    48  		{
    49  			name: "if there are no code references, migrate",
    50  			args: args{
    51  				configDir: "testdata/nomention",
    52  				state: states.BuildState(func(s *states.SyncState) {
    53  					s.SetResourceInstanceCurrent(
    54  						mustParseInstAddr("random_id.example"),
    55  						&states.ResourceInstanceObjectSrc{
    56  							Status:    states.ObjectReady,
    57  							AttrsJSON: []byte(`{}`),
    58  						},
    59  						makeRootProviderAddr("registry.terraform.io/hashicorp/random"),
    60  					)
    61  					s.SetResourceInstanceCurrent(
    62  						mustParseInstAddr("aws_instance.example"),
    63  						&states.ResourceInstanceObjectSrc{
    64  							Status:    states.ObjectReady,
    65  							AttrsJSON: []byte(`{}`),
    66  						},
    67  						makeRootProviderAddr("registry.terraform.io/hashicorp/aws"),
    68  					)
    69  				}),
    70  			},
    71  			want: states.BuildState(func(s *states.SyncState) {
    72  				s.SetResourceInstanceCurrent(
    73  					mustParseInstAddr("random_id.example"),
    74  					&states.ResourceInstanceObjectSrc{
    75  						Status:    states.ObjectReady,
    76  						AttrsJSON: []byte(`{}`),
    77  					},
    78  					makeRootProviderAddr("registry.opentofu.org/hashicorp/random"),
    79  				)
    80  				s.SetResourceInstanceCurrent(
    81  					mustParseInstAddr("aws_instance.example"),
    82  					&states.ResourceInstanceObjectSrc{
    83  						Status:    states.ObjectReady,
    84  						AttrsJSON: []byte(`{}`),
    85  					},
    86  					makeRootProviderAddr("registry.opentofu.org/hashicorp/aws"),
    87  				)
    88  			}),
    89  		},
    90  		{
    91  			name: "if there are some full-form references in the code, only migrate the ones not referenced",
    92  			args: args{
    93  				configDir: "testdata/mention",
    94  				state: states.BuildState(func(s *states.SyncState) {
    95  					s.SetResourceInstanceCurrent(
    96  						mustParseInstAddr("random_id.example"),
    97  						&states.ResourceInstanceObjectSrc{
    98  							Status:    states.ObjectReady,
    99  							AttrsJSON: []byte(`{}`),
   100  						},
   101  						makeRootProviderAddr("registry.terraform.io/hashicorp/random"),
   102  					)
   103  					s.SetResourceInstanceCurrent(
   104  						mustParseInstAddr("aws_instance.example"),
   105  						&states.ResourceInstanceObjectSrc{
   106  							Status:    states.ObjectReady,
   107  							AttrsJSON: []byte(`{}`),
   108  						},
   109  						makeRootProviderAddr("registry.terraform.io/hashicorp/aws"),
   110  					)
   111  				}),
   112  			},
   113  			want: states.BuildState(func(s *states.SyncState) {
   114  				s.SetResourceInstanceCurrent(
   115  					mustParseInstAddr("random_id.example"),
   116  					&states.ResourceInstanceObjectSrc{
   117  						Status:    states.ObjectReady,
   118  						AttrsJSON: []byte(`{}`),
   119  					},
   120  					makeRootProviderAddr("registry.opentofu.org/hashicorp/random"),
   121  				)
   122  				s.SetResourceInstanceCurrent(
   123  					mustParseInstAddr("aws_instance.example"),
   124  					&states.ResourceInstanceObjectSrc{
   125  						Status:    states.ObjectReady,
   126  						AttrsJSON: []byte(`{}`),
   127  					},
   128  					makeRootProviderAddr("registry.terraform.io/hashicorp/aws"),
   129  				)
   130  			}),
   131  		},
   132  		{
   133  			name: "if the state file contains no legacy references, return statefile unchanged",
   134  			args: args{
   135  				configDir: "testdata/nomention",
   136  				state: states.BuildState(func(s *states.SyncState) {
   137  					s.SetResourceInstanceCurrent(
   138  						mustParseInstAddr("random_id.example"),
   139  						&states.ResourceInstanceObjectSrc{
   140  							Status:    states.ObjectReady,
   141  							AttrsJSON: []byte(`{}`),
   142  						},
   143  						makeRootProviderAddr("registry.opentofu.org/hashicorp/random"),
   144  					)
   145  					s.SetResourceInstanceCurrent(
   146  						mustParseInstAddr("aws_instance.example"),
   147  						&states.ResourceInstanceObjectSrc{
   148  							Status:    states.ObjectReady,
   149  							AttrsJSON: []byte(`{}`),
   150  						},
   151  						makeRootProviderAddr("registry.opentofu.org/hashicorp/aws"),
   152  					)
   153  				}),
   154  			},
   155  			want: states.BuildState(func(s *states.SyncState) {
   156  				s.SetResourceInstanceCurrent(
   157  					mustParseInstAddr("random_id.example"),
   158  					&states.ResourceInstanceObjectSrc{
   159  						Status:    states.ObjectReady,
   160  						AttrsJSON: []byte(`{}`),
   161  					},
   162  					makeRootProviderAddr("registry.opentofu.org/hashicorp/random"),
   163  				)
   164  				s.SetResourceInstanceCurrent(
   165  					mustParseInstAddr("aws_instance.example"),
   166  					&states.ResourceInstanceObjectSrc{
   167  						Status:    states.ObjectReady,
   168  						AttrsJSON: []byte(`{}`),
   169  					},
   170  					makeRootProviderAddr("registry.opentofu.org/hashicorp/aws"),
   171  				)
   172  			}),
   173  		},
   174  		{
   175  			name: "if there is no code, migrate",
   176  			args: args{
   177  				configDir: "",
   178  				state: states.BuildState(func(s *states.SyncState) {
   179  					s.SetResourceInstanceCurrent(
   180  						mustParseInstAddr("random_id.example"),
   181  						&states.ResourceInstanceObjectSrc{
   182  							Status:    states.ObjectReady,
   183  							AttrsJSON: []byte(`{}`),
   184  						},
   185  						makeRootProviderAddr("registry.terraform.io/hashicorp/random"),
   186  					)
   187  					s.SetResourceInstanceCurrent(
   188  						mustParseInstAddr("aws_instance.example"),
   189  						&states.ResourceInstanceObjectSrc{
   190  							Status:    states.ObjectReady,
   191  							AttrsJSON: []byte(`{}`),
   192  						},
   193  						makeRootProviderAddr("registry.terraform.io/hashicorp/aws"),
   194  					)
   195  				}),
   196  			},
   197  			want: states.BuildState(func(s *states.SyncState) {
   198  				s.SetResourceInstanceCurrent(
   199  					mustParseInstAddr("random_id.example"),
   200  					&states.ResourceInstanceObjectSrc{
   201  						Status:    states.ObjectReady,
   202  						AttrsJSON: []byte(`{}`),
   203  					},
   204  					makeRootProviderAddr("registry.opentofu.org/hashicorp/random"),
   205  				)
   206  				s.SetResourceInstanceCurrent(
   207  					mustParseInstAddr("aws_instance.example"),
   208  					&states.ResourceInstanceObjectSrc{
   209  						Status:    states.ObjectReady,
   210  						AttrsJSON: []byte(`{}`),
   211  					},
   212  					makeRootProviderAddr("registry.opentofu.org/hashicorp/aws"),
   213  				)
   214  			}),
   215  		},
   216  	}
   217  	for _, tt := range tests {
   218  		t.Run(tt.name, func(t *testing.T) {
   219  			var cfg *configs.Config
   220  			if tt.args.configDir != "" {
   221  				var hclDiags hcl.Diagnostics
   222  				cfg, hclDiags = loader.LoadConfig(tt.args.configDir)
   223  				if hclDiags.HasErrors() {
   224  					t.Fatalf("invalid configuration: %s", hclDiags.Error())
   225  				}
   226  			}
   227  
   228  			got, err := MigrateStateProviderAddresses(cfg, tt.args.state)
   229  			if !reflect.DeepEqual(got, tt.want) {
   230  				t.Errorf("MigrateStateProviderAddresses() got = %v, want %v", got, tt.want)
   231  			}
   232  			if err != nil {
   233  				t.Errorf("MigrateStateProviderAddresses() err = %v, want %v", err, nil)
   234  			}
   235  		})
   236  	}
   237  }