1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package uuid
23
24 import (
25 "bytes"
26 "crypto/rand"
27 "encoding/binary"
28 "errors"
29 "fmt"
30 "net"
31 "strings"
32 "testing"
33 "time"
34 )
35
36 func TestGenerator(t *testing.T) {
37 t.Run("NewV1", testNewV1)
38 t.Run("NewV3", testNewV3)
39 t.Run("NewV4", testNewV4)
40 t.Run("NewV5", testNewV5)
41 t.Run("NewV6", testNewV6)
42 t.Run("NewV7", testNewV7)
43 }
44
45 func testNewV1(t *testing.T) {
46 t.Run("Basic", testNewV1Basic)
47 t.Run("DifferentAcrossCalls", testNewV1DifferentAcrossCalls)
48 t.Run("StaleEpoch", testNewV1StaleEpoch)
49 t.Run("FaultyRand", testNewV1FaultyRand)
50 t.Run("MissingNetwork", testNewV1MissingNetwork)
51 t.Run("MissingNetworkFaultyRand", testNewV1MissingNetworkFaultyRand)
52 }
53
54 func TestNewGenWithHWAF(t *testing.T) {
55 addr := []byte{0, 1, 2, 3, 4, 42}
56
57 fn := func() (net.HardwareAddr, error) {
58 return addr, nil
59 }
60
61 var g *Gen
62 var err error
63 var uuid UUID
64
65 g = NewGenWithHWAF(fn)
66
67 if g == nil {
68 t.Fatal("g is unexpectedly nil")
69 }
70
71 uuid, err = g.NewV1()
72 if err != nil {
73 t.Fatalf("g.NewV1() err = %v, want <nil>", err)
74 }
75
76 node := uuid[10:]
77
78 if !bytes.Equal(addr, node) {
79 t.Fatalf("node = %v, want %v", node, addr)
80 }
81 }
82
83 func testNewV1Basic(t *testing.T) {
84 u, err := NewV1()
85 if err != nil {
86 t.Fatal(err)
87 }
88 if got, want := u.Version(), V1; got != want {
89 t.Errorf("generated UUID with version %d, want %d", got, want)
90 }
91 if got, want := u.Variant(), VariantRFC4122; got != want {
92 t.Errorf("generated UUID with variant %d, want %d", got, want)
93 }
94 }
95
96 func testNewV1DifferentAcrossCalls(t *testing.T) {
97 u1, err := NewV1()
98 if err != nil {
99 t.Fatal(err)
100 }
101 u2, err := NewV1()
102 if err != nil {
103 t.Fatal(err)
104 }
105 if u1 == u2 {
106 t.Errorf("generated identical UUIDs across calls: %v", u1)
107 }
108 }
109
110 func testNewV1StaleEpoch(t *testing.T) {
111 g := &Gen{
112 epochFunc: func() time.Time {
113 return time.Unix(0, 0)
114 },
115 hwAddrFunc: defaultHWAddrFunc,
116 rand: rand.Reader,
117 }
118 u1, err := g.NewV1()
119 if err != nil {
120 t.Fatal(err)
121 }
122 u2, err := g.NewV1()
123 if err != nil {
124 t.Fatal(err)
125 }
126 if u1 == u2 {
127 t.Errorf("generated identical UUIDs across calls: %v", u1)
128 }
129 }
130
131 func testNewV1FaultyRand(t *testing.T) {
132 g := &Gen{
133 epochFunc: time.Now,
134 hwAddrFunc: defaultHWAddrFunc,
135 rand: &faultyReader{
136 readToFail: 0,
137 },
138 }
139 u, err := g.NewV1()
140 if err == nil {
141 t.Fatalf("got %v, want error", u)
142 }
143 if u != Nil {
144 t.Fatalf("got %v on error, want Nil", u)
145 }
146 }
147
148 func testNewV1MissingNetwork(t *testing.T) {
149 g := &Gen{
150 epochFunc: time.Now,
151 hwAddrFunc: func() (net.HardwareAddr, error) {
152 return []byte{}, fmt.Errorf("uuid: no hw address found")
153 },
154 rand: rand.Reader,
155 }
156 _, err := g.NewV1()
157 if err != nil {
158 t.Errorf("did not handle missing network interfaces: %v", err)
159 }
160 }
161
162 func testNewV1MissingNetworkFaultyRand(t *testing.T) {
163 g := &Gen{
164 epochFunc: time.Now,
165 hwAddrFunc: func() (net.HardwareAddr, error) {
166 return []byte{}, fmt.Errorf("uuid: no hw address found")
167 },
168 rand: &faultyReader{
169 readToFail: 1,
170 },
171 }
172 u, err := g.NewV1()
173 if err == nil {
174 t.Errorf("did not error on faulty reader and missing network, got %v", u)
175 }
176 }
177
178 func testNewV3(t *testing.T) {
179 t.Run("Basic", testNewV3Basic)
180 t.Run("EqualNames", testNewV3EqualNames)
181 t.Run("DifferentNamespaces", testNewV3DifferentNamespaces)
182 }
183
184 func testNewV3Basic(t *testing.T) {
185 ns := NamespaceDNS
186 name := "www.example.com"
187 u := NewV3(ns, name)
188 if got, want := u.Version(), V3; got != want {
189 t.Errorf("NewV3(%v, %q): got version %d, want %d", ns, name, got, want)
190 }
191 if got, want := u.Variant(), VariantRFC4122; got != want {
192 t.Errorf("NewV3(%v, %q): got variant %d, want %d", ns, name, got, want)
193 }
194 want := "5df41881-3aed-3515-88a7-2f4a814cf09e"
195 if got := u.String(); got != want {
196 t.Errorf("NewV3(%v, %q) = %q, want %q", ns, name, got, want)
197 }
198 }
199
200 func testNewV3EqualNames(t *testing.T) {
201 ns := NamespaceDNS
202 name := "example.com"
203 u1 := NewV3(ns, name)
204 u2 := NewV3(ns, name)
205 if u1 != u2 {
206 t.Errorf("NewV3(%v, %q) generated %v and %v across two calls", ns, name, u1, u2)
207 }
208 }
209
210 func testNewV3DifferentNamespaces(t *testing.T) {
211 name := "example.com"
212 ns1 := NamespaceDNS
213 ns2 := NamespaceURL
214 u1 := NewV3(ns1, name)
215 u2 := NewV3(ns2, name)
216 if u1 == u2 {
217 t.Errorf("NewV3(%v, %q) == NewV3(%d, %q) (%v)", ns1, name, ns2, name, u1)
218 }
219 }
220
221 func testNewV4(t *testing.T) {
222 t.Run("Basic", testNewV4Basic)
223 t.Run("DifferentAcrossCalls", testNewV4DifferentAcrossCalls)
224 t.Run("FaultyRand", testNewV4FaultyRand)
225 t.Run("ShortRandomRead", testNewV4ShortRandomRead)
226 }
227
228 func testNewV4Basic(t *testing.T) {
229 u, err := NewV4()
230 if err != nil {
231 t.Fatal(err)
232 }
233 if got, want := u.Version(), V4; got != want {
234 t.Errorf("got version %d, want %d", got, want)
235 }
236 if got, want := u.Variant(), VariantRFC4122; got != want {
237 t.Errorf("got variant %d, want %d", got, want)
238 }
239 }
240
241 func testNewV4DifferentAcrossCalls(t *testing.T) {
242 u1, err := NewV4()
243 if err != nil {
244 t.Fatal(err)
245 }
246 u2, err := NewV4()
247 if err != nil {
248 t.Fatal(err)
249 }
250 if u1 == u2 {
251 t.Errorf("generated identical UUIDs across calls: %v", u1)
252 }
253 }
254
255 func testNewV4FaultyRand(t *testing.T) {
256 g := &Gen{
257 epochFunc: time.Now,
258 hwAddrFunc: defaultHWAddrFunc,
259 rand: &faultyReader{
260 readToFail: 0,
261 },
262 }
263 u, err := g.NewV4()
264 if err == nil {
265 t.Errorf("got %v, nil error", u)
266 }
267 }
268
269 func testNewV4ShortRandomRead(t *testing.T) {
270 g := &Gen{
271 epochFunc: time.Now,
272 hwAddrFunc: func() (net.HardwareAddr, error) {
273 return []byte{}, fmt.Errorf("uuid: no hw address found")
274 },
275 rand: bytes.NewReader([]byte{42}),
276 }
277 u, err := g.NewV4()
278 if err == nil {
279 t.Errorf("got %v, nil error", u)
280 }
281 }
282
283 func testNewV5(t *testing.T) {
284 t.Run("Basic", testNewV5Basic)
285 t.Run("EqualNames", testNewV5EqualNames)
286 t.Run("DifferentNamespaces", testNewV5DifferentNamespaces)
287 }
288
289 func testNewV5Basic(t *testing.T) {
290 ns := NamespaceDNS
291 name := "www.example.com"
292 u := NewV5(ns, name)
293 if got, want := u.Version(), V5; got != want {
294 t.Errorf("NewV5(%v, %q): got version %d, want %d", ns, name, got, want)
295 }
296 if got, want := u.Variant(), VariantRFC4122; got != want {
297 t.Errorf("NewV5(%v, %q): got variant %d, want %d", ns, name, got, want)
298 }
299 want := "2ed6657d-e927-568b-95e1-2665a8aea6a2"
300 if got := u.String(); got != want {
301 t.Errorf("NewV5(%v, %q) = %q, want %q", ns, name, got, want)
302 }
303 }
304
305 func testNewV5EqualNames(t *testing.T) {
306 ns := NamespaceDNS
307 name := "example.com"
308 u1 := NewV5(ns, name)
309 u2 := NewV5(ns, name)
310 if u1 != u2 {
311 t.Errorf("NewV5(%v, %q) generated %v and %v across two calls", ns, name, u1, u2)
312 }
313 }
314
315 func testNewV5DifferentNamespaces(t *testing.T) {
316 name := "example.com"
317 ns1 := NamespaceDNS
318 ns2 := NamespaceURL
319 u1 := NewV5(ns1, name)
320 u2 := NewV5(ns2, name)
321 if u1 == u2 {
322 t.Errorf("NewV5(%v, %q) == NewV5(%v, %q) (%v)", ns1, name, ns2, name, u1)
323 }
324 }
325
326 func testNewV6(t *testing.T) {
327 t.Run("Basic", testNewV6Basic)
328 t.Run("DifferentAcrossCalls", testNewV6DifferentAcrossCalls)
329 t.Run("StaleEpoch", testNewV6StaleEpoch)
330 t.Run("FaultyRand", testNewV6FaultyRand)
331 t.Run("ShortRandomRead", testNewV6ShortRandomRead)
332 t.Run("KSortable", testNewV6KSortable)
333 }
334
335 func testNewV6Basic(t *testing.T) {
336 u, err := NewV6()
337 if err != nil {
338 t.Fatal(err)
339 }
340 if got, want := u.Version(), V6; got != want {
341 t.Errorf("generated UUID with version %d, want %d", got, want)
342 }
343 if got, want := u.Variant(), VariantRFC4122; got != want {
344 t.Errorf("generated UUID with variant %d, want %d", got, want)
345 }
346 }
347
348 func testNewV6DifferentAcrossCalls(t *testing.T) {
349 u1, err := NewV6()
350 if err != nil {
351 t.Fatal(err)
352 }
353 u2, err := NewV6()
354 if err != nil {
355 t.Fatal(err)
356 }
357 if u1 == u2 {
358 t.Errorf("generated identical UUIDs across calls: %v", u1)
359 }
360 }
361
362 func testNewV6StaleEpoch(t *testing.T) {
363 g := &Gen{
364 epochFunc: func() time.Time {
365 return time.Unix(0, 0)
366 },
367 hwAddrFunc: defaultHWAddrFunc,
368 rand: rand.Reader,
369 }
370 u1, err := g.NewV6()
371 if err != nil {
372 t.Fatal(err)
373 }
374 u2, err := g.NewV6()
375 if err != nil {
376 t.Fatal(err)
377 }
378 if u1 == u2 {
379 t.Errorf("generated identical UUIDs across calls: %v", u1)
380 }
381 }
382
383 func testNewV6FaultyRand(t *testing.T) {
384 t.Run("randomData", func(t *testing.T) {
385 g := &Gen{
386 epochFunc: time.Now,
387 hwAddrFunc: defaultHWAddrFunc,
388 rand: &faultyReader{
389 readToFail: 0,
390 },
391 }
392 u, err := g.NewV6()
393 if err == nil {
394 t.Fatalf("got %v, want error", u)
395 }
396 if u != Nil {
397 t.Fatalf("got %v on error, want Nil", u)
398 }
399 })
400
401 t.Run("clockSequence", func(t *testing.T) {
402 g := &Gen{
403 epochFunc: time.Now,
404 hwAddrFunc: defaultHWAddrFunc,
405 rand: &faultyReader{
406 readToFail: 1,
407 },
408 }
409 u, err := g.NewV6()
410 if err == nil {
411 t.Fatalf("got %v, want error", u)
412 }
413 if u != Nil {
414 t.Fatalf("got %v on error, want Nil", u)
415 }
416 })
417 }
418
419 func testNewV6ShortRandomRead(t *testing.T) {
420 g := &Gen{
421 epochFunc: time.Now,
422 rand: bytes.NewReader([]byte{42}),
423 }
424 u, err := g.NewV6()
425 if err == nil {
426 t.Errorf("got %v, nil error", u)
427 }
428 }
429
430 func testNewV6KSortable(t *testing.T) {
431 uuids := make([]UUID, 10)
432 for i := range uuids {
433 u, err := NewV6()
434 testErrCheck(t, "NewV6()", "", err)
435
436 uuids[i] = u
437
438 time.Sleep(time.Microsecond)
439 }
440
441 for i := 1; i < len(uuids); i++ {
442 p, n := uuids[i-1], uuids[i]
443 isLess := p.String() < n.String()
444 if !isLess {
445 t.Errorf("uuids[%d] (%s) not less than uuids[%d] (%s)", i-1, p, i, n)
446 }
447 }
448 }
449
450 func testNewV7(t *testing.T) {
451 t.Run("Basic", makeTestNewV7Basic())
452 t.Run("Basic10000000", makeTestNewV7Basic10000000())
453 t.Run("DifferentAcrossCalls", makeTestNewV7DifferentAcrossCalls())
454 t.Run("StaleEpoch", makeTestNewV7StaleEpoch())
455 t.Run("FaultyRand", makeTestNewV7FaultyRand())
456 t.Run("ShortRandomRead", makeTestNewV7ShortRandomRead())
457 t.Run("KSortable", makeTestNewV7KSortable())
458 }
459
460 func makeTestNewV7Basic() func(t *testing.T) {
461 return func(t *testing.T) {
462 u, err := NewV7()
463 if err != nil {
464 t.Fatal(err)
465 }
466 if got, want := u.Version(), V7; got != want {
467 t.Errorf("got version %d, want %d", got, want)
468 }
469 if got, want := u.Variant(), VariantRFC4122; got != want {
470 t.Errorf("got variant %d, want %d", got, want)
471 }
472 }
473 }
474
475 func makeTestNewV7Basic10000000() func(t *testing.T) {
476 return func(t *testing.T) {
477 if testing.Short() {
478 t.Skip("skipping test in short mode.")
479 }
480
481 g := NewGen()
482
483 for i := 0; i < 10000000; i++ {
484 u, err := g.NewV7()
485 if err != nil {
486 t.Fatal(err)
487 }
488 if got, want := u.Version(), V7; got != want {
489 t.Errorf("got version %d, want %d", got, want)
490 }
491 if got, want := u.Variant(), VariantRFC4122; got != want {
492 t.Errorf("got variant %d, want %d", got, want)
493 }
494 }
495 }
496 }
497
498 func makeTestNewV7DifferentAcrossCalls() func(t *testing.T) {
499 return func(t *testing.T) {
500 g := NewGen()
501
502 u1, err := g.NewV7()
503 if err != nil {
504 t.Fatal(err)
505 }
506 u2, err := g.NewV7()
507 if err != nil {
508 t.Fatal(err)
509 }
510 if u1 == u2 {
511 t.Errorf("generated identical UUIDs across calls: %v", u1)
512 }
513 }
514 }
515
516 func makeTestNewV7StaleEpoch() func(t *testing.T) {
517 return func(t *testing.T) {
518 g := &Gen{
519 epochFunc: func() time.Time {
520 return time.Unix(0, 0)
521 },
522 rand: rand.Reader,
523 }
524 u1, err := g.NewV7()
525 if err != nil {
526 t.Fatal(err)
527 }
528 u2, err := g.NewV7()
529 if err != nil {
530 t.Fatal(err)
531 }
532 if u1 == u2 {
533 t.Errorf("generated identical UUIDs across calls: %v", u1)
534 }
535 }
536 }
537
538 func makeTestNewV7FaultyRand() func(t *testing.T) {
539 return func(t *testing.T) {
540 g := &Gen{
541 epochFunc: time.Now,
542 rand: &faultyReader{
543 readToFail: 0,
544 },
545 }
546 u, err := g.NewV7()
547 if err == nil {
548 t.Errorf("got %v, nil error", u)
549 }
550 }
551 }
552
553 func makeTestNewV7ShortRandomRead() func(t *testing.T) {
554 return func(t *testing.T) {
555 g := &Gen{
556 epochFunc: time.Now,
557 rand: bytes.NewReader([]byte{42}),
558 }
559 u, err := g.NewV7()
560 if err == nil {
561 t.Errorf("got %v, nil error", u)
562 }
563 }
564 }
565
566 func makeTestNewV7KSortable() func(t *testing.T) {
567 return func(t *testing.T) {
568 uuids := make([]UUID, 10)
569 for i := range uuids {
570 u, err := NewV7()
571 testErrCheck(t, "NewV7()", "", err)
572
573 uuids[i] = u
574 time.Sleep(time.Millisecond)
575 }
576
577 for i := 1; i < len(uuids); i++ {
578 p, n := uuids[i-1], uuids[i]
579 isLess := p.String() < n.String()
580 if !isLess {
581 t.Errorf("uuids[%d] (%s) not less than uuids[%d] (%s)", i-1, p, i, n)
582 }
583 }
584 }
585 }
586
587 func testNewV7ClockSequence(t *testing.T) {
588 if testing.Short() {
589 t.Skip("skipping test in short mode.")
590 }
591
592 g := NewGen()
593
594
595 nsec := time.Now().Nanosecond()
596 sleepDur := int(time.Second) - nsec
597 time.Sleep(time.Duration(sleepDur))
598
599 u1, err := g.NewV7()
600 if err != nil {
601 t.Fatalf("failed to generate V7 UUID #1: %v", err)
602 }
603
604 u2, err := g.NewV7()
605 if err != nil {
606 t.Fatalf("failed to generate V7 UUID #2: %v", err)
607 }
608
609 time.Sleep(time.Millisecond)
610
611 u3, err := g.NewV7()
612 if err != nil {
613 t.Fatalf("failed to generate V7 UUID #3: %v", err)
614 }
615
616 time.Sleep(time.Second)
617
618 u4, err := g.NewV7()
619 if err != nil {
620 t.Fatalf("failed to generate V7 UUID #3: %v", err)
621 }
622
623 s1 := binary.BigEndian.Uint16(u1[6:8]) & 0xfff
624 s2 := binary.BigEndian.Uint16(u2[6:8]) & 0xfff
625 s3 := binary.BigEndian.Uint16(u3[6:8]) & 0xfff
626 s4 := binary.BigEndian.Uint16(u4[6:8]) & 0xfff
627
628 if s1 != 0 {
629 t.Errorf("sequence 1 should be zero, was %d", s1)
630 }
631
632 if s2 != s1+1 {
633 t.Errorf("sequence 2 expected to be one above sequence 1; seq 1: %d, seq 2: %d", s1, s2)
634 }
635
636 if s3 != 0 {
637 t.Errorf("sequence 3 should be zero, was %d", s3)
638 }
639
640 if s4 != 0 {
641 t.Errorf("sequence 4 should be zero, was %d", s4)
642 }
643 }
644
645 func TestDefaultHWAddrFunc(t *testing.T) {
646 tests := []struct {
647 n string
648 fn func() ([]net.Interface, error)
649 hw net.HardwareAddr
650 e string
651 }{
652 {
653 n: "Error",
654 fn: func() ([]net.Interface, error) {
655 return nil, errors.New("controlled failure")
656 },
657 e: "controlled failure",
658 },
659 {
660 n: "NoValidHWAddrReturned",
661 fn: func() ([]net.Interface, error) {
662 s := []net.Interface{
663 {
664 Index: 1,
665 MTU: 1500,
666 Name: "test0",
667 HardwareAddr: net.HardwareAddr{1, 2, 3, 4},
668 },
669 {
670 Index: 2,
671 MTU: 1500,
672 Name: "lo0",
673 HardwareAddr: net.HardwareAddr{5, 6, 7, 8},
674 },
675 }
676
677 return s, nil
678 },
679 e: "uuid: no HW address found",
680 },
681 {
682 n: "ValidHWAddrReturned",
683 fn: func() ([]net.Interface, error) {
684 s := []net.Interface{
685 {
686 Index: 1,
687 MTU: 1500,
688 Name: "test0",
689 HardwareAddr: net.HardwareAddr{1, 2, 3, 4},
690 },
691 {
692 Index: 2,
693 MTU: 1500,
694 Name: "lo0",
695 HardwareAddr: net.HardwareAddr{5, 6, 7, 8, 9, 0},
696 },
697 }
698
699 return s, nil
700 },
701 hw: net.HardwareAddr{5, 6, 7, 8, 9, 0},
702 },
703 }
704
705 for _, tt := range tests {
706 t.Run(tt.n, func(t *testing.T) {
707
708
709 netInterfaces = tt.fn
710 defer func() {
711 netInterfaces = net.Interfaces
712 }()
713
714 var hw net.HardwareAddr
715 var err error
716
717 hw, err = defaultHWAddrFunc()
718
719 if len(tt.e) > 0 {
720 if err == nil {
721 t.Fatalf("defaultHWAddrFunc() error = <nil>, should contain %q", tt.e)
722 }
723
724 if !strings.Contains(err.Error(), tt.e) {
725 t.Fatalf("defaultHWAddrFunc() error = %q, should contain %q", err.Error(), tt.e)
726 }
727
728 return
729 }
730
731 if err != nil && tt.e == "" {
732 t.Fatalf("defaultHWAddrFunc() error = %q, want <nil>", err.Error())
733 }
734
735 if !bytes.Equal(hw, tt.hw) {
736 t.Fatalf("hw = %#v, want %#v", hw, tt.hw)
737 }
738 })
739 }
740 }
741
742 func BenchmarkGenerator(b *testing.B) {
743 b.Run("NewV1", func(b *testing.B) {
744 for i := 0; i < b.N; i++ {
745 NewV1()
746 }
747 })
748 b.Run("NewV3", func(b *testing.B) {
749 for i := 0; i < b.N; i++ {
750 NewV3(NamespaceDNS, "www.example.com")
751 }
752 })
753 b.Run("NewV4", func(b *testing.B) {
754 for i := 0; i < b.N; i++ {
755 NewV4()
756 }
757 })
758 b.Run("NewV5", func(b *testing.B) {
759 for i := 0; i < b.N; i++ {
760 NewV5(NamespaceDNS, "www.example.com")
761 }
762 })
763 }
764
765 type faultyReader struct {
766 callsNum int
767 readToFail int
768 }
769
770 func (r *faultyReader) Read(dest []byte) (int, error) {
771 r.callsNum++
772 if (r.callsNum - 1) == r.readToFail {
773 return 0, fmt.Errorf("io: reader is faulty")
774 }
775 return rand.Read(dest)
776 }
777
778
779
780
781
782 func testErrCheck(t *testing.T, name string, errContains string, err error) bool {
783 t.Helper()
784
785 if len(errContains) > 0 {
786 if err == nil {
787 t.Fatalf("%s error = <nil>, should contain %q", name, errContains)
788 return false
789 }
790
791 if errStr := err.Error(); !strings.Contains(errStr, errContains) {
792 t.Fatalf("%s error = %q, should contain %q", name, errStr, errContains)
793 return false
794 }
795
796 return false
797 }
798
799 if err != nil && len(errContains) == 0 {
800 t.Fatalf("%s unexpected error: %v", name, err)
801 return false
802 }
803
804 return true
805 }
806
View as plain text