github.com/opentofu/opentofu@v1.7.1/internal/legacy/tofu/upgrade_state_v1_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 tofu
     7  
     8  import (
     9  	"bytes"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/davecgh/go-spew/spew"
    15  )
    16  
    17  // TestReadUpgradeStateV1toV3 tests the state upgrade process from the V1 state
    18  // to the current version, and needs editing each time. This means it tests the
    19  // entire pipeline of upgrades (which migrate version to version).
    20  func TestReadUpgradeStateV1toV3(t *testing.T) {
    21  	// ReadState should transparently detect the old version but will upgrade
    22  	// it on Write.
    23  	actual, err := ReadState(strings.NewReader(testV1State))
    24  	if err != nil {
    25  		t.Fatalf("err: %s", err)
    26  	}
    27  
    28  	buf := new(bytes.Buffer)
    29  	if err := WriteState(actual, buf); err != nil {
    30  		t.Fatalf("err: %s", err)
    31  	}
    32  
    33  	if actual.Version != 3 {
    34  		t.Fatalf("bad: State version not incremented; is %d", actual.Version)
    35  	}
    36  
    37  	roundTripped, err := ReadState(buf)
    38  	if err != nil {
    39  		t.Fatalf("err: %s", err)
    40  	}
    41  
    42  	if !reflect.DeepEqual(actual, roundTripped) {
    43  		t.Logf("actual:\n%#v", actual)
    44  		t.Fatalf("roundTripped:\n%#v", roundTripped)
    45  	}
    46  }
    47  
    48  func TestReadUpgradeStateV1toV3_outputs(t *testing.T) {
    49  	// ReadState should transparently detect the old version but will upgrade
    50  	// it on Write.
    51  	actual, err := ReadState(strings.NewReader(testV1StateWithOutputs))
    52  	if err != nil {
    53  		t.Fatalf("err: %s", err)
    54  	}
    55  
    56  	buf := new(bytes.Buffer)
    57  	if err := WriteState(actual, buf); err != nil {
    58  		t.Fatalf("err: %s", err)
    59  	}
    60  
    61  	if actual.Version != 3 {
    62  		t.Fatalf("bad: State version not incremented; is %d", actual.Version)
    63  	}
    64  
    65  	roundTripped, err := ReadState(buf)
    66  	if err != nil {
    67  		t.Fatalf("err: %s", err)
    68  	}
    69  
    70  	if !reflect.DeepEqual(actual, roundTripped) {
    71  		spew.Config.DisableMethods = true
    72  		t.Fatalf("bad:\n%s\n\nround tripped:\n%s\n", spew.Sdump(actual), spew.Sdump(roundTripped))
    73  		spew.Config.DisableMethods = false
    74  	}
    75  }
    76  
    77  // Upgrading the state should not lose empty module Outputs and Resources maps
    78  // during upgrade. The init for a new module initializes new maps, so we may not
    79  // be expecting to check for a nil map.
    80  func TestReadUpgradeStateV1toV3_emptyState(t *testing.T) {
    81  	// ReadState should transparently detect the old version but will upgrade
    82  	// it on Write.
    83  	orig, err := ReadStateV1([]byte(testV1EmptyState))
    84  	if err != nil {
    85  		t.Fatalf("err: %s", err)
    86  	}
    87  
    88  	stateV2, err := upgradeStateV1ToV2(orig)
    89  	if err != nil {
    90  		t.Fatalf("error attempting upgradeStateV1ToV2: %s", err)
    91  	}
    92  
    93  	for _, m := range stateV2.Modules {
    94  		if m.Resources == nil {
    95  			t.Fatal("V1 to V2 upgrade lost module.Resources")
    96  		}
    97  		if m.Outputs == nil {
    98  			t.Fatal("V1 to V2 upgrade lost module.Outputs")
    99  		}
   100  	}
   101  
   102  	stateV3, err := upgradeStateV2ToV3(stateV2)
   103  	if err != nil {
   104  		t.Fatalf("error attempting to upgradeStateV2ToV3: %s", err)
   105  	}
   106  	for _, m := range stateV3.Modules {
   107  		if m.Resources == nil {
   108  			t.Fatal("V2 to V3 upgrade lost module.Resources")
   109  		}
   110  		if m.Outputs == nil {
   111  			t.Fatal("V2 to V3 upgrade lost module.Outputs")
   112  		}
   113  	}
   114  
   115  }
   116  
   117  const testV1EmptyState = `{
   118      "version": 1,
   119      "serial": 0,
   120      "modules": [
   121          {
   122              "path": [
   123                  "root"
   124              ],
   125              "outputs": {},
   126              "resources": {}
   127          }
   128      ]
   129  }
   130  `
   131  
   132  const testV1State = `{
   133      "version": 1,
   134      "serial": 9,
   135      "remote": {
   136          "type": "http",
   137          "config": {
   138              "url": "http://my-cool-server.com/"
   139          }
   140      },
   141      "modules": [
   142          {
   143              "path": [
   144                  "root"
   145              ],
   146              "outputs": null,
   147              "resources": {
   148                  "foo": {
   149                      "type": "",
   150                      "primary": {
   151                          "id": "bar"
   152                      }
   153                  }
   154              },
   155              "depends_on": [
   156                  "aws_instance.bar"
   157              ]
   158          }
   159      ]
   160  }
   161  `
   162  
   163  const testV1StateWithOutputs = `{
   164      "version": 1,
   165      "serial": 9,
   166      "remote": {
   167          "type": "http",
   168          "config": {
   169              "url": "http://my-cool-server.com/"
   170          }
   171      },
   172      "modules": [
   173          {
   174              "path": [
   175                  "root"
   176              ],
   177              "outputs": {
   178              	"foo": "bar",
   179              	"baz": "foo"
   180              },
   181              "resources": {
   182                  "foo": {
   183                      "type": "",
   184                      "primary": {
   185                          "id": "bar"
   186                      }
   187                  }
   188              },
   189              "depends_on": [
   190                  "aws_instance.bar"
   191              ]
   192          }
   193      ]
   194  }
   195  `