Skip to content

Commit

Permalink
Added integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
cmaglie committed Oct 8, 2024
1 parent ac6ec6d commit eb0b39d
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 0 deletions.
52 changes: 52 additions & 0 deletions internal/integrationtest/arduino-cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,42 @@ func (cli *ArduinoCLI) InstallMockedSerialMonitor(t *testing.T) {
}
}

// InstallMockedAvrdude will replace the already installed avrdude with a mocked one.
func (cli *ArduinoCLI) InstallMockedAvrdude(t *testing.T) {
fmt.Println(color.BlueString("<<< Install mocked avrdude"))

// Build mocked serial-discovery
mockDir := FindRepositoryRootPath(t).Join("internal", "mock_avrdude")
gobuild, err := paths.NewProcess(nil, "go", "build")
require.NoError(t, err)
gobuild.SetDirFromPath(mockDir)
require.NoError(t, gobuild.Run(), "Building mocked avrdude")
ext := ""
if runtime.GOOS == "windows" {
ext = ".exe"
}
mockBin := mockDir.Join("mock_avrdude" + ext)
require.True(t, mockBin.Exist())
fmt.Println(color.HiBlackString(" Build of mocked avrdude succeeded."))

// Install it replacing the current avrdudes
dataDir := cli.DataDir()
require.NotNil(t, dataDir, "data dir missing")

avrdudes, err := dataDir.Join("packages", "arduino", "tools", "avrdude").ReadDirRecursiveFiltered(
nil, paths.AndFilter(
paths.FilterNames("avrdude"+ext),
paths.FilterOutDirectories(),
),
)
require.NoError(t, err, "scanning data dir for avrdude(s)")
require.NotEmpty(t, avrdudes, "no avrdude(s) found in data dir")
for _, avrdude := range avrdudes {
require.NoError(t, mockBin.CopyTo(avrdude), "installing mocked avrdude to %s", avrdude)
fmt.Println(color.HiBlackString(" Mocked avrdude installed in " + avrdude.String()))
}
}

// 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) {
var stdoutBuf, stderrBuf bytes.Buffer
Expand Down Expand Up @@ -642,3 +678,19 @@ func (inst *ArduinoCLIInstance) Monitor(ctx context.Context, port *commands.Port
})
return monitorClient, err
}

// Upload calls the "Upload" gRPC method.
func (inst *ArduinoCLIInstance) Upload(ctx context.Context, fqbn, sketchPath, port, protocol string) (commands.ArduinoCoreService_UploadClient, error) {
uploadCl, err := inst.cli.daemonClient.Upload(ctx, &commands.UploadRequest{
Instance: inst.instance,
Fqbn: fqbn,
SketchPath: sketchPath,
Verbose: true,
Port: &commands.Port{
Address: port,
Protocol: protocol,
},
})
logCallf(">>> Upload(%v %v port/protocol=%s/%s)\n", fqbn, sketchPath, port, protocol)
return uploadCl, err
}
120 changes: 120 additions & 0 deletions internal/integrationtest/daemon/upload_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// This file is part of arduino-cli.
//
// Copyright 2024 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 daemon_test

import (
"context"
"errors"
"fmt"
"io"
"os"
"strings"
"testing"
"time"

"github.com/arduino/arduino-cli/internal/integrationtest"
"github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/go-paths-helper"
"github.com/stretchr/testify/require"
)

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

grpcInst := cli.Create()
require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) {
fmt.Printf("INIT> %v\n", ir.GetMessage())
}))

plInst, err := grpcInst.PlatformInstall(context.Background(), "arduino", "avr", "1.8.6", true)
require.NoError(t, err)
for {
msg, err := plInst.Recv()
if errors.Is(err, io.EOF) {
break
}
require.NoError(t, err)
fmt.Printf("INSTALL> %v\n", msg)
}

// Mock avrdude
cli.InstallMockedAvrdude(t)

// Re-init instance to update changes
require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) {
fmt.Printf("INIT> %v\n", ir.GetMessage())
}))

// Build sketch for upload
sk := paths.New("testdata", "bare_minimum")
compile, err := grpcInst.Compile(context.Background(), "arduino:avr:uno", sk.String(), "")
require.NoError(t, err)
for {
msg, err := compile.Recv()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
fmt.Println("COMPILE ERROR>", err)
require.FailNow(t, "Expected successful compile", "compilation failed")
break
}
if msg.GetOutStream() != nil {
fmt.Printf("COMPILE OUT> %v\n", string(msg.GetOutStream()))
}
if msg.GetErrStream() != nil {
fmt.Printf("COMPILE ERR> %v\n", string(msg.GetErrStream()))
}
}

// Try upload and interrupt the call after 1 sec
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
upload, err := grpcInst.Upload(ctx, "arduino:avr:uno", sk.String(), "/dev/ttyACM0", "serial")
require.NoError(t, err)
checkFile := ""
for {
msg, err := upload.Recv()
if errors.Is(err, io.EOF) {
require.FailNow(t, "Expected interrupted upload", "upload succeded")
break
}
if err != nil {
fmt.Println("UPLOAD ERROR>", err)
break
}
if out := string(msg.GetOutStream()); out != "" {
fmt.Printf("UPLOAD OUT> %v\n", string(out))
if strings.HasPrefix(out, "CHECKFILE: ") {
checkFile = strings.TrimSpace(out[11:])
}
}
if msg.GetErrStream() != nil {
fmt.Printf("UPLOAD ERR> %v\n", string(msg.GetErrStream()))
}
}
cancel()

// Wait 5 seconds.
// If the mocked avrdude is not killed it will create a checkfile and it will remove it after 5 seconds.
time.Sleep(5 * time.Second)

// Test if the checkfile is still there (if the file is there it means that mocked avrdude
// has been correctly killed).
require.NotEmpty(t, checkFile)
require.FileExists(t, checkFile)
require.NoError(t, os.Remove(checkFile))
}
1 change: 1 addition & 0 deletions internal/mock_avrdude/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mock_avrdude
46 changes: 46 additions & 0 deletions internal/mock_avrdude/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// 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 (
"fmt"
"os"
"time"

"github.com/arduino/go-paths-helper"
)

func main() {
tmp, err := paths.MkTempFile(nil, "test")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
tmp.Close()
tmpPath := paths.New(tmp.Name())

fmt.Println("CHECKFILE:", tmpPath)

// Just sit here for 5 seconds
time.Sleep(5 * time.Second)

// Remove the check file at the end
tmpPath.Remove()

fmt.Println("COMPLETED")
}

0 comments on commit eb0b39d

Please sign in to comment.