Skip to content

Commit

Permalink
[skip-changelog] testsuite: added mocked serial discovery for integra…
Browse files Browse the repository at this point in the history
…tion tests (#2376)

* Added implementation of serial_discovery mock

* Added first mocked integration test
  • Loading branch information
cmaglie authored Oct 19, 2023
1 parent 5ed8d4b commit 710ecba
Show file tree
Hide file tree
Showing 6 changed files with 354 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/arduino/go-properties-orderedmap v1.8.0
github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b
github.com/arduino/go-win32-utils v1.0.0
github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.1.1
github.com/cmaglie/pb v1.0.27
github.com/codeclysm/extract/v3 v3.1.1
github.com/djherbis/buffer v1.2.0
Expand Down
187 changes: 187 additions & 0 deletions go.sum

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions internal/integrationtest/arduino-cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,33 @@ func (cli *ArduinoCLI) convertEnvForExecutils(env map[string]string) []string {
return envVars
}

// InstallMockedSerialDiscovery will replace the already installed serial-discovery
// with a mocked one.
func (cli *ArduinoCLI) InstallMockedSerialDiscovery(t *testing.T) {
// Build mocked serial-discovery
mockDir := FindRepositoryRootPath(t).Join("internal", "integrationtest", "mock_serial_discovery")
gobuild, err := executils.NewProcess(nil, "go", "build")
require.NoError(t, err)
gobuild.SetDirFromPath(mockDir)
require.NoError(t, gobuild.Run(), "Building mocked serial-discovery")

// Install it replacing the current serial discovery
mockBin := mockDir.Join("mock_serial_discovery")
dataDir := cli.DataDir()
require.NotNil(t, dataDir, "data dir missing")
serialDiscoveries, err := dataDir.Join("packages", "builtin", "tools", "serial-discovery").ReadDirRecursiveFiltered(
nil, paths.AndFilter(
paths.FilterNames("serial-discovery"),
paths.FilterOutDirectories(),
),
)
require.NoError(t, err, "scanning data dir for serial-discoveries")
require.NotEmpty(t, serialDiscoveries, "no serial-discoveries found in data dir")
for _, serialDiscovery := range serialDiscoveries {
require.NoError(t, mockBin.CopyTo(serialDiscovery), "installing mocked serial discovery to %s", serialDiscovery)
}
}

// RunWithCustomEnv executes the given arduino-cli command with the given custom env and returns the output.
func (cli *ArduinoCLI) RunWithCustomEnv(env map[string]string, args ...string) ([]byte, []byte, error) {
if cli.cliConfigPath != nil {
Expand Down
38 changes: 38 additions & 0 deletions internal/integrationtest/board/board_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,44 @@ func TestBoardList(t *testing.T) {
MustBeEmpty()
}

func TestBoardListMock(t *testing.T) {
env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t)
defer env.CleanUp()

_, _, err := cli.Run("core", "update-index")
require.NoError(t, err)

cli.InstallMockedSerialDiscovery(t)

stdout, _, err := cli.Run("board", "list", "--format", "json")
require.NoError(t, err)

// check is a valid json and contains a list of ports
requirejson.Contains(t, stdout, `[
{
"matching_boards": [
{
"name": "Arduino Yún",
"fqbn": "arduino:avr:yun"
}
],
"port": {
"address": "/dev/ttyCIAO",
"label": "Mocked Serial port",
"protocol": "serial",
"protocol_label": "Serial",
"properties": {
"pid": "0x0041",
"serial": "123456",
"vid": "0x2341"
},
"hardware_id": "123456"
}
}
]
`)
}

func TestBoardListWithFqbnFilter(t *testing.T) {
if os.Getenv("CI") != "" {
t.Skip("VMs have no serial ports")
Expand Down
1 change: 1 addition & 0 deletions internal/integrationtest/mock_serial_discovery/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mock_serial_discovery
100 changes: 100 additions & 0 deletions internal/integrationtest/mock_serial_discovery/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// This file is part arduino-cli.
//
// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
//
// This software is released under the GNU General Public License version 3,
// which covers the main part of arduino-cli.
// The terms of this license can be found at:
// https://www.gnu.org/licenses/gpl-3.0.en.html
//
// You can be released from the requirements of the above licenses by purchasing
// a commercial license. Buying such a license is mandatory if you want to modify or
// otherwise use the software for commercial activities involving the Arduino
// software without disclosing the source code of your own applications. To purchase
// a commercial license, send an email to [email protected].
//

package main

import (
"errors"
"os"
"time"

"github.com/arduino/go-properties-orderedmap"
discovery "github.com/arduino/pluggable-discovery-protocol-handler/v2"
)

type mockSerialDiscovery struct {
startSyncCount int
closeChan chan<- bool
}

func main() {
dummy := &mockSerialDiscovery{}
server := discovery.NewServer(dummy)
if err := server.Run(os.Stdin, os.Stdout); err != nil {
os.Exit(1)
}
}

// Hello does nothing here...
func (d *mockSerialDiscovery) Hello(userAgent string, protocol int) error {
return nil
}

// Quit does nothing here...
func (d *mockSerialDiscovery) Quit() {}

// Stop terminates the discovery loop
func (d *mockSerialDiscovery) Stop() error {
if d.closeChan != nil {
d.closeChan <- true
close(d.closeChan)
d.closeChan = nil
}
return nil
}

// StartSync starts the goroutine that generates fake Ports.
func (d *mockSerialDiscovery) StartSync(eventCB discovery.EventCallback, errorCB discovery.ErrorCallback) error {
// Every 5 starts produce an error
d.startSyncCount++
if d.startSyncCount%5 == 0 {
return errors.New("could not start_sync every 5 times")
}

c := make(chan bool)
d.closeChan = c

// Start asynchronous event emitter
go func() {
var closeChan <-chan bool = c

// Output initial port state
eventCB("add", &discovery.Port{
Address: "/dev/ttyCIAO",
AddressLabel: "Mocked Serial port",
Protocol: "serial",
ProtocolLabel: "Serial",
HardwareID: "123456",
Properties: properties.NewFromHashmap(map[string]string{
"vid": "0x2341",
"pid": "0x0041",
"serial": "123456",
}),
})

select {
case <-closeChan:
return
case <-time.After(5 * time.Second):
errorCB("unrecoverable error, cannot send more events")
}

<-closeChan
}()

return nil
}

0 comments on commit 710ecba

Please sign in to comment.