Skip to content

Commit a7317dc

Browse files
authored
[API] Change the GET /v1/bricks/{id} variables field (#126)
* add config variables for brick details * update unit tests * update openapi and e2e test * code review fix * make lint happy
1 parent 17f979f commit a7317dc

File tree

6 files changed

+94
-27
lines changed

6 files changed

+94
-27
lines changed

internal/api/docs/openapi.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,11 @@ components:
13201320
$ref: '#/components/schemas/AIModel'
13211321
nullable: true
13221322
type: array
1323+
config_variables:
1324+
items:
1325+
$ref: '#/components/schemas/BrickConfigVariable'
1326+
nullable: true
1327+
type: array
13231328
description:
13241329
type: string
13251330
id:
@@ -1340,6 +1345,9 @@ components:
13401345
variables:
13411346
additionalProperties:
13421347
$ref: '#/components/schemas/BrickVariable'
1348+
description: 'Deprecated: use config_variables instead. This field is kept
1349+
for backward compatibility.'
1350+
nullable: true
13431351
type: object
13441352
type: object
13451353
BrickInstance:

internal/e2e/client/client.gen.go

Lines changed: 16 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/e2e/daemon/brick_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,21 @@ func TestBricksDetails(t *testing.T) {
127127
Name: f.Ptr("Person classification"),
128128
Description: f.Ptr("Person classification model based on WakeVision dataset. This model is trained to classify images into two categories: person and not-person."),
129129
}}
130+
expectConfigVariables := []client.BrickConfigVariable{
131+
{
132+
Name: f.Ptr("CUSTOM_MODEL_PATH"),
133+
Value: f.Ptr("/home/arduino/.arduino-bricks/ei-models"),
134+
Description: f.Ptr("path to the custom model directory"),
135+
Required: f.Ptr(false),
136+
},
137+
{
138+
Name: f.Ptr("EI_CLASSIFICATION_MODEL"),
139+
Value: f.Ptr("/models/ootb/ei/mobilenet-v2-224px.eim"),
140+
Description: f.Ptr("path to the model file"),
141+
Required: f.Ptr(false),
142+
},
143+
}
144+
130145
response, err := httpClient.GetBrickDetailsWithResponse(t.Context(), validBrickID, func(ctx context.Context, req *http.Request) error { return nil })
131146
require.NoError(t, err)
132147
require.Equal(t, http.StatusOK, response.StatusCode(), "status code should be 200 ok")
@@ -147,5 +162,7 @@ func TestBricksDetails(t *testing.T) {
147162
require.Equal(t, expectedUsedByApps, *(response.JSON200.UsedByApps))
148163
require.NotNil(t, response.JSON200.CompatibleModels, "Models should not be nil")
149164
require.Equal(t, expectedModelLiteInfo, *(response.JSON200.CompatibleModels))
165+
require.NotNil(t, response.JSON200.ConfigVariables, "ConfigVariables should not be nil")
166+
require.Equal(t, expectConfigVariables, *(response.JSON200.ConfigVariables))
150167
})
151168
}

internal/orchestrator/bricks/bricks.go

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func (s *Service) AppBrickInstancesList(a *app.ArduinoApp) (AppBrickInstancesRes
7878
return AppBrickInstancesResult{}, fmt.Errorf("brick not found with id %s", brickInstance.ID)
7979
}
8080

81-
variablesMap, configVariables := getBrickConfigDetails(brick, brickInstance.Variables)
81+
variablesMap, configVariables := getInstanceBrickConfigVariableDetails(brick, brickInstance.Variables)
8282

