github.com/muyo/sno@v1.2.1/partition_test.go (about) 1 package sno 2 3 import ( 4 "sync/atomic" 5 "testing" 6 ) 7 8 func TestPartition_Public_Conversions(t *testing.T) { 9 t.Run("AsUint16", func(t *testing.T) { 10 src := Partition{255, 255} 11 expected := uint16(MaxPartition) 12 actual := src.AsUint16() 13 14 if actual != expected { 15 t.Errorf("expected [%d], got [%d]", expected, actual) 16 } 17 }) 18 19 t.Run("PutUint16", func(t *testing.T) { 20 expected := Partition{255, 255} 21 actual := Partition{} 22 actual.PutUint16(MaxPartition) 23 24 if actual != expected { 25 t.Errorf("expected [%s], got [%s]", expected, actual) 26 } 27 }) 28 } 29 30 func TestPartition_Internal_Conversions(t *testing.T) { 31 public := Partition{255, 255} 32 internal := uint32(MaxPartition) << 16 33 34 t.Run("to-internal", func(t *testing.T) { 35 expected := internal 36 actual := partitionToInternalRepr(public) 37 38 if actual != expected { 39 t.Errorf("expected [%d], got [%d]", expected, actual) 40 } 41 }) 42 43 t.Run("to-public", func(t *testing.T) { 44 expected := public 45 actual := partitionToPublicRepr(internal) 46 47 if actual != expected { 48 t.Errorf("expected [%d], got [%d]", expected, actual) 49 } 50 }) 51 } 52 53 func TestPartition_Internal_Generation(t *testing.T) { 54 t.Run("monotonic-increments", func(t *testing.T) { 55 // Reset global count (leaving seed as is). 56 atomic.StoreUint32(&partitions, 0) 57 58 var prevPartition = uint32(seed) << 16 59 60 for i := 0; i < 100; i++ { 61 p, err := genPartition() 62 if err != nil { 63 t.Fatal(err) 64 } 65 66 // Note: genPartition() shifts to make space for the sequence, 67 // so we can't simply check for an increment of 1 within the resulting 68 // uint32. The below is a tiny bit faster than converting back 69 // to an uint16. 70 if p-prevPartition != 1<<16 { 71 t.Errorf("expected [%d], got [%d]", prevPartition+1<<16, p) 72 break 73 } 74 75 prevPartition = p 76 } 77 }) 78 79 t.Run("pool-exhaustion", func(t *testing.T) { 80 // Reset global count (leaving seed as is). 81 atomic.StoreUint32(&partitions, 0) 82 83 for i := 0; i < 2*MaxPartition; i++ { 84 _, err := genPartition() 85 86 if err != nil { 87 verr, ok := err.(*PartitionPoolExhaustedError) 88 if !ok { 89 t.Fatalf("expected error type [%T], got [%T]", &PartitionPoolExhaustedError{}, err) 90 return 91 } 92 93 if i < MaxPartition { 94 t.Fatalf("expected errors no sooner than after [%d] iterations, got to [%d]", MaxPartition, i) 95 return 96 } 97 98 errMsgActual := verr.Error() 99 errMsgExpected := errPartitionPoolExhaustedMsg 100 101 if errMsgActual != errMsgExpected { 102 t.Fatalf("expected error msg [%s], got [%s]", errMsgExpected, errMsgActual) 103 } 104 } 105 106 if i >= MaxPartition { 107 if err == nil { 108 t.Fatalf("expected constant errors after [%d] iterations, got no error at [%d]", MaxPartition, i) 109 return 110 } 111 } 112 } 113 }) 114 115 // Clean up. 116 atomic.StoreUint32(&partitions, 0) 117 }