github.com/moby/docker@v26.1.3+incompatible/libnetwork/datastore/datastore_test.go (about)

     1  package datastore
     2  
     3  import (
     4  	"encoding/json"
     5  	"testing"
     6  
     7  	"github.com/docker/docker/libnetwork/options"
     8  	"gotest.tools/v3/assert"
     9  	is "gotest.tools/v3/assert/cmp"
    10  )
    11  
    12  const dummyKey = "dummy"
    13  
    14  // NewTestDataStore can be used by other Tests in order to use custom datastore
    15  func NewTestDataStore() *Store {
    16  	s := NewMockStore()
    17  	return &Store{store: s, cache: newCache(s)}
    18  }
    19  
    20  func TestKey(t *testing.T) {
    21  	sKey := Key("hello", "world")
    22  	const expected = "docker/network/v1.0/hello/world/"
    23  	assert.Check(t, is.Equal(sKey, expected))
    24  }
    25  
    26  func TestInvalidDataStore(t *testing.T) {
    27  	_, err := New(ScopeCfg{
    28  		Client: ScopeClientCfg{
    29  			Provider: "invalid",
    30  			Address:  "localhost:8500",
    31  		},
    32  	})
    33  	assert.Check(t, is.Error(err, "unsupported KV store"))
    34  }
    35  
    36  func TestKVObjectFlatKey(t *testing.T) {
    37  	store := NewTestDataStore()
    38  	expected := dummyKVObject("1000", true)
    39  	err := store.PutObjectAtomic(expected)
    40  	assert.Check(t, err)
    41  
    42  	n := dummyObject{ID: "1000"} // GetObject uses KVObject.Key() for cache lookup.
    43  	err = store.GetObject(&n)
    44  	assert.Check(t, err)
    45  	assert.Check(t, is.Equal(n.Name, expected.Name))
    46  }
    47  
    48  func TestAtomicKVObjectFlatKey(t *testing.T) {
    49  	store := NewTestDataStore()
    50  	expected := dummyKVObject("1111", true)
    51  	assert.Check(t, !expected.Exists())
    52  	err := store.PutObjectAtomic(expected)
    53  	assert.Check(t, err)
    54  	assert.Check(t, expected.Exists())
    55  
    56  	// PutObjectAtomic automatically sets the Index again. Hence the following must pass.
    57  
    58  	err = store.PutObjectAtomic(expected)
    59  	assert.Check(t, err, "Atomic update should succeed.")
    60  
    61  	// Get the latest index and try PutObjectAtomic again for the same Key
    62  	// This must succeed as well
    63  	n := dummyObject{ID: "1111"} // GetObject uses KVObject.Key() for cache lookup.
    64  	err = store.GetObject(&n)
    65  	assert.Check(t, err)
    66  	n.ReturnValue = true
    67  	err = store.PutObjectAtomic(&n)
    68  	assert.Check(t, err)
    69  
    70  	// Get the Object using GetObject, then set again.
    71  	newObj := dummyObject{ID: "1111"} // GetObject uses KVObject.Key() for cache lookup.
    72  	err = store.GetObject(&newObj)
    73  	assert.Check(t, err)
    74  	assert.Check(t, newObj.Exists())
    75  	err = store.PutObjectAtomic(&n)
    76  	assert.Check(t, err)
    77  }
    78  
    79  // dummy data used to test the datastore
    80  type dummyObject struct {
    81  	Name        string                `kv:"leaf"`
    82  	NetworkType string                `kv:"leaf"`
    83  	EnableIPv6  bool                  `kv:"leaf"`
    84  	Rec         *recStruct            `kv:"recursive"`
    85  	Dict        map[string]*recStruct `kv:"iterative"`
    86  	Generic     options.Generic       `kv:"iterative"`
    87  	ID          string
    88  	DBIndex     uint64
    89  	DBExists    bool
    90  	SkipSave    bool
    91  	ReturnValue bool
    92  }
    93  
    94  func (n *dummyObject) Key() []string {
    95  	return []string{dummyKey, n.ID}
    96  }
    97  
    98  func (n *dummyObject) KeyPrefix() []string {
    99  	return []string{dummyKey}
   100  }
   101  
   102  func (n *dummyObject) Value() []byte {
   103  	if !n.ReturnValue {
   104  		return nil
   105  	}
   106  
   107  	b, err := json.Marshal(n)
   108  	if err != nil {
   109  		return nil
   110  	}
   111  	return b
   112  }
   113  
   114  func (n *dummyObject) SetValue(value []byte) error {
   115  	return json.Unmarshal(value, n)
   116  }
   117  
   118  func (n *dummyObject) Index() uint64 {
   119  	return n.DBIndex
   120  }
   121  
   122  func (n *dummyObject) SetIndex(index uint64) {
   123  	n.DBIndex = index
   124  	n.DBExists = true
   125  }
   126  
   127  func (n *dummyObject) Exists() bool {
   128  	return n.DBExists
   129  }
   130  
   131  func (n *dummyObject) Skip() bool {
   132  	return n.SkipSave
   133  }
   134  
   135  func (n *dummyObject) MarshalJSON() ([]byte, error) {
   136  	return json.Marshal(map[string]interface{}{
   137  		"name":        n.Name,
   138  		"networkType": n.NetworkType,
   139  		"enableIPv6":  n.EnableIPv6,
   140  		"generic":     n.Generic,
   141  	})
   142  }
   143  
   144  func (n *dummyObject) UnmarshalJSON(b []byte) error {
   145  	var netMap map[string]interface{}
   146  	if err := json.Unmarshal(b, &netMap); err != nil {
   147  		return err
   148  	}
   149  	n.Name = netMap["name"].(string)
   150  	n.NetworkType = netMap["networkType"].(string)
   151  	n.EnableIPv6 = netMap["enableIPv6"].(bool)
   152  	n.Generic = netMap["generic"].(map[string]interface{})
   153  	return nil
   154  }
   155  
   156  func (n *dummyObject) New() KVObject {
   157  	return &dummyObject{}
   158  }
   159  
   160  func (n *dummyObject) CopyTo(o KVObject) error {
   161  	if err := o.SetValue(n.Value()); err != nil {
   162  		return err
   163  	}
   164  	o.SetIndex(n.Index())
   165  	return nil
   166  }
   167  
   168  // dummy structure to test "recursive" cases
   169  type recStruct struct {
   170  	Name     string            `kv:"leaf"`
   171  	Field1   int               `kv:"leaf"`
   172  	Dict     map[string]string `kv:"iterative"`
   173  	DBIndex  uint64
   174  	DBExists bool
   175  	SkipSave bool
   176  }
   177  
   178  func (r *recStruct) Key() []string {
   179  	return []string{"recStruct"}
   180  }
   181  
   182  func (r *recStruct) Value() []byte {
   183  	b, err := json.Marshal(r)
   184  	if err != nil {
   185  		return nil
   186  	}
   187  	return b
   188  }
   189  
   190  func (r *recStruct) SetValue(value []byte) error {
   191  	return json.Unmarshal(value, r)
   192  }
   193  
   194  func (r *recStruct) Index() uint64 {
   195  	return r.DBIndex
   196  }
   197  
   198  func (r *recStruct) SetIndex(index uint64) {
   199  	r.DBIndex = index
   200  	r.DBExists = true
   201  }
   202  
   203  func (r *recStruct) Exists() bool {
   204  	return r.DBExists
   205  }
   206  
   207  func (r *recStruct) Skip() bool {
   208  	return r.SkipSave
   209  }
   210  
   211  func dummyKVObject(id string, retValue bool) *dummyObject {
   212  	cDict := map[string]string{
   213  		"foo":   "bar",
   214  		"hello": "world",
   215  	}
   216  	return &dummyObject{
   217  		Name:        "testNw",
   218  		NetworkType: "bridge",
   219  		EnableIPv6:  true,
   220  		Rec:         &recStruct{Name: "gen", Field1: 5, Dict: cDict},
   221  		ID:          id,
   222  		DBIndex:     0,
   223  		ReturnValue: retValue,
   224  		DBExists:    false,
   225  		SkipSave:    false,
   226  		Generic: map[string]interface{}{
   227  			"label1": &recStruct{Name: "value1", Field1: 1, Dict: cDict},
   228  			"label2": "subnet=10.1.1.0/16",
   229  		},
   230  	}
   231  }