1
0
mirror of https://github.com/google/uuid.git synced 2025-07-05 00:58:42 +02:00

Fix govet issues and make node.go thread safe.

Includes changes from mischief and shawnps.
This commit is contained in:
Paul Borman
2016-02-09 09:58:31 -08:00
parent ae80070655
commit 6cc520cd8b
4 changed files with 110 additions and 53 deletions

20
node.go
View File

@ -4,9 +4,13 @@
package uuid package uuid
import "net" import (
"net"
"sync"
)
var ( var (
nodeMu sync.Mutex
interfaces []net.Interface // cached list of interfaces interfaces []net.Interface // cached list of interfaces
ifname string // name of interface being used ifname string // name of interface being used
nodeID []byte // hardware for version 1 UUIDs nodeID []byte // hardware for version 1 UUIDs
@ -16,6 +20,8 @@ var (
// derived. The interface "user" is returned if the NodeID was set by // derived. The interface "user" is returned if the NodeID was set by
// SetNodeID. // SetNodeID.
func NodeInterface() string { func NodeInterface() string {
defer nodeMu.Unlock()
nodeMu.Lock()
return ifname return ifname
} }
@ -26,6 +32,12 @@ func NodeInterface() string {
// //
// SetNodeInterface never fails when name is "". // SetNodeInterface never fails when name is "".
func SetNodeInterface(name string) bool { func SetNodeInterface(name string) bool {
defer nodeMu.Unlock()
nodeMu.Lock()
return setNodeInterface(name)
}
func setNodeInterface(name string) bool {
if interfaces == nil { if interfaces == nil {
var err error var err error
interfaces, err = net.Interfaces() interfaces, err = net.Interfaces()
@ -59,8 +71,10 @@ func SetNodeInterface(name string) bool {
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID // NodeID returns a slice of a copy of the current Node ID, setting the Node ID
// if not already set. // if not already set.
func NodeID() []byte { func NodeID() []byte {
defer nodeMu.Unlock()
nodeMu.Lock()
if nodeID == nil { if nodeID == nil {
SetNodeInterface("") setNodeInterface("")
} }
nid := make([]byte, 6) nid := make([]byte, 6)
copy(nid, nodeID) copy(nid, nodeID)
@ -71,6 +85,8 @@ func NodeID() []byte {
// of id are used. If id is less than 6 bytes then false is returned and the // of id are used. If id is less than 6 bytes then false is returned and the
// Node ID is not set. // Node ID is not set.
func SetNodeID(id []byte) bool { func SetNodeID(id []byte) bool {
defer nodeMu.Unlock()
nodeMu.Lock()
if setNodeID(id) { if setNodeID(id) {
ifname = "user" ifname = "user"
return true return true

14
time.go
View File

@ -23,7 +23,7 @@ const (
) )
var ( var (
mu sync.Mutex timeMu sync.Mutex
lasttime uint64 // last time we returned lasttime uint64 // last time we returned
clock_seq uint16 // clock sequence for this run clock_seq uint16 // clock sequence for this run
@ -43,8 +43,8 @@ func (t Time) UnixTime() (sec, nsec int64) {
// clock sequence as well as adjusting the clock sequence as needed. An error // clock sequence as well as adjusting the clock sequence as needed. An error
// is returned if the current time cannot be determined. // is returned if the current time cannot be determined.
func GetTime() (Time, uint16, error) { func GetTime() (Time, uint16, error) {
defer mu.Unlock() defer timeMu.Unlock()
mu.Lock() timeMu.Lock()
return getTime() return getTime()
} }
@ -75,8 +75,8 @@ func getTime() (Time, uint16, error) {
// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated // ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated
// for // for
func ClockSequence() int { func ClockSequence() int {
defer mu.Unlock() defer timeMu.Unlock()
mu.Lock() timeMu.Lock()
return clockSequence() return clockSequence()
} }
@ -90,8 +90,8 @@ func clockSequence() int {
// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to // SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to
// -1 causes a new sequence to be generated. // -1 causes a new sequence to be generated.
func SetClockSequence(seq int) { func SetClockSequence(seq int) {
defer mu.Unlock() defer timeMu.Unlock()
mu.Lock() timeMu.Lock()
setClockSequence(seq) setClockSequence(seq)
} }

View File

@ -113,7 +113,6 @@ func (uuid UUID) Variant() Variant {
default: default:
return Reserved return Reserved
} }
panic("unreachable")
} }
// Version returns the version of uuid. It returns false if uuid is not // Version returns the version of uuid. It returns false if uuid is not

View File

@ -112,7 +112,7 @@ func TestConstants(t *testing.T) {
t.Errorf("%x: %v: not a stringer", x, v) t.Errorf("%x: %v: not a stringer", x, v)
} else if s := v.String(); s != tt.name { } else if s := v.String(); s != tt.name {
v, _ := tt.c.(int) v, _ := tt.c.(int)
t.Errorf("%x: Constant %T:%d gives %q, expected %q\n", x, tt.c, v, s, tt.name) t.Errorf("%x: Constant %T:%d gives %q, expected %q", x, tt.c, v, s, tt.name)
} }
} }
} }
@ -123,14 +123,14 @@ func TestRandomUUID(t *testing.T) {
uuid := NewRandom() uuid := NewRandom()
s := uuid.String() s := uuid.String()
if m[s] { if m[s] {
t.Errorf("NewRandom returned duplicated UUID %s\n", s) t.Errorf("NewRandom returned duplicated UUID %s", s)
} }
m[s] = true m[s] = true
if v, _ := uuid.Version(); v != 4 { if v, _ := uuid.Version(); v != 4 {
t.Errorf("Random UUID of version %s\n", v) t.Errorf("Random UUID of version %s", v)
} }
if uuid.Variant() != RFC4122 { if uuid.Variant() != RFC4122 {
t.Errorf("Random UUID is variant %d\n", uuid.Variant()) t.Errorf("Random UUID is variant %d", uuid.Variant())
} }
} }
} }
@ -140,19 +140,19 @@ func TestNew(t *testing.T) {
for x := 1; x < 32; x++ { for x := 1; x < 32; x++ {
s := New() s := New()
if m[s] { if m[s] {
t.Errorf("New returned duplicated UUID %s\n", s) t.Errorf("New returned duplicated UUID %s", s)
} }
m[s] = true m[s] = true
uuid := Parse(s) uuid := Parse(s)
if uuid == nil { if uuid == nil {
t.Errorf("New returned %q which does not decode\n", s) t.Errorf("New returned %q which does not decode", s)
continue continue
} }
if v, _ := uuid.Version(); v != 4 { if v, _ := uuid.Version(); v != 4 {
t.Errorf("Random UUID of version %s\n", v) t.Errorf("Random UUID of version %s", v)
} }
if uuid.Variant() != RFC4122 { if uuid.Variant() != RFC4122 {
t.Errorf("Random UUID is variant %d\n", uuid.Variant()) t.Errorf("Random UUID is variant %d", uuid.Variant())
} }
} }
} }
@ -160,7 +160,7 @@ func TestNew(t *testing.T) {
func clockSeq(t *testing.T, uuid UUID) int { func clockSeq(t *testing.T, uuid UUID) int {
seq, ok := uuid.ClockSequence() seq, ok := uuid.ClockSequence()
if !ok { if !ok {
t.Fatalf("%s: invalid clock sequence\n", uuid) t.Fatalf("%s: invalid clock sequence", uuid)
} }
return seq return seq
} }
@ -179,7 +179,7 @@ func TestClockSeq(t *testing.T) {
uuid2 := NewUUID() uuid2 := NewUUID()
if clockSeq(t, uuid1) != clockSeq(t, uuid2) { if clockSeq(t, uuid1) != clockSeq(t, uuid2) {
t.Errorf("clock sequence %d != %d\n", clockSeq(t, uuid1), clockSeq(t, uuid2)) t.Errorf("clock sequence %d != %d", clockSeq(t, uuid1), clockSeq(t, uuid2))
} }
SetClockSequence(-1) SetClockSequence(-1)
@ -192,13 +192,13 @@ func TestClockSeq(t *testing.T) {
uuid2 = NewUUID() uuid2 = NewUUID()
} }
if clockSeq(t, uuid1) == clockSeq(t, uuid2) { if clockSeq(t, uuid1) == clockSeq(t, uuid2) {
t.Errorf("Duplicate clock sequence %d\n", clockSeq(t, uuid1)) t.Errorf("Duplicate clock sequence %d", clockSeq(t, uuid1))
} }
SetClockSequence(0x1234) SetClockSequence(0x1234)
uuid1 = NewUUID() uuid1 = NewUUID()
if seq := clockSeq(t, uuid1); seq != 0x1234 { if seq := clockSeq(t, uuid1); seq != 0x1234 {
t.Errorf("%s: expected seq 0x1234 got 0x%04x\n", uuid1, seq) t.Errorf("%s: expected seq 0x1234 got 0x%04x", uuid1, seq)
} }
} }
@ -213,15 +213,15 @@ func TestCoding(t *testing.T) {
0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2,
} }
if v := data.String(); v != text { if v := data.String(); v != text {
t.Errorf("%x: encoded to %s, expected %s\n", data, v, text) t.Errorf("%x: encoded to %s, expected %s", data, v, text)
} }
if v := data.URN(); v != urn { if v := data.URN(); v != urn {
t.Errorf("%x: urn is %s, expected %s\n", data, v, urn) t.Errorf("%x: urn is %s, expected %s", data, v, urn)
} }
uuid := Parse(text) uuid := Parse(text)
if !Equal(uuid, data) { if !Equal(uuid, data) {
t.Errorf("%s: decoded to %s, expected %s\n", text, uuid, data) t.Errorf("%s: decoded to %s, expected %s", text, uuid, data)
} }
} }
@ -230,30 +230,30 @@ func TestVersion1(t *testing.T) {
uuid2 := NewUUID() uuid2 := NewUUID()
if Equal(uuid1, uuid2) { if Equal(uuid1, uuid2) {
t.Errorf("%s:duplicate uuid\n", uuid1) t.Errorf("%s:duplicate uuid", uuid1)
} }
if v, _ := uuid1.Version(); v != 1 { if v, _ := uuid1.Version(); v != 1 {
t.Errorf("%s: version %s expected 1\n", uuid1, v) t.Errorf("%s: version %s expected 1", uuid1, v)
} }
if v, _ := uuid2.Version(); v != 1 { if v, _ := uuid2.Version(); v != 1 {
t.Errorf("%s: version %s expected 1\n", uuid2, v) t.Errorf("%s: version %s expected 1", uuid2, v)
} }
n1 := uuid1.NodeID() n1 := uuid1.NodeID()
n2 := uuid2.NodeID() n2 := uuid2.NodeID()
if !bytes.Equal(n1, n2) { if !bytes.Equal(n1, n2) {
t.Errorf("Different nodes %x != %x\n", n1, n2) t.Errorf("Different nodes %x != %x", n1, n2)
} }
t1, ok := uuid1.Time() t1, ok := uuid1.Time()
if !ok { if !ok {
t.Errorf("%s: invalid time\n", uuid1) t.Errorf("%s: invalid time", uuid1)
} }
t2, ok := uuid2.Time() t2, ok := uuid2.Time()
if !ok { if !ok {
t.Errorf("%s: invalid time\n", uuid2) t.Errorf("%s: invalid time", uuid2)
} }
q1, ok := uuid1.ClockSequence() q1, ok := uuid1.ClockSequence()
if !ok { if !ok {
t.Errorf("%s: invalid clock sequence\n", uuid1) t.Errorf("%s: invalid clock sequence", uuid1)
} }
q2, ok := uuid2.ClockSequence() q2, ok := uuid2.ClockSequence()
if !ok { if !ok {
@ -262,11 +262,53 @@ func TestVersion1(t *testing.T) {
switch { switch {
case t1 == t2 && q1 == q2: case t1 == t2 && q1 == q2:
t.Errorf("time stopped\n") t.Error("time stopped")
case t1 > t2 && q1 == q2: case t1 > t2 && q1 == q2:
t.Errorf("time reversed\n") t.Error("time reversed")
case t1 < t2 && q1 != q2: case t1 < t2 && q1 != q2:
t.Errorf("clock sequence chaned unexpectedly\n") t.Error("clock sequence chaned unexpectedly")
}
}
func TestNode(t *testing.T) {
// This test is mostly to make sure we don't leave nodeMu locked.
ifname = ""
if ni := NodeInterface(); ni != "" {
t.Errorf("NodeInterface got %q, want %q", ni, "")
}
if SetNodeInterface("xyzzy") {
t.Error("SetNodeInterface succeeded on a bad interface name")
}
if !SetNodeInterface("") {
t.Error("SetNodeInterface failed")
}
if ni := NodeInterface(); ni == "" {
t.Error("NodeInterface returned an empty string")
}
ni := NodeID()
if len(ni) != 6 {
t.Errorf("ni got %d bytes, want 6", len(ni))
}
hasData := false
for _, b := range ni {
if b != 0 {
hasData = true
}
}
if !hasData {
t.Error("nodeid is all zeros")
}
id := []byte{1,2,3,4,5,6,7,8}
SetNodeID(id)
ni = NodeID()
if !bytes.Equal(ni, id[:6]) {
t.Errorf("got nodeid %v, want %v", ni, id[:6])
}
if ni := NodeInterface(); ni != "user" {
t.Errorf("got inteface %q, want %q", ni, "user")
} }
} }
@ -284,10 +326,10 @@ func TestNodeAndTime(t *testing.T) {
t.Errorf("Got time %v, want %v", c, want) t.Errorf("Got time %v, want %v", c, want)
} }
} else { } else {
t.Errorf("%s: bad time\n", uuid) t.Errorf("%s: bad time", uuid)
} }
if !bytes.Equal(node, uuid.NodeID()) { if !bytes.Equal(node, uuid.NodeID()) {
t.Errorf("Expected node %v got %v\n", node, uuid.NodeID()) t.Errorf("Expected node %v got %v", node, uuid.NodeID())
} }
} }
@ -295,7 +337,7 @@ func TestMD5(t *testing.T) {
uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String() uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String()
want := "6fa459ea-ee8a-3ca4-894e-db77e160355e" want := "6fa459ea-ee8a-3ca4-894e-db77e160355e"
if uuid != want { if uuid != want {
t.Errorf("MD5: got %q expected %q\n", uuid, want) t.Errorf("MD5: got %q expected %q", uuid, want)
} }
} }
@ -303,7 +345,7 @@ func TestSHA1(t *testing.T) {
uuid := NewSHA1(NameSpace_DNS, []byte("python.org")).String() uuid := NewSHA1(NameSpace_DNS, []byte("python.org")).String()
want := "886313e1-3b8a-5372-9b90-0c9aee199e5d" want := "886313e1-3b8a-5372-9b90-0c9aee199e5d"
if uuid != want { if uuid != want {
t.Errorf("SHA1: got %q expected %q\n", uuid, want) t.Errorf("SHA1: got %q expected %q", uuid, want)
} }
} }
@ -312,49 +354,49 @@ func TestNodeID(t *testing.T) {
SetNodeInterface("") SetNodeInterface("")
s := NodeInterface() s := NodeInterface()
if s == "" || s == "user" { if s == "" || s == "user" {
t.Errorf("NodeInterface %q after SetInteface\n", s) t.Errorf("NodeInterface %q after SetInteface", s)
} }
node1 := NodeID() node1 := NodeID()
if node1 == nil { if node1 == nil {
t.Errorf("NodeID nil after SetNodeInterface\n", s) t.Error("NodeID nil after SetNodeInterface", s)
} }
SetNodeID(nid) SetNodeID(nid)
s = NodeInterface() s = NodeInterface()
if s != "user" { if s != "user" {
t.Errorf("Expected NodeInterface %q got %q\n", "user", s) t.Errorf("Expected NodeInterface %q got %q", "user", s)
} }
node2 := NodeID() node2 := NodeID()
if node2 == nil { if node2 == nil {
t.Errorf("NodeID nil after SetNodeID\n", s) t.Error("NodeID nil after SetNodeID", s)
} }
if bytes.Equal(node1, node2) { if bytes.Equal(node1, node2) {
t.Errorf("NodeID not changed after SetNodeID\n", s) t.Error("NodeID not changed after SetNodeID", s)
} else if !bytes.Equal(nid, node2) { } else if !bytes.Equal(nid, node2) {
t.Errorf("NodeID is %x, expected %x\n", node2, nid) t.Errorf("NodeID is %x, expected %x", node2, nid)
} }
} }
func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) { func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) {
if uuid == nil { if uuid == nil {
t.Errorf("%s failed\n", name) t.Errorf("%s failed", name)
return return
} }
if v, _ := uuid.Version(); v != 2 { if v, _ := uuid.Version(); v != 2 {
t.Errorf("%s: %s: expected version 2, got %s\n", name, uuid, v) t.Errorf("%s: %s: expected version 2, got %s", name, uuid, v)
return return
} }
if v, ok := uuid.Domain(); !ok || v != domain { if v, ok := uuid.Domain(); !ok || v != domain {
if !ok { if !ok {
t.Errorf("%s: %d: Domain failed\n", name, uuid) t.Errorf("%s: %d: Domain failed", name, uuid)
} else { } else {
t.Errorf("%s: %s: expected domain %d, got %d\n", name, uuid, domain, v) t.Errorf("%s: %s: expected domain %d, got %d", name, uuid, domain, v)
} }
} }
if v, ok := uuid.Id(); !ok || v != id { if v, ok := uuid.Id(); !ok || v != id {
if !ok { if !ok {
t.Errorf("%s: %d: Id failed\n", name, uuid) t.Errorf("%s: %d: Id failed", name, uuid)
} else { } else {
t.Errorf("%s: %s: expected id %d, got %d\n", name, uuid, id, v) t.Errorf("%s: %s: expected id %d, got %d", name, uuid, id, v)
} }
} }
} }
@ -379,12 +421,12 @@ func TestBadRand(t *testing.T) {
uuid1 := New() uuid1 := New()
uuid2 := New() uuid2 := New()
if uuid1 != uuid2 { if uuid1 != uuid2 {
t.Errorf("execpted duplicates, got %q and %q\n", uuid1, uuid2) t.Errorf("execpted duplicates, got %q and %q", uuid1, uuid2)
} }
SetRand(nil) SetRand(nil)
uuid1 = New() uuid1 = New()
uuid2 = New() uuid2 = New()
if uuid1 == uuid2 { if uuid1 == uuid2 {
t.Errorf("unexecpted duplicates, got %q\n", uuid1) t.Errorf("unexecpted duplicates, got %q", uuid1)
} }
} }