Skip to content

Commit d1e01fe

Browse files
committed
feat(bricks): enhance error messages and add tests for BrickCreate functionality
1 parent 68ad650 commit d1e01fe

File tree

6 files changed

+72
-11
lines changed

6 files changed

+72
-11
lines changed

go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ require (
129129
github.com/fsnotify/fsnotify v1.9.0 // indirect
130130
github.com/fvbommel/sortorder v1.1.0 // indirect
131131
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
132-
github.com/getkin/kin-openapi v0.132.0 // indirect
132+
github.com/getkin/kin-openapi v0.133.0 // indirect
133133
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
134134
github.com/go-git/go-billy/v5 v5.6.2 // indirect
135135
github.com/go-git/go-git/v5 v5.16.2 // indirect
@@ -206,7 +206,7 @@ require (
206206
github.com/morikuni/aec v1.0.0 // indirect
207207
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
208208
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
209-
github.com/oapi-codegen/oapi-codegen/v2 v2.5.0 // indirect
209+
github.com/oapi-codegen/oapi-codegen/v2 v2.5.1 // indirect
210210
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
211211
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
212212
github.com/opencontainers/go-digest v1.0.0 // indirect
@@ -257,6 +257,7 @@ require (
257257
github.com/ulikunitz/xz v0.5.15 // indirect
258258
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
259259
github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
260+
github.com/woodsbury/decimal128 v1.3.0 // indirect
260261
github.com/x448/float16 v0.8.4 // indirect
261262
github.com/xanzy/ssh-agent v0.3.3 // indirect
262263
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv
312312
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
313313
github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk=
314314
github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58=
315+
github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ=
316+
github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE=
315317
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
316318
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
317319
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
@@ -678,6 +680,8 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
678680
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
679681
github.com/oapi-codegen/oapi-codegen/v2 v2.5.0 h1:iJvF8SdB/3/+eGOXEpsWkD8FQAHj6mqkb6Fnsoc8MFU=
680682
github.com/oapi-codegen/oapi-codegen/v2 v2.5.0/go.mod h1:fwlMxUEMuQK5ih9aymrxKPQqNm2n8bdLk1ppjH+lr9w=
683+
github.com/oapi-codegen/oapi-codegen/v2 v2.5.1 h1:5vHNY1uuPBRBWqB2Dp0G7YB03phxLQZupZTIZaeorjc=
684+
github.com/oapi-codegen/oapi-codegen/v2 v2.5.1/go.mod h1:ro0npU1BWkcGpCgGD9QwPp44l5OIZ94tB3eabnT7DjQ=
681685
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
682686
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
683687
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY=
@@ -909,6 +913,8 @@ github.com/warthog618/go-gpiocdev v0.9.1 h1:pwHPaqjJfhCipIQl78V+O3l9OKHivdRDdmgX
909913
github.com/warthog618/go-gpiocdev v0.9.1/go.mod h1:dN3e3t/S2aSNC+hgigGE/dBW8jE1ONk9bDSEYfoPyl8=
910914
github.com/warthog618/go-gpiosim v0.1.1 h1:MRAEv+T+itmw+3GeIGpQJBfanUVyg0l3JCTwHtwdre4=
911915
github.com/warthog618/go-gpiosim v0.1.1/go.mod h1:YXsnB+I9jdCMY4YAlMSRrlts25ltjmuIsrnoUrBLdqU=
916+
github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0=
917+
github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds=
912918
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
913919
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
914920
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=

internal/orchestrator/bricks/bricks.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -186,23 +186,23 @@ func (s *Service) BrickCreate(
186186
) error {
187187
brick, present := s.bricksIndex.FindBrickByID(req.ID)
188188
if !present {
189-
return fmt.Errorf("brick not found with id %s", req.ID)
189+
return fmt.Errorf("brick '%s' not found", req.ID)
190190
}
191191

192192
for name, reqValue := range req.Variables {
193193
value, exist := brick.GetVariable(name)
194194
if !exist {
195-
return errors.New("variable does not exist")
195+
return fmt.Errorf("variable '%s' does not exist on brick '%s'", name, brick.ID)
196196
}
197197
if value.DefaultValue == "" && reqValue == "" {
198-
return errors.New("variable default value cannot be empty")
198+
return fmt.Errorf("variable '%s' cannot be empty", name)
199199
}
200200
}
201201

202202
for _, brickVar := range brick.Variables {
203203
if brickVar.DefaultValue == "" {
204204
if _, exist := req.Variables[brickVar.Name]; !exist {
205-
return errors.New("variable does not exist")
205+
return fmt.Errorf("required variable '%s' is mandatory", brickVar.Name)
206206
}
207207
}
208208
}
@@ -226,25 +226,20 @@ func (s *Service) BrickCreate(
226226
if idx == -1 {
227227
return fmt.Errorf("model %s does not exsist", *req.Model)
228228
}
229-
230229
brickInstance.Model = models[idx].ID
231230
}
232231
brickInstance.Variables = req.Variables
233232

234233
if brickIndex == -1 {
235-
236234
appCurrent.Descriptor.Bricks = append(appCurrent.Descriptor.Bricks, brickInstance)
237-
238235
} else {
239236
appCurrent.Descriptor.Bricks[brickIndex] = brickInstance
240-
241237
}
242238

243239
err := appCurrent.Save()
244240
if err != nil {
245241
return fmt.Errorf("cannot save brick instance with id %s", req.ID)
246242
}
247-
248243
return nil
249244
}
250245

internal/orchestrator/bricks/bricks_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,54 @@ import (
2828
"github.com/arduino/go-paths-helper"
2929
)
3030

31+
func TestBrickCreate(t *testing.T) {
32+
bricksIndex, err := bricksindex.GenerateBricksIndexFromFile(paths.New("testdata"))
33+
require.Nil(t, err)
34+
brickService := NewService(nil, bricksIndex, nil)
35+
36+
t.Run("fails if brick id does not exist", func(t *testing.T) {
37+
err = brickService.BrickCreate(BrickCreateUpdateRequest{ID: "not-existing-id"}, f.Must(app.Load("./testdata/my-app")))
38+
require.Error(t, err)
39+
require.Equal(t, "brick 'not-existing-id' not found", err.Error())
40+
})
41+
42+
t.Run("fails if the requestes variable is not present in the brick definition", func(t *testing.T) {
43+
req := BrickCreateUpdateRequest{ID: "arduino:arduino_cloud", Variables: map[string]string{
44+
"NON_EXISTING_VARIABLE": "some-value",
45+
}}
46+
err = brickService.BrickCreate(req, f.Must(app.Load("./testdata/my-app")))
47+
require.Error(t, err)
48+
require.Equal(t, "variable 'NON_EXISTING_VARIABLE' does not exist on brick 'arduino:arduino_cloud'", err.Error())
49+
})
50+
51+
t.Run("fails if a required variable is set empty", func(t *testing.T) {
52+
req := BrickCreateUpdateRequest{ID: "arduino:arduino_cloud", Variables: map[string]string{
53+
"ARDUINO_DEVICE_ID": "",
54+
"ARDUINO_SECRET": "a-secret-a",
55+
}}
56+
err = brickService.BrickCreate(req, f.Must(app.Load("./testdata/my-app")))
57+
require.Error(t, err)
58+
require.Equal(t, "variable 'ARDUINO_DEVICE_ID' cannot be empty", err.Error())
59+
})
60+
61+
t.Run("fails if a mandatory variable is not present in the request", func(t *testing.T) {
62+
req := BrickCreateUpdateRequest{ID: "arduino:arduino_cloud", Variables: map[string]string{
63+
"ARDUINO_SECRET": "a-secret-a",
64+
}}
65+
err = brickService.BrickCreate(req, f.Must(app.Load("./testdata/my-app")))
66+
require.Error(t, err)
67+
require.Equal(t, "required variable 'ARDUINO_DEVICE_ID' is mandatory", err.Error())
68+
})
69+
70+
t.Run("the brick is added if it does not exist in the app", func(t *testing.T) {
71+
req := BrickCreateUpdateRequest{ID: "arduino:dbstorage_sqlstore"}
72+
// TODO: find a better way to test if the brick has been added to the app.yaml
73+
// Currently we only check that there is no error since the app.yaml is populated with the brick at every test execution.
74+
err = brickService.BrickCreate(req, f.Must(app.Load("./testdata/my-app")))
75+
require.Nil(t, err)
76+
})
77+
}
78+
3179
func TestOverrideBrickVariablesOfApp(t *testing.T) {
3280
bricksIndex, err := bricksindex.GenerateBricksIndexFromFile(paths.New("testdata"))
3381
require.Nil(t, err)

internal/orchestrator/bricks/testdata/bricks-list.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,13 @@ bricks:
1313
description: Arduino Cloud Device ID
1414
- name: ARDUINO_SECRET
1515
description: Arduino Cloud Secret
16+
- id: arduino:dbstorage_sqlstore
17+
name: Database - SQL
18+
description: Simplified database storage layer for Arduino sensor data using SQLite
19+
local database.
20+
require_container: false
21+
require_model: false
22+
require_devices: false
23+
mount_devices_into_container: false
24+
ports: []
25+
category: storage

internal/orchestrator/bricks/testdata/my-app/app.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ bricks:
66
variables:
77
ARDUINO_DEVICE_ID: my-device-id-79c4b05ef7b6a39
88
ARDUINO_SECRET: my-device-secret-43f4a190b1ffb8ce
9+
- arduino:dbstorage_sqlstore: {}
910
icon: ☁️

0 commit comments

Comments
 (0)