github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/uuid/generator_test.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 // Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru> 12 // Use of this source code is governed by a MIT-style 13 // license that can be found in licenses/MIT-gofrs.txt. 14 15 // This code originated in github.com/gofrs/uuid. 16 17 package uuid 18 19 import ( 20 "bytes" 21 "crypto/rand" 22 "fmt" 23 "net" 24 "testing" 25 "time" 26 27 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 28 ) 29 30 func TestGenerator(t *testing.T) { 31 t.Run("NewV1", testNewV1) 32 t.Run("NewV3", testNewV3) 33 t.Run("NewV4", testNewV4) 34 t.Run("NewV5", testNewV5) 35 } 36 37 func testNewV1(t *testing.T) { 38 t.Run("Basic", testNewV1Basic) 39 t.Run("DifferentAcrossCalls", testNewV1DifferentAcrossCalls) 40 t.Run("StaleEpoch", testNewV1StaleEpoch) 41 t.Run("FaultyRand", testNewV1FaultyRand) 42 t.Run("MissingNetwork", testNewV1MissingNetwork) 43 t.Run("MissingNetworkFaultyRand", testNewV1MissingNetworkFaultyRand) 44 } 45 46 func TestNewGenWithHWAF(t *testing.T) { 47 addr := []byte{0, 1, 2, 3, 4, 42} 48 49 fn := func() (net.HardwareAddr, error) { 50 return addr, nil 51 } 52 53 var g *Gen 54 var err error 55 var uuid UUID 56 57 g = NewGenWithHWAF(fn) 58 59 if g == nil { 60 t.Fatal("g is unexpectedly nil") 61 } 62 63 uuid, err = g.NewV1() 64 if err != nil { 65 t.Fatalf("g.NewV1() err = %v, want <nil>", err) 66 } 67 68 node := uuid[10:] 69 70 if !bytes.Equal(addr, node) { 71 t.Fatalf("node = %v, want %v", node, addr) 72 } 73 } 74 75 func testNewV1Basic(t *testing.T) { 76 u, err := NewV1() 77 if err != nil { 78 t.Fatal(err) 79 } 80 if got, want := u.Version(), V1; got != want { 81 t.Errorf("generated UUID with version %d, want %d", got, want) 82 } 83 if got, want := u.Variant(), VariantRFC4122; got != want { 84 t.Errorf("generated UUID with variant %d, want %d", got, want) 85 } 86 } 87 88 func testNewV1DifferentAcrossCalls(t *testing.T) { 89 u1, err := NewV1() 90 if err != nil { 91 t.Fatal(err) 92 } 93 u2, err := NewV1() 94 if err != nil { 95 t.Fatal(err) 96 } 97 if u1 == u2 { 98 t.Errorf("generated identical UUIDs across calls: %v", u1) 99 } 100 } 101 102 func testNewV1StaleEpoch(t *testing.T) { 103 g := &Gen{ 104 epochFunc: func() time.Time { 105 return timeutil.Unix(0, 0) 106 }, 107 hwAddrFunc: defaultHWAddrFunc, 108 rand: rand.Reader, 109 } 110 u1, err := g.NewV1() 111 if err != nil { 112 t.Fatal(err) 113 } 114 u2, err := g.NewV1() 115 if err != nil { 116 t.Fatal(err) 117 } 118 if u1 == u2 { 119 t.Errorf("generated identical UUIDs across calls: %v", u1) 120 } 121 } 122 123 func testNewV1FaultyRand(t *testing.T) { 124 g := &Gen{ 125 epochFunc: time.Now, 126 hwAddrFunc: defaultHWAddrFunc, 127 rand: &faultyReader{ 128 readToFail: 0, // fail immediately 129 }, 130 } 131 u, err := g.NewV1() 132 if err == nil { 133 t.Fatalf("got %v, want error", u) 134 } 135 if u != Nil { 136 t.Fatalf("got %v on error, want Nil", u) 137 } 138 } 139 140 func testNewV1MissingNetwork(t *testing.T) { 141 g := &Gen{ 142 epochFunc: time.Now, 143 hwAddrFunc: func() (net.HardwareAddr, error) { 144 return []byte{}, fmt.Errorf("uuid: no hw address found") 145 }, 146 rand: rand.Reader, 147 } 148 _, err := g.NewV1() 149 if err != nil { 150 t.Errorf("did not handle missing network interfaces: %v", err) 151 } 152 } 153 154 func testNewV1MissingNetworkFaultyRand(t *testing.T) { 155 g := &Gen{ 156 epochFunc: time.Now, 157 hwAddrFunc: func() (net.HardwareAddr, error) { 158 return []byte{}, fmt.Errorf("uuid: no hw address found") 159 }, 160 rand: &faultyReader{ 161 readToFail: 1, 162 }, 163 } 164 u, err := g.NewV1() 165 if err == nil { 166 t.Errorf("did not error on faulty reader and missing network, got %v", u) 167 } 168 } 169 170 func testNewV3(t *testing.T) { 171 t.Run("Basic", testNewV3Basic) 172 t.Run("EqualNames", testNewV3EqualNames) 173 t.Run("DifferentNamespaces", testNewV3DifferentNamespaces) 174 } 175 176 func testNewV3Basic(t *testing.T) { 177 ns := NamespaceDNS 178 name := "www.example.com" 179 u := NewV3(ns, name) 180 if got, want := u.Version(), V3; got != want { 181 t.Errorf("NewV3(%v, %q): got version %d, want %d", ns, name, got, want) 182 } 183 if got, want := u.Variant(), VariantRFC4122; got != want { 184 t.Errorf("NewV3(%v, %q): got variant %d, want %d", ns, name, got, want) 185 } 186 want := "5df41881-3aed-3515-88a7-2f4a814cf09e" 187 if got := u.String(); got != want { 188 t.Errorf("NewV3(%v, %q) = %q, want %q", ns, name, got, want) 189 } 190 } 191 192 func testNewV3EqualNames(t *testing.T) { 193 for _, ns := range []UUID{ 194 NamespaceDNS, 195 NamespaceOID, 196 NamespaceURL, 197 NamespaceX500, 198 } { 199 name := "example.com" 200 u1 := NewV3(ns, name) 201 u2 := NewV3(ns, name) 202 if u1 != u2 { 203 t.Errorf("NewV3(%v, %q) generated %v and %v across two calls", ns, name, u1, u2) 204 } 205 } 206 } 207 208 func testNewV3DifferentNamespaces(t *testing.T) { 209 name := "example.com" 210 ns1 := NamespaceDNS 211 ns2 := NamespaceURL 212 u1 := NewV3(ns1, name) 213 u2 := NewV3(ns2, name) 214 if u1 == u2 { 215 t.Errorf("NewV3(%v, %q) == NewV3(%d, %q) (%v)", ns1, name, ns2, name, u1) 216 } 217 } 218 219 func testNewV4(t *testing.T) { 220 t.Run("Basic", testNewV4Basic) 221 t.Run("DifferentAcrossCalls", testNewV4DifferentAcrossCalls) 222 t.Run("FaultyRand", testNewV4FaultyRand) 223 t.Run("ShortRandomRead", testNewV4ShortRandomRead) 224 } 225 226 func testNewV4Basic(t *testing.T) { 227 u, err := NewV4() 228 if err != nil { 229 t.Fatal(err) 230 } 231 if got, want := u.Version(), V4; got != want { 232 t.Errorf("got version %d, want %d", got, want) 233 } 234 if got, want := u.Variant(), VariantRFC4122; got != want { 235 t.Errorf("got variant %d, want %d", got, want) 236 } 237 } 238 239 func testNewV4DifferentAcrossCalls(t *testing.T) { 240 u1, err := NewV4() 241 if err != nil { 242 t.Fatal(err) 243 } 244 u2, err := NewV4() 245 if err != nil { 246 t.Fatal(err) 247 } 248 if u1 == u2 { 249 t.Errorf("generated identical UUIDs across calls: %v", u1) 250 } 251 } 252 253 func testNewV4FaultyRand(t *testing.T) { 254 g := &Gen{ 255 epochFunc: time.Now, 256 hwAddrFunc: defaultHWAddrFunc, 257 rand: &faultyReader{ 258 readToFail: 0, // fail immediately 259 }, 260 } 261 u, err := g.NewV4() 262 if err == nil { 263 t.Errorf("got %v, nil error", u) 264 } 265 } 266 267 func testNewV4ShortRandomRead(t *testing.T) { 268 g := &Gen{ 269 epochFunc: time.Now, 270 hwAddrFunc: func() (net.HardwareAddr, error) { 271 return []byte{}, fmt.Errorf("uuid: no hw address found") 272 }, 273 rand: bytes.NewReader([]byte{42}), 274 } 275 u, err := g.NewV4() 276 if err == nil { 277 t.Errorf("got %v, nil error", u) 278 } 279 } 280 281 func testNewV5(t *testing.T) { 282 t.Run("Basic", testNewV5Basic) 283 t.Run("EqualNames", testNewV5EqualNames) 284 t.Run("DifferentNamespaces", testNewV5DifferentNamespaces) 285 } 286 287 func testNewV5Basic(t *testing.T) { 288 ns := NamespaceDNS 289 name := "www.example.com" 290 u := NewV5(ns, name) 291 if got, want := u.Version(), V5; got != want { 292 t.Errorf("NewV5(%v, %q): got version %d, want %d", ns, name, got, want) 293 } 294 if got, want := u.Variant(), VariantRFC4122; got != want { 295 t.Errorf("NewV5(%v, %q): got variant %d, want %d", ns, name, got, want) 296 } 297 want := "2ed6657d-e927-568b-95e1-2665a8aea6a2" 298 if got := u.String(); got != want { 299 t.Errorf("NewV5(%v, %q) = %q, want %q", ns, name, got, want) 300 } 301 } 302 303 func testNewV5EqualNames(t *testing.T) { 304 ns := NamespaceDNS 305 name := "example.com" 306 u1 := NewV5(ns, name) 307 u2 := NewV5(ns, name) 308 if u1 != u2 { 309 t.Errorf("NewV5(%v, %q) generated %v and %v across two calls", ns, name, u1, u2) 310 } 311 } 312 313 func testNewV5DifferentNamespaces(t *testing.T) { 314 name := "example.com" 315 ns1 := NamespaceDNS 316 ns2 := NamespaceURL 317 u1 := NewV5(ns1, name) 318 u2 := NewV5(ns2, name) 319 if u1 == u2 { 320 t.Errorf("NewV5(%v, %q) == NewV5(%v, %q) (%v)", ns1, name, ns2, name, u1) 321 } 322 } 323 324 func BenchmarkGenerator(b *testing.B) { 325 b.Run("NewV1", func(b *testing.B) { 326 for i := 0; i < b.N; i++ { 327 Must(NewV1()) 328 } 329 }) 330 b.Run("NewV3", func(b *testing.B) { 331 for i := 0; i < b.N; i++ { 332 NewV3(NamespaceDNS, "www.example.com") 333 } 334 }) 335 b.Run("NewV4", func(b *testing.B) { 336 for i := 0; i < b.N; i++ { 337 Must(NewV4()) 338 } 339 }) 340 b.Run("NewV5", func(b *testing.B) { 341 for i := 0; i < b.N; i++ { 342 NewV5(NamespaceDNS, "www.example.com") 343 } 344 }) 345 } 346 347 type faultyReader struct { 348 callsNum int 349 readToFail int // Read call number to fail 350 } 351 352 func (r *faultyReader) Read(dest []byte) (int, error) { 353 r.callsNum++ 354 if (r.callsNum - 1) == r.readToFail { 355 return 0, fmt.Errorf("io: reader is faulty") 356 } 357 return rand.Read(dest) 358 }