github.com/opentofu/opentofu@v1.7.1/internal/states/statemgr/statemgr_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 statemgr
     7  
     8  import (
     9  	"context"
    10  	"encoding/json"
    11  	"flag"
    12  	"os"
    13  	"testing"
    14  	"time"
    15  
    16  	_ "github.com/opentofu/opentofu/internal/logging"
    17  )
    18  
    19  func TestNewLockInfo(t *testing.T) {
    20  	info1 := NewLockInfo()
    21  	info2 := NewLockInfo()
    22  
    23  	if info1.ID == "" {
    24  		t.Fatal("LockInfo missing ID")
    25  	}
    26  
    27  	if info1.Version == "" {
    28  		t.Fatal("LockInfo missing version")
    29  	}
    30  
    31  	if info1.Created.IsZero() {
    32  		t.Fatal("LockInfo missing Created")
    33  	}
    34  
    35  	if info1.ID == info2.ID {
    36  		t.Fatal("multiple LockInfo with identical IDs")
    37  	}
    38  
    39  	// test the JSON output is valid
    40  	newInfo := &LockInfo{}
    41  	err := json.Unmarshal(info1.Marshal(), newInfo)
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  }
    46  
    47  func TestLockWithContext(t *testing.T) {
    48  	s := NewFullFake(nil, TestFullInitialState())
    49  
    50  	id, err := s.Lock(NewLockInfo())
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  
    55  	// use a cancelled context for an immediate timeout
    56  	ctx, cancel := context.WithCancel(context.Background())
    57  	cancel()
    58  
    59  	info := NewLockInfo()
    60  	info.Info = "lock with context"
    61  	_, err = LockWithContext(ctx, s, info)
    62  	if err == nil {
    63  		t.Fatal("lock should have failed immediately")
    64  	}
    65  
    66  	// block until LockwithContext has made a first attempt
    67  	attempted := make(chan struct{})
    68  	postLockHook = func() {
    69  		close(attempted)
    70  		postLockHook = nil
    71  	}
    72  
    73  	// unlock the state during LockWithContext
    74  	unlocked := make(chan struct{})
    75  	var unlockErr error
    76  	go func() {
    77  		defer close(unlocked)
    78  		<-attempted
    79  		unlockErr = s.Unlock(id)
    80  	}()
    81  
    82  	ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
    83  	defer cancel()
    84  
    85  	id, err = LockWithContext(ctx, s, info)
    86  	if err != nil {
    87  		t.Fatal("lock should have completed within 2s:", err)
    88  	}
    89  
    90  	// ensure the goruotine completes
    91  	<-unlocked
    92  	if unlockErr != nil {
    93  		t.Fatal(unlockErr)
    94  	}
    95  }
    96  
    97  func TestMain(m *testing.M) {
    98  	flag.Parse()
    99  	os.Exit(m.Run())
   100  }