@@ -29,9 +29,12 @@ package gocql
29
29
30
30
import (
31
31
"context"
32
+ "crypto/tls"
32
33
"fmt"
33
34
"net"
35
+ "sync"
34
36
"testing"
37
+ "time"
35
38
)
36
39
37
40
func TestSessionAPI (t * testing.T ) {
@@ -424,3 +427,113 @@ func TestRetryType_IgnoreRethrow(t *testing.T) {
424
427
resetObserved ()
425
428
}
426
429
}
430
+
431
+ type sessionCache struct {
432
+ orig tls.ClientSessionCache
433
+ values map [string ][][]byte
434
+ caches map [string ][]int64
435
+ valuesLock sync.Mutex
436
+ }
437
+
438
+ func (c * sessionCache ) Get (sessionKey string ) (session * tls.ClientSessionState , ok bool ) {
439
+ return c .orig .Get (sessionKey )
440
+ }
441
+
442
+ func (c * sessionCache ) Put (sessionKey string , cs * tls.ClientSessionState ) {
443
+ ticket , _ , err := cs .ResumptionState ()
444
+ if err != nil {
445
+ panic (err )
446
+ }
447
+ if len (ticket ) == 0 {
448
+ panic ("ticket should not be empty" )
449
+ }
450
+ c .valuesLock .Lock ()
451
+ c .values [sessionKey ] = append (c .values [sessionKey ], ticket )
452
+ c .valuesLock .Unlock ()
453
+ c .orig .Put (sessionKey , cs )
454
+ }
455
+
456
+ func (c * sessionCache ) NumberOfTickets () int {
457
+ c .valuesLock .Lock ()
458
+ defer c .valuesLock .Unlock ()
459
+ total := 0
460
+ for _ , tickets := range c .values {
461
+ total += len (tickets )
462
+ }
463
+ return total
464
+ }
465
+
466
+ func newSessionCache () * sessionCache {
467
+ return & sessionCache {
468
+ orig : tls .NewLRUClientSessionCache (1024 ),
469
+ values : make (map [string ][][]byte ),
470
+ caches : make (map [string ][]int64 ),
471
+ valuesLock : sync.Mutex {},
472
+ }
473
+ }
474
+
475
+ func withSessionCache (cache tls.ClientSessionCache ) func (config * ClusterConfig ) {
476
+ return func (config * ClusterConfig ) {
477
+ config .SslOpts = & SslOptions {
478
+ EnableHostVerification : false ,
479
+ Config : & tls.Config {
480
+ ClientSessionCache : cache ,
481
+ InsecureSkipVerify : true ,
482
+ },
483
+ }
484
+ }
485
+ }
486
+
487
+ func TestTLSTicketResumption (t * testing.T ) {
488
+ t .Skip ("TLS ticket resumption is only supported by 2025.2 and later" )
489
+
490
+ c := newSessionCache ()
491
+ session := createSession (t , withSessionCache (c ))
492
+ defer session .Close ()
493
+
494
+ waitAllConnectionsOpened := func () error {
495
+ println ("wait all connections opened" )
496
+ defer println ("end of wait all connections closed" )
497
+ endtime := time .Now ().UTC ().Add (time .Second * 10 )
498
+ for {
499
+ if time .Now ().UTC ().After (endtime ) {
500
+ return fmt .Errorf ("timed out waiting for all connections opened" )
501
+ }
502
+ missing , err := session .MissingConnections ()
503
+ if err != nil {
504
+ return fmt .Errorf ("failed to get missing connections count: %w" , err )
505
+ }
506
+ if missing == 0 {
507
+ return nil
508
+ }
509
+ time .Sleep (time .Millisecond * 100 )
510
+ }
511
+ }
512
+
513
+ if err := waitAllConnectionsOpened (); err != nil {
514
+ t .Fatal (err )
515
+ }
516
+ tickets := c .NumberOfTickets ()
517
+ if tickets == 0 {
518
+ t .Fatal ("no tickets learned, which means that server does not support TLS tickets" )
519
+ }
520
+
521
+ session .CloseAllConnections ()
522
+ if err := waitAllConnectionsOpened (); err != nil {
523
+ t .Fatal (err )
524
+ }
525
+ newTickets1 := c .NumberOfTickets ()
526
+
527
+ session .CloseAllConnections ()
528
+ if err := waitAllConnectionsOpened (); err != nil {
529
+ t .Fatal (err )
530
+ }
531
+ newTickets2 := c .NumberOfTickets ()
532
+
533
+ if newTickets1 != tickets {
534
+ t .Fatalf ("new tickets learned, it looks like tls tickets where not reused: new %d, was %d" , newTickets1 , tickets )
535
+ }
536
+ if newTickets2 != tickets {
537
+ t .Fatalf ("new tickets learned, it looks like tls tickets where not reused: new %d, was %d" , newTickets2 , tickets )
538
+ }
539
+ }
0 commit comments