Skip to content

Commit 0a73143

Browse files
mirkoCrobumirkoCrobu
authored andcommitted
add integration tests and code review fix
1 parent 557ff11 commit 0a73143

24 files changed

+2008
-8
lines changed

internal/orchestrator/bricks/bricks.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,11 @@ func (s *Service) BricksDetails(id string) (BrickDetailsResult, error) {
154154
if err != nil {
155155
return BrickDetailsResult{}, fmt.Errorf("cannot open code examples for brick %s: %w", id, err)
156156
}
157-
var codeExamples []CodeExample
158-
if examplePaths != nil {
159-
codeExamples = f.Map(examplePaths, func(p *paths.Path) CodeExample {
160-
return CodeExample{
161-
Path: p.String(),
162-
}
163-
})
164-
}
157+
var codeExamples []CodeExample = f.Map(examplePaths, func(p *paths.Path) CodeExample {
158+
return CodeExample{
159+
Path: p.String(),
160+
}
161+
})
165162

166163
return BrickDetailsResult{
167164
ID: id,
Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
package bricks
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
8+
"github.com/arduino/go-paths-helper"
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
"go.bug.st/f"
12+
13+
"github.com/arduino/arduino-app-cli/internal/orchestrator/app"
14+
"github.com/arduino/arduino-app-cli/internal/orchestrator/bricksindex"
15+
"github.com/arduino/arduino-app-cli/internal/orchestrator/config"
16+
"github.com/arduino/arduino-app-cli/internal/store"
17+
)
18+
19+
func TestBrickInstanceDetails(t *testing.T) {
20+
basaedir := getBasedir(t)
21+
service := setupTestService(t, basaedir)
22+
app := getTestApp(t, "testdata/object-detection", "object-detection")
23+
24+
testCases := []struct {
25+
name string
26+
brickID string
27+
wantErr bool
28+
wantErrMsg string
29+
expectedBrickInstance BrickInstance
30+
}{
31+
{
32+
name: "Success - brick instance found in app",
33+
brickID: "arduino:arduino_cloud",
34+
wantErr: false,
35+
expectedBrickInstance: BrickInstance{
36+
ID: "arduino:arduino_cloud",
37+
Name: "Arduino Cloud",
38+
Author: "Arduino",
39+
Category: "",
40+
Status: "installed",
41+
Variables: map[string]string{
42+
"ARDUINO_DEVICE_ID": "<YOUR_DEVICE_ID>",
43+
"ARDUINO_SECRET": "<YOUR_SECRET>",
44+
},
45+
ModelID: "",
46+
},
47+
},
48+
{
49+
name: "Error - brick not found in index",
50+
brickID: "arduino:non_existing_brick",
51+
wantErr: true,
52+
wantErrMsg: "brick not found",
53+
},
54+
{
55+
name: "Error - brick exists but is not in app",
56+
brickID: "arduino:dbstorage_sqlstore",
57+
wantErr: true,
58+
wantErrMsg: "not added in the app",
59+
},
60+
}
61+
62+
for _, tc := range testCases {
63+
t.Run(tc.name, func(t *testing.T) {
64+
brickInstance, err := service.AppBrickInstanceDetails(&app, tc.brickID)
65+
66+
if tc.wantErr {
67+
require.Error(t, err)
68+
if tc.wantErrMsg != "" {
69+
require.Contains(t, err.Error(), tc.wantErrMsg)
70+
}
71+
72+
assert.Equal(t, BrickInstance{}, brickInstance)
73+
return
74+
}
75+
76+
require.NoError(t, err)
77+
assert.Equal(t, tc.expectedBrickInstance, brickInstance)
78+
})
79+
}
80+
}
81+
func TestBricksDetails1(t *testing.T) {
82+
basaedir := getBasedir(t)
83+
service := setupTestService(t, basaedir)
84+
testDataAssetsPath := paths.New(basaedir)
85+
86+
expectedVars := map[string]BrickVariable{
87+
"ARDUINO_DEVICE_ID": {
88+
DefaultValue: "<YOUR_DEVICE_ID>",
89+
Description: "Arduino Cloud Device ID",
90+
Required: false,
91+
},
92+
"ARDUINO_SECRET": {
93+
DefaultValue: "<YOUR_SECRET>",
94+
Description: "Arduino Cloud Secret",
95+
Required: false,
96+
},
97+
}
98+
readmePath := testDataAssetsPath.Join("docs", "arduino", "arduino_cloud", "README.md")
99+
expectedReadmeBytes, err := os.ReadFile(readmePath.String())
100+
require.NoError(t, err, "Failed to read test readme file")
101+
expectedReadme := string(expectedReadmeBytes)
102+
expectedAPIPath := testDataAssetsPath.Join("api-docs", "arduino", "app_bricks", "arduino_cloud", "API.md").String()
103+
examplesBasePath := testDataAssetsPath.Join("examples", "arduino", "arduino_cloud")
104+
expectedExamples := []CodeExample{
105+
{Path: examplesBasePath.Join("1_led_blink.py").String()},
106+
{Path: examplesBasePath.Join("2_light_with_colors_monitor.py").String()},
107+
{Path: examplesBasePath.Join("3_light_with_colors_command.py").String()},
108+
}
109+
110+
testCases := []struct {
111+
name string
112+
brickID string
113+
wantErr bool
114+
wantErrMsg string
115+
expectedResult BrickDetailsResult
116+
}{
117+
{
118+
name: "Success - brick found",
119+
brickID: "arduino:arduino_cloud",
120+
wantErr: false,
121+
expectedResult: BrickDetailsResult{
122+
ID: "arduino:arduino_cloud",
123+
Name: "Arduino Cloud",
124+
Author: "Arduino",
125+
Description: "Connects to Arduino Cloud",
126+
Category: "",
127+
Status: "installed",
128+
Variables: expectedVars,
129+
Readme: expectedReadme,
130+
ApiDocsPath: expectedAPIPath,
131+
CodeExamples: expectedExamples,
132+
},
133+
},
134+
{
135+
name: "Error - brick not found",
136+
brickID: "arduino:non_existing_brick",
137+
wantErr: true,
138+
wantErrMsg: "brick not found",
139+
},
140+
}
141+
142+
for _, tc := range testCases {
143+
t.Run(tc.name, func(t *testing.T) {
144+
result, err := service.BricksDetails(tc.brickID)
145+
146+
if tc.wantErr {
147+
require.Error(t, err)
148+
if tc.wantErrMsg != "" {
149+
require.Contains(t, err.Error(), tc.wantErrMsg)
150+
}
151+
assert.Equal(t, BrickDetailsResult{}, result)
152+
return
153+
}
154+
require.NoError(t, err)
155+
assert.Equal(t, tc.expectedResult, result)
156+
})
157+
}
158+
}
159+
160+
func TestBricksDetails(t *testing.T) {
161+
162+
basaedir := getBasedir(t)
163+
service := setupTestService(t, basaedir)
164+
testDataAssetsPath := paths.New(basaedir)
165+
166+
testCases := []struct {
167+
name string
168+
brickID string
169+
wantErr bool
170+
wantErrMsg string
171+
expectedResult BrickDetailsResult
172+
}{
173+
{
174+
name: "Success - brick found",
175+
brickID: "arduino:arduino_cloud",
176+
wantErr: false,
177+
expectedResult: BrickDetailsResult{
178+
ID: "arduino:arduino_cloud",
179+
Name: "Arduino Cloud",
180+
Author: "Arduino",
181+
Description: "Connects to Arduino Cloud",
182+
Category: "",
183+
Status: "installed",
184+
Variables: map[string]BrickVariable{
185+
"ARDUINO_DEVICE_ID": {
186+
DefaultValue: "<YOUR_DEVICE_ID>",
187+
Description: "Arduino Cloud Device ID",
188+
Required: false,
189+
},
190+
"ARDUINO_SECRET": {
191+
DefaultValue: "<YOUR_SECRET>",
192+
Description: "Arduino Cloud Secret",
193+
Required: false,
194+
},
195+
},
196+
Readme: string(mustReadFile(t, testDataAssetsPath.Join(
197+
"docs", "arduino", "arduino_cloud", "README.md",
198+
).String())),
199+
ApiDocsPath: testDataAssetsPath.Join(
200+
"api-docs", "arduino", "app_bricks", "arduino_cloud", "API.md",
201+
).String(),
202+
CodeExamples: []CodeExample{
203+
{Path: testDataAssetsPath.Join("examples", "arduino", "arduino_cloud", "1_led_blink.py").String()},
204+
{Path: testDataAssetsPath.Join("examples", "arduino", "arduino_cloud", "2_light_with_colors_monitor.py").String()},
205+
{Path: testDataAssetsPath.Join("examples", "arduino", "arduino_cloud", "3_light_with_colors_command.py").String()},
206+
},
207+
},
208+
},
209+
{
210+
name: "Error - brick not found",
211+
brickID: "arduino:non_existing_brick",
212+
wantErr: true,
213+
wantErrMsg: "brick not found",
214+
},
215+
{
216+
name: "Success - brick with nil examples",
217+
brickID: "arduino:streamlit_ui",
218+
wantErr: false,
219+
expectedResult: BrickDetailsResult{
220+
ID: "arduino:streamlit_ui",
221+
Name: "WebUI - Streamlit",
222+
Author: "Arduino",
223+
Description: "A simplified user interface based on Streamlit and Python.",
224+
Category: "ui",
225+
Status: "installed",
226+
Variables: map[string]BrickVariable{},
227+
Readme: string(mustReadFile(t, testDataAssetsPath.Join(
228+
"docs", "arduino", "streamlit_ui", "README.md",
229+
).String())),
230+
ApiDocsPath: testDataAssetsPath.Join(
231+
"api-docs", "arduino", "app_bricks", "streamlit_ui", "API.md",
232+
).String(),
233+
CodeExamples: []CodeExample{},
234+
},
235+
},
236+
}
237+
for _, tc := range testCases {
238+
t.Run(tc.name, func(t *testing.T) {
239+
result, err := service.BricksDetails(tc.brickID)
240+
241+
if tc.wantErr {
242+
// --- Error Case ---
243+
require.Error(t, err)
244+
if tc.wantErrMsg != "" {
245+
require.Contains(t, err.Error(), tc.wantErrMsg)
246+
}
247+
assert.Equal(t, BrickDetailsResult{}, result)
248+
return
249+
}
250+
251+
// --- Success Case ---
252+
require.NoError(t, err)
253+
assert.Equal(t, tc.expectedResult, result)
254+
})
255+
}
256+
}
257+
258+
func setupTestService(t *testing.T, baseDir string) *Service {
259+
store := store.NewStaticStore(baseDir)
260+
261+
bricksIndex, err := bricksindex.GenerateBricksIndexFromFile(paths.New(baseDir))
262+
require.NoError(t, err)
263+
264+
service := NewService(nil, bricksIndex, store)
265+
return service
266+
}
267+
268+
func getBasedir(t *testing.T) string {
269+
cfg, err := config.NewFromEnv()
270+
require.NoError(t, err)
271+
baseDir := paths.New("../../e2e/daemon/testdata", "assets", cfg.RunnerVersion).String()
272+
return baseDir
273+
}
274+
func getTestApp(t *testing.T, appPath, appName string) app.ArduinoApp {
275+
app, err := app.Load(appPath)
276+
assert.NoError(t, err)
277+
assert.NotEmpty(t, app)
278+
assert.NotNil(t, app.MainPythonFile)
279+
assert.Equal(t, f.Must(filepath.Abs("testdata/"+appName+"/python/main.py")), app.MainPythonFile.String())
280+
// in case you want to test sketch based apps too
281+
// assert.NotNil(t, app.MainSketchPath)
282+
//assert.Equal(t, f.Must(filepath.Abs("testdata/"+appName+"/sketch")), app.MainSketchPath.String())
283+
return app
284+
}
285+
286+
func mustReadFile(t *testing.T, path string) []byte {
287+
t.Helper()
288+
bytes, err := os.ReadFile(path)
289+
require.NoError(t, err, "failed to read test file: %s", path)
290+
return bytes
291+
}

0 commit comments

Comments
 (0)