github.com/clly/consul@v1.4.5/agent/consul/state/session_test.go (about)

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/hashicorp/consul/agent/structs"
    11  	"github.com/hashicorp/consul/api"
    12  	"github.com/hashicorp/consul/types"
    13  	"github.com/hashicorp/go-memdb"
    14  )
    15  
    16  func TestStateStore_SessionCreate_SessionGet(t *testing.T) {
    17  	s := testStateStore(t)
    18  
    19  	// SessionGet returns nil if the session doesn't exist
    20  	ws := memdb.NewWatchSet()
    21  	idx, session, err := s.SessionGet(ws, testUUID())
    22  	if session != nil || err != nil {
    23  		t.Fatalf("expected (nil, nil), got: (%#v, %#v)", session, err)
    24  	}
    25  	if idx != 0 {
    26  		t.Fatalf("bad index: %d", idx)
    27  	}
    28  
    29  	// Registering without a session ID is disallowed
    30  	err = s.SessionCreate(1, &structs.Session{})
    31  	if err != ErrMissingSessionID {
    32  		t.Fatalf("expected %#v, got: %#v", ErrMissingSessionID, err)
    33  	}
    34  
    35  	// Invalid session behavior throws error
    36  	sess := &structs.Session{
    37  		ID:       testUUID(),
    38  		Behavior: "nope",
    39  	}
    40  	err = s.SessionCreate(1, sess)
    41  	if err == nil || !strings.Contains(err.Error(), "session behavior") {
    42  		t.Fatalf("expected session behavior error, got: %#v", err)
    43  	}
    44  
    45  	// Registering with an unknown node is disallowed
    46  	sess = &structs.Session{ID: testUUID()}
    47  	if err := s.SessionCreate(1, sess); err != ErrMissingNode {
    48  		t.Fatalf("expected %#v, got: %#v", ErrMissingNode, err)
    49  	}
    50  
    51  	// None of the errored operations modified the index
    52  	if idx := s.maxIndex("sessions"); idx != 0 {
    53  		t.Fatalf("bad index: %d", idx)
    54  	}
    55  	if watchFired(ws) {
    56  		t.Fatalf("bad")
    57  	}
    58  
    59  	// Valid session is able to register
    60  	testRegisterNode(t, s, 1, "node1")
    61  	sess = &structs.Session{
    62  		ID:   testUUID(),
    63  		Node: "node1",
    64  	}
    65  	if err := s.SessionCreate(2, sess); err != nil {
    66  		t.Fatalf("err: %s", err)
    67  	}
    68  	if idx := s.maxIndex("sessions"); idx != 2 {
    69  		t.Fatalf("bad index: %s", err)
    70  	}
    71  	if !watchFired(ws) {
    72  		t.Fatalf("bad")
    73  	}
    74  
    75  	// Retrieve the session again
    76  	ws = memdb.NewWatchSet()
    77  	idx, session, err = s.SessionGet(ws, sess.ID)
    78  	if err != nil {
    79  		t.Fatalf("err: %s", err)
    80  	}
    81  	if idx != 2 {
    82  		t.Fatalf("bad index: %d", idx)
    83  	}
    84  
    85  	// Ensure the session looks correct and was assigned the
    86  	// proper default value for session behavior.
    87  	expect := &structs.Session{
    88  		ID:       sess.ID,
    89  		Behavior: structs.SessionKeysRelease,
    90  		Node:     "node1",
    91  		RaftIndex: structs.RaftIndex{
    92  			CreateIndex: 2,
    93  			ModifyIndex: 2,
    94  		},
    95  	}
    96  	if !reflect.DeepEqual(expect, session) {
    97  		t.Fatalf("bad session: %#v", session)
    98  	}
    99  
   100  	// Registering with a non-existent check is disallowed
   101  	sess = &structs.Session{
   102  		ID:     testUUID(),
   103  		Node:   "node1",
   104  		Checks: []types.CheckID{"check1"},
   105  	}
   106  	err = s.SessionCreate(3, sess)
   107  	if err == nil || !strings.Contains(err.Error(), "Missing check") {
   108  		t.Fatalf("expected missing check error, got: %#v", err)
   109  	}
   110  
   111  	// Registering with a critical check is disallowed
   112  	testRegisterCheck(t, s, 3, "node1", "", "check1", api.HealthCritical)
   113  	err = s.SessionCreate(4, sess)
   114  	if err == nil || !strings.Contains(err.Error(), api.HealthCritical) {
   115  		t.Fatalf("expected critical state error, got: %#v", err)
   116  	}
   117  	if watchFired(ws) {
   118  		t.Fatalf("bad")
   119  	}
   120  
   121  	// Registering with a healthy check succeeds (doesn't hit the watch since
   122  	// we are looking at the old session).
   123  	testRegisterCheck(t, s, 4, "node1", "", "check1", api.HealthPassing)
   124  	if err := s.SessionCreate(5, sess); err != nil {
   125  		t.Fatalf("err: %s", err)
   126  	}
   127  	if watchFired(ws) {
   128  		t.Fatalf("bad")
   129  	}
   130  
   131  	// Register a session against two checks.
   132  	testRegisterCheck(t, s, 5, "node1", "", "check2", api.HealthPassing)
   133  	sess2 := &structs.Session{
   134  		ID:     testUUID(),
   135  		Node:   "node1",
   136  		Checks: []types.CheckID{"check1", "check2"},
   137  	}
   138  	if err := s.SessionCreate(6, sess2); err != nil {
   139  		t.Fatalf("err: %s", err)
   140  	}
   141  
   142  	tx := s.db.Txn(false)
   143  	defer tx.Abort()
   144  
   145  	// Check mappings were inserted
   146  	{
   147  		check, err := tx.First("session_checks", "session", sess.ID)
   148  		if err != nil {
   149  			t.Fatalf("err: %s", err)
   150  		}
   151  		if check == nil {
   152  			t.Fatalf("missing session check")
   153  		}
   154  		expectCheck := &sessionCheck{
   155  			Node:    "node1",
   156  			CheckID: "check1",
   157  			Session: sess.ID,
   158  		}
   159  		if actual := check.(*sessionCheck); !reflect.DeepEqual(actual, expectCheck) {
   160  			t.Fatalf("expected %#v, got: %#v", expectCheck, actual)
   161  		}
   162  	}
   163  	checks, err := tx.Get("session_checks", "session", sess2.ID)
   164  	if err != nil {
   165  		t.Fatalf("err: %s", err)
   166  	}
   167  	for i, check := 0, checks.Next(); check != nil; i, check = i+1, checks.Next() {
   168  		expectCheck := &sessionCheck{
   169  			Node:    "node1",
   170  			CheckID: types.CheckID(fmt.Sprintf("check%d", i+1)),
   171  			Session: sess2.ID,
   172  		}
   173  		if actual := check.(*sessionCheck); !reflect.DeepEqual(actual, expectCheck) {
   174  			t.Fatalf("expected %#v, got: %#v", expectCheck, actual)
   175  		}
   176  	}
   177  
   178  	// Pulling a nonexistent session gives the table index.
   179  	idx, session, err = s.SessionGet(nil, testUUID())
   180  	if err != nil {
   181  		t.Fatalf("err: %s", err)
   182  	}
   183  	if session != nil {
   184  		t.Fatalf("expected not to get a session: %v", session)
   185  	}
   186  	if idx != 6 {
   187  		t.Fatalf("bad index: %d", idx)
   188  	}
   189  }
   190  
   191  func TegstStateStore_SessionList(t *testing.T) {
   192  	s := testStateStore(t)
   193  
   194  	// Listing when no sessions exist returns nil
   195  	ws := memdb.NewWatchSet()
   196  	idx, res, err := s.SessionList(ws)
   197  	if idx != 0 || res != nil || err != nil {
   198  		t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, res, err)
   199  	}
   200  
   201  	// Register some nodes
   202  	testRegisterNode(t, s, 1, "node1")
   203  	testRegisterNode(t, s, 2, "node2")
   204  	testRegisterNode(t, s, 3, "node3")
   205  
   206  	// Create some sessions in the state store
   207  	sessions := structs.Sessions{
   208  		&structs.Session{
   209  			ID:       testUUID(),
   210  			Node:     "node1",
   211  			Behavior: structs.SessionKeysDelete,
   212  		},
   213  		&structs.Session{
   214  			ID:       testUUID(),
   215  			Node:     "node2",
   216  			Behavior: structs.SessionKeysRelease,
   217  		},
   218  		&structs.Session{
   219  			ID:       testUUID(),
   220  			Node:     "node3",
   221  			Behavior: structs.SessionKeysDelete,
   222  		},
   223  	}
   224  	for i, session := range sessions {
   225  		if err := s.SessionCreate(uint64(4+i), session); err != nil {
   226  			t.Fatalf("err: %s", err)
   227  		}
   228  	}
   229  	if !watchFired(ws) {
   230  		t.Fatalf("bad")
   231  	}
   232  
   233  	// List out all of the sessions
   234  	idx, sessionList, err := s.SessionList(nil)
   235  	if err != nil {
   236  		t.Fatalf("err: %s", err)
   237  	}
   238  	if idx != 6 {
   239  		t.Fatalf("bad index: %d", idx)
   240  	}
   241  	if !reflect.DeepEqual(sessionList, sessions) {
   242  		t.Fatalf("bad: %#v", sessions)
   243  	}
   244  }
   245  
   246  func TestStateStore_NodeSessions(t *testing.T) {
   247  	s := testStateStore(t)
   248  
   249  	// Listing sessions with no results returns nil
   250  	ws := memdb.NewWatchSet()
   251  	idx, res, err := s.NodeSessions(ws, "node1")
   252  	if idx != 0 || res != nil || err != nil {
   253  		t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, res, err)
   254  	}
   255  
   256  	// Create the nodes
   257  	testRegisterNode(t, s, 1, "node1")
   258  	testRegisterNode(t, s, 2, "node2")
   259  
   260  	// Register some sessions with the nodes
   261  	sessions1 := structs.Sessions{
   262  		&structs.Session{
   263  			ID:   testUUID(),
   264  			Node: "node1",
   265  		},
   266  		&structs.Session{
   267  			ID:   testUUID(),
   268  			Node: "node1",
   269  		},
   270  	}
   271  	sessions2 := []*structs.Session{
   272  		&structs.Session{
   273  			ID:   testUUID(),
   274  			Node: "node2",
   275  		},
   276  		&structs.Session{
   277  			ID:   testUUID(),
   278  			Node: "node2",
   279  		},
   280  	}
   281  	for i, sess := range append(sessions1, sessions2...) {
   282  		if err := s.SessionCreate(uint64(3+i), sess); err != nil {
   283  			t.Fatalf("err: %s", err)
   284  		}
   285  	}
   286  	if !watchFired(ws) {
   287  		t.Fatalf("bad")
   288  	}
   289  
   290  	// Query all of the sessions associated with a specific
   291  	// node in the state store.
   292  	ws1 := memdb.NewWatchSet()
   293  	idx, res, err = s.NodeSessions(ws1, "node1")
   294  	if err != nil {
   295  		t.Fatalf("err: %s", err)
   296  	}
   297  	if len(res) != len(sessions1) {
   298  		t.Fatalf("bad: %#v", res)
   299  	}
   300  	if idx != 6 {
   301  		t.Fatalf("bad index: %d", idx)
   302  	}
   303  
   304  	ws2 := memdb.NewWatchSet()
   305  	idx, res, err = s.NodeSessions(ws2, "node2")
   306  	if err != nil {
   307  		t.Fatalf("err: %s", err)
   308  	}
   309  	if len(res) != len(sessions2) {
   310  		t.Fatalf("bad: %#v", res)
   311  	}
   312  	if idx != 6 {
   313  		t.Fatalf("bad index: %d", idx)
   314  	}
   315  
   316  	// Destroying a session on node1 should not affect node2's watch.
   317  	if err := s.SessionDestroy(100, sessions1[0].ID); err != nil {
   318  		t.Fatalf("err: %s", err)
   319  	}
   320  	if !watchFired(ws1) {
   321  		t.Fatalf("bad")
   322  	}
   323  	if watchFired(ws2) {
   324  		t.Fatalf("bad")
   325  	}
   326  }
   327  
   328  func TestStateStore_SessionDestroy(t *testing.T) {
   329  	s := testStateStore(t)
   330  
   331  	// Session destroy is idempotent and returns no error
   332  	// if the session doesn't exist.
   333  	if err := s.SessionDestroy(1, testUUID()); err != nil {
   334  		t.Fatalf("err: %s", err)
   335  	}
   336  
   337  	// Ensure the index was not updated if nothing was destroyed.
   338  	if idx := s.maxIndex("sessions"); idx != 0 {
   339  		t.Fatalf("bad index: %d", idx)
   340  	}
   341  
   342  	// Register a node.
   343  	testRegisterNode(t, s, 1, "node1")
   344  
   345  	// Register a new session
   346  	sess := &structs.Session{
   347  		ID:   testUUID(),
   348  		Node: "node1",
   349  	}
   350  	if err := s.SessionCreate(2, sess); err != nil {
   351  		t.Fatalf("err: %s", err)
   352  	}
   353  
   354  	// Destroy the session.
   355  	if err := s.SessionDestroy(3, sess.ID); err != nil {
   356  		t.Fatalf("err: %s", err)
   357  	}
   358  
   359  	// Check that the index was updated
   360  	if idx := s.maxIndex("sessions"); idx != 3 {
   361  		t.Fatalf("bad index: %d", idx)
   362  	}
   363  
   364  	// Make sure the session is really gone.
   365  	tx := s.db.Txn(false)
   366  	sessions, err := tx.Get("sessions", "id")
   367  	if err != nil || sessions.Next() != nil {
   368  		t.Fatalf("session should not exist")
   369  	}
   370  	tx.Abort()
   371  }
   372  
   373  func TestStateStore_Session_Snapshot_Restore(t *testing.T) {
   374  	s := testStateStore(t)
   375  
   376  	// Register some nodes and checks.
   377  	testRegisterNode(t, s, 1, "node1")
   378  	testRegisterNode(t, s, 2, "node2")
   379  	testRegisterNode(t, s, 3, "node3")
   380  	testRegisterCheck(t, s, 4, "node1", "", "check1", api.HealthPassing)
   381  
   382  	// Create some sessions in the state store.
   383  	session1 := testUUID()
   384  	sessions := structs.Sessions{
   385  		&structs.Session{
   386  			ID:       session1,
   387  			Node:     "node1",
   388  			Behavior: structs.SessionKeysDelete,
   389  			Checks:   []types.CheckID{"check1"},
   390  		},
   391  		&structs.Session{
   392  			ID:        testUUID(),
   393  			Node:      "node2",
   394  			Behavior:  structs.SessionKeysRelease,
   395  			LockDelay: 10 * time.Second,
   396  		},
   397  		&structs.Session{
   398  			ID:       testUUID(),
   399  			Node:     "node3",
   400  			Behavior: structs.SessionKeysDelete,
   401  			TTL:      "1.5s",
   402  		},
   403  	}
   404  	for i, session := range sessions {
   405  		if err := s.SessionCreate(uint64(5+i), session); err != nil {
   406  			t.Fatalf("err: %s", err)
   407  		}
   408  	}
   409  
   410  	// Snapshot the sessions.
   411  	snap := s.Snapshot()
   412  	defer snap.Close()
   413  
   414  	// Alter the real state store.
   415  	if err := s.SessionDestroy(8, session1); err != nil {
   416  		t.Fatalf("err: %s", err)
   417  	}
   418  
   419  	// Verify the snapshot.
   420  	if idx := snap.LastIndex(); idx != 7 {
   421  		t.Fatalf("bad index: %d", idx)
   422  	}
   423  	iter, err := snap.Sessions()
   424  	if err != nil {
   425  		t.Fatalf("err: %s", err)
   426  	}
   427  	var dump structs.Sessions
   428  	for session := iter.Next(); session != nil; session = iter.Next() {
   429  		sess := session.(*structs.Session)
   430  		dump = append(dump, sess)
   431  
   432  		found := false
   433  		for i := range sessions {
   434  			if sess.ID == sessions[i].ID {
   435  				if !reflect.DeepEqual(sess, sessions[i]) {
   436  					t.Fatalf("bad: %#v", sess)
   437  				}
   438  				found = true
   439  			}
   440  		}
   441  		if !found {
   442  			t.Fatalf("bad: %#v", sess)
   443  		}
   444  	}
   445  
   446  	// Restore the sessions into a new state store.
   447  	func() {
   448  		s := testStateStore(t)
   449  		restore := s.Restore()
   450  		for _, session := range dump {
   451  			if err := restore.Session(session); err != nil {
   452  				t.Fatalf("err: %s", err)
   453  			}
   454  		}
   455  		restore.Commit()
   456  
   457  		// Read the restored sessions back out and verify that they
   458  		// match.
   459  		idx, res, err := s.SessionList(nil)
   460  		if err != nil {
   461  			t.Fatalf("err: %s", err)
   462  		}
   463  		if idx != 7 {
   464  			t.Fatalf("bad index: %d", idx)
   465  		}
   466  		for _, sess := range res {
   467  			found := false
   468  			for i := range sessions {
   469  				if sess.ID == sessions[i].ID {
   470  					if !reflect.DeepEqual(sess, sessions[i]) {
   471  						t.Fatalf("bad: %#v", sess)
   472  					}
   473  					found = true
   474  				}
   475  			}
   476  			if !found {
   477  				t.Fatalf("bad: %#v", sess)
   478  			}
   479  		}
   480  
   481  		// Check that the index was updated.
   482  		if idx := s.maxIndex("sessions"); idx != 7 {
   483  			t.Fatalf("bad index: %d", idx)
   484  		}
   485  
   486  		// Manually verify that the session check mapping got restored.
   487  		tx := s.db.Txn(false)
   488  		defer tx.Abort()
   489  
   490  		check, err := tx.First("session_checks", "session", session1)
   491  		if err != nil {
   492  			t.Fatalf("err: %s", err)
   493  		}
   494  		if check == nil {
   495  			t.Fatalf("missing session check")
   496  		}
   497  		expectCheck := &sessionCheck{
   498  			Node:    "node1",
   499  			CheckID: "check1",
   500  			Session: session1,
   501  		}
   502  		if actual := check.(*sessionCheck); !reflect.DeepEqual(actual, expectCheck) {
   503  			t.Fatalf("expected %#v, got: %#v", expectCheck, actual)
   504  		}
   505  	}()
   506  }
   507  
   508  func TestStateStore_Session_Invalidate_DeleteNode(t *testing.T) {
   509  	s := testStateStore(t)
   510  
   511  	// Set up our test environment.
   512  	if err := s.EnsureNode(3, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil {
   513  		t.Fatalf("err: %v", err)
   514  	}
   515  	session := &structs.Session{
   516  		ID:   testUUID(),
   517  		Node: "foo",
   518  	}
   519  	if err := s.SessionCreate(14, session); err != nil {
   520  		t.Fatalf("err: %v", err)
   521  	}
   522  
   523  	// Delete the node and make sure the watch fires.
   524  	ws := memdb.NewWatchSet()
   525  	idx, s2, err := s.SessionGet(ws, session.ID)
   526  	if err != nil {
   527  		t.Fatalf("err: %v", err)
   528  	}
   529  	if err := s.DeleteNode(15, "foo"); err != nil {
   530  		t.Fatalf("err: %v", err)
   531  	}
   532  	if !watchFired(ws) {
   533  		t.Fatalf("bad")
   534  	}
   535  
   536  	// Lookup by ID, should be nil.
   537  	idx, s2, err = s.SessionGet(nil, session.ID)
   538  	if err != nil {
   539  		t.Fatalf("err: %v", err)
   540  	}
   541  	if s2 != nil {
   542  		t.Fatalf("session should be invalidated")
   543  	}
   544  	if idx != 15 {
   545  		t.Fatalf("bad index: %d", idx)
   546  	}
   547  }
   548  
   549  func TestStateStore_Session_Invalidate_DeleteService(t *testing.T) {
   550  	s := testStateStore(t)
   551  
   552  	// Set up our test environment.
   553  	if err := s.EnsureNode(11, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil {
   554  		t.Fatalf("err: %v", err)
   555  	}
   556  	if err := s.EnsureService(12, "foo", &structs.NodeService{ID: "api", Service: "api", Tags: nil, Address: "", Port: 5000}); err != nil {
   557  		t.Fatalf("err: %v", err)
   558  	}
   559  	check := &structs.HealthCheck{
   560  		Node:      "foo",
   561  		CheckID:   "api",
   562  		Name:      "Can connect",
   563  		Status:    api.HealthPassing,
   564  		ServiceID: "api",
   565  	}
   566  	if err := s.EnsureCheck(13, check); err != nil {
   567  		t.Fatalf("err: %v", err)
   568  	}
   569  	session := &structs.Session{
   570  		ID:     testUUID(),
   571  		Node:   "foo",
   572  		Checks: []types.CheckID{"api"},
   573  	}
   574  	if err := s.SessionCreate(14, session); err != nil {
   575  		t.Fatalf("err: %v", err)
   576  	}
   577  
   578  	// Delete the service and make sure the watch fires.
   579  	ws := memdb.NewWatchSet()
   580  	idx, s2, err := s.SessionGet(ws, session.ID)
   581  	if err != nil {
   582  		t.Fatalf("err: %v", err)
   583  	}
   584  	if err := s.DeleteService(15, "foo", "api"); err != nil {
   585  		t.Fatalf("err: %v", err)
   586  	}
   587  	if !watchFired(ws) {
   588  		t.Fatalf("bad")
   589  	}
   590  
   591  	// Lookup by ID, should be nil.
   592  	idx, s2, err = s.SessionGet(nil, session.ID)
   593  	if err != nil {
   594  		t.Fatalf("err: %v", err)
   595  	}
   596  	if s2 != nil {
   597  		t.Fatalf("session should be invalidated")
   598  	}
   599  	if idx != 15 {
   600  		t.Fatalf("bad index: %d", idx)
   601  	}
   602  }
   603  
   604  func TestStateStore_Session_Invalidate_Critical_Check(t *testing.T) {
   605  	s := testStateStore(t)
   606  
   607  	// Set up our test environment.
   608  	if err := s.EnsureNode(3, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil {
   609  		t.Fatalf("err: %v", err)
   610  	}
   611  	check := &structs.HealthCheck{
   612  		Node:    "foo",
   613  		CheckID: "bar",
   614  		Status:  api.HealthPassing,
   615  	}
   616  	if err := s.EnsureCheck(13, check); err != nil {
   617  		t.Fatalf("err: %v", err)
   618  	}
   619  	session := &structs.Session{
   620  		ID:     testUUID(),
   621  		Node:   "foo",
   622  		Checks: []types.CheckID{"bar"},
   623  	}
   624  	if err := s.SessionCreate(14, session); err != nil {
   625  		t.Fatalf("err: %v", err)
   626  	}
   627  
   628  	// Invalidate the check and make sure the watches fire.
   629  	ws := memdb.NewWatchSet()
   630  	idx, s2, err := s.SessionGet(ws, session.ID)
   631  	if err != nil {
   632  		t.Fatalf("err: %v", err)
   633  	}
   634  	check.Status = api.HealthCritical
   635  	if err := s.EnsureCheck(15, check); err != nil {
   636  		t.Fatalf("err: %v", err)
   637  	}
   638  	if !watchFired(ws) {
   639  		t.Fatalf("bad")
   640  	}
   641  
   642  	// Lookup by ID, should be nil.
   643  	idx, s2, err = s.SessionGet(nil, session.ID)
   644  	if err != nil {
   645  		t.Fatalf("err: %v", err)
   646  	}
   647  	if s2 != nil {
   648  		t.Fatalf("session should be invalidated")
   649  	}
   650  	if idx != 15 {
   651  		t.Fatalf("bad index: %d", idx)
   652  	}
   653  }
   654  
   655  func TestStateStore_Session_Invalidate_DeleteCheck(t *testing.T) {
   656  	s := testStateStore(t)
   657  
   658  	// Set up our test environment.
   659  	if err := s.EnsureNode(3, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil {
   660  		t.Fatalf("err: %v", err)
   661  	}
   662  	check := &structs.HealthCheck{
   663  		Node:    "foo",
   664  		CheckID: "bar",
   665  		Status:  api.HealthPassing,
   666  	}
   667  	if err := s.EnsureCheck(13, check); err != nil {
   668  		t.Fatalf("err: %v", err)
   669  	}
   670  	session := &structs.Session{
   671  		ID:     testUUID(),
   672  		Node:   "foo",
   673  		Checks: []types.CheckID{"bar"},
   674  	}
   675  	if err := s.SessionCreate(14, session); err != nil {
   676  		t.Fatalf("err: %v", err)
   677  	}
   678  
   679  	// Delete the check and make sure the watches fire.
   680  	ws := memdb.NewWatchSet()
   681  	idx, s2, err := s.SessionGet(ws, session.ID)
   682  	if err != nil {
   683  		t.Fatalf("err: %v", err)
   684  	}
   685  	if err := s.DeleteCheck(15, "foo", "bar"); err != nil {
   686  		t.Fatalf("err: %v", err)
   687  	}
   688  	if !watchFired(ws) {
   689  		t.Fatalf("bad")
   690  	}
   691  
   692  	// Lookup by ID, should be nil.
   693  	idx, s2, err = s.SessionGet(nil, session.ID)
   694  	if err != nil {
   695  		t.Fatalf("err: %v", err)
   696  	}
   697  	if s2 != nil {
   698  		t.Fatalf("session should be invalidated")
   699  	}
   700  	if idx != 15 {
   701  		t.Fatalf("bad index: %d", idx)
   702  	}
   703  
   704  	// Manually make sure the session checks mapping is clear.
   705  	tx := s.db.Txn(false)
   706  	mapping, err := tx.First("session_checks", "session", session.ID)
   707  	if err != nil {
   708  		t.Fatalf("err: %s", err)
   709  	}
   710  	if mapping != nil {
   711  		t.Fatalf("unexpected session check")
   712  	}
   713  	tx.Abort()
   714  }
   715  
   716  func TestStateStore_Session_Invalidate_Key_Unlock_Behavior(t *testing.T) {
   717  	s := testStateStore(t)
   718  
   719  	// Set up our test environment.
   720  	if err := s.EnsureNode(3, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil {
   721  		t.Fatalf("err: %v", err)
   722  	}
   723  	session := &structs.Session{
   724  		ID:        testUUID(),
   725  		Node:      "foo",
   726  		LockDelay: 50 * time.Millisecond,
   727  	}
   728  	if err := s.SessionCreate(4, session); err != nil {
   729  		t.Fatalf("err: %v", err)
   730  	}
   731  
   732  	// Lock a key with the session.
   733  	d := &structs.DirEntry{
   734  		Key:     "/foo",
   735  		Flags:   42,
   736  		Value:   []byte("test"),
   737  		Session: session.ID,
   738  	}
   739  	ok, err := s.KVSLock(5, d)
   740  	if err != nil {
   741  		t.Fatalf("err: %v", err)
   742  	}
   743  	if !ok {
   744  		t.Fatalf("unexpected fail")
   745  	}
   746  
   747  	// Delete the node and make sure the watches fire.
   748  	ws := memdb.NewWatchSet()
   749  	idx, s2, err := s.SessionGet(ws, session.ID)
   750  	if err != nil {
   751  		t.Fatalf("err: %v", err)
   752  	}
   753  	if err := s.DeleteNode(6, "foo"); err != nil {
   754  		t.Fatalf("err: %v", err)
   755  	}
   756  	if !watchFired(ws) {
   757  		t.Fatalf("bad")
   758  	}
   759  
   760  	// Lookup by ID, should be nil.
   761  	idx, s2, err = s.SessionGet(nil, session.ID)
   762  	if err != nil {
   763  		t.Fatalf("err: %v", err)
   764  	}
   765  	if s2 != nil {
   766  		t.Fatalf("session should be invalidated")
   767  	}
   768  	if idx != 6 {
   769  		t.Fatalf("bad index: %d", idx)
   770  	}
   771  
   772  	// Key should be unlocked.
   773  	idx, d2, err := s.KVSGet(nil, "/foo")
   774  	if err != nil {
   775  		t.Fatalf("err: %s", err)
   776  	}
   777  	if d2.ModifyIndex != 6 {
   778  		t.Fatalf("bad index: %v", d2.ModifyIndex)
   779  	}
   780  	if d2.LockIndex != 1 {
   781  		t.Fatalf("bad: %v", *d2)
   782  	}
   783  	if d2.Session != "" {
   784  		t.Fatalf("bad: %v", *d2)
   785  	}
   786  	if idx != 6 {
   787  		t.Fatalf("bad index: %d", idx)
   788  	}
   789  
   790  	// Key should have a lock delay.
   791  	expires := s.KVSLockDelay("/foo")
   792  	if expires.Before(time.Now().Add(30 * time.Millisecond)) {
   793  		t.Fatalf("Bad: %v", expires)
   794  	}
   795  }
   796  
   797  func TestStateStore_Session_Invalidate_Key_Delete_Behavior(t *testing.T) {
   798  	s := testStateStore(t)
   799  
   800  	// Set up our test environment.
   801  	if err := s.EnsureNode(3, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil {
   802  		t.Fatalf("err: %v", err)
   803  	}
   804  	session := &structs.Session{
   805  		ID:        testUUID(),
   806  		Node:      "foo",
   807  		LockDelay: 50 * time.Millisecond,
   808  		Behavior:  structs.SessionKeysDelete,
   809  	}
   810  	if err := s.SessionCreate(4, session); err != nil {
   811  		t.Fatalf("err: %v", err)
   812  	}
   813  
   814  	// Lock a key with the session.
   815  	d := &structs.DirEntry{
   816  		Key:     "/bar",
   817  		Flags:   42,
   818  		Value:   []byte("test"),
   819  		Session: session.ID,
   820  	}
   821  	ok, err := s.KVSLock(5, d)
   822  	if err != nil {
   823  		t.Fatalf("err: %v", err)
   824  	}
   825  	if !ok {
   826  		t.Fatalf("unexpected fail")
   827  	}
   828  
   829  	// Delete the node and make sure the watches fire.
   830  	ws := memdb.NewWatchSet()
   831  	idx, s2, err := s.SessionGet(ws, session.ID)
   832  	if err != nil {
   833  		t.Fatalf("err: %v", err)
   834  	}
   835  	if err := s.DeleteNode(6, "foo"); err != nil {
   836  		t.Fatalf("err: %v", err)
   837  	}
   838  	if !watchFired(ws) {
   839  		t.Fatalf("bad")
   840  	}
   841  
   842  	// Lookup by ID, should be nil.
   843  	idx, s2, err = s.SessionGet(nil, session.ID)
   844  	if err != nil {
   845  		t.Fatalf("err: %v", err)
   846  	}
   847  	if s2 != nil {
   848  		t.Fatalf("session should be invalidated")
   849  	}
   850  	if idx != 6 {
   851  		t.Fatalf("bad index: %d", idx)
   852  	}
   853  
   854  	// Key should be deleted.
   855  	idx, d2, err := s.KVSGet(nil, "/bar")
   856  	if err != nil {
   857  		t.Fatalf("err: %s", err)
   858  	}
   859  	if d2 != nil {
   860  		t.Fatalf("unexpected deleted key")
   861  	}
   862  	if idx != 6 {
   863  		t.Fatalf("bad index: %d", idx)
   864  	}
   865  
   866  	// Key should have a lock delay.
   867  	expires := s.KVSLockDelay("/bar")
   868  	if expires.Before(time.Now().Add(30 * time.Millisecond)) {
   869  		t.Fatalf("Bad: %v", expires)
   870  	}
   871  }
   872  
   873  func TestStateStore_Session_Invalidate_PreparedQuery_Delete(t *testing.T) {
   874  	s := testStateStore(t)
   875  
   876  	// Set up our test environment.
   877  	testRegisterNode(t, s, 1, "foo")
   878  	testRegisterService(t, s, 2, "foo", "redis")
   879  	session := &structs.Session{
   880  		ID:   testUUID(),
   881  		Node: "foo",
   882  	}
   883  	if err := s.SessionCreate(3, session); err != nil {
   884  		t.Fatalf("err: %v", err)
   885  	}
   886  	query := &structs.PreparedQuery{
   887  		ID:      testUUID(),
   888  		Session: session.ID,
   889  		Service: structs.ServiceQuery{
   890  			Service: "redis",
   891  		},
   892  	}
   893  	if err := s.PreparedQuerySet(4, query); err != nil {
   894  		t.Fatalf("err: %s", err)
   895  	}
   896  
   897  	// Invalidate the session and make sure the watches fire.
   898  	ws := memdb.NewWatchSet()
   899  	idx, s2, err := s.SessionGet(ws, session.ID)
   900  	if err != nil {
   901  		t.Fatalf("err: %v", err)
   902  	}
   903  	if err := s.SessionDestroy(5, session.ID); err != nil {
   904  		t.Fatalf("err: %v", err)
   905  	}
   906  	if !watchFired(ws) {
   907  		t.Fatalf("bad")
   908  	}
   909  
   910  	// Make sure the session is gone.
   911  	idx, s2, err = s.SessionGet(nil, session.ID)
   912  	if err != nil {
   913  		t.Fatalf("err: %v", err)
   914  	}
   915  	if s2 != nil {
   916  		t.Fatalf("session should be invalidated")
   917  	}
   918  	if idx != 5 {
   919  		t.Fatalf("bad index: %d", idx)
   920  	}
   921  
   922  	// Make sure the query is gone and the index is updated.
   923  	idx, q2, err := s.PreparedQueryGet(nil, query.ID)
   924  	if err != nil {
   925  		t.Fatalf("err: %s", err)
   926  	}
   927  	if idx != 5 {
   928  		t.Fatalf("bad index: %d", idx)
   929  	}
   930  	if q2 != nil {
   931  		t.Fatalf("bad: %v", q2)
   932  	}
   933  }