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  }