github.com/clly/consul@v1.4.5/agent/consul/fsm/commands_oss_test.go (about)

     1  package fsm
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"os"
     7  	"reflect"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/hashicorp/consul/agent/connect"
    12  	"github.com/hashicorp/consul/agent/consul/autopilot"
    13  	"github.com/hashicorp/consul/agent/structs"
    14  	"github.com/hashicorp/consul/api"
    15  	"github.com/hashicorp/consul/types"
    16  	"github.com/hashicorp/go-uuid"
    17  	"github.com/hashicorp/serf/coordinate"
    18  	"github.com/mitchellh/mapstructure"
    19  	"github.com/pascaldekloe/goe/verify"
    20  	"github.com/stretchr/testify/assert"
    21  )
    22  
    23  func generateUUID() (ret string) {
    24  	var err error
    25  	if ret, err = uuid.GenerateUUID(); err != nil {
    26  		panic(fmt.Sprintf("Unable to generate a UUID, %v", err))
    27  	}
    28  	return ret
    29  }
    30  
    31  func generateRandomCoordinate() *coordinate.Coordinate {
    32  	config := coordinate.DefaultConfig()
    33  	coord := coordinate.NewCoordinate(config)
    34  	for i := range coord.Vec {
    35  		coord.Vec[i] = rand.NormFloat64()
    36  	}
    37  	coord.Error = rand.NormFloat64()
    38  	coord.Adjustment = rand.NormFloat64()
    39  	return coord
    40  }
    41  
    42  func TestFSM_RegisterNode(t *testing.T) {
    43  	t.Parallel()
    44  	fsm, err := New(nil, os.Stderr)
    45  	if err != nil {
    46  		t.Fatalf("err: %v", err)
    47  	}
    48  
    49  	req := structs.RegisterRequest{
    50  		Datacenter: "dc1",
    51  		Node:       "foo",
    52  		Address:    "127.0.0.1",
    53  	}
    54  	buf, err := structs.Encode(structs.RegisterRequestType, req)
    55  	if err != nil {
    56  		t.Fatalf("err: %v", err)
    57  	}
    58  
    59  	resp := fsm.Apply(makeLog(buf))
    60  	if resp != nil {
    61  		t.Fatalf("resp: %v", resp)
    62  	}
    63  
    64  	// Verify we are registered
    65  	_, node, err := fsm.state.GetNode("foo")
    66  	if err != nil {
    67  		t.Fatalf("err: %s", err)
    68  	}
    69  	if node == nil {
    70  		t.Fatalf("not found!")
    71  	}
    72  	if node.ModifyIndex != 1 {
    73  		t.Fatalf("bad index: %d", node.ModifyIndex)
    74  	}
    75  
    76  	// Verify service registered
    77  	_, services, err := fsm.state.NodeServices(nil, "foo")
    78  	if err != nil {
    79  		t.Fatalf("err: %s", err)
    80  	}
    81  	if len(services.Services) != 0 {
    82  		t.Fatalf("Services: %v", services)
    83  	}
    84  }
    85  
    86  func TestFSM_RegisterNode_Service(t *testing.T) {
    87  	t.Parallel()
    88  	fsm, err := New(nil, os.Stderr)
    89  	if err != nil {
    90  		t.Fatalf("err: %v", err)
    91  	}
    92  
    93  	req := structs.RegisterRequest{
    94  		Datacenter: "dc1",
    95  		Node:       "foo",
    96  		Address:    "127.0.0.1",
    97  		Service: &structs.NodeService{
    98  			ID:      "db",
    99  			Service: "db",
   100  			Tags:    []string{"master"},
   101  			Port:    8000,
   102  		},
   103  		Check: &structs.HealthCheck{
   104  			Node:      "foo",
   105  			CheckID:   "db",
   106  			Name:      "db connectivity",
   107  			Status:    api.HealthPassing,
   108  			ServiceID: "db",
   109  		},
   110  	}
   111  	buf, err := structs.Encode(structs.RegisterRequestType, req)
   112  	if err != nil {
   113  		t.Fatalf("err: %v", err)
   114  	}
   115  
   116  	resp := fsm.Apply(makeLog(buf))
   117  	if resp != nil {
   118  		t.Fatalf("resp: %v", resp)
   119  	}
   120  
   121  	// Verify we are registered
   122  	_, node, err := fsm.state.GetNode("foo")
   123  	if err != nil {
   124  		t.Fatalf("err: %s", err)
   125  	}
   126  	if node == nil {
   127  		t.Fatalf("not found!")
   128  	}
   129  
   130  	// Verify service registered
   131  	_, services, err := fsm.state.NodeServices(nil, "foo")
   132  	if err != nil {
   133  		t.Fatalf("err: %s", err)
   134  	}
   135  	if _, ok := services.Services["db"]; !ok {
   136  		t.Fatalf("not registered!")
   137  	}
   138  
   139  	// Verify check
   140  	_, checks, err := fsm.state.NodeChecks(nil, "foo")
   141  	if err != nil {
   142  		t.Fatalf("err: %s", err)
   143  	}
   144  	if checks[0].CheckID != "db" {
   145  		t.Fatalf("not registered!")
   146  	}
   147  }
   148  
   149  func TestFSM_DeregisterService(t *testing.T) {
   150  	t.Parallel()
   151  	fsm, err := New(nil, os.Stderr)
   152  	if err != nil {
   153  		t.Fatalf("err: %v", err)
   154  	}
   155  
   156  	req := structs.RegisterRequest{
   157  		Datacenter: "dc1",
   158  		Node:       "foo",
   159  		Address:    "127.0.0.1",
   160  		Service: &structs.NodeService{
   161  			ID:      "db",
   162  			Service: "db",
   163  			Tags:    []string{"master"},
   164  			Port:    8000,
   165  		},
   166  	}
   167  	buf, err := structs.Encode(structs.RegisterRequestType, req)
   168  	if err != nil {
   169  		t.Fatalf("err: %v", err)
   170  	}
   171  
   172  	resp := fsm.Apply(makeLog(buf))
   173  	if resp != nil {
   174  		t.Fatalf("resp: %v", resp)
   175  	}
   176  
   177  	dereg := structs.DeregisterRequest{
   178  		Datacenter: "dc1",
   179  		Node:       "foo",
   180  		ServiceID:  "db",
   181  	}
   182  	buf, err = structs.Encode(structs.DeregisterRequestType, dereg)
   183  	if err != nil {
   184  		t.Fatalf("err: %v", err)
   185  	}
   186  
   187  	resp = fsm.Apply(makeLog(buf))
   188  	if resp != nil {
   189  		t.Fatalf("resp: %v", resp)
   190  	}
   191  
   192  	// Verify we are registered
   193  	_, node, err := fsm.state.GetNode("foo")
   194  	if err != nil {
   195  		t.Fatalf("err: %s", err)
   196  	}
   197  	if node == nil {
   198  		t.Fatalf("not found!")
   199  	}
   200  
   201  	// Verify service not registered
   202  	_, services, err := fsm.state.NodeServices(nil, "foo")
   203  	if err != nil {
   204  		t.Fatalf("err: %s", err)
   205  	}
   206  	if _, ok := services.Services["db"]; ok {
   207  		t.Fatalf("db registered!")
   208  	}
   209  }
   210  
   211  func TestFSM_DeregisterCheck(t *testing.T) {
   212  	t.Parallel()
   213  	fsm, err := New(nil, os.Stderr)
   214  	if err != nil {
   215  		t.Fatalf("err: %v", err)
   216  	}
   217  
   218  	req := structs.RegisterRequest{
   219  		Datacenter: "dc1",
   220  		Node:       "foo",
   221  		Address:    "127.0.0.1",
   222  		Check: &structs.HealthCheck{
   223  			Node:    "foo",
   224  			CheckID: "mem",
   225  			Name:    "memory util",
   226  			Status:  api.HealthPassing,
   227  		},
   228  	}
   229  	buf, err := structs.Encode(structs.RegisterRequestType, req)
   230  	if err != nil {
   231  		t.Fatalf("err: %v", err)
   232  	}
   233  
   234  	resp := fsm.Apply(makeLog(buf))
   235  	if resp != nil {
   236  		t.Fatalf("resp: %v", resp)
   237  	}
   238  
   239  	dereg := structs.DeregisterRequest{
   240  		Datacenter: "dc1",
   241  		Node:       "foo",
   242  		CheckID:    "mem",
   243  	}
   244  	buf, err = structs.Encode(structs.DeregisterRequestType, dereg)
   245  	if err != nil {
   246  		t.Fatalf("err: %v", err)
   247  	}
   248  
   249  	resp = fsm.Apply(makeLog(buf))
   250  	if resp != nil {
   251  		t.Fatalf("resp: %v", resp)
   252  	}
   253  
   254  	// Verify we are registered
   255  	_, node, err := fsm.state.GetNode("foo")
   256  	if err != nil {
   257  		t.Fatalf("err: %s", err)
   258  	}
   259  	if node == nil {
   260  		t.Fatalf("not found!")
   261  	}
   262  
   263  	// Verify check not registered
   264  	_, checks, err := fsm.state.NodeChecks(nil, "foo")
   265  	if err != nil {
   266  		t.Fatalf("err: %s", err)
   267  	}
   268  	if len(checks) != 0 {
   269  		t.Fatalf("check registered!")
   270  	}
   271  }
   272  
   273  func TestFSM_DeregisterNode(t *testing.T) {
   274  	t.Parallel()
   275  	fsm, err := New(nil, os.Stderr)
   276  	if err != nil {
   277  		t.Fatalf("err: %v", err)
   278  	}
   279  
   280  	req := structs.RegisterRequest{
   281  		Datacenter: "dc1",
   282  		Node:       "foo",
   283  		Address:    "127.0.0.1",
   284  		Service: &structs.NodeService{
   285  			ID:      "db",
   286  			Service: "db",
   287  			Tags:    []string{"master"},
   288  			Port:    8000,
   289  		},
   290  		Check: &structs.HealthCheck{
   291  			Node:      "foo",
   292  			CheckID:   "db",
   293  			Name:      "db connectivity",
   294  			Status:    api.HealthPassing,
   295  			ServiceID: "db",
   296  		},
   297  	}
   298  	buf, err := structs.Encode(structs.RegisterRequestType, req)
   299  	if err != nil {
   300  		t.Fatalf("err: %v", err)
   301  	}
   302  
   303  	resp := fsm.Apply(makeLog(buf))
   304  	if resp != nil {
   305  		t.Fatalf("resp: %v", resp)
   306  	}
   307  
   308  	dereg := structs.DeregisterRequest{
   309  		Datacenter: "dc1",
   310  		Node:       "foo",
   311  	}
   312  	buf, err = structs.Encode(structs.DeregisterRequestType, dereg)
   313  	if err != nil {
   314  		t.Fatalf("err: %v", err)
   315  	}
   316  
   317  	resp = fsm.Apply(makeLog(buf))
   318  	if resp != nil {
   319  		t.Fatalf("resp: %v", resp)
   320  	}
   321  
   322  	// Verify we are not registered
   323  	_, node, err := fsm.state.GetNode("foo")
   324  	if err != nil {
   325  		t.Fatalf("err: %s", err)
   326  	}
   327  	if node != nil {
   328  		t.Fatalf("found!")
   329  	}
   330  
   331  	// Verify service not registered
   332  	_, services, err := fsm.state.NodeServices(nil, "foo")
   333  	if err != nil {
   334  		t.Fatalf("err: %s", err)
   335  	}
   336  	if services != nil {
   337  		t.Fatalf("Services: %v", services)
   338  	}
   339  
   340  	// Verify checks not registered
   341  	_, checks, err := fsm.state.NodeChecks(nil, "foo")
   342  	if err != nil {
   343  		t.Fatalf("err: %s", err)
   344  	}
   345  	if len(checks) != 0 {
   346  		t.Fatalf("Services: %v", services)
   347  	}
   348  }
   349  
   350  func TestFSM_KVSDelete(t *testing.T) {
   351  	t.Parallel()
   352  	fsm, err := New(nil, os.Stderr)
   353  	if err != nil {
   354  		t.Fatalf("err: %v", err)
   355  	}
   356  
   357  	req := structs.KVSRequest{
   358  		Datacenter: "dc1",
   359  		Op:         api.KVSet,
   360  		DirEnt: structs.DirEntry{
   361  			Key:   "/test/path",
   362  			Flags: 0,
   363  			Value: []byte("test"),
   364  		},
   365  	}
   366  	buf, err := structs.Encode(structs.KVSRequestType, req)
   367  	if err != nil {
   368  		t.Fatalf("err: %v", err)
   369  	}
   370  	resp := fsm.Apply(makeLog(buf))
   371  	if resp != nil {
   372  		t.Fatalf("resp: %v", resp)
   373  	}
   374  
   375  	// Run the delete
   376  	req.Op = api.KVDelete
   377  	buf, err = structs.Encode(structs.KVSRequestType, req)
   378  	if err != nil {
   379  		t.Fatalf("err: %v", err)
   380  	}
   381  	resp = fsm.Apply(makeLog(buf))
   382  	if resp != nil {
   383  		t.Fatalf("resp: %v", resp)
   384  	}
   385  
   386  	// Verify key is not set
   387  	_, d, err := fsm.state.KVSGet(nil, "/test/path")
   388  	if err != nil {
   389  		t.Fatalf("err: %v", err)
   390  	}
   391  	if d != nil {
   392  		t.Fatalf("key present")
   393  	}
   394  }
   395  
   396  func TestFSM_KVSDeleteTree(t *testing.T) {
   397  	t.Parallel()
   398  	fsm, err := New(nil, os.Stderr)
   399  	if err != nil {
   400  		t.Fatalf("err: %v", err)
   401  	}
   402  
   403  	req := structs.KVSRequest{
   404  		Datacenter: "dc1",
   405  		Op:         api.KVSet,
   406  		DirEnt: structs.DirEntry{
   407  			Key:   "/test/path",
   408  			Flags: 0,
   409  			Value: []byte("test"),
   410  		},
   411  	}
   412  	buf, err := structs.Encode(structs.KVSRequestType, req)
   413  	if err != nil {
   414  		t.Fatalf("err: %v", err)
   415  	}
   416  	resp := fsm.Apply(makeLog(buf))
   417  	if resp != nil {
   418  		t.Fatalf("resp: %v", resp)
   419  	}
   420  
   421  	// Run the delete tree
   422  	req.Op = api.KVDeleteTree
   423  	req.DirEnt.Key = "/test"
   424  	buf, err = structs.Encode(structs.KVSRequestType, req)
   425  	if err != nil {
   426  		t.Fatalf("err: %v", err)
   427  	}
   428  	resp = fsm.Apply(makeLog(buf))
   429  	if resp != nil {
   430  		t.Fatalf("resp: %v", resp)
   431  	}
   432  
   433  	// Verify key is not set
   434  	_, d, err := fsm.state.KVSGet(nil, "/test/path")
   435  	if err != nil {
   436  		t.Fatalf("err: %v", err)
   437  	}
   438  	if d != nil {
   439  		t.Fatalf("key present")
   440  	}
   441  }
   442  
   443  func TestFSM_KVSDeleteCheckAndSet(t *testing.T) {
   444  	t.Parallel()
   445  	fsm, err := New(nil, os.Stderr)
   446  	if err != nil {
   447  		t.Fatalf("err: %v", err)
   448  	}
   449  
   450  	req := structs.KVSRequest{
   451  		Datacenter: "dc1",
   452  		Op:         api.KVSet,
   453  		DirEnt: structs.DirEntry{
   454  			Key:   "/test/path",
   455  			Flags: 0,
   456  			Value: []byte("test"),
   457  		},
   458  	}
   459  	buf, err := structs.Encode(structs.KVSRequestType, req)
   460  	if err != nil {
   461  		t.Fatalf("err: %v", err)
   462  	}
   463  	resp := fsm.Apply(makeLog(buf))
   464  	if resp != nil {
   465  		t.Fatalf("resp: %v", resp)
   466  	}
   467  
   468  	// Verify key is set
   469  	_, d, err := fsm.state.KVSGet(nil, "/test/path")
   470  	if err != nil {
   471  		t.Fatalf("err: %v", err)
   472  	}
   473  	if d == nil {
   474  		t.Fatalf("key missing")
   475  	}
   476  
   477  	// Run the check-and-set
   478  	req.Op = api.KVDeleteCAS
   479  	req.DirEnt.ModifyIndex = d.ModifyIndex
   480  	buf, err = structs.Encode(structs.KVSRequestType, req)
   481  	if err != nil {
   482  		t.Fatalf("err: %v", err)
   483  	}
   484  	resp = fsm.Apply(makeLog(buf))
   485  	if resp.(bool) != true {
   486  		t.Fatalf("resp: %v", resp)
   487  	}
   488  
   489  	// Verify key is gone
   490  	_, d, err = fsm.state.KVSGet(nil, "/test/path")
   491  	if err != nil {
   492  		t.Fatalf("err: %v", err)
   493  	}
   494  	if d != nil {
   495  		t.Fatalf("bad: %v", d)
   496  	}
   497  }
   498  
   499  func TestFSM_KVSCheckAndSet(t *testing.T) {
   500  	t.Parallel()
   501  	fsm, err := New(nil, os.Stderr)
   502  	if err != nil {
   503  		t.Fatalf("err: %v", err)
   504  	}
   505  
   506  	req := structs.KVSRequest{
   507  		Datacenter: "dc1",
   508  		Op:         api.KVSet,
   509  		DirEnt: structs.DirEntry{
   510  			Key:   "/test/path",
   511  			Flags: 0,
   512  			Value: []byte("test"),
   513  		},
   514  	}
   515  	buf, err := structs.Encode(structs.KVSRequestType, req)
   516  	if err != nil {
   517  		t.Fatalf("err: %v", err)
   518  	}
   519  	resp := fsm.Apply(makeLog(buf))
   520  	if resp != nil {
   521  		t.Fatalf("resp: %v", resp)
   522  	}
   523  
   524  	// Verify key is set
   525  	_, d, err := fsm.state.KVSGet(nil, "/test/path")
   526  	if err != nil {
   527  		t.Fatalf("err: %v", err)
   528  	}
   529  	if d == nil {
   530  		t.Fatalf("key missing")
   531  	}
   532  
   533  	// Run the check-and-set
   534  	req.Op = api.KVCAS
   535  	req.DirEnt.ModifyIndex = d.ModifyIndex
   536  	req.DirEnt.Value = []byte("zip")
   537  	buf, err = structs.Encode(structs.KVSRequestType, req)
   538  	if err != nil {
   539  		t.Fatalf("err: %v", err)
   540  	}
   541  	resp = fsm.Apply(makeLog(buf))
   542  	if resp.(bool) != true {
   543  		t.Fatalf("resp: %v", resp)
   544  	}
   545  
   546  	// Verify key is updated
   547  	_, d, err = fsm.state.KVSGet(nil, "/test/path")
   548  	if err != nil {
   549  		t.Fatalf("err: %v", err)
   550  	}
   551  	if string(d.Value) != "zip" {
   552  		t.Fatalf("bad: %v", d)
   553  	}
   554  }
   555  
   556  func TestFSM_KVSLock(t *testing.T) {
   557  	t.Parallel()
   558  	fsm, err := New(nil, os.Stderr)
   559  	if err != nil {
   560  		t.Fatalf("err: %v", err)
   561  	}
   562  
   563  	fsm.state.EnsureNode(1, &structs.Node{Node: "foo", Address: "127.0.0.1"})
   564  	session := &structs.Session{ID: generateUUID(), Node: "foo"}
   565  	fsm.state.SessionCreate(2, session)
   566  
   567  	req := structs.KVSRequest{
   568  		Datacenter: "dc1",
   569  		Op:         api.KVLock,
   570  		DirEnt: structs.DirEntry{
   571  			Key:     "/test/path",
   572  			Value:   []byte("test"),
   573  			Session: session.ID,
   574  		},
   575  	}
   576  	buf, err := structs.Encode(structs.KVSRequestType, req)
   577  	if err != nil {
   578  		t.Fatalf("err: %v", err)
   579  	}
   580  	resp := fsm.Apply(makeLog(buf))
   581  	if resp != true {
   582  		t.Fatalf("resp: %v", resp)
   583  	}
   584  
   585  	// Verify key is locked
   586  	_, d, err := fsm.state.KVSGet(nil, "/test/path")
   587  	if err != nil {
   588  		t.Fatalf("err: %v", err)
   589  	}
   590  	if d == nil {
   591  		t.Fatalf("missing")
   592  	}
   593  	if d.LockIndex != 1 {
   594  		t.Fatalf("bad: %v", *d)
   595  	}
   596  	if d.Session != session.ID {
   597  		t.Fatalf("bad: %v", *d)
   598  	}
   599  }
   600  
   601  func TestFSM_KVSUnlock(t *testing.T) {
   602  	t.Parallel()
   603  	fsm, err := New(nil, os.Stderr)
   604  	if err != nil {
   605  		t.Fatalf("err: %v", err)
   606  	}
   607  
   608  	fsm.state.EnsureNode(1, &structs.Node{Node: "foo", Address: "127.0.0.1"})
   609  	session := &structs.Session{ID: generateUUID(), Node: "foo"}
   610  	fsm.state.SessionCreate(2, session)
   611  
   612  	req := structs.KVSRequest{
   613  		Datacenter: "dc1",
   614  		Op:         api.KVLock,
   615  		DirEnt: structs.DirEntry{
   616  			Key:     "/test/path",
   617  			Value:   []byte("test"),
   618  			Session: session.ID,
   619  		},
   620  	}
   621  	buf, err := structs.Encode(structs.KVSRequestType, req)
   622  	if err != nil {
   623  		t.Fatalf("err: %v", err)
   624  	}
   625  	resp := fsm.Apply(makeLog(buf))
   626  	if resp != true {
   627  		t.Fatalf("resp: %v", resp)
   628  	}
   629  
   630  	req = structs.KVSRequest{
   631  		Datacenter: "dc1",
   632  		Op:         api.KVUnlock,
   633  		DirEnt: structs.DirEntry{
   634  			Key:     "/test/path",
   635  			Value:   []byte("test"),
   636  			Session: session.ID,
   637  		},
   638  	}
   639  	buf, err = structs.Encode(structs.KVSRequestType, req)
   640  	if err != nil {
   641  		t.Fatalf("err: %v", err)
   642  	}
   643  	resp = fsm.Apply(makeLog(buf))
   644  	if resp != true {
   645  		t.Fatalf("resp: %v", resp)
   646  	}
   647  
   648  	// Verify key is unlocked
   649  	_, d, err := fsm.state.KVSGet(nil, "/test/path")
   650  	if err != nil {
   651  		t.Fatalf("err: %v", err)
   652  	}
   653  	if d == nil {
   654  		t.Fatalf("missing")
   655  	}
   656  	if d.LockIndex != 1 {
   657  		t.Fatalf("bad: %v", *d)
   658  	}
   659  	if d.Session != "" {
   660  		t.Fatalf("bad: %v", *d)
   661  	}
   662  }
   663  
   664  func TestFSM_CoordinateUpdate(t *testing.T) {
   665  	t.Parallel()
   666  	fsm, err := New(nil, os.Stderr)
   667  	if err != nil {
   668  		t.Fatalf("err: %v", err)
   669  	}
   670  
   671  	// Register some nodes.
   672  	fsm.state.EnsureNode(1, &structs.Node{Node: "node1", Address: "127.0.0.1"})
   673  	fsm.state.EnsureNode(2, &structs.Node{Node: "node2", Address: "127.0.0.1"})
   674  
   675  	// Write a batch of two coordinates.
   676  	updates := structs.Coordinates{
   677  		&structs.Coordinate{
   678  			Node:  "node1",
   679  			Coord: generateRandomCoordinate(),
   680  		},
   681  		&structs.Coordinate{
   682  			Node:  "node2",
   683  			Coord: generateRandomCoordinate(),
   684  		},
   685  	}
   686  	buf, err := structs.Encode(structs.CoordinateBatchUpdateType, updates)
   687  	if err != nil {
   688  		t.Fatalf("err: %v", err)
   689  	}
   690  	resp := fsm.Apply(makeLog(buf))
   691  	if resp != nil {
   692  		t.Fatalf("resp: %v", resp)
   693  	}
   694  
   695  	// Read back the two coordinates to make sure they got updated.
   696  	_, coords, err := fsm.state.Coordinates(nil)
   697  	if err != nil {
   698  		t.Fatalf("err: %s", err)
   699  	}
   700  	if !reflect.DeepEqual(coords, updates) {
   701  		t.Fatalf("bad: %#v", coords)
   702  	}
   703  }
   704  
   705  func TestFSM_SessionCreate_Destroy(t *testing.T) {
   706  	t.Parallel()
   707  	fsm, err := New(nil, os.Stderr)
   708  	if err != nil {
   709  		t.Fatalf("err: %v", err)
   710  	}
   711  
   712  	fsm.state.EnsureNode(1, &structs.Node{Node: "foo", Address: "127.0.0.1"})
   713  	fsm.state.EnsureCheck(2, &structs.HealthCheck{
   714  		Node:    "foo",
   715  		CheckID: "web",
   716  		Status:  api.HealthPassing,
   717  	})
   718  
   719  	// Create a new session
   720  	req := structs.SessionRequest{
   721  		Datacenter: "dc1",
   722  		Op:         structs.SessionCreate,
   723  		Session: structs.Session{
   724  			ID:     generateUUID(),
   725  			Node:   "foo",
   726  			Checks: []types.CheckID{"web"},
   727  		},
   728  	}
   729  	buf, err := structs.Encode(structs.SessionRequestType, req)
   730  	if err != nil {
   731  		t.Fatalf("err: %v", err)
   732  	}
   733  	resp := fsm.Apply(makeLog(buf))
   734  	if err, ok := resp.(error); ok {
   735  		t.Fatalf("resp: %v", err)
   736  	}
   737  
   738  	// Get the session
   739  	id := resp.(string)
   740  	_, session, err := fsm.state.SessionGet(nil, id)
   741  	if err != nil {
   742  		t.Fatalf("err: %v", err)
   743  	}
   744  	if session == nil {
   745  		t.Fatalf("missing")
   746  	}
   747  
   748  	// Verify the session
   749  	if session.ID != id {
   750  		t.Fatalf("bad: %v", *session)
   751  	}
   752  	if session.Node != "foo" {
   753  		t.Fatalf("bad: %v", *session)
   754  	}
   755  	if session.Checks[0] != "web" {
   756  		t.Fatalf("bad: %v", *session)
   757  	}
   758  
   759  	// Try to destroy
   760  	destroy := structs.SessionRequest{
   761  		Datacenter: "dc1",
   762  		Op:         structs.SessionDestroy,
   763  		Session: structs.Session{
   764  			ID: id,
   765  		},
   766  	}
   767  	buf, err = structs.Encode(structs.SessionRequestType, destroy)
   768  	if err != nil {
   769  		t.Fatalf("err: %v", err)
   770  	}
   771  	resp = fsm.Apply(makeLog(buf))
   772  	if resp != nil {
   773  		t.Fatalf("resp: %v", resp)
   774  	}
   775  
   776  	_, session, err = fsm.state.SessionGet(nil, id)
   777  	if err != nil {
   778  		t.Fatalf("err: %v", err)
   779  	}
   780  	if session != nil {
   781  		t.Fatalf("should be destroyed")
   782  	}
   783  }
   784  
   785  func TestFSM_ACL_CRUD(t *testing.T) {
   786  	t.Parallel()
   787  	fsm, err := New(nil, os.Stderr)
   788  	if err != nil {
   789  		t.Fatalf("err: %v", err)
   790  	}
   791  
   792  	// Create a new ACL.
   793  	req := structs.ACLRequest{
   794  		Datacenter: "dc1",
   795  		Op:         structs.ACLSet,
   796  		ACL: structs.ACL{
   797  			ID:   generateUUID(),
   798  			Name: "User token",
   799  			Type: structs.ACLTokenTypeClient,
   800  		},
   801  	}
   802  	buf, err := structs.Encode(structs.ACLRequestType, req)
   803  	if err != nil {
   804  		t.Fatalf("err: %v", err)
   805  	}
   806  	resp := fsm.Apply(makeLog(buf))
   807  	if err, ok := resp.(error); ok {
   808  		t.Fatalf("resp: %v", err)
   809  	}
   810  
   811  	// Get the ACL.
   812  	id := resp.(string)
   813  	_, acl, err := fsm.state.ACLTokenGetBySecret(nil, id)
   814  	if err != nil {
   815  		t.Fatalf("err: %v", err)
   816  	}
   817  	if acl == nil {
   818  		t.Fatalf("missing")
   819  	}
   820  
   821  	// Verify the ACL.
   822  	if acl.SecretID != id {
   823  		t.Fatalf("bad: %v", *acl)
   824  	}
   825  	if acl.Description != "User token" {
   826  		t.Fatalf("bad: %v", *acl)
   827  	}
   828  	if acl.Type != structs.ACLTokenTypeClient {
   829  		t.Fatalf("bad: %v", *acl)
   830  	}
   831  
   832  	// Try to destroy.
   833  	destroy := structs.ACLRequest{
   834  		Datacenter: "dc1",
   835  		Op:         structs.ACLDelete,
   836  		ACL: structs.ACL{
   837  			ID: id,
   838  		},
   839  	}
   840  	buf, err = structs.Encode(structs.ACLRequestType, destroy)
   841  	if err != nil {
   842  		t.Fatalf("err: %v", err)
   843  	}
   844  	resp = fsm.Apply(makeLog(buf))
   845  	if resp != nil {
   846  		t.Fatalf("resp: %v", resp)
   847  	}
   848  
   849  	_, acl, err = fsm.state.ACLTokenGetBySecret(nil, id)
   850  	if err != nil {
   851  		t.Fatalf("err: %v", err)
   852  	}
   853  	if acl != nil {
   854  		t.Fatalf("should be destroyed")
   855  	}
   856  
   857  	// Initialize bootstrap (should work since we haven't made a management
   858  	// token).
   859  	init := structs.ACLRequest{
   860  		Datacenter: "dc1",
   861  		Op:         structs.ACLBootstrapInit,
   862  	}
   863  	buf, err = structs.Encode(structs.ACLRequestType, init)
   864  	if err != nil {
   865  		t.Fatalf("err: %v", err)
   866  	}
   867  	resp = fsm.Apply(makeLog(buf))
   868  	if enabled, ok := resp.(bool); !ok || !enabled {
   869  		t.Fatalf("resp: %v", resp)
   870  	}
   871  	canBootstrap, _, err := fsm.state.CanBootstrapACLToken()
   872  	if err != nil {
   873  		t.Fatalf("err: %v", err)
   874  	}
   875  	if !canBootstrap {
   876  		t.Fatalf("bad: shouldn't be able to bootstrap")
   877  	}
   878  
   879  	// Do a bootstrap.
   880  	bootstrap := structs.ACLRequest{
   881  		Datacenter: "dc1",
   882  		Op:         structs.ACLBootstrapNow,
   883  		ACL: structs.ACL{
   884  			ID:   generateUUID(),
   885  			Name: "Bootstrap Token",
   886  			Type: structs.ACLTokenTypeManagement,
   887  		},
   888  	}
   889  	buf, err = structs.Encode(structs.ACLRequestType, bootstrap)
   890  	if err != nil {
   891  		t.Fatalf("err: %v", err)
   892  	}
   893  	resp = fsm.Apply(makeLog(buf))
   894  	respACL, ok := resp.(*structs.ACL)
   895  	if !ok {
   896  		t.Fatalf("resp: %v", resp)
   897  	}
   898  	bootstrap.ACL.CreateIndex = respACL.CreateIndex
   899  	bootstrap.ACL.ModifyIndex = respACL.ModifyIndex
   900  	verify.Values(t, "", respACL, &bootstrap.ACL)
   901  }
   902  
   903  func TestFSM_PreparedQuery_CRUD(t *testing.T) {
   904  	t.Parallel()
   905  	fsm, err := New(nil, os.Stderr)
   906  	if err != nil {
   907  		t.Fatalf("err: %v", err)
   908  	}
   909  
   910  	// Register a service to query on.
   911  	fsm.state.EnsureNode(1, &structs.Node{Node: "foo", Address: "127.0.0.1"})
   912  	fsm.state.EnsureService(2, "foo", &structs.NodeService{ID: "web", Service: "web", Tags: nil, Address: "127.0.0.1", Port: 80})
   913  
   914  	// Create a new query.
   915  	query := structs.PreparedQueryRequest{
   916  		Op: structs.PreparedQueryCreate,
   917  		Query: &structs.PreparedQuery{
   918  			ID: generateUUID(),
   919  			Service: structs.ServiceQuery{
   920  				Service: "web",
   921  			},
   922  		},
   923  	}
   924  	{
   925  		buf, err := structs.Encode(structs.PreparedQueryRequestType, query)
   926  		if err != nil {
   927  			t.Fatalf("err: %v", err)
   928  		}
   929  		resp := fsm.Apply(makeLog(buf))
   930  		if resp != nil {
   931  			t.Fatalf("resp: %v", resp)
   932  		}
   933  	}
   934  
   935  	// Verify it's in the state store.
   936  	{
   937  		_, actual, err := fsm.state.PreparedQueryGet(nil, query.Query.ID)
   938  		if err != nil {
   939  			t.Fatalf("err: %s", err)
   940  		}
   941  
   942  		actual.CreateIndex, actual.ModifyIndex = 0, 0
   943  		if !reflect.DeepEqual(actual, query.Query) {
   944  			t.Fatalf("bad: %v", actual)
   945  		}
   946  	}
   947  
   948  	// Make an update to the query.
   949  	query.Op = structs.PreparedQueryUpdate
   950  	query.Query.Name = "my-query"
   951  	{
   952  		buf, err := structs.Encode(structs.PreparedQueryRequestType, query)
   953  		if err != nil {
   954  			t.Fatalf("err: %v", err)
   955  		}
   956  		resp := fsm.Apply(makeLog(buf))
   957  		if resp != nil {
   958  			t.Fatalf("resp: %v", resp)
   959  		}
   960  	}
   961  
   962  	// Verify the update.
   963  	{
   964  		_, actual, err := fsm.state.PreparedQueryGet(nil, query.Query.ID)
   965  		if err != nil {
   966  			t.Fatalf("err: %s", err)
   967  		}
   968  
   969  		actual.CreateIndex, actual.ModifyIndex = 0, 0
   970  		if !reflect.DeepEqual(actual, query.Query) {
   971  			t.Fatalf("bad: %v", actual)
   972  		}
   973  	}
   974  
   975  	// Delete the query.
   976  	query.Op = structs.PreparedQueryDelete
   977  	{
   978  		buf, err := structs.Encode(structs.PreparedQueryRequestType, query)
   979  		if err != nil {
   980  			t.Fatalf("err: %v", err)
   981  		}
   982  		resp := fsm.Apply(makeLog(buf))
   983  		if resp != nil {
   984  			t.Fatalf("resp: %v", resp)
   985  		}
   986  	}
   987  
   988  	// Make sure it's gone.
   989  	{
   990  		_, actual, err := fsm.state.PreparedQueryGet(nil, query.Query.ID)
   991  		if err != nil {
   992  			t.Fatalf("err: %s", err)
   993  		}
   994  
   995  		if actual != nil {
   996  			t.Fatalf("bad: %v", actual)
   997  		}
   998  	}
   999  }
  1000  
  1001  func TestFSM_TombstoneReap(t *testing.T) {
  1002  	t.Parallel()
  1003  	fsm, err := New(nil, os.Stderr)
  1004  	if err != nil {
  1005  		t.Fatalf("err: %v", err)
  1006  	}
  1007  
  1008  	// Create some tombstones
  1009  	fsm.state.KVSSet(11, &structs.DirEntry{
  1010  		Key:   "/remove",
  1011  		Value: []byte("foo"),
  1012  	})
  1013  	fsm.state.KVSDelete(12, "/remove")
  1014  	idx, _, err := fsm.state.KVSList(nil, "/remove")
  1015  	if err != nil {
  1016  		t.Fatalf("err: %s", err)
  1017  	}
  1018  	if idx != 12 {
  1019  		t.Fatalf("bad index: %d", idx)
  1020  	}
  1021  
  1022  	// Create a new reap request
  1023  	req := structs.TombstoneRequest{
  1024  		Datacenter: "dc1",
  1025  		Op:         structs.TombstoneReap,
  1026  		ReapIndex:  12,
  1027  	}
  1028  	buf, err := structs.Encode(structs.TombstoneRequestType, req)
  1029  	if err != nil {
  1030  		t.Fatalf("err: %v", err)
  1031  	}
  1032  	resp := fsm.Apply(makeLog(buf))
  1033  	if err, ok := resp.(error); ok {
  1034  		t.Fatalf("resp: %v", err)
  1035  	}
  1036  
  1037  	// Verify the tombstones are gone
  1038  	snap := fsm.state.Snapshot()
  1039  	defer snap.Close()
  1040  	stones, err := snap.Tombstones()
  1041  	if err != nil {
  1042  		t.Fatalf("err: %s", err)
  1043  	}
  1044  	if stones.Next() != nil {
  1045  		t.Fatalf("unexpected extra tombstones")
  1046  	}
  1047  }
  1048  
  1049  func TestFSM_Txn(t *testing.T) {
  1050  	t.Parallel()
  1051  	fsm, err := New(nil, os.Stderr)
  1052  	if err != nil {
  1053  		t.Fatalf("err: %v", err)
  1054  	}
  1055  
  1056  	// Set a key using a transaction.
  1057  	req := structs.TxnRequest{
  1058  		Datacenter: "dc1",
  1059  		Ops: structs.TxnOps{
  1060  			&structs.TxnOp{
  1061  				KV: &structs.TxnKVOp{
  1062  					Verb: api.KVSet,
  1063  					DirEnt: structs.DirEntry{
  1064  						Key:   "/test/path",
  1065  						Flags: 0,
  1066  						Value: []byte("test"),
  1067  					},
  1068  				},
  1069  			},
  1070  		},
  1071  	}
  1072  	buf, err := structs.Encode(structs.TxnRequestType, req)
  1073  	if err != nil {
  1074  		t.Fatalf("err: %v", err)
  1075  	}
  1076  	resp := fsm.Apply(makeLog(buf))
  1077  	if _, ok := resp.(structs.TxnResponse); !ok {
  1078  		t.Fatalf("bad response type: %T", resp)
  1079  	}
  1080  
  1081  	// Verify key is set directly in the state store.
  1082  	_, d, err := fsm.state.KVSGet(nil, "/test/path")
  1083  	if err != nil {
  1084  		t.Fatalf("err: %v", err)
  1085  	}
  1086  	if d == nil {
  1087  		t.Fatalf("missing")
  1088  	}
  1089  }
  1090  
  1091  func TestFSM_Autopilot(t *testing.T) {
  1092  	t.Parallel()
  1093  	fsm, err := New(nil, os.Stderr)
  1094  	if err != nil {
  1095  		t.Fatalf("err: %v", err)
  1096  	}
  1097  
  1098  	// Set the autopilot config using a request.
  1099  	req := structs.AutopilotSetConfigRequest{
  1100  		Datacenter: "dc1",
  1101  		Config: autopilot.Config{
  1102  			CleanupDeadServers:   true,
  1103  			LastContactThreshold: 10 * time.Second,
  1104  			MaxTrailingLogs:      300,
  1105  		},
  1106  	}
  1107  	buf, err := structs.Encode(structs.AutopilotRequestType, req)
  1108  	if err != nil {
  1109  		t.Fatalf("err: %v", err)
  1110  	}
  1111  	resp := fsm.Apply(makeLog(buf))
  1112  	if _, ok := resp.(error); ok {
  1113  		t.Fatalf("bad: %v", resp)
  1114  	}
  1115  
  1116  	// Verify key is set directly in the state store.
  1117  	_, config, err := fsm.state.AutopilotConfig()
  1118  	if err != nil {
  1119  		t.Fatalf("err: %v", err)
  1120  	}
  1121  	if config.CleanupDeadServers != req.Config.CleanupDeadServers {
  1122  		t.Fatalf("bad: %v", config.CleanupDeadServers)
  1123  	}
  1124  	if config.LastContactThreshold != req.Config.LastContactThreshold {
  1125  		t.Fatalf("bad: %v", config.LastContactThreshold)
  1126  	}
  1127  	if config.MaxTrailingLogs != req.Config.MaxTrailingLogs {
  1128  		t.Fatalf("bad: %v", config.MaxTrailingLogs)
  1129  	}
  1130  
  1131  	// Now use CAS and provide an old index
  1132  	req.CAS = true
  1133  	req.Config.CleanupDeadServers = false
  1134  	req.Config.ModifyIndex = config.ModifyIndex - 1
  1135  	buf, err = structs.Encode(structs.AutopilotRequestType, req)
  1136  	if err != nil {
  1137  		t.Fatalf("err: %v", err)
  1138  	}
  1139  	resp = fsm.Apply(makeLog(buf))
  1140  	if _, ok := resp.(error); ok {
  1141  		t.Fatalf("bad: %v", resp)
  1142  	}
  1143  
  1144  	_, config, err = fsm.state.AutopilotConfig()
  1145  	if err != nil {
  1146  		t.Fatalf("err: %v", err)
  1147  	}
  1148  	if !config.CleanupDeadServers {
  1149  		t.Fatalf("bad: %v", config.CleanupDeadServers)
  1150  	}
  1151  }
  1152  
  1153  func TestFSM_Intention_CRUD(t *testing.T) {
  1154  	t.Parallel()
  1155  
  1156  	assert := assert.New(t)
  1157  	fsm, err := New(nil, os.Stderr)
  1158  	assert.Nil(err)
  1159  
  1160  	// Create a new intention.
  1161  	ixn := structs.IntentionRequest{
  1162  		Datacenter: "dc1",
  1163  		Op:         structs.IntentionOpCreate,
  1164  		Intention:  structs.TestIntention(t),
  1165  	}
  1166  	ixn.Intention.ID = generateUUID()
  1167  	ixn.Intention.UpdatePrecedence()
  1168  
  1169  	{
  1170  		buf, err := structs.Encode(structs.IntentionRequestType, ixn)
  1171  		assert.Nil(err)
  1172  		assert.Nil(fsm.Apply(makeLog(buf)))
  1173  	}
  1174  
  1175  	// Verify it's in the state store.
  1176  	{
  1177  		_, actual, err := fsm.state.IntentionGet(nil, ixn.Intention.ID)
  1178  		assert.Nil(err)
  1179  
  1180  		actual.CreateIndex, actual.ModifyIndex = 0, 0
  1181  		actual.CreatedAt = ixn.Intention.CreatedAt
  1182  		actual.UpdatedAt = ixn.Intention.UpdatedAt
  1183  		assert.Equal(ixn.Intention, actual)
  1184  	}
  1185  
  1186  	// Make an update
  1187  	ixn.Op = structs.IntentionOpUpdate
  1188  	ixn.Intention.SourceName = "api"
  1189  	{
  1190  		buf, err := structs.Encode(structs.IntentionRequestType, ixn)
  1191  		assert.Nil(err)
  1192  		assert.Nil(fsm.Apply(makeLog(buf)))
  1193  	}
  1194  
  1195  	// Verify the update.
  1196  	{
  1197  		_, actual, err := fsm.state.IntentionGet(nil, ixn.Intention.ID)
  1198  		assert.Nil(err)
  1199  
  1200  		actual.CreateIndex, actual.ModifyIndex = 0, 0
  1201  		actual.CreatedAt = ixn.Intention.CreatedAt
  1202  		actual.UpdatedAt = ixn.Intention.UpdatedAt
  1203  		assert.Equal(ixn.Intention, actual)
  1204  	}
  1205  
  1206  	// Delete
  1207  	ixn.Op = structs.IntentionOpDelete
  1208  	{
  1209  		buf, err := structs.Encode(structs.IntentionRequestType, ixn)
  1210  		assert.Nil(err)
  1211  		assert.Nil(fsm.Apply(makeLog(buf)))
  1212  	}
  1213  
  1214  	// Make sure it's gone.
  1215  	{
  1216  		_, actual, err := fsm.state.IntentionGet(nil, ixn.Intention.ID)
  1217  		assert.Nil(err)
  1218  		assert.Nil(actual)
  1219  	}
  1220  }
  1221  
  1222  func TestFSM_CAConfig(t *testing.T) {
  1223  	t.Parallel()
  1224  
  1225  	assert := assert.New(t)
  1226  	fsm, err := New(nil, os.Stderr)
  1227  	assert.Nil(err)
  1228  
  1229  	// Set the autopilot config using a request.
  1230  	req := structs.CARequest{
  1231  		Op: structs.CAOpSetConfig,
  1232  		Config: &structs.CAConfiguration{
  1233  			Provider: "consul",
  1234  			Config: map[string]interface{}{
  1235  				"PrivateKey":     "asdf",
  1236  				"RootCert":       "qwer",
  1237  				"RotationPeriod": 90 * 24 * time.Hour,
  1238  			},
  1239  		},
  1240  	}
  1241  	buf, err := structs.Encode(structs.ConnectCARequestType, req)
  1242  	assert.Nil(err)
  1243  	resp := fsm.Apply(makeLog(buf))
  1244  	if _, ok := resp.(error); ok {
  1245  		t.Fatalf("bad: %v", resp)
  1246  	}
  1247  
  1248  	// Verify key is set directly in the state store.
  1249  	_, config, err := fsm.state.CAConfig()
  1250  	if err != nil {
  1251  		t.Fatalf("err: %v", err)
  1252  	}
  1253  	var conf *structs.ConsulCAProviderConfig
  1254  	if err := mapstructure.WeakDecode(config.Config, &conf); err != nil {
  1255  		t.Fatalf("error decoding config: %s, %v", err, config.Config)
  1256  	}
  1257  	if got, want := config.Provider, req.Config.Provider; got != want {
  1258  		t.Fatalf("got %v, want %v", got, want)
  1259  	}
  1260  	if got, want := conf.PrivateKey, "asdf"; got != want {
  1261  		t.Fatalf("got %v, want %v", got, want)
  1262  	}
  1263  	if got, want := conf.RootCert, "qwer"; got != want {
  1264  		t.Fatalf("got %v, want %v", got, want)
  1265  	}
  1266  	if got, want := conf.RotationPeriod, 90*24*time.Hour; got != want {
  1267  		t.Fatalf("got %v, want %v", got, want)
  1268  	}
  1269  
  1270  	// Now use CAS and provide an old index
  1271  	req.Config.Provider = "static"
  1272  	req.Config.ModifyIndex = config.ModifyIndex - 1
  1273  	buf, err = structs.Encode(structs.ConnectCARequestType, req)
  1274  	if err != nil {
  1275  		t.Fatalf("err: %v", err)
  1276  	}
  1277  	resp = fsm.Apply(makeLog(buf))
  1278  	if _, ok := resp.(error); ok {
  1279  		t.Fatalf("bad: %v", resp)
  1280  	}
  1281  
  1282  	_, config, err = fsm.state.CAConfig()
  1283  	assert.Nil(err)
  1284  	if config.Provider != "static" {
  1285  		t.Fatalf("bad: %v", config.Provider)
  1286  	}
  1287  }
  1288  
  1289  func TestFSM_CARoots(t *testing.T) {
  1290  	t.Parallel()
  1291  
  1292  	assert := assert.New(t)
  1293  	fsm, err := New(nil, os.Stderr)
  1294  	assert.Nil(err)
  1295  
  1296  	// Roots
  1297  	ca1 := connect.TestCA(t, nil)
  1298  	ca2 := connect.TestCA(t, nil)
  1299  	ca2.Active = false
  1300  
  1301  	// Create a new request.
  1302  	req := structs.CARequest{
  1303  		Op:    structs.CAOpSetRoots,
  1304  		Roots: []*structs.CARoot{ca1, ca2},
  1305  	}
  1306  
  1307  	{
  1308  		buf, err := structs.Encode(structs.ConnectCARequestType, req)
  1309  		assert.Nil(err)
  1310  		assert.True(fsm.Apply(makeLog(buf)).(bool))
  1311  	}
  1312  
  1313  	// Verify it's in the state store.
  1314  	{
  1315  		_, roots, err := fsm.state.CARoots(nil)
  1316  		assert.Nil(err)
  1317  		assert.Len(roots, 2)
  1318  	}
  1319  }
  1320  
  1321  func TestFSM_CABuiltinProvider(t *testing.T) {
  1322  	t.Parallel()
  1323  
  1324  	assert := assert.New(t)
  1325  	fsm, err := New(nil, os.Stderr)
  1326  	assert.Nil(err)
  1327  
  1328  	// Provider state.
  1329  	expected := &structs.CAConsulProviderState{
  1330  		ID:         "foo",
  1331  		PrivateKey: "a",
  1332  		RootCert:   "b",
  1333  		RaftIndex: structs.RaftIndex{
  1334  			CreateIndex: 1,
  1335  			ModifyIndex: 1,
  1336  		},
  1337  	}
  1338  
  1339  	// Create a new request.
  1340  	req := structs.CARequest{
  1341  		Op:            structs.CAOpSetProviderState,
  1342  		ProviderState: expected,
  1343  	}
  1344  
  1345  	{
  1346  		buf, err := structs.Encode(structs.ConnectCARequestType, req)
  1347  		assert.Nil(err)
  1348  		assert.True(fsm.Apply(makeLog(buf)).(bool))
  1349  	}
  1350  
  1351  	// Verify it's in the state store.
  1352  	{
  1353  		_, state, err := fsm.state.CAProviderState("foo")
  1354  		assert.Nil(err)
  1355  		assert.Equal(expected, state)
  1356  	}
  1357  }