github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/legacy/terraform/upgrade_state_v1_test.go (about)

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