8383
res.BrickInstances[i] = BrickInstanceListItem{
8484
ID: brick.ID,
@@ -107,7 +107,7 @@ func (s *Service) AppBrickInstanceDetails(a *app.ArduinoApp, brickID string) (Br
107107
return BrickInstance{}, fmt.Errorf("brick %s not added in the app", brickID)
108108
}
109109

110-
variables, configVariables := getBrickConfigDetails(brick, a.Descriptor.Bricks[brickIndex].Variables)
110+
variables, configVariables := getInstanceBrickConfigVariableDetails(brick, a.Descriptor.Bricks[brickIndex].Variables)
111111

112112
modelID := a.Descriptor.Bricks[brickIndex].Model
113113
if modelID == "" {
@@ -134,7 +134,7 @@ func (s *Service) AppBrickInstanceDetails(a *app.ArduinoApp, brickID string) (Br
134134
}, nil
135135
}
136136

137-
func getBrickConfigDetails(
137+
func getInstanceBrickConfigVariableDetails(
138138
brick *bricksindex.Brick, userVariables map[string]string,
139139
) (map[string]string, []BrickConfigVariable) {
140140
variablesMap := make(map[string]string, len(brick.Variables))
@@ -167,15 +167,6 @@ func (s *Service) BricksDetails(id string, idProvider *app.IDProvider,
167167
return BrickDetailsResult{}, ErrBrickNotFound
168168
}
169169

170-
variables := make(map[string]BrickVariable, len(brick.Variables))
171-
for _, v := range brick.Variables {
172-
variables[v.Name] = BrickVariable{
173-
DefaultValue: v.DefaultValue,
174-
Description: v.Description,
175-
Required: v.IsRequired(),
176-
}
177-
}
178-
179170
readme, err := s.staticStore.GetBrickReadmeFromID(brick.ID)
180171
if err != nil {
181172
return BrickDetailsResult{}, fmt.Errorf("cannot open docs for brick %s: %w", id, err)
@@ -200,6 +191,9 @@ func (s *Service) BricksDetails(id string, idProvider *app.IDProvider,
200191
if err != nil {
201192
return BrickDetailsResult{}, fmt.Errorf("unable to get used by apps: %w", err)
202193
}
194+
195+
variables, configVariables := getBrickConfigVariableDetails(brick)
196+
203197
return BrickDetailsResult{
204198
ID: id,
205199
Name: brick.Name,
@@ -220,9 +214,33 @@ func (s *Service) BricksDetails(id string, idProvider *app.IDProvider,
220214
Description: m.ModuleDescription,
221215
}
222216
}),
217+
ConfigVariables: configVariables,
223218
}, nil
224219
}
225220

221+
func getBrickConfigVariableDetails(
222+
brick *bricksindex.Brick) (map[string]BrickVariable, []BrickConfigVariable) {
223+
variablesMap := make(map[string]BrickVariable, len(brick.Variables))
224+
variableDetails := make([]BrickConfigVariable, 0, len(brick.Variables))
225+
226+
for _, v := range brick.Variables {
227+
variablesMap[v.Name] = BrickVariable{
228+
DefaultValue: v.DefaultValue,
229+
Description: v.Description,
230+
Required: v.IsRequired(),
231+
}
232+
233+
variableDetails = append(variableDetails, BrickConfigVariable{
234+
Name: v.Name,
235+
Value: v.DefaultValue,
236+
Description: v.Description,
237+
Required: v.IsRequired(),
238+
})
239+
}
240+
241+
return variablesMap, variableDetails
242+
}
243+
226244
func getUsedByApps(
227245
cfg config.Configuration, brickId string, idProvider *app.IDProvider) ([]AppReference, error) {
228246
var (

internal/orchestrator/bricks/bricks_test.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ func TestGetBrickInstanceVariableDetails(t *testing.T) {
317317

318318
for _, tt := range tests {
319319
t.Run(tt.name, func(t *testing.T) {
320-
actualVariableMap, actualConfigVariables := getBrickConfigDetails(tt.brick, tt.userVariables)
320+
actualVariableMap, actualConfigVariables := getInstanceBrickConfigVariableDetails(tt.brick, tt.userVariables)
321321
require.Equal(t, tt.expectedVariableMap, actualVariableMap)
322322
require.Equal(t, tt.expectedConfigVariables, actualConfigVariables)
323323
})
@@ -402,6 +402,21 @@ func TestBricksDetails(t *testing.T) {
402402
})
403403

404404
t.Run("Success - Full Details - multiple models", func(t *testing.T) {
405+
expectConfigVariables := []BrickConfigVariable{
406+
{
407+
Name: "EI_OBJ_DETECTION_MODEL",
408+
Value: "default_path",
409+
Description: "path to the model file",
410+
Required: false,
411+
},
412+
{
413+
Name: "CUSTOM_MODEL_PATH",
414+
Value: "/home/arduino/.arduino-bricks/ei-models",
415+
Description: "path to the custom model directory",
416+
Required: false,
417+
},
418+
}
419+
405420
res, err := svc.BricksDetails("arduino:object_detection", idProvider, cfg)
406421
require.NoError(t, err)
407422

@@ -425,6 +440,8 @@ func TestBricksDetails(t *testing.T) {
425440
require.Equal(t, "face-detection", res.CompatibleModels[1].ID)
426441
require.Equal(t, "Lightweight-Face-Detection", res.CompatibleModels[1].Name)
427442
require.Equal(t, "", res.CompatibleModels[1].Description)
443+
require.Len(t, res.ConfigVariables, 2)
444+
require.Equal(t, expectConfigVariables, res.ConfigVariables)
428445
})
429446

430447
t.Run("Success - Full Details - no models", func(t *testing.T) {
@@ -444,6 +461,7 @@ func TestBricksDetails(t *testing.T) {
444461
require.Equal(t, "My App", res.UsedByApps[0].Name)
445462
require.NotEmpty(t, res.UsedByApps[0].ID)
446463
require.Len(t, res.CompatibleModels, 0)
464+
require.Empty(t, res.ConfigVariables)
447465
})
448466

449467
t.Run("Success - Full Details - one model", func(t *testing.T) {
@@ -456,6 +474,8 @@ func TestBricksDetails(t *testing.T) {
456474
require.Equal(t, "face-detection", res.CompatibleModels[0].ID)
457475
require.Equal(t, "Lightweight-Face-Detection", res.CompatibleModels[0].Name)
458476
require.Equal(t, "", res.CompatibleModels[0].Description)
477+
require.Empty(t, res.ConfigVariables)
478+
require.Empty(t, res.Variables)
459479
})
460480
}
461481

internal/orchestrator/bricks/types.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,11 @@ type BrickDetailsResult struct {
9191
Category string `json:"category"`
9292
Status string `json:"status"`
9393
RequireModel bool `json:"require_model"`
94-
Variables map[string]BrickVariable `json:"variables,omitempty"`
94+
Variables map[string]BrickVariable `json:"variables,omitempty" description:"Deprecated: use config_variables instead. This field is kept for backward compatibility."`
9595
Readme string `json:"readme"`
9696
ApiDocsPath string `json:"api_docs_path"`
9797
CodeExamples []CodeExample `json:"code_examples"`
9898
UsedByApps []AppReference `json:"used_by_apps"`
9999
CompatibleModels []AIModel `json:"compatible_models"`
100+
ConfigVariables []BrickConfigVariable `json:"config_variables"`
100101
}

0 commit comments

Comments
 (0)