Skip to content

Commit 710ecba

Browse files
authored
[skip-changelog] testsuite: added mocked serial discovery for integration tests (#2376)
* Added implementation of serial_discovery mock * Added first mocked integration test
1 parent 5ed8d4b commit 710ecba

File tree

6 files changed

+354
-0
lines changed

6 files changed

+354
-0
lines changed

Diff for: go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/arduino/go-properties-orderedmap v1.8.0
1212
github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b
1313
github.com/arduino/go-win32-utils v1.0.0
14+
github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.1.1
1415
github.com/cmaglie/pb v1.0.27
1516
github.com/codeclysm/extract/v3 v3.1.1
1617
github.com/djherbis/buffer v1.2.0

Diff for: go.sum

+187
Large diffs are not rendered by default.

Diff for: internal/integrationtest/arduino-cli.go

+27
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,33 @@ func (cli *ArduinoCLI) convertEnvForExecutils(env map[string]string) []string {
201201
return envVars
202202
}
203203

204+
// InstallMockedSerialDiscovery will replace the already installed serial-discovery
205+
// with a mocked one.
206+
func (cli *ArduinoCLI) InstallMockedSerialDiscovery(t *testing.T) {
207+
// Build mocked serial-discovery
208+
mockDir := FindRepositoryRootPath(t).Join("internal", "integrationtest", "mock_serial_discovery")
209+
gobuild, err := executils.NewProcess(nil, "go", "build")
210+
require.NoError(t, err)
211+
gobuild.SetDirFromPath(mockDir)
212+
require.NoError(t, gobuild.Run(), "Building mocked serial-discovery")
213+
214+
// Install it replacing the current serial discovery
215+
mockBin := mockDir.Join("mock_serial_discovery")
216+
dataDir := cli.DataDir()
217+
require.NotNil(t, dataDir, "data dir missing")
218+
serialDiscoveries, err := dataDir.Join("packages", "builtin", "tools", "serial-discovery").ReadDirRecursiveFiltered(
219+
nil, paths.AndFilter(
220+
paths.FilterNames("serial-discovery"),
221+
paths.FilterOutDirectories(),
222+
),
223+
)
224+
require.NoError(t, err, "scanning data dir for serial-discoveries")
225+
require.NotEmpty(t, serialDiscoveries, "no serial-discoveries found in data dir")
226+
for _, serialDiscovery := range serialDiscoveries {
227+
require.NoError(t, mockBin.CopyTo(serialDiscovery), "installing mocked serial discovery to %s", serialDiscovery)
228+
}
229+
}
230+
204231
// RunWithCustomEnv executes the given arduino-cli command with the given custom env and returns the output.
205232
func (cli *ArduinoCLI) RunWithCustomEnv(env map[string]string, args ...string) ([]byte, []byte, error) {
206233
if cli.cliConfigPath != nil {

Diff for: internal/integrationtest/board/board_test.go

+38
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,44 @@ func TestBoardList(t *testing.T) {
9191
MustBeEmpty()
9292
}
9393

94+
func TestBoardListMock(t *testing.T) {
95+
env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t)
96+
defer env.CleanUp()
97+
98+
_, _, err := cli.Run("core", "update-index")
99+
require.NoError(t, err)
100+
101+
cli.InstallMockedSerialDiscovery(t)
102+
103+
stdout, _, err := cli.Run("board", "list", "--format", "json")
104+
require.NoError(t, err)
105+
106+
// check is a valid json and contains a list of ports
107+
requirejson.Contains(t, stdout, `[
108+
{
109+
"matching_boards": [
110+
{
111+
"name": "Arduino Yún",
112+
"fqbn": "arduino:avr:yun"
113+
}
114+
],
115+
"port": {
116+
"address": "/dev/ttyCIAO",
117+
"label": "Mocked Serial port",
118+
"protocol": "serial",
119+
"protocol_label": "Serial",
120+
"properties": {
121+
"pid": "0x0041",
122+
"serial": "123456",
123+
"vid": "0x2341"
124+
},
125+
"hardware_id": "123456"
126+
}
127+
}
128+
]
129+
`)
130+
}
131+
94132
func TestBoardListWithFqbnFilter(t *testing.T) {
95133
if os.Getenv("CI") != "" {
96134
t.Skip("VMs have no serial ports")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mock_serial_discovery
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//
2+
// This file is part arduino-cli.
3+
//
4+
// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
5+
//
6+
// This software is released under the GNU General Public License version 3,
7+
// which covers the main part of arduino-cli.
8+
// The terms of this license can be found at:
9+
// https://www.gnu.org/licenses/gpl-3.0.en.html
10+
//
11+
// You can be released from the requirements of the above licenses by purchasing
12+
// a commercial license. Buying such a license is mandatory if you want to modify or
13+
// otherwise use the software for commercial activities involving the Arduino
14+
// software without disclosing the source code of your own applications. To purchase
15+
// a commercial license, send an email to license@arduino.cc.
16+
//
17+
18+
package main
19+
20+
import (
21+
"errors"
22+
"os"
23+
"time"
24+
25+
"github.com/arduino/go-properties-orderedmap"
26+
discovery "github.com/arduino/pluggable-discovery-protocol-handler/v2"
27+
)
28+
29+
type mockSerialDiscovery struct {
30+
startSyncCount int
31+
closeChan chan<- bool
32+
}
33+
34+
func main() {
35+
dummy := &mockSerialDiscovery{}
36+
server := discovery.NewServer(dummy)
37+
if err := server.Run(os.Stdin, os.Stdout); err != nil {
38+
os.Exit(1)
39+
}
40+
}
41+
42+
// Hello does nothing here...
43+
func (d *mockSerialDiscovery) Hello(userAgent string, protocol int) error {
44+
return nil
45+
}
46+
47+
// Quit does nothing here...
48+
func (d *mockSerialDiscovery) Quit() {}
49+
50+
// Stop terminates the discovery loop
51+
func (d *mockSerialDiscovery) Stop() error {
52+
if d.closeChan != nil {
53+
d.closeChan <- true
54+
close(d.closeChan)
55+
d.closeChan = nil
56+
}
57+
return nil
58+
}
59+
60+
// StartSync starts the goroutine that generates fake Ports.
61+
func (d *mockSerialDiscovery) StartSync(eventCB discovery.EventCallback, errorCB discovery.ErrorCallback) error {
62+
// Every 5 starts produce an error
63+
d.startSyncCount++
64+
if d.startSyncCount%5 == 0 {
65+
return errors.New("could not start_sync every 5 times")
66+
}
67+
68+
c := make(chan bool)
69+
d.closeChan = c
70+
71+
// Start asynchronous event emitter
72+
go func() {
73+
var closeChan <-chan bool = c
74+
75+
// Output initial port state
76+
eventCB("add", &discovery.Port{
77+
Address: "/dev/ttyCIAO",
78+
AddressLabel: "Mocked Serial port",
79+
Protocol: "serial",
80+
ProtocolLabel: "Serial",
81+
HardwareID: "123456",
82+
Properties: properties.NewFromHashmap(map[string]string{
83+
"vid": "0x2341",
84+
"pid": "0x0041",
85+
"serial": "123456",
86+
}),
87+
})
88+
89+
select {
90+
case <-closeChan:
91+
return
92+
case <-time.After(5 * time.Second):
93+
errorCB("unrecoverable error, cannot send more events")
94+
}
95+
96+
<-closeChan
97+
}()
98+
99+
return nil
100+
}

0 commit comments

Comments
 (0)