Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions internal/api/docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1320,6 +1320,11 @@ components:
$ref: '#/components/schemas/AIModel'
nullable: true
type: array
config_variables:
items:
$ref: '#/components/schemas/BrickConfigVariable'
nullable: true
type: array
description:
type: string
id:
Expand All @@ -1340,6 +1345,9 @@ components:
variables:
additionalProperties:
$ref: '#/components/schemas/BrickVariable'
description: 'Deprecated: use config_variables instead. This field is kept
for backward compatibility.'
nullable: true
type: object
type: object
BrickInstance:
Expand Down
29 changes: 16 additions & 13 deletions internal/e2e/client/client.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions internal/e2e/daemon/brick_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,21 @@ func TestBricksDetails(t *testing.T) {
Name: f.Ptr("Person classification"),
Description: f.Ptr("Person classification model based on WakeVision dataset. This model is trained to classify images into two categories: person and not-person."),
}}
expectConfigVariables := []client.BrickConfigVariable{
{
Name: f.Ptr("CUSTOM_MODEL_PATH"),
Value: f.Ptr("/home/arduino/.arduino-bricks/ei-models"),
Description: f.Ptr("path to the custom model directory"),
Required: f.Ptr(false),
},
{
Name: f.Ptr("EI_CLASSIFICATION_MODEL"),
Value: f.Ptr("/models/ootb/ei/mobilenet-v2-224px.eim"),
Description: f.Ptr("path to the model file"),
Required: f.Ptr(false),
},
}

response, err := httpClient.GetBrickDetailsWithResponse(t.Context(), validBrickID, func(ctx context.Context, req *http.Request) error { return nil })
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode(), "status code should be 200 ok")
Expand All @@ -147,5 +162,7 @@ func TestBricksDetails(t *testing.T) {
require.Equal(t, expectedUsedByApps, *(response.JSON200.UsedByApps))
require.NotNil(t, response.JSON200.CompatibleModels, "Models should not be nil")
require.Equal(t, expectedModelLiteInfo, *(response.JSON200.CompatibleModels))
require.NotNil(t, response.JSON200.ConfigVariables, "ConfigVariables should not be nil")
require.Equal(t, expectConfigVariables, *(response.JSON200.ConfigVariables))
})
}
42 changes: 30 additions & 12 deletions internal/orchestrator/bricks/bricks.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (s *Service) AppBrickInstancesList(a *app.ArduinoApp) (AppBrickInstancesRes
return AppBrickInstancesResult{}, fmt.Errorf("brick not found with id %s", brickInstance.ID)
}

variablesMap, configVariables := getBrickConfigDetails(brick, brickInstance.Variables)
variablesMap, configVariables := getInstanceBrickConfigVariableDetails(brick, brickInstance.Variables)

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

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

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

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

variables := make(map[string]BrickVariable, len(brick.Variables))
for _, v := range brick.Variables {
variables[v.Name] = BrickVariable{
DefaultValue: v.DefaultValue,
Description: v.Description,
Required: v.IsRequired(),
}
}

readme, err := s.staticStore.GetBrickReadmeFromID(brick.ID)
if err != nil {
return BrickDetailsResult{}, fmt.Errorf("cannot open docs for brick %s: %w", id, err)
Expand All @@ -200,6 +191,9 @@ func (s *Service) BricksDetails(id string, idProvider *app.IDProvider,
if err != nil {
return BrickDetailsResult{}, fmt.Errorf("unable to get used by apps: %w", err)
}

variables, configVariables := getBrickConfigVariableDetails(brick)

return BrickDetailsResult{
ID: id,
Name: brick.Name,
Expand All @@ -220,9 +214,33 @@ func (s *Service) BricksDetails(id string, idProvider *app.IDProvider,
Description: m.ModuleDescription,
}
}),
ConfigVariables: configVariables,
}, nil
}

func getBrickConfigVariableDetails(
brick *bricksindex.Brick) (map[string]BrickVariable, []BrickConfigVariable) {
variablesMap := make(map[string]BrickVariable, len(brick.Variables))
variableDetails := make([]BrickConfigVariable, 0, len(brick.Variables))

for _, v := range brick.Variables {
variablesMap[v.Name] = BrickVariable{
DefaultValue: v.DefaultValue,
Description: v.Description,
Required: v.IsRequired(),
}

variableDetails = append(variableDetails, BrickConfigVariable{
Name: v.Name,
Value: v.DefaultValue,
Description: v.Description,
Required: v.IsRequired(),
})
}

return variablesMap, variableDetails
}

func getUsedByApps(
cfg config.Configuration, brickId string, idProvider *app.IDProvider) ([]AppReference, error) {
var (
Expand Down
22 changes: 21 additions & 1 deletion internal/orchestrator/bricks/bricks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ func TestGetBrickInstanceVariableDetails(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actualVariableMap, actualConfigVariables := getBrickConfigDetails(tt.brick, tt.userVariables)
actualVariableMap, actualConfigVariables := getInstanceBrickConfigVariableDetails(tt.brick, tt.userVariables)
require.Equal(t, tt.expectedVariableMap, actualVariableMap)
require.Equal(t, tt.expectedConfigVariables, actualConfigVariables)
})
Expand Down Expand Up @@ -402,6 +402,21 @@ func TestBricksDetails(t *testing.T) {
})

t.Run("Success - Full Details - multiple models", func(t *testing.T) {
expectConfigVariables := []BrickConfigVariable{
{
Name: "EI_OBJ_DETECTION_MODEL",
Value: "default_path",
Description: "path to the model file",
Required: false,
},
{
Name: "CUSTOM_MODEL_PATH",
Value: "/home/arduino/.arduino-bricks/ei-models",
Description: "path to the custom model directory",
Required: false,
},
}

res, err := svc.BricksDetails("arduino:object_detection", idProvider, cfg)
require.NoError(t, err)

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

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

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

Expand Down
3 changes: 2 additions & 1 deletion internal/orchestrator/bricks/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,11 @@ type BrickDetailsResult struct {
Category string `json:"category"`
Status string `json:"status"`
RequireModel bool `json:"require_model"`
Variables map[string]BrickVariable `json:"variables,omitempty"`
Variables map[string]BrickVariable `json:"variables,omitempty" description:"Deprecated: use config_variables instead. This field is kept for backward compatibility."`
Readme string `json:"readme"`
ApiDocsPath string `json:"api_docs_path"`
CodeExamples []CodeExample `json:"code_examples"`
UsedByApps []AppReference `json:"used_by_apps"`
CompatibleModels []AIModel `json:"compatible_models"`
ConfigVariables []BrickConfigVariable `json:"config_variables"`
}