1// Copyright 2016 Google Inc.  All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package uuid
6
7import (
8	"flag"
9	"runtime"
10	"testing"
11	"time"
12)
13
14// This test is only run when --regressions is passed on the go test line.
15var regressions = flag.Bool("regressions", false, "run uuid regression tests")
16
17// TestClockSeqRace tests for a particular race condition of returning two
18// identical Version1 UUIDs.  The duration of 1 minute was chosen as the race
19// condition, before being fixed, nearly always occurred in under 30 seconds.
20func TestClockSeqRace(t *testing.T) {
21	if !*regressions {
22		t.Skip("skipping regression tests")
23	}
24	duration := time.Minute
25
26	done := make(chan struct{})
27	defer close(done)
28
29	ch := make(chan UUID, 10000)
30	ncpu := runtime.NumCPU()
31	switch ncpu {
32	case 0, 1:
33		// We can't run the test effectively.
34		t.Skip("skipping race test, only one CPU detected")
35		return
36	default:
37		runtime.GOMAXPROCS(ncpu)
38	}
39	for i := 0; i < ncpu; i++ {
40		go func() {
41			for {
42				select {
43				case <-done:
44					return
45				case ch <- Must(NewUUID()):
46				}
47			}
48		}()
49	}
50
51	uuids := make(map[string]bool)
52	cnt := 0
53	start := time.Now()
54	for u := range ch {
55		s := u.String()
56		if uuids[s] {
57			t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s)
58			return
59		}
60		uuids[s] = true
61		if time.Since(start) > duration {
62			return
63		}
64		cnt++
65	}
66}
67