对接
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
package serial
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// New appends a 26-character base32 value with 128 random bits to prefix.
|
||||
func New(prefix string) (string, error) {
|
||||
var entropy [16]byte
|
||||
if _, err := rand.Read(entropy[:]); err != nil {
|
||||
return "", fmt.Errorf("generate serial number: %w", err)
|
||||
}
|
||||
return prefix + base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(entropy[:]), nil
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package serial
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var validSerial = regexp.MustCompile(`^(DS|CZ)[A-Z2-7]{26}$`)
|
||||
|
||||
func TestNewPreservesPrefixAndPaymentSafeLength(t *testing.T) {
|
||||
for _, prefix := range []string{"DS", "CZ"} {
|
||||
t.Run(prefix, func(t *testing.T) {
|
||||
value, err := New(prefix)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(value) != 28 || !strings.HasPrefix(value, prefix) || !validSerial.MatchString(value) {
|
||||
t.Fatalf("unexpected serial format: %q", value)
|
||||
}
|
||||
entropy, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(strings.TrimPrefix(value, prefix))
|
||||
if err != nil || len(entropy) != 16 {
|
||||
t.Fatalf("serial does not carry 128 bits: bytes=%d error=%v", len(entropy), err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewIsUniqueAcrossRapidSequentialCalls(t *testing.T) {
|
||||
const count = 10000
|
||||
for _, prefix := range []string{"DS", "CZ"} {
|
||||
t.Run(prefix, func(t *testing.T) {
|
||||
seen := make(map[string]struct{}, count)
|
||||
for index := 0; index < count; index++ {
|
||||
value, err := New(prefix)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, exists := seen[value]; exists {
|
||||
t.Fatalf("duplicate serial at call %d: %q", index, value)
|
||||
}
|
||||
seen[value] = struct{}{}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewIsUniqueAcrossParallelCalls(t *testing.T) {
|
||||
const workers, perWorker = 32, 500
|
||||
type result struct {
|
||||
value string
|
||||
err error
|
||||
}
|
||||
start := make(chan struct{})
|
||||
results := make(chan result, workers)
|
||||
var group sync.WaitGroup
|
||||
for worker := 0; worker < workers; worker++ {
|
||||
group.Add(1)
|
||||
go func(worker int) {
|
||||
defer group.Done()
|
||||
prefix := "DS"
|
||||
if worker%2 == 0 {
|
||||
prefix = "CZ"
|
||||
}
|
||||
<-start
|
||||
for index := 0; index < perWorker; index++ {
|
||||
value, err := New(prefix)
|
||||
results <- result{value: value, err: err}
|
||||
}
|
||||
}(worker)
|
||||
}
|
||||
go func() {
|
||||
group.Wait()
|
||||
close(results)
|
||||
}()
|
||||
close(start)
|
||||
seen := make(map[string]struct{}, workers*perWorker)
|
||||
for result := range results {
|
||||
if result.err != nil {
|
||||
t.Errorf("generate parallel serial: %v", result.err)
|
||||
continue
|
||||
}
|
||||
if !validSerial.MatchString(result.value) || len(result.value) > 32 {
|
||||
t.Errorf("invalid parallel serial format: %q", result.value)
|
||||
}
|
||||
if _, exists := seen[result.value]; exists {
|
||||
t.Errorf("duplicate parallel serial: %q", result.value)
|
||||
}
|
||||
seen[result.value] = struct{}{}
|
||||
}
|
||||
if len(seen) != workers*perWorker {
|
||||
t.Fatalf("unique serials=%d, want %d", len(seen), workers*perWorker)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user