1

I'm doing some testing and it would be useful to have a known set of UUIDs that are getting used by our code. However, I'm having trouble figuring out how to create a deterministic set of UUIDs in golang.

I've tried a few approaches, but neither seemed to work:


type KnownReader struct {
    store *Store
}

type Store struct {
    val uint16
}

func (r KnownReader) Read(p []byte) (n int, err error) {
    ret := r.store.val
    r.store.val = ret + 1
    fmt.Printf("\nStore: %v", r.store.val)
    p = make([]byte, 4)
    binary.LittleEndian.PutUint16(p, uint16(ret))
    fmt.Printf("\nreader p: % x", p)
    return binary.MaxVarintLen16, nil
}

func main() {
    r := KnownReader{
        store: &Store{val: 111},
    }
    uuid.SetRand(r)
    u, _ := uuid.NewRandomFromReader(r)
    fmt.Printf("\n%v",u)
    u, _ = uuid.NewRandomFromReader(r)
    fmt.Printf("\n%v",u)
}

---- OUTPUT ----

Store: 1
reader p: 00 00 00 00
Store: 2
reader p: 01 00 00 00
Store: 3
reader p: 02 00 00 00
Store: 4
reader p: 03 00 00 00
Store: 5
reader p: 04 00 00 00
Store: 6
reader p: 05 00 00 00
00000000-0000-4000-8000-000000000000
Store: 7
reader p: 06 00 00 00
Store: 8
reader p: 07 00 00 00
Store: 9
reader p: 08 00 00 00
Store: 10
reader p: 09 00 00 00
Store: 11
reader p: 0a 00 00 00
Store: 12
reader p: 0b 00 00 00
00000000-0000-4000-8000-000000000000

As you can see, the UUID, does not change between calls

I also tried using uuid.FromBytes, but that didn't seem to work either:


func getbytes(num uint16) []byte {
    p := make([]byte, 4)
    binary.LittleEndian.PutUint16(p, num)
    fmt.Printf("\ngetbytes p: % x", p)
    return p
}

func main() {
    var i uint16 = 0
    fmt.Printf("\nout getbytes: % x", getbytes(i))
    u, _ := uuid.FromBytes(getbytes(i))
    i = i + 1
    fmt.Printf("\nUUID: %v", u)
    fmt.Printf("\nout getbytes: % x", getbytes(i))
    u, _ = uuid.FromBytes(getbytes(i))
    fmt.Printf("\nUUID: %v", u)
}

---- OUTPUT ----

getbytes p: 00 00 00 00
out getbytes: 00 00 00 00
getbytes p: 00 00 00 00
UUID: 00000000-0000-0000-0000-000000000000
getbytes p: 01 00 00 00
out getbytes: 01 00 00 00
getbytes p: 01 00 00 00
UUID: 00000000-0000-0000-0000-000000000000

As you can see the UUIDs are still the same here as well.

So, is there something I'm missing? How can I get a consistent set of UUIDs?

Thanks

caffein
  • 575
  • 8
  • 26
  • 1
    Wy not just use a [v3 or v5 UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based)) from an existing package? – JimB May 27 '21 at 20:55
  • 4
    If you want predicable, why not `00000000-0000-0000-0000-000000000001`, `00000000-0000-0000-0000-000000000002`, `00000000-0000-0000-0000-000000000003` etc? – Bohemian May 27 '21 at 20:57
  • 4
    Which UUID package are you using? If you're using Google's, you can call [`SetRand`](https://pkg.go.dev/github.com/google/uuid#SetRand) to provide an RNG with a static seed, which will produce predictable results. Satori does not expose a way to provide an RNG. – Adrian May 27 '21 at 21:03

1 Answers1

2

Thanks Adrian, I think I figured out the answer:

rnd := rand.New(rand.NewSource(1))
uuid.SetRand(rnd)
u, _ = uuid.NewRandomFromReader(rnd)
fmt.Printf("\n%v", u)
u, _ = uuid.NewRandomFromReader(rnd)
fmt.Printf("\n%v", u)

--- OUTPUT ---

52fdfc07-2182-454f-963f-5f0f9a621d72
9566c74d-1003-4c4d-bbbb-0407d1e2c649

caffein
  • 575
  • 8
  • 26