From ddbe2833a88a81d48b5f0d0e1ce527108c070f99 Mon Sep 17 00:00:00 2001 From: Jonathan Vuillemin Date: Mon, 18 Nov 2024 13:48:27 +0100 Subject: [PATCH] feat(fxgenerate): Added UUIDv6 generation (#303) --- fxgenerate/.golangci.yml | 2 +- fxgenerate/README.md | 80 ++++++++++++++++++- fxgenerate/fxgeneratetest/uuidv6/factory.go | 35 ++++++++ .../fxgeneratetest/uuidv6/factory_test.go | 64 +++++++++++++++ fxgenerate/go.mod | 2 +- fxgenerate/go.sum | 4 +- fxgenerate/module.go | 17 ++++ fxgenerate/module_test.go | 54 +++++++++++++ fxgenerate/testdata/uuidv6/factory.go | 21 +++++ 9 files changed, 271 insertions(+), 8 deletions(-) create mode 100644 fxgenerate/fxgeneratetest/uuidv6/factory.go create mode 100644 fxgenerate/fxgeneratetest/uuidv6/factory_test.go create mode 100644 fxgenerate/testdata/uuidv6/factory.go diff --git a/fxgenerate/.golangci.yml b/fxgenerate/.golangci.yml index edf0e9ec..c5443fc8 100644 --- a/fxgenerate/.golangci.yml +++ b/fxgenerate/.golangci.yml @@ -40,7 +40,7 @@ linters: - importas - ineffassign - interfacebloat - - logrlint + - loggercheck - maintidx - makezero - misspell diff --git a/fxgenerate/README.md b/fxgenerate/README.md index 91256d5d..a331c9d2 100644 --- a/fxgenerate/README.md +++ b/fxgenerate/README.md @@ -16,9 +16,12 @@ * [UUID V4](#uuid-v4) * [Usage](#usage) * [Testing](#testing) - * [UUID V7](#uuid-v7) + * [UUID V6](#uuid-v6) * [Usage](#usage-1) * [Testing](#testing-1) + * [UUID V7](#uuid-v7) + * [Usage](#usage-2) + * [Testing](#testing-2) * [Override](#override) @@ -108,7 +111,7 @@ func main() { fx.ResultTags(`name:"generate-test-uuid-value"`), ), ), - fx.Decorate(fxtestuuid.NewFxTestUuidGeneratorFactory), // override the module with the TestUuidGeneratorFactory + fx.Decorate(fxtestuuid.NewFxTestUuidGeneratorFactory), // override the module with the test factory fx.Invoke(func(generator uuid.UuidGenerator) { // invoke the generator fmt.Printf("uuid: %s", generator.Generate()) // uuid: some deterministic value }), @@ -116,6 +119,75 @@ func main() { } ``` +#### UUID V6 + +##### Usage + +This module provides a [UuidV6Generator](https://github.com/ankorstore/yokai/blob/main/generate/uuidv6/generator.go), made available into the Fx container. + +```go +package main + +import ( + "fmt" + + "github.com/ankorstore/yokai/generate/uuidv6" + "github.com/ankorstore/yokai/fxgenerate" + "go.uber.org/fx" +) + +func main() { + fx.New( + fxgenerate.FxGenerateModule, // load the module + fx.Invoke(func(generator uuidv6.UuidV7Generator) { + uuid, _ := generator.Generate() // invoke the uuid v6 generator + fmt.Printf("uuid: %s", uuid.String()) // uuid: 1efa5a47-e5d0-6667-9d00-49bf4f758c68 + }), + ).Run() +} +``` + +##### Testing + +This module provides the possibility to make your [UuidV6Generator](https://github.com/ankorstore/yokai/blob/main/generate/uuidv6/generator.go) generate deterministic values, for testing purposes. + +You need to: + +- first provide into the Fx container the deterministic value to be used for generation, annotated with `name:"generate-test-uuid-v6-value"` +- then decorate into the Fx container the `UuidV6GeneratorFactory` with the provided [TestUuidGeneratorV6Factory](fxgeneratetest/uuidv6/factory.go) + +```go +package main + +import ( + "fmt" + + "github.com/ankorstore/yokai/fxgenerate" + fxtestuuidv6 "github.com/ankorstore/yokai/fxgenerate/fxgeneratetest/uuidv6" + "github.com/ankorstore/yokai/generate/uuidv6" + "go.uber.org/fx" +) + +func main() { + fx.New( + fxgenerate.FxGenerateModule, // load the module + fx.Provide( // provide and annotate the deterministic value + fx.Annotate( + func() string { + return "1efa5a47-e5d0-6663-99da-f6e8045dd166" + }, + fx.ResultTags(`name:"generate-test-uuid-v6-value"`), + ), + ), + fx.Decorate(fxtestuuidv6.NewFxTestUuidV6GeneratorFactory), // override the module with the test factory + fx.Invoke(func(generator uuidv6.UuidV6Generator) { // invoke the generator + uuid, _ := generator.Generate() + fmt.Printf("uuid: %s", uuid.String()) // uuid: 1efa5a47-e5d0-6663-99da-f6e8045dd166 + }), + ).Run() +} +``` + #### UUID V7 ##### Usage @@ -176,8 +248,8 @@ func main() { fx.ResultTags(`name:"generate-test-uuid-v7-value"`), ), ), - fx.Decorate(fxtestuuidv7.NewFxTestUuidV7GeneratorFactory), // override the module with the TestUuidGeneratorFactory - fx.Invoke(func(generator uuidv7.UuidV7Generator) { // invoke the generator + fx.Decorate(fxtestuuidv7.NewFxTestUuidV7GeneratorFactory), // override the module with the test factory + fx.Invoke(func(generator uuidv7.UuidV7Generator) { // invoke the generator uuid, _ := generator.Generate() fmt.Printf("uuid: %s", uuid.String()) // uuid: 018fdd68-1b41-7eb0-afad-57f45297c7c1 }), diff --git a/fxgenerate/fxgeneratetest/uuidv6/factory.go b/fxgenerate/fxgeneratetest/uuidv6/factory.go new file mode 100644 index 00000000..aa25ad89 --- /dev/null +++ b/fxgenerate/fxgeneratetest/uuidv6/factory.go @@ -0,0 +1,35 @@ +package uuidv6 + +import ( + uuidv6test "github.com/ankorstore/yokai/generate/generatetest/uuidv6" + "github.com/ankorstore/yokai/generate/uuidv6" + "go.uber.org/fx" +) + +// FxTestUuidV6GeneratorFactoryParam is used to retrieve the provided generate-test-uuid-V6-value from Fx. +type FxTestUuidV6GeneratorFactoryParam struct { + fx.In + Value string `name:"generate-test-uuid-v6-value"` +} + +// TestUuidGeneratorV6Factory is a [uuidv6.Ui] implementation. +type TestUuidGeneratorV6Factory struct { + value string +} + +// NewFxTestUuidV6GeneratorFactory returns a new [TestUuidGeneratorV6Factory], implementing [uuidv6.UuidV6GeneratorFactory]. +func NewFxTestUuidV6GeneratorFactory(p FxTestUuidV6GeneratorFactoryParam) uuidv6.UuidV6GeneratorFactory { + return &TestUuidGeneratorV6Factory{ + value: p.Value, + } +} + +// Create returns a new [uuidv6.UuidV6Generator]. +func (f *TestUuidGeneratorV6Factory) Create() uuidv6.UuidV6Generator { + generator, err := uuidv6test.NewTestUuidV6Generator(f.value) + if err != nil { + return nil + } + + return generator +} diff --git a/fxgenerate/fxgeneratetest/uuidv6/factory_test.go b/fxgenerate/fxgeneratetest/uuidv6/factory_test.go new file mode 100644 index 00000000..a987f21d --- /dev/null +++ b/fxgenerate/fxgeneratetest/uuidv6/factory_test.go @@ -0,0 +1,64 @@ +package uuidv6_test + +import ( + "testing" + + "github.com/ankorstore/yokai/fxgenerate" + fxgeneratetestuuidv6 "github.com/ankorstore/yokai/fxgenerate/fxgeneratetest/uuidv6" + testuuidv6 "github.com/ankorstore/yokai/fxgenerate/testdata/uuidv6" + "github.com/ankorstore/yokai/generate/uuidv6" + "github.com/stretchr/testify/assert" + "go.uber.org/fx" + "go.uber.org/fx/fxtest" +) + +func TestTestUuidV6GeneratorSuccess(t *testing.T) { + t.Parallel() + + var generator uuidv6.UuidV6Generator + + fxtest.New( + t, + fx.NopLogger, + fxgenerate.FxGenerateModule, + fx.Provide( + fx.Annotate( + func() string { + return testuuidv6.TestUUIDV6 + }, + fx.ResultTags(`name:"generate-test-uuid-v6-value"`), + ), + ), + fx.Decorate(fxgeneratetestuuidv6.NewFxTestUuidV6GeneratorFactory), + fx.Populate(&generator), + ).RequireStart().RequireStop() + + value, err := generator.Generate() + assert.NoError(t, err) + + assert.Equal(t, testuuidv6.TestUUIDV6, value.String()) +} + +func TestTestUuidV6GeneratorError(t *testing.T) { + t.Parallel() + + var generator uuidv6.UuidV6Generator + + fxtest.New( + t, + fx.NopLogger, + fxgenerate.FxGenerateModule, + fx.Provide( + fx.Annotate( + func() string { + return "invalid" + }, + fx.ResultTags(`name:"generate-test-uuid-v6-value"`), + ), + ), + fx.Decorate(fxgeneratetestuuidv6.NewFxTestUuidV6GeneratorFactory), + fx.Populate(&generator), + ).RequireStart().RequireStop() + + assert.Nil(t, generator) +} diff --git a/fxgenerate/go.mod b/fxgenerate/go.mod index 27fa5843..4ee4f2e3 100644 --- a/fxgenerate/go.mod +++ b/fxgenerate/go.mod @@ -3,7 +3,7 @@ module github.com/ankorstore/yokai/fxgenerate go 1.20 require ( - github.com/ankorstore/yokai/generate v1.2.0 + github.com/ankorstore/yokai/generate v1.3.0 github.com/google/uuid v1.6.0 github.com/stretchr/testify v1.9.0 go.uber.org/fx v1.22.0 diff --git a/fxgenerate/go.sum b/fxgenerate/go.sum index ff4d260d..eca433bf 100644 --- a/fxgenerate/go.sum +++ b/fxgenerate/go.sum @@ -1,5 +1,5 @@ -github.com/ankorstore/yokai/generate v1.2.0 h1:37siukjPGSS2kRnCnPhiuiF373+0tgwp0teXHnMsBhA= -github.com/ankorstore/yokai/generate v1.2.0/go.mod h1:gqS/i20wnvCOhcXydYdiGcASzBaeuW7GK6YYg/kkuY4= +github.com/ankorstore/yokai/generate v1.3.0 h1:Fgu3vjjA9pThOqG9GPkWIB30LufSVCLPzGUel5zcPcY= +github.com/ankorstore/yokai/generate v1.3.0/go.mod h1:gqS/i20wnvCOhcXydYdiGcASzBaeuW7GK6YYg/kkuY4= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= diff --git a/fxgenerate/module.go b/fxgenerate/module.go index e7cecf8a..be7918f1 100644 --- a/fxgenerate/module.go +++ b/fxgenerate/module.go @@ -2,6 +2,7 @@ package fxgenerate import ( "github.com/ankorstore/yokai/generate/uuid" + "github.com/ankorstore/yokai/generate/uuidv6" "github.com/ankorstore/yokai/generate/uuidv7" "go.uber.org/fx" ) @@ -19,11 +20,16 @@ var FxGenerateModule = fx.Module( uuid.NewDefaultUuidGeneratorFactory, fx.As(new(uuid.UuidGeneratorFactory)), ), + fx.Annotate( + uuidv6.NewDefaultUuidV6GeneratorFactory, + fx.As(new(uuidv6.UuidV6GeneratorFactory)), + ), fx.Annotate( uuidv7.NewDefaultUuidV7GeneratorFactory, fx.As(new(uuidv7.UuidV7GeneratorFactory)), ), NewFxUuidGenerator, + NewFxUuidV6Generator, NewFxUuidV7Generator, ), ) @@ -39,6 +45,17 @@ func NewFxUuidGenerator(p FxUuidGeneratorParam) uuid.UuidGenerator { return p.Factory.Create() } +// FxUuidV6GeneratorParam allows injection of the required dependencies in [NewFxUuidV6Generator]. +type FxUuidV6GeneratorParam struct { + fx.In + Factory uuidv6.UuidV6GeneratorFactory +} + +// NewFxUuidV6Generator returns a [uuidv6.UuidV6Generator]. +func NewFxUuidV6Generator(p FxUuidV6GeneratorParam) uuidv6.UuidV6Generator { + return p.Factory.Create() +} + // FxUuidV7GeneratorParam allows injection of the required dependencies in [NewFxUuidV7Generator]. type FxUuidV7GeneratorParam struct { fx.In diff --git a/fxgenerate/module_test.go b/fxgenerate/module_test.go index 50906621..53802313 100644 --- a/fxgenerate/module_test.go +++ b/fxgenerate/module_test.go @@ -1,3 +1,4 @@ +//nolint:dupl package fxgenerate_test import ( @@ -5,8 +6,10 @@ import ( "github.com/ankorstore/yokai/fxgenerate" testuuid "github.com/ankorstore/yokai/fxgenerate/testdata/uuid" + testuuidv6 "github.com/ankorstore/yokai/fxgenerate/testdata/uuidv6" testuuidv7 "github.com/ankorstore/yokai/fxgenerate/testdata/uuidv7" "github.com/ankorstore/yokai/generate/uuid" + "github.com/ankorstore/yokai/generate/uuidv6" "github.com/ankorstore/yokai/generate/uuidv7" googleuuid "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -43,6 +46,38 @@ func TestModuleUuidGenerator(t *testing.T) { assert.Equal(t, value2, parsedValue2.String()) } +func TestModuleUuidV6Generator(t *testing.T) { + t.Parallel() + + var generator uuidv6.UuidV6Generator + + fxtest.New( + t, + fx.NopLogger, + fxgenerate.FxGenerateModule, + fx.Populate(&generator), + ).RequireStart().RequireStop() + + value1, err := generator.Generate() + assert.NoError(t, err) + + value2, err := generator.Generate() + assert.NoError(t, err) + + assert.NotEqual(t, value1, value2) + + parsedValue1, err := googleuuid.Parse(value1.String()) + assert.NoError(t, err) + + parsedValue2, err := googleuuid.Parse(value2.String()) + assert.NoError(t, err) + + assert.NotEqual(t, parsedValue1.String(), parsedValue2.String()) + + assert.Equal(t, value1.String(), parsedValue1.String()) + assert.Equal(t, value2.String(), parsedValue2.String()) +} + func TestModuleUuidV7Generator(t *testing.T) { t.Parallel() @@ -91,6 +126,25 @@ func TestModuleUuidGeneratorDecoration(t *testing.T) { assert.Equal(t, "static", generator.Generate()) } +func TestModuleUuidV6GeneratorDecoration(t *testing.T) { + t.Parallel() + + var generator uuidv6.UuidV6Generator + + fxtest.New( + t, + fx.NopLogger, + fxgenerate.FxGenerateModule, + fx.Decorate(testuuidv6.NewTestStaticUuidV6GeneratorFactory), + fx.Populate(&generator), + ).RequireStart().RequireStop() + + value, err := generator.Generate() + assert.NoError(t, err) + + assert.Equal(t, testuuidv6.TestUUIDV6, value.String()) +} + func TestModuleUuidV7GeneratorDecoration(t *testing.T) { t.Parallel() diff --git a/fxgenerate/testdata/uuidv6/factory.go b/fxgenerate/testdata/uuidv6/factory.go new file mode 100644 index 00000000..527a4a81 --- /dev/null +++ b/fxgenerate/testdata/uuidv6/factory.go @@ -0,0 +1,21 @@ +package uuidv6 + +import ( + uuidtest "github.com/ankorstore/yokai/generate/generatetest/uuidv6" + "github.com/ankorstore/yokai/generate/uuidv6" +) + +const TestUUIDV6 = "1efa5a47-e5d2-6d70-8953-776e81422ff3" + +type TestStaticUuidV6GeneratorFactory struct{} + +func NewTestStaticUuidV6GeneratorFactory() uuidv6.UuidV6GeneratorFactory { + return &TestStaticUuidV6GeneratorFactory{} +} + +func (f *TestStaticUuidV6GeneratorFactory) Create() uuidv6.UuidV6Generator { + //nolint:errcheck + generator, _ := uuidtest.NewTestUuidV6Generator(TestUUIDV6) + + return generator +}