Skip to content

Commit d30ff4d

Browse files
committed
add unit tests
1 parent 90b64a1 commit d30ff4d

File tree

2 files changed

+169
-9
lines changed

2 files changed

+169
-9
lines changed

internal/orchestrator/bricks/bricks_test.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
"github.com/arduino/arduino-app-cli/internal/orchestrator/app"
2626
"github.com/arduino/arduino-app-cli/internal/orchestrator/bricksindex"
27+
"github.com/arduino/arduino-app-cli/internal/orchestrator/modelsindex"
2728
)
2829

2930
func TestBrickCreate(t *testing.T) {
@@ -190,3 +191,155 @@ func TestGetBrickInstanceVariableDetails(t *testing.T) {
190191
})
191192
}
192193
}
194+
195+
func TestAppBrickInstanceModelsDetails(t *testing.T) {
196+
197+
bIndex := &bricksindex.BricksIndex{
198+
Bricks: []bricksindex.Brick{
199+
{
200+
ID: "arduino:object_detection",
201+
Name: "Object Detection",
202+
Category: "video",
203+
ModelName: "yolox-object-detection", // Default model
204+
Variables: []bricksindex.BrickVariable{
205+
{Name: "EI_OBJ_DETECTION_MODEL", DefaultValue: "default_path", Description: "path to the model file"},
206+
{Name: "CUSTOM_MODEL_PATH", DefaultValue: "/home/arduino/.arduino-bricks/ei-models", Description: "path to the custom model directory"},
207+
},
208+
},
209+
{
210+
ID: "arduino:weather_forecast",
211+
Name: "Weather Forecast",
212+
Category: "miscellaneous",
213+
ModelName: "",
214+
},
215+
},
216+
}
217+
218+
mIndex := &modelsindex.ModelsIndex{
219+
Models: []modelsindex.AIModel{
220+
221+
{
222+
ID: "yolox-object-detection",
223+
Name: "General purpose object detection - YoloX",
224+
ModuleDescription: "General purpose object detection...",
225+
Bricks: []string{"arduino:object_detection", "arduino:video_object_detection"},
226+
},
227+
{
228+
ID: "face-detection",
229+
Name: "Lightweight-Face-Detection",
230+
Bricks: []string{"arduino:object_detection", "arduino:video_object_detection"},
231+
},
232+
}}
233+
234+
svc := &Service{
235+
bricksIndex: bIndex,
236+
modelsIndex: mIndex,
237+
}
238+
239+
tests := []struct {
240+
name string
241+
app *app.ArduinoApp
242+
brickID string
243+
expectedError string
244+
validate func(*testing.T, BrickInstance)
245+
}{
246+
{
247+
name: "Brick not found in global Index",
248+
brickID: "arduino:non_existent_brick",
249+
app: &app.ArduinoApp{
250+
Descriptor: app.AppDescriptor{Bricks: []app.Brick{}},
251+
},
252+
expectedError: "brick not found",
253+
},
254+
{
255+
name: "Brick found in Index but not added to App",
256+
brickID: "arduino:object_detection",
257+
app: &app.ArduinoApp{
258+
Descriptor: app.AppDescriptor{
259+
Bricks: []app.Brick{
260+
{ID: "arduino:weather_forecast"},
261+
},
262+
},
263+
},
264+
expectedError: "brick arduino:object_detection not added in the app",
265+
},
266+
{
267+
name: "Success - Standard Brick without Model",
268+
brickID: "arduino:weather_forecast",
269+
app: &app.ArduinoApp{
270+
Descriptor: app.AppDescriptor{
271+
Bricks: []app.Brick{
272+
{ID: "arduino:weather_forecast"},
273+
},
274+
},
275+
},
276+
validate: func(t *testing.T, res BrickInstance) {
277+
require.Equal(t, "arduino:weather_forecast", res.ID)
278+
require.Equal(t, "Weather Forecast", res.Name)
279+
require.Equal(t, "installed", res.Status)
280+
require.Empty(t, res.ModelID)
281+
require.Empty(t, res.CompatibleModels)
282+
},
283+
},
284+
{
285+
name: "Success - Brick with Default Model",
286+
brickID: "arduino:object_detection",
287+
app: &app.ArduinoApp{
288+
Descriptor: app.AppDescriptor{
289+
Bricks: []app.Brick{
290+
{
291+
ID: "arduino:object_detection",
292+
},
293+
},
294+
},
295+
},
296+
validate: func(t *testing.T, res BrickInstance) {
297+
require.Equal(t, "arduino:object_detection", res.ID)
298+
require.Equal(t, "yolox-object-detection", res.ModelID)
299+
require.Len(t, res.CompatibleModels, 2)
300+
require.Equal(t, "yolox-object-detection", res.CompatibleModels[0].ID)
301+
require.Equal(t, "face-detection", res.CompatibleModels[1].ID)
302+
},
303+
},
304+
{
305+
name: "Success - Brick with Overridden Model in App",
306+
brickID: "arduino:object_detection",
307+
app: &app.ArduinoApp{
308+
Descriptor: app.AppDescriptor{
309+
Bricks: []app.Brick{
310+
{
311+
ID: "arduino:object_detection",
312+
Model: "face-detection",
313+
},
314+
},
315+
},
316+
},
317+
validate: func(t *testing.T, res BrickInstance) {
318+
require.Equal(t, "arduino:object_detection", res.ID)
319+
require.Equal(t, "face-detection", res.ModelID)
320+
require.Len(t, res.CompatibleModels, 2)
321+
require.Equal(t, "yolox-object-detection", res.CompatibleModels[0].ID)
322+
require.Equal(t, "face-detection", res.CompatibleModels[1].ID)
323+
},
324+
},
325+
}
326+
327+
for _, tt := range tests {
328+
t.Run(tt.name, func(t *testing.T) {
329+
result, err := svc.AppBrickInstanceDetails(tt.app, tt.brickID)
330+
331+
if tt.expectedError != "" {
332+
require.Error(t, err)
333+
if err != nil {
334+
require.Contains(t, err.Error(), tt.expectedError)
335+
}
336+
return
337+
}
338+
339+
require.NoError(t, err)
340+
if tt.validate != nil {
341+
tt.validate(t, result)
342+
}
343+
})
344+
}
345+
}

internal/orchestrator/modelsindex/models_index.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,26 +54,33 @@ type AIModel struct {
5454
}
5555

5656
type ModelsIndex struct {
57-
models []AIModel
57+
Models []AIModel
58+
}
59+
60+
// NewModelsIndex creates a new index instance (Helper for tests or manual creation)
61+
func NewModelsIndex(models []AIModel) *ModelsIndex {
62+
return &ModelsIndex{
63+
Models: models,
64+
}
5865
}
5966

6067
func (m *ModelsIndex) GetModels() []AIModel {
61-
return m.models
68+
return m.Models
6269
}
6370

6471
func (m *ModelsIndex) GetModelByID(id string) (*AIModel, bool) {
65-
idx := slices.IndexFunc(m.models, func(v AIModel) bool { return v.ID == id })
72+
idx := slices.IndexFunc(m.Models, func(v AIModel) bool { return v.ID == id })
6673
if idx == -1 {
6774
return nil, false
6875
}
69-
return &m.models[idx], true
76+
return &m.Models[idx], true
7077
}
7178

7279
func (m *ModelsIndex) GetModelsByBrick(brick string) []AIModel {
7380
var matches []AIModel
74-
for i := range m.models {
75-
if len(m.models[i].Bricks) > 0 && slices.Contains(m.models[i].Bricks, brick) {
76-
matches = append(matches, m.models[i])
81+
for i := range m.Models {
82+
if len(m.Models[i].Bricks) > 0 && slices.Contains(m.Models[i].Bricks, brick) {
83+
matches = append(matches, m.Models[i])
7784
}
7885
}
7986
if len(matches) == 0 {
@@ -84,7 +91,7 @@ func (m *ModelsIndex) GetModelsByBrick(brick string) []AIModel {
8491

8592
func (m *ModelsIndex) GetModelsByBricks(bricks []string) []AIModel {
8693
var matchingModels []AIModel
87-
for _, model := range m.models {
94+
for _, model := range m.Models {
8895
for _, modelBrick := range model.Bricks {
8996
if slices.Contains(bricks, modelBrick) {
9097
matchingModels = append(matchingModels, model)
@@ -113,5 +120,5 @@ func GenerateModelsIndexFromFile(dir *paths.Path) (*ModelsIndex, error) {
113120
models[i] = model
114121
}
115122
}
116-
return &ModelsIndex{models: models}, nil
123+
return &ModelsIndex{Models: models}, nil
117124
}

0 commit comments

Comments
 (0)