github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/states/remote/remote_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package remote
     5  
     6  import (
     7  	"crypto/md5"
     8  	"encoding/json"
     9  	"testing"
    10  )
    11  
    12  func TestRemoteClient_noPayload(t *testing.T) {
    13  	s := &State{
    14  		Client: nilClient{},
    15  	}
    16  	if err := s.RefreshState(); err != nil {
    17  		t.Fatal("error refreshing empty remote state")
    18  	}
    19  }
    20  
    21  // nilClient returns nil for everything
    22  type nilClient struct{}
    23  
    24  func (nilClient) Get() (*Payload, error) { return nil, nil }
    25  
    26  func (c nilClient) Put([]byte) error { return nil }
    27  
    28  func (c nilClient) Delete() error { return nil }
    29  
    30  // mockClient is a client that tracks persisted state snapshots only in
    31  // memory and also logs what it has been asked to do for use in test
    32  // assertions.
    33  type mockClient struct {
    34  	current []byte
    35  	log     []mockClientRequest
    36  }
    37  
    38  type mockClientRequest struct {
    39  	Method  string
    40  	Content map[string]interface{}
    41  }
    42  
    43  func (c *mockClient) Get() (*Payload, error) {
    44  	c.appendLog("Get", c.current)
    45  	if c.current == nil {
    46  		return nil, nil
    47  	}
    48  	checksum := md5.Sum(c.current)
    49  	return &Payload{
    50  		Data: c.current,
    51  		MD5:  checksum[:],
    52  	}, nil
    53  }
    54  
    55  func (c *mockClient) Put(data []byte) error {
    56  	c.appendLog("Put", data)
    57  	c.current = data
    58  	return nil
    59  }
    60  
    61  func (c *mockClient) Delete() error {
    62  	c.appendLog("Delete", c.current)
    63  	c.current = nil
    64  	return nil
    65  }
    66  
    67  func (c *mockClient) appendLog(method string, content []byte) {
    68  	// For easier test assertions, we actually log the result of decoding
    69  	// the content JSON rather than the raw bytes. Callers are in principle
    70  	// allowed to provide any arbitrary bytes here, but we know we're only
    71  	// using this to test our own State implementation here and that always
    72  	// uses the JSON state format, so this is fine.
    73  
    74  	var contentVal map[string]interface{}
    75  	if content != nil {
    76  		err := json.Unmarshal(content, &contentVal)
    77  		if err != nil {
    78  			panic(err) // should never happen because our tests control this input
    79  		}
    80  	}
    81  	c.log = append(c.log, mockClientRequest{method, contentVal})
    82  }
    83  
    84  // mockClientForcePusher is like mockClient, but also implements
    85  // EnableForcePush, allowing testing for this behavior
    86  type mockClientForcePusher struct {
    87  	current []byte
    88  	force   bool
    89  	log     []mockClientRequest
    90  }
    91  
    92  func (c *mockClientForcePusher) Get() (*Payload, error) {
    93  	c.appendLog("Get", c.current)
    94  	if c.current == nil {
    95  		return nil, nil
    96  	}
    97  	checksum := md5.Sum(c.current)
    98  	return &Payload{
    99  		Data: c.current,
   100  		MD5:  checksum[:],
   101  	}, nil
   102  }
   103  
   104  func (c *mockClientForcePusher) Put(data []byte) error {
   105  	if c.force {
   106  		c.appendLog("Force Put", data)
   107  	} else {
   108  		c.appendLog("Put", data)
   109  	}
   110  	c.current = data
   111  	return nil
   112  }
   113  
   114  // Implements remote.ClientForcePusher
   115  func (c *mockClientForcePusher) EnableForcePush() {
   116  	c.force = true
   117  }
   118  
   119  func (c *mockClientForcePusher) Delete() error {
   120  	c.appendLog("Delete", c.current)
   121  	c.current = nil
   122  	return nil
   123  }
   124  func (c *mockClientForcePusher) appendLog(method string, content []byte) {
   125  	var contentVal map[string]interface{}
   126  	if content != nil {
   127  		err := json.Unmarshal(content, &contentVal)
   128  		if err != nil {
   129  			panic(err) // should never happen because our tests control this input
   130  		}
   131  	}
   132  	c.log = append(c.log, mockClientRequest{method, contentVal})
   133  }