Skip to content

Commit 802d6a7

Browse files
committed
CHASM: include library name in fully qualified component/task type name
1 parent 530081c commit 802d6a7

6 files changed

+52
-36
lines changed

chasm/library.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ package chasm
2828

2929
type (
3030
Library interface {
31-
Name() string
31+
Namer
3232
Components() []*RegistrableComponent
3333
Tasks() []*RegistrableTask
3434
// Service()
@@ -37,6 +37,10 @@ type (
3737
}
3838

3939
UnimplementedLibrary struct{}
40+
41+
Namer interface {
42+
Name() string
43+
}
4044
)
4145

4246
func (UnimplementedLibrary) Components() []*RegistrableComponent {
@@ -48,3 +52,7 @@ func (UnimplementedLibrary) Tasks() []*RegistrableTask {
4852
}
4953

5054
func (UnimplementedLibrary) mustEmbedUnimplementedLibrary() {}
55+
56+
func fullyQualifiedName(libName, name string) string {
57+
return libName + "." + name
58+
}

chasm/registrable_component.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
type (
3232
RegistrableComponent struct {
3333
componentType string
34+
library Namer
3435
goType reflect.Type
3536

3637
ephemeral bool
@@ -43,10 +44,12 @@ type (
4344

4445
func NewRegistrableComponent[C Component](
4546
componentType string,
47+
lib Namer,
4648
opts ...RegistrableComponentOption,
4749
) *RegistrableComponent {
4850
rc := &RegistrableComponent{
4951
componentType: componentType,
52+
library: lib,
5053
goType: reflect.TypeFor[C](),
5154
shardingFn: defaultShardingFn,
5255
}
@@ -77,6 +80,9 @@ func WithShardingFn(
7780
}
7881
}
7982

83+
// Type returns the fully qualified name of the component, which is a combination of
84+
// the library name and the component type. This is used to uniquely identify
85+
// the component in the registry.
8086
func (rc RegistrableComponent) Type() string {
81-
return rc.componentType
87+
return fullyQualifiedName(rc.library.Name(), rc.componentType)
8288
}

chasm/registrable_task.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
type (
3232
RegistrableTask struct {
3333
taskType string
34+
library Namer
3435
goType reflect.Type
3536
componentGoType reflect.Type // It is not clear how this one is used.
3637
handler any
@@ -42,11 +43,13 @@ type (
4243
// NOTE: C is not Component but any.
4344
func NewRegistrableTask[C any, T any](
4445
taskType string,
46+
lib Namer,
4547
handler TaskHandler[C, T],
4648
opts ...RegistrableTaskOption,
4749
) *RegistrableTask {
4850
rt := &RegistrableTask{
4951
taskType: taskType,
52+
library: lib,
5053
goType: reflect.TypeFor[T](),
5154
componentGoType: reflect.TypeFor[C](),
5255
handler: handler,
@@ -57,6 +60,9 @@ func NewRegistrableTask[C any, T any](
5760
return rt
5861
}
5962

60-
func (rt RegistrableTask) Type() string {
61-
return rt.taskType
63+
// Type returns the fully qualified name of the task, which is a combination of
64+
// the library name and the task type. This is used to uniquely identify
65+
// the task in the registry.
66+
func (rc RegistrableTask) Type() string {
67+
return fullyQualifiedName(rc.library.Name(), rc.taskType)
6268
}

chasm/registry.go

+2-6
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,14 @@ func (r *Registry) taskFor(taskInstance any) (*RegistrableTask, bool) {
9292
return rt, ok
9393
}
9494

95-
func (r *Registry) fqn(libName, name string) string {
96-
return libName + "." + name
97-
}
98-
9995
func (r *Registry) registerComponent(
10096
libName string,
10197
rc *RegistrableComponent,
10298
) error {
10399
if err := r.validateName(rc.componentType); err != nil {
104100
return err
105101
}
106-
fqn := r.fqn(libName, rc.componentType)
102+
fqn := fullyQualifiedName(libName, rc.componentType)
107103
if _, ok := r.componentByType[fqn]; ok {
108104
return fmt.Errorf("component %s is already registered", fqn)
109105
}
@@ -127,7 +123,7 @@ func (r *Registry) registerTask(
127123
if err := r.validateName(rt.taskType); err != nil {
128124
return err
129125
}
130-
fqn := r.fqn(libName, rt.taskType)
126+
fqn := fullyQualifiedName(libName, rt.taskType)
131127
if _, ok := r.taskByType[fqn]; ok {
132128
return fmt.Errorf("task %s is already registered", fqn)
133129
}

chasm/registry_test.go

+22-22
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func TestRegistry_RegisterComponents_Success(t *testing.T) {
4646
lib := chasm.NewMockLibrary(ctrl)
4747
lib.EXPECT().Name().Return("TestLibrary").AnyTimes()
4848
lib.EXPECT().Components().Return([]*chasm.RegistrableComponent{
49-
chasm.NewRegistrableComponent[*chasm.MockComponent]("Component1"),
49+
chasm.NewRegistrableComponent[*chasm.MockComponent]("Component1", lib),
5050
})
5151

5252
lib.EXPECT().Tasks().Return(nil)
@@ -56,7 +56,7 @@ func TestRegistry_RegisterComponents_Success(t *testing.T) {
5656

5757
rc1, ok := r.Component("TestLibrary.Component1")
5858
require.True(t, ok)
59-
require.Equal(t, "Component1", rc1.Type())
59+
require.Equal(t, "TestLibrary.Component1", rc1.Type())
6060

6161
missingRC, ok := r.Component("TestLibrary.Component2")
6262
require.False(t, ok)
@@ -65,7 +65,7 @@ func TestRegistry_RegisterComponents_Success(t *testing.T) {
6565
cInstance1 := chasm.NewMockComponent(ctrl)
6666
rc2, ok := r.ComponentFor(cInstance1)
6767
require.True(t, ok)
68-
require.Equal(t, "Component1", rc2.Type())
68+
require.Equal(t, "TestLibrary.Component1", rc2.Type())
6969

7070
cInstance2 := "invalid component instance"
7171
rc3, ok := r.ComponentFor(cInstance2)
@@ -81,16 +81,16 @@ func TestRegistry_RegisterTasks_Success(t *testing.T) {
8181
lib.EXPECT().Components().Return(nil)
8282

8383
lib.EXPECT().Tasks().Return([]*chasm.RegistrableTask{
84-
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("Task1", chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
85-
chasm.NewRegistrableTask[testTaskComponentInterface, testTask2]("Task2", chasm.NewMockTaskHandler[testTaskComponentInterface, testTask2](ctrl)),
84+
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("Task1", lib, chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
85+
chasm.NewRegistrableTask[testTaskComponentInterface, testTask2]("Task2", lib, chasm.NewMockTaskHandler[testTaskComponentInterface, testTask2](ctrl)),
8686
})
8787

8888
err := r.Register(lib)
8989
require.NoError(t, err)
9090

9191
rt1, ok := r.Task("TestLibrary.Task1")
9292
require.True(t, ok)
93-
require.Equal(t, "Task1", rt1.Type())
93+
require.Equal(t, "TestLibrary.Task1", rt1.Type())
9494

9595
missingRT, ok := r.Task("TestLibrary.TaskMissing")
9696
require.False(t, ok)
@@ -99,7 +99,7 @@ func TestRegistry_RegisterTasks_Success(t *testing.T) {
9999
tInstance1 := testTask2{}
100100
rt2, ok := r.TaskFor(tInstance1)
101101
require.True(t, ok)
102-
require.Equal(t, "Task2", rt2.Type())
102+
require.Equal(t, "TestLibrary.Task2", rt2.Type())
103103

104104
tInstance2 := "invalid task instance"
105105
rt3, ok := r.TaskFor(tInstance2)
@@ -135,7 +135,7 @@ func TestRegistry_RegisterComponents_Error(t *testing.T) {
135135

136136
t.Run("component name must not be empty", func(t *testing.T) {
137137
lib.EXPECT().Components().Return([]*chasm.RegistrableComponent{
138-
chasm.NewRegistrableComponent[*chasm.MockComponent](""),
138+
chasm.NewRegistrableComponent[*chasm.MockComponent]("", lib),
139139
})
140140
r := chasm.NewRegistry()
141141
err := r.Register(lib)
@@ -145,7 +145,7 @@ func TestRegistry_RegisterComponents_Error(t *testing.T) {
145145

146146
t.Run("component name must follow rules", func(t *testing.T) {
147147
lib.EXPECT().Components().Return([]*chasm.RegistrableComponent{
148-
chasm.NewRegistrableComponent[*chasm.MockComponent]("bad.component.name"),
148+
chasm.NewRegistrableComponent[*chasm.MockComponent]("bad.component.name", lib),
149149
})
150150
r := chasm.NewRegistry()
151151
err := r.Register(lib)
@@ -155,8 +155,8 @@ func TestRegistry_RegisterComponents_Error(t *testing.T) {
155155

156156
t.Run("component is already registered by name", func(t *testing.T) {
157157
lib.EXPECT().Components().Return([]*chasm.RegistrableComponent{
158-
chasm.NewRegistrableComponent[*chasm.MockComponent]("Component1"),
159-
chasm.NewRegistrableComponent[*chasm.MockComponent]("Component1"),
158+
chasm.NewRegistrableComponent[*chasm.MockComponent]("Component1", lib),
159+
chasm.NewRegistrableComponent[*chasm.MockComponent]("Component1", lib),
160160
})
161161
r := chasm.NewRegistry()
162162
err := r.Register(lib)
@@ -166,8 +166,8 @@ func TestRegistry_RegisterComponents_Error(t *testing.T) {
166166

167167
t.Run("component is already registered by type", func(t *testing.T) {
168168
lib.EXPECT().Components().Return([]*chasm.RegistrableComponent{
169-
chasm.NewRegistrableComponent[*chasm.MockComponent]("Component1"),
170-
chasm.NewRegistrableComponent[*chasm.MockComponent]("Component2"),
169+
chasm.NewRegistrableComponent[*chasm.MockComponent]("Component1", lib),
170+
chasm.NewRegistrableComponent[*chasm.MockComponent]("Component2", lib),
171171
})
172172
r := chasm.NewRegistry()
173173

@@ -178,7 +178,7 @@ func TestRegistry_RegisterComponents_Error(t *testing.T) {
178178

179179
t.Run("component must be a struct", func(t *testing.T) {
180180
lib.EXPECT().Components().Return([]*chasm.RegistrableComponent{
181-
chasm.NewRegistrableComponent[chasm.Component]("Component1"),
181+
chasm.NewRegistrableComponent[chasm.Component]("Component1", lib),
182182
})
183183
r := chasm.NewRegistry()
184184

@@ -198,7 +198,7 @@ func TestRegistry_RegisterTasks_Error(t *testing.T) {
198198
t.Run("task name must not be empty", func(t *testing.T) {
199199
r := chasm.NewRegistry()
200200
lib.EXPECT().Tasks().Return([]*chasm.RegistrableTask{
201-
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("", chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
201+
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("", lib, chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
202202
})
203203
err := r.Register(lib)
204204
require.Error(t, err)
@@ -207,7 +207,7 @@ func TestRegistry_RegisterTasks_Error(t *testing.T) {
207207

208208
t.Run("task name must follow rules", func(t *testing.T) {
209209
lib.EXPECT().Tasks().Return([]*chasm.RegistrableTask{
210-
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("bad.task.name", chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
210+
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("bad.task.name", lib, chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
211211
})
212212
r := chasm.NewRegistry()
213213
err := r.Register(lib)
@@ -217,8 +217,8 @@ func TestRegistry_RegisterTasks_Error(t *testing.T) {
217217

218218
t.Run("task is already registered by name", func(t *testing.T) {
219219
lib.EXPECT().Tasks().Return([]*chasm.RegistrableTask{
220-
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("Task1", chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
221-
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("Task1", chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
220+
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("Task1", lib, chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
221+
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("Task1", lib, chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
222222
})
223223
r := chasm.NewRegistry()
224224
err := r.Register(lib)
@@ -228,8 +228,8 @@ func TestRegistry_RegisterTasks_Error(t *testing.T) {
228228

229229
t.Run("task is already registered by type", func(t *testing.T) {
230230
lib.EXPECT().Tasks().Return([]*chasm.RegistrableTask{
231-
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("Task1", chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
232-
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("Task2", chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
231+
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("Task1", lib, chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
232+
chasm.NewRegistrableTask[*chasm.MockComponent, testTask1]("Task2", lib, chasm.NewMockTaskHandler[*chasm.MockComponent, testTask1](ctrl)),
233233
})
234234
r := chasm.NewRegistry()
235235
err := r.Register(lib)
@@ -240,7 +240,7 @@ func TestRegistry_RegisterTasks_Error(t *testing.T) {
240240
t.Run("task component struct must implement Component", func(t *testing.T) {
241241
lib.EXPECT().Tasks().Return([]*chasm.RegistrableTask{
242242
// MockComponent has only pointer receivers and therefore does not implement Component interface.
243-
chasm.NewRegistrableTask[chasm.MockComponent, testTask1]("Task1", chasm.NewMockTaskHandler[chasm.MockComponent, testTask1](ctrl)),
243+
chasm.NewRegistrableTask[chasm.MockComponent, testTask1]("Task1", lib, chasm.NewMockTaskHandler[chasm.MockComponent, testTask1](ctrl)),
244244
})
245245
r := chasm.NewRegistry()
246246
err := r.Register(lib)
@@ -250,7 +250,7 @@ func TestRegistry_RegisterTasks_Error(t *testing.T) {
250250

251251
t.Run("task must be struct", func(t *testing.T) {
252252
lib.EXPECT().Tasks().Return([]*chasm.RegistrableTask{
253-
chasm.NewRegistrableTask[*chasm.MockComponent, string]("Task1", chasm.NewMockTaskHandler[*chasm.MockComponent, string](ctrl)),
253+
chasm.NewRegistrableTask[*chasm.MockComponent, string]("Task1", lib, chasm.NewMockTaskHandler[*chasm.MockComponent, string](ctrl)),
254254
})
255255
r := chasm.NewRegistry()
256256
err := r.Register(lib)

chasm/test_library_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ func (l *TestLibrary) Name() string {
3838

3939
func (l *TestLibrary) Components() []*RegistrableComponent {
4040
return []*RegistrableComponent{
41-
NewRegistrableComponent[*TestComponent]("test_component"),
42-
NewRegistrableComponent[*TestSubComponent1]("test_sub_component_1"),
43-
NewRegistrableComponent[*TestSubComponent11]("test_sub_component_11"),
44-
NewRegistrableComponent[*TestSubComponent2]("test_sub_component_2"),
41+
NewRegistrableComponent[*TestComponent]("test_component", l),
42+
NewRegistrableComponent[*TestSubComponent1]("test_sub_component_1", l),
43+
NewRegistrableComponent[*TestSubComponent11]("test_sub_component_11", l),
44+
NewRegistrableComponent[*TestSubComponent2]("test_sub_component_2", l),
4545
}
4646
}

0 commit comments

Comments
 (0)