Skip to content

Commit 4b385aa

Browse files
authored
Improve identifier generation (#304)
* Test identifier generation * Document magic numbers
1 parent 8d9b356 commit 4b385aa

File tree

2 files changed

+65
-11
lines changed

2 files changed

+65
-11
lines changed

task/common/identifier.go

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,22 @@ import (
1313

1414
type Identifier string
1515

16+
const (
17+
maximumLongLength = 50
18+
shortLength = 16
19+
)
20+
1621
func (i Identifier) Long() string {
1722
re := regexp.MustCompile(`(?s)^tpi-([a-z0-9]+(?:[a-z0-9-]*[a-z0-9])?)-([a-z0-9]+)-([a-z0-9]+)$`)
1823

19-
if match := re.FindStringSubmatch(string(i)); len(match) > 0 && hash(match[1]+match[2], 4) == match[3] {
24+
if match := re.FindStringSubmatch(string(i)); len(match) > 0 && hash(match[1]+match[2], shortLength/2) == match[3] {
2025
return match[0]
2126
}
2227

23-
name := normalize(string(i), 50)
24-
digest := hash(string(i), 4)
28+
name := normalize(string(i), maximumLongLength-shortLength-uint32(len("tpi---")))
29+
digest := hash(string(i), shortLength/2)
2530

26-
return fmt.Sprintf("tpi-%s-%s-%s", name, digest, hash(name+digest, 4))
31+
return fmt.Sprintf("tpi-%s-%s-%s", name, digest, hash(name+digest, shortLength/2))
2732
}
2833

2934
func (i Identifier) Short() string {
@@ -33,13 +38,18 @@ func (i Identifier) Short() string {
3338

3439
// hash deterministically generates a Base36 digest of `size`
3540
// characters using `identifier` as the seed.
36-
func hash(identifier string, size uint32) string {
41+
func hash(identifier string, size uint8) string {
3742
digest := sha256.Sum256([]byte(identifier))
3843
random := uid.NewRandCustom(bytes.NewReader(digest[:]))
3944
encoder := uid.NewEncoderBase36()
40-
provider := uid.NewProviderCustom(size, random, encoder)
45+
provider := uid.NewProviderCustom(sha256.Size, random, encoder)
46+
result := provider.MustGenerate().String()
4147

42-
return provider.MustGenerate().String()
48+
if len(result) < int(size) {
49+
panic("not enough bytes to satisfy requested size")
50+
}
51+
52+
return result[:size]
4353
}
4454

4555
// normalize normalizes user-provided identifiers by adapting them to
@@ -48,13 +58,10 @@ func normalize(identifier string, truncate uint32) string {
4858
lowercase := strings.ToLower(identifier)
4959

5060
normalized := regexp.MustCompile("[^a-z0-9]+").ReplaceAllString(lowercase, "-")
51-
normalized = regexp.MustCompile("(^-)|(-$)").ReplaceAllString(normalized, "")
5261

5362
if len(normalized) > int(truncate) {
5463
normalized = normalized[:truncate]
5564
}
5665

57-
return normalized
66+
return regexp.MustCompile("(^-)|(-$)").ReplaceAllString(normalized, "")
5867
}
59-
60-
// func NormalizeIdentifier(identifier common.Identifier, long bool) string {

task/common/identifier_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package common
2+
3+
import (
4+
"testing"
5+
6+
"github.com/brianvoe/gofakeit/v6"
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestIdentifier(t *testing.T) {
11+
name := gofakeit.NewCrypto().Sentence(512)
12+
13+
t.Run("idempotence", func(t *testing.T) {
14+
identifier := Identifier(name)
15+
16+
once := identifier.Long()
17+
twice := Identifier(once).Long()
18+
require.Equal(t, once, twice)
19+
})
20+
21+
t.Run("stability", func(t *testing.T) {
22+
identifier := Identifier(name)
23+
24+
require.Equal(t, identifier.Long(), identifier.Long())
25+
require.Equal(t, identifier.Short(), identifier.Short())
26+
})
27+
28+
t.Run("homogeneity", func(t *testing.T) {
29+
identifier := Identifier(name)
30+
31+
long := identifier.Long()
32+
short := identifier.Short()
33+
34+
require.Regexp(t, "^tpi-[a-z0-9-]+$", long)
35+
require.Regexp(t, "^[a-z0-9]+$", short)
36+
37+
require.LessOrEqual(t, len(long), maximumLongLength)
38+
require.Equal(t, len(short), shortLength)
39+
})
40+
41+
t.Run("compatibility", func(t *testing.T) {
42+
identifier := Identifier("test")
43+
44+
require.Equal(t, "tpi-test-3z4xlzwq-3u0vweb4", identifier.Long())
45+
require.Equal(t, "3z4xlzwq3u0vweb4", identifier.Short())
46+
})
47+
}

0 commit comments

Comments
 (0)