github.com/eliastor/durgaform@v0.0.0-20220816172711-d0ab2d17673e/internal/states/instance_object_test.go (about)

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