// Copyright (c) The OpenTofu Authors // SPDX-License-Identifier: MPL-2.0 // Copyright (c) 2023 HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package states import ( "sync" "testing" "github.com/google/go-cmp/cmp" "github.com/opentofu/opentofu/internal/addrs" "github.com/zclconf/go-cty/cty" ) func TestResourceInstanceObject_encode(t *testing.T) { value := cty.ObjectVal(map[string]cty.Value{ "foo": cty.True, }) // The in-memory order of resource dependencies is random, since they're an // unordered set. depsOne := []addrs.ConfigResource{ addrs.RootModule.Resource(addrs.ManagedResourceMode, "test", "honk"), addrs.RootModule.Child("child").Resource(addrs.ManagedResourceMode, "test", "flub"), addrs.RootModule.Resource(addrs.ManagedResourceMode, "test", "boop"), } depsTwo := []addrs.ConfigResource{ addrs.RootModule.Child("child").Resource(addrs.ManagedResourceMode, "test", "flub"), addrs.RootModule.Resource(addrs.ManagedResourceMode, "test", "boop"), addrs.RootModule.Resource(addrs.ManagedResourceMode, "test", "honk"), } // multiple instances may have been assigned the same deps slice objs := []*ResourceInstanceObject{ &ResourceInstanceObject{ Value: value, Status: ObjectPlanned, Dependencies: depsOne, }, &ResourceInstanceObject{ Value: value, Status: ObjectPlanned, Dependencies: depsTwo, }, &ResourceInstanceObject{ Value: value, Status: ObjectPlanned, Dependencies: depsOne, }, &ResourceInstanceObject{ Value: value, Status: ObjectPlanned, Dependencies: depsOne, }, } var encoded []*ResourceInstanceObjectSrc // Encoding can happen concurrently, so we need to make sure the shared // Dependencies are safely handled var wg sync.WaitGroup var mu sync.Mutex for _, obj := range objs { obj := obj wg.Add(1) go func() { defer wg.Done() rios, err := obj.Encode(value.Type(), 0) if err != nil { t.Errorf("unexpected error: %s", err) } mu.Lock() encoded = append(encoded, rios) mu.Unlock() }() } wg.Wait() // However, identical sets of dependencies should always be written to state // in an identical order, so we don't do meaningless state updates on refresh. for i := 0; i < len(encoded)-1; i++ { if diff := cmp.Diff(encoded[i].Dependencies, encoded[i+1].Dependencies); diff != "" { t.Errorf("identical dependencies got encoded in different orders:\n%s", diff) } } }