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

     1  package api
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/pascaldekloe/goe/verify"
    10  )
    11  
    12  func TestAPI_SessionCreateDestroy(t *testing.T) {
    13  	t.Parallel()
    14  	c, s := makeClient(t)
    15  	defer s.Stop()
    16  
    17  	s.WaitForSerfCheck(t)
    18  
    19  	session := c.Session()
    20  
    21  	id, meta, err := session.Create(nil, nil)
    22  	if err != nil {
    23  		t.Fatalf("err: %v", err)
    24  	}
    25  
    26  	if meta.RequestTime == 0 {
    27  		t.Fatalf("bad: %v", meta)
    28  	}
    29  
    30  	if id == "" {
    31  		t.Fatalf("invalid: %v", id)
    32  	}
    33  
    34  	meta, err = session.Destroy(id, nil)
    35  	if err != nil {
    36  		t.Fatalf("err: %v", err)
    37  	}
    38  
    39  	if meta.RequestTime == 0 {
    40  		t.Fatalf("bad: %v", meta)
    41  	}
    42  }
    43  
    44  func TestAPI_SessionCreateRenewDestroy(t *testing.T) {
    45  	t.Parallel()
    46  	c, s := makeClient(t)
    47  	defer s.Stop()
    48  
    49  	s.WaitForSerfCheck(t)
    50  
    51  	session := c.Session()
    52  
    53  	se := &SessionEntry{
    54  		TTL: "10s",
    55  	}
    56  
    57  	id, meta, err := session.Create(se, nil)
    58  	if err != nil {
    59  		t.Fatalf("err: %v", err)
    60  	}
    61  	defer session.Destroy(id, nil)
    62  
    63  	if meta.RequestTime == 0 {
    64  		t.Fatalf("bad: %v", meta)
    65  	}
    66  
    67  	if id == "" {
    68  		t.Fatalf("invalid: %v", id)
    69  	}
    70  
    71  	if meta.RequestTime == 0 {
    72  		t.Fatalf("bad: %v", meta)
    73  	}
    74  
    75  	renew, meta, err := session.Renew(id, nil)
    76  
    77  	if err != nil {
    78  		t.Fatalf("err: %v", err)
    79  	}
    80  	if meta.RequestTime == 0 {
    81  		t.Fatalf("bad: %v", meta)
    82  	}
    83  
    84  	if renew == nil {
    85  		t.Fatalf("should get session")
    86  	}
    87  
    88  	if renew.ID != id {
    89  		t.Fatalf("should have matching id")
    90  	}
    91  
    92  	if renew.TTL != "10s" {
    93  		t.Fatalf("should get session with TTL")
    94  	}
    95  }
    96  
    97  func TestAPI_SessionCreateRenewDestroyRenew(t *testing.T) {
    98  	t.Parallel()
    99  	c, s := makeClient(t)
   100  	defer s.Stop()
   101  
   102  	s.WaitForSerfCheck(t)
   103  
   104  	session := c.Session()
   105  
   106  	entry := &SessionEntry{
   107  		Behavior: SessionBehaviorDelete,
   108  		TTL:      "500s", // disable ttl
   109  	}
   110  
   111  	id, meta, err := session.Create(entry, nil)
   112  	if err != nil {
   113  		t.Fatalf("err: %v", err)
   114  	}
   115  
   116  	if meta.RequestTime == 0 {
   117  		t.Fatalf("bad: %v", meta)
   118  	}
   119  
   120  	if id == "" {
   121  		t.Fatalf("invalid: %v", id)
   122  	}
   123  
   124  	// Extend right after create. Everything should be fine.
   125  	entry, _, err = session.Renew(id, nil)
   126  	if err != nil {
   127  		t.Fatalf("err: %v", err)
   128  	}
   129  	if entry == nil {
   130  		t.Fatal("session unexpectedly vanished")
   131  	}
   132  
   133  	// Simulate TTL loss by manually destroying the session.
   134  	meta, err = session.Destroy(id, nil)
   135  	if err != nil {
   136  		t.Fatalf("err: %v", err)
   137  	}
   138  
   139  	if meta.RequestTime == 0 {
   140  		t.Fatalf("bad: %v", meta)
   141  	}
   142  
   143  	// Extend right after delete. The 404 should proxy as a nil.
   144  	entry, _, err = session.Renew(id, nil)
   145  	if err != nil {
   146  		t.Fatalf("err: %v", err)
   147  	}
   148  	if entry != nil {
   149  		t.Fatal("session still exists")
   150  	}
   151  }
   152  
   153  func TestAPI_SessionCreateDestroyRenewPeriodic(t *testing.T) {
   154  	t.Parallel()
   155  	c, s := makeClient(t)
   156  	defer s.Stop()
   157  
   158  	s.WaitForSerfCheck(t)
   159  
   160  	session := c.Session()
   161  
   162  	entry := &SessionEntry{
   163  		Behavior: SessionBehaviorDelete,
   164  		TTL:      "500s", // disable ttl
   165  	}
   166  
   167  	id, meta, err := session.Create(entry, nil)
   168  	if err != nil {
   169  		t.Fatalf("err: %v", err)
   170  	}
   171  
   172  	if meta.RequestTime == 0 {
   173  		t.Fatalf("bad: %v", meta)
   174  	}
   175  
   176  	if id == "" {
   177  		t.Fatalf("invalid: %v", id)
   178  	}
   179  
   180  	// This only tests Create/Destroy/RenewPeriodic to avoid the more
   181  	// difficult case of testing all of the timing code.
   182  
   183  	// Simulate TTL loss by manually destroying the session.
   184  	meta, err = session.Destroy(id, nil)
   185  	if err != nil {
   186  		t.Fatalf("err: %v", err)
   187  	}
   188  
   189  	if meta.RequestTime == 0 {
   190  		t.Fatalf("bad: %v", meta)
   191  	}
   192  
   193  	// Extend right after delete. The 404 should terminate the loop quickly and return ErrSessionExpired.
   194  	errCh := make(chan error, 1)
   195  	doneCh := make(chan struct{})
   196  	go func() { errCh <- session.RenewPeriodic("1s", id, nil, doneCh) }()
   197  	defer close(doneCh)
   198  
   199  	select {
   200  	case <-time.After(1 * time.Second):
   201  		t.Fatal("timedout: missing session did not terminate renewal loop")
   202  	case err = <-errCh:
   203  		if err != ErrSessionExpired {
   204  			t.Fatalf("err: %v", err)
   205  		}
   206  	}
   207  }
   208  
   209  func TestAPI_SessionRenewPeriodic_Cancel(t *testing.T) {
   210  	t.Parallel()
   211  	c, s := makeClient(t)
   212  	defer s.Stop()
   213  
   214  	s.WaitForSerfCheck(t)
   215  
   216  	session := c.Session()
   217  	entry := &SessionEntry{
   218  		Behavior: SessionBehaviorDelete,
   219  		TTL:      "500s", // disable ttl
   220  	}
   221  
   222  	t.Run("done channel", func(t *testing.T) {
   223  		id, _, err := session.Create(entry, nil)
   224  		if err != nil {
   225  			t.Fatalf("err: %v", err)
   226  		}
   227  
   228  		errCh := make(chan error, 1)
   229  		doneCh := make(chan struct{})
   230  		go func() { errCh <- session.RenewPeriodic("1s", id, nil, doneCh) }()
   231  
   232  		close(doneCh)
   233  
   234  		select {
   235  		case <-time.After(1 * time.Second):
   236  			t.Fatal("renewal loop didn't terminate")
   237  		case err = <-errCh:
   238  			if err != nil {
   239  				t.Fatalf("err: %v", err)
   240  			}
   241  		}
   242  
   243  		sess, _, err := session.Info(id, nil)
   244  		if err != nil {
   245  			t.Fatalf("err: %v", err)
   246  		}
   247  		if sess != nil {
   248  			t.Fatalf("session was not expired")
   249  		}
   250  	})
   251  
   252  	t.Run("context", func(t *testing.T) {
   253  		id, _, err := session.Create(entry, nil)
   254  		if err != nil {
   255  			t.Fatalf("err: %v", err)
   256  		}
   257  
   258  		ctx, cancel := context.WithCancel(context.Background())
   259  		wo := new(WriteOptions).WithContext(ctx)
   260  
   261  		errCh := make(chan error, 1)
   262  		go func() { errCh <- session.RenewPeriodic("1s", id, wo, nil) }()
   263  
   264  		cancel()
   265  
   266  		select {
   267  		case <-time.After(1 * time.Second):
   268  			t.Fatal("renewal loop didn't terminate")
   269  		case err = <-errCh:
   270  			if err == nil || !strings.Contains(err.Error(), "context canceled") {
   271  				t.Fatalf("err: %v", err)
   272  			}
   273  		}
   274  
   275  		// See comment in session.go for why the session isn't removed
   276  		// in this case.
   277  		sess, _, err := session.Info(id, nil)
   278  		if err != nil {
   279  			t.Fatalf("err: %v", err)
   280  		}
   281  		if sess == nil {
   282  			t.Fatalf("session should not be expired")
   283  		}
   284  	})
   285  }
   286  
   287  func TestAPI_SessionInfo(t *testing.T) {
   288  	t.Parallel()
   289  	c, s := makeClient(t)
   290  	defer s.Stop()
   291  
   292  	s.WaitForSerfCheck(t)
   293  
   294  	session := c.Session()
   295  
   296  	id, _, err := session.Create(nil, nil)
   297  	if err != nil {
   298  		t.Fatalf("err: %v", err)
   299  	}
   300  	defer session.Destroy(id, nil)
   301  
   302  	info, qm, err := session.Info(id, nil)
   303  	if err != nil {
   304  		t.Fatalf("err: %v", err)
   305  	}
   306  	if qm.LastIndex == 0 {
   307  		t.Fatalf("bad: %v", qm)
   308  	}
   309  	if !qm.KnownLeader {
   310  		t.Fatalf("bad: %v", qm)
   311  	}
   312  
   313  	if info.CreateIndex == 0 {
   314  		t.Fatalf("bad: %v", info)
   315  	}
   316  	info.CreateIndex = 0
   317  
   318  	want := &SessionEntry{
   319  		ID:        id,
   320  		Node:      s.Config.NodeName,
   321  		Checks:    []string{"serfHealth"},
   322  		LockDelay: 15 * time.Second,
   323  		Behavior:  SessionBehaviorRelease,
   324  	}
   325  	verify.Values(t, "", info, want)
   326  }
   327  
   328  func TestAPI_SessionInfo_NoChecks(t *testing.T) {
   329  	t.Parallel()
   330  	c, s := makeClient(t)
   331  	defer s.Stop()
   332  
   333  	session := c.Session()
   334  
   335  	id, _, err := session.CreateNoChecks(nil, nil)
   336  	if err != nil {
   337  		t.Fatalf("err: %v", err)
   338  	}
   339  	defer session.Destroy(id, nil)
   340  
   341  	info, qm, err := session.Info(id, nil)
   342  	if err != nil {
   343  		t.Fatalf("err: %v", err)
   344  	}
   345  
   346  	if qm.LastIndex == 0 {
   347  		t.Fatalf("bad: %v", qm)
   348  	}
   349  	if !qm.KnownLeader {
   350  		t.Fatalf("bad: %v", qm)
   351  	}
   352  
   353  	if info.CreateIndex == 0 {
   354  		t.Fatalf("bad: %v", info)
   355  	}
   356  	info.CreateIndex = 0
   357  
   358  	want := &SessionEntry{
   359  		ID:        id,
   360  		Node:      s.Config.NodeName,
   361  		Checks:    []string{},
   362  		LockDelay: 15 * time.Second,
   363  		Behavior:  SessionBehaviorRelease,
   364  	}
   365  	verify.Values(t, "", info, want)
   366  }
   367  
   368  func TestAPI_SessionNode(t *testing.T) {
   369  	t.Parallel()
   370  	c, s := makeClient(t)
   371  	defer s.Stop()
   372  
   373  	s.WaitForSerfCheck(t)
   374  
   375  	session := c.Session()
   376  
   377  	id, _, err := session.Create(nil, nil)
   378  	if err != nil {
   379  		t.Fatalf("err: %v", err)
   380  	}
   381  	defer session.Destroy(id, nil)
   382  
   383  	info, qm, err := session.Info(id, nil)
   384  	if err != nil {
   385  		t.Fatalf("err: %v", err)
   386  	}
   387  
   388  	sessions, qm, err := session.Node(info.Node, nil)
   389  	if err != nil {
   390  		t.Fatalf("err: %v", err)
   391  	}
   392  
   393  	if len(sessions) != 1 {
   394  		t.Fatalf("bad: %v", sessions)
   395  	}
   396  
   397  	if qm.LastIndex == 0 {
   398  		t.Fatalf("bad: %v", qm)
   399  	}
   400  	if !qm.KnownLeader {
   401  		t.Fatalf("bad: %v", qm)
   402  	}
   403  }
   404  
   405  func TestAPI_SessionList(t *testing.T) {
   406  	t.Parallel()
   407  	c, s := makeClient(t)
   408  	defer s.Stop()
   409  
   410  	s.WaitForSerfCheck(t)
   411  
   412  	session := c.Session()
   413  
   414  	id, _, err := session.Create(nil, nil)
   415  	if err != nil {
   416  		t.Fatalf("err: %v", err)
   417  	}
   418  	defer session.Destroy(id, nil)
   419  
   420  	sessions, qm, err := session.List(nil)
   421  	if err != nil {
   422  		t.Fatalf("err: %v", err)
   423  	}
   424  
   425  	if len(sessions) != 1 {
   426  		t.Fatalf("bad: %v", sessions)
   427  	}
   428  
   429  	if qm.LastIndex == 0 {
   430  		t.Fatalf("bad: %v", qm)
   431  	}
   432  	if !qm.KnownLeader {
   433  		t.Fatalf("bad: %v", qm)
   434  	}
   435  }