Skip to content

Commit

Permalink
switches from xid to ulid (#411)
Browse files Browse the repository at this point in the history
  • Loading branch information
pastuxso committed Nov 3, 2023
1 parent a1052d7 commit bbe7ece
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 14 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ require (
github.com/mattn/go-isatty v0.0.20
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
github.com/muesli/cancelreader v0.2.2
github.com/oklog/ulid/v2 v2.1.0
github.com/rogpeppe/go-internal v1.11.0
github.com/rs/cors v1.10.1
github.com/rs/xid v1.5.0
github.com/rwtodd/Go.Sed v0.0.0-20230610052213-ba3e9c186f0a
github.com/vektah/gqlparser/v2 v2.5.10
github.com/yuin/goldmark v1.5.6
Expand Down
5 changes: 3 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,11 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
Expand All @@ -175,8 +178,6 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo=
github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rwtodd/Go.Sed v0.0.0-20230610052213-ba3e9c186f0a h1:URwYffGNuBQkfwkcn+1CZhb8IE/mKSXxPXp/zzQsn80=
github.com/rwtodd/Go.Sed v0.0.0-20230610052213-ba3e9c186f0a/go.mod h1:c6qgHcSUeSISur4+Kcf3WYTvpL07S8eAsoP40hDiQ1I=
Expand Down
63 changes: 63 additions & 0 deletions internal/idgen/id.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Package utils contains utility functions for the application
package idgen

import (
"io"
"regexp"
"sync"
"time"

"github.com/oklog/ulid/v2"
"golang.org/x/exp/rand"
)

var (
entropy io.Reader
entropyOnce sync.Once
)

// DefaultEntropy returns a reader that generates ULID entropy.
// The default entropy function utilizes math/rand.Rand, which is not safe for concurrent use by multiple goroutines.
// Therefore, this function employs x/exp/rand, as recommended by the authors of the library.
func DefaultEntropy() io.Reader {
entropyOnce.Do(func() {
seed := uint64(time.Now().UnixNano())
source := rand.NewSource(seed)
rng := rand.New(source)

entropy = &ulid.LockedMonotonicReader{
MonotonicReader: ulid.Monotonic(rng, 0),
}
})
return entropy
}

// IsULID checks if the given string is a valid ULID
// ULID pattern:
//
// 01AN4Z07BY 79KA1307SR9X4MV3
// |----------| |----------------|
// Timestamp Randomness
//
// 10 characters 16 characters
// Crockford's Base32 is used (excludes I, L, O, and U to avoid confusion and abuse)
func isULID(s string) bool {
ulidRegex := `^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$`
matched, _ := regexp.MatchString(ulidRegex, s)
return matched
}

// ValidID checks if the given id is valid
func ValidID(id string) bool {
_, err := ulid.Parse(id)

return err == nil && isULID(id)
}

// GenerateID generates a new universal ID
func GenerateID() string {
entropy := DefaultEntropy()
now := time.Now()
ts := ulid.Timestamp(now)
return ulid.MustNew(ts, entropy).String()
}
66 changes: 66 additions & 0 deletions internal/idgen/id_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package idgen

import (
"sync"
"testing"

"github.com/stretchr/testify/assert"
)

func TestValidID(t *testing.T) {
validULID := GenerateID()

tests := []struct {
id string
expected bool
}{
{validULID, true},
{"0", false},
{"invalidulid", false},
{"invalidulid", false},
{"01B4E6BXY0PRJ5G420D25MWQY!", false},
}

for _, tt := range tests {
t.Run(tt.id, func(t *testing.T) {
if got := ValidID(tt.id); got != tt.expected {
assert.Equal(t, tt.expected, got)
}
})
}
}

func TestGenerateUniqueID(t *testing.T) {
Generator := func() string { return GenerateID() }

t.Run("uniqueness", func(t *testing.T) {
id1 := Generator()
id2 := Generator()
assert.NotEqual(t, id1, id2)
})

t.Run("concurrent uniqueness", func(t *testing.T) {
var wg sync.WaitGroup
ids := make(map[string]struct{})
mu := sync.Mutex{}

generateAndStoreID := func() {
defer wg.Done()
id := Generator()
mu.Lock()
defer mu.Unlock()
ids[id] = struct{}{}
}

numIDs := 10000

wg.Add(numIDs)
for i := 0; i < numIDs; i++ {
go generateAndStoreID()
}

wg.Wait()

assert.Equal(t, numIDs, len(ids))
})
}
6 changes: 3 additions & 3 deletions internal/runner/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (

"github.com/creack/pty"
"github.com/pkg/errors"
"github.com/rs/xid"
"github.com/stateful/runme/internal/idgen"
"go.uber.org/multierr"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -198,8 +198,8 @@ func newCommand(cfg *commandConfig) (*command, error) {
extraArgs = append(extraArgs, "-c", script)
case CommandModeTempFile:
for {
id := xid.New()
tempScriptFile = filepath.Join(cfg.Directory, fmt.Sprintf(".runme-script-%s", id.String()))
id := idgen.GenerateID()
tempScriptFile = filepath.Join(cfg.Directory, fmt.Sprintf(".runme-script-%s", id))

if fileExtension != "" {
tempScriptFile += "." + fileExtension
Expand Down
4 changes: 2 additions & 2 deletions internal/runner/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (

"github.com/creack/pty"
"github.com/pkg/errors"
"github.com/rs/xid"
"github.com/stateful/runme/internal/env"
runnerv1 "github.com/stateful/runme/internal/gen/proto/go/runme/runner/v1"
"github.com/stateful/runme/internal/idgen"
"github.com/stateful/runme/internal/rbuffer"
"github.com/stateful/runme/pkg/project"
"go.uber.org/zap"
Expand Down Expand Up @@ -155,7 +155,7 @@ func ConvertRunnerProject(runnerProj *runnerv1.Project) (project.Project, error)
}

func (r *runnerService) Execute(srv runnerv1.RunnerService_ExecuteServer) error {
logger := r.logger.With(zap.String("_id", xid.New().String()))
logger := r.logger.With(zap.String("_id", idgen.GenerateID()))

logger.Info("running Execute in runnerService")

Expand Down
4 changes: 2 additions & 2 deletions internal/runner/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"sync"

lru "github.com/hashicorp/golang-lru/v2"
"github.com/rs/xid"
"github.com/stateful/runme/internal/idgen"
"github.com/stateful/runme/pkg/project"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -36,7 +36,7 @@ func NewSession(envs []string, proj project.Project, logger *zap.Logger) (*Sessi
}

s := &Session{
ID: xid.New().String(),
ID: idgen.GenerateID(),

envStore: newEnvStore(sessionEnvs...),
logger: logger,
Expand Down
26 changes: 24 additions & 2 deletions internal/runner/session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func Test_SessionList(t *testing.T) {

session2, err := createSession()
require.NoError(t, err)

assert.NotEqual(t, session1.ID, session2.ID)

list.AddSession(session2)

found, ok := list.GetSession(session1.ID)
Expand All @@ -62,10 +65,19 @@ func Test_SessionList(t *testing.T) {
session2, err := list.CreateAndAddSession(createSession)
require.NoError(t, err)

assert.NotEqual(t, session1.ID, session2.ID)

sessions, err := list.ListSessions()
require.NoError(t, err)

assert.Equal(t, []*Session{session1, session2}, sessions)
expected := []string{session1.ID, session2.ID}
actual := []string{}

for _, session := range sessions {
actual = append(actual, session.ID)
}

assert.Equal(t, expected, actual)
})

t.Run("DeleteSession", func(t *testing.T) {
Expand All @@ -78,6 +90,8 @@ func Test_SessionList(t *testing.T) {
session2, err := list.CreateAndAddSession(createSession)
require.NoError(t, err)

assert.NotEqual(t, session1.ID, session2.ID)

{
sessionList, err := list.ListSessions()
require.NoError(t, err)
Expand All @@ -91,7 +105,15 @@ func Test_SessionList(t *testing.T) {
sessionList, err := list.ListSessions()
require.NoError(t, err)
assert.Equal(t, 1, len(sessionList))
assert.Equal(t, session1, sessionList[0])

expected := []string{session1.ID}
actual := []string{}

for _, session := range sessionList {
actual = append(actual, session.ID)
}

assert.Equal(t, expected, actual)
}

deleted = list.DeleteSession(session1.ID)
Expand Down
4 changes: 2 additions & 2 deletions internal/runner/shell_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

"github.com/creack/pty"
"github.com/pkg/errors"
"github.com/rs/xid"
"github.com/stateful/runme/internal/idgen"
xpty "github.com/stateful/runme/internal/pty"
"golang.org/x/term"
)
Expand All @@ -25,7 +25,7 @@ type ShellSession struct {
}

func NewShellSession(command string) (*ShellSession, error) {
id := xid.New().String()
id := idgen.GenerateID()

cmd := exec.Command(command)
cmd.Env = append(os.Environ(), "RUNMESHELL="+id)
Expand Down

0 comments on commit bbe7ece

Please sign in to comment.