github.hscsec.cn/hashicorp/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 }