github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/states/instance_object_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package states 5 6 import ( 7 "sync" 8 "testing" 9 10 "github.com/google/go-cmp/cmp" 11 "github.com/terramate-io/tf/addrs" 12 "github.com/zclconf/go-cty/cty" 13 ) 14 15 func TestResourceInstanceObject_encode(t *testing.T) { 16 value := cty.ObjectVal(map[string]cty.Value{ 17 "foo": cty.True, 18 }) 19 // The in-memory order of resource dependencies is random, since they're an 20 // unordered set. 21 depsOne := []addrs.ConfigResource{ 22 addrs.RootModule.Resource(addrs.ManagedResourceMode, "test", "honk"), 23 addrs.RootModule.Child("child").Resource(addrs.ManagedResourceMode, "test", "flub"), 24 addrs.RootModule.Resource(addrs.ManagedResourceMode, "test", "boop"), 25 } 26 depsTwo := []addrs.ConfigResource{ 27 addrs.RootModule.Child("child").Resource(addrs.ManagedResourceMode, "test", "flub"), 28 addrs.RootModule.Resource(addrs.ManagedResourceMode, "test", "boop"), 29 addrs.RootModule.Resource(addrs.ManagedResourceMode, "test", "honk"), 30 } 31 32 // multiple instances may have been assigned the same deps slice 33 objs := []*ResourceInstanceObject{ 34 &ResourceInstanceObject{ 35 Value: value, 36 Status: ObjectPlanned, 37 Dependencies: depsOne, 38 }, 39 &ResourceInstanceObject{ 40 Value: value, 41 Status: ObjectPlanned, 42 Dependencies: depsTwo, 43 }, 44 &ResourceInstanceObject{ 45 Value: value, 46 Status: ObjectPlanned, 47 Dependencies: depsOne, 48 }, 49 &ResourceInstanceObject{ 50 Value: value, 51 Status: ObjectPlanned, 52 Dependencies: depsOne, 53 }, 54 } 55 56 var encoded []*ResourceInstanceObjectSrc 57 58 // Encoding can happen concurrently, so we need to make sure the shared 59 // Dependencies are safely handled 60 var wg sync.WaitGroup 61 var mu sync.Mutex 62 63 for _, obj := range objs { 64 obj := obj 65 wg.Add(1) 66 go func() { 67 defer wg.Done() 68 rios, err := obj.Encode(value.Type(), 0) 69 if err != nil { 70 t.Errorf("unexpected error: %s", err) 71 } 72 mu.Lock() 73 encoded = append(encoded, rios) 74 mu.Unlock() 75 }() 76 } 77 wg.Wait() 78 79 // However, identical sets of dependencies should always be written to state 80 // in an identical order, so we don't do meaningless state updates on refresh. 81 for i := 0; i < len(encoded)-1; i++ { 82 if diff := cmp.Diff(encoded[i].Dependencies, encoded[i+1].Dependencies); diff != "" { 83 t.Errorf("identical dependencies got encoded in different orders:\n%s", diff) 84 } 85 } 86 }