diff --git a/.github/workflows/test-go-task.yml b/.github/workflows/test-go-task.yml index f841f9d376c..84f839a0130 100644 --- a/.github/workflows/test-go-task.yml +++ b/.github/workflows/test-go-task.yml @@ -58,13 +58,61 @@ jobs: echo "result=$RESULT" >> $GITHUB_OUTPUT - test: + tests-collector: + runs-on: ubuntu-latest needs: run-determination if: needs.run-determination.outputs.result == 'true' + outputs: + tests-data: ${{ steps.collection.outputs.tests-data }} + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Collect tests + id: collection + run: | + echo "tests-data=$(go list ./internal/integrationtest/... | grep integrationtest/ | tr "/" " " | cut -d " " -f 6 | jq -cR '[inputs]')" >> $GITHUB_OUTPUT + test-integration: + needs: tests-collector strategy: - fail-fast: false + matrix: + operating-system: + - ubuntu-latest + - windows-latest + - macos-latest + tests: ${{ fromJSON(needs.tests-collector.outputs.tests-data) }} + + runs-on: ${{ matrix.operating-system }} + + steps: + # By default, actions/checkout converts the repo's LF line endings to CRLF on the Windows runner. + - name: Disable EOL conversions + run: git config --global core.autocrlf false + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Task + uses: arduino/setup-task@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Run tests + shell: bash + run: | + export GO_TEST_PACKAGE="github.com/arduino/arduino-cli/internal/integrationtest/${{ matrix.tests }}" + task go:integration-test + + test: + needs: run-determination + strategy: matrix: operating-system: - ubuntu-latest diff --git a/Taskfile.yml b/Taskfile.yml index 86ca98cd289..a793036b136 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -105,6 +105,23 @@ tasks: {{default .DEFAULT_GO_PACKAGES .GO_PACKAGES}} \ {{.TEST_LDFLAGS}} + go:integration-test: + desc: Run the Go-based integration tests + deps: + - task: go:build + dir: '{{default "./" .GO_MODULE_PATH}}' + cmds: + - | + go test \ + -v \ + -short \ + {{ .GO_TEST_PACKAGE }} \ + -run '{{default ".*" .GO_TEST_REGEX}}' \ + {{default "-timeout 20m -coverpkg=./... -covermode=atomic" .GO_TEST_FLAGS}} \ + -coverprofile=coverage_unit.txt \ + {{default .DEFAULT_INTEGRATIONTEST_GO_PACKAGES .GO_PACKAGES}} \ + {{.TEST_LDFLAGS}} + # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/test-go-integration-task/Taskfile.yml go:test-integration: desc: Run integration tests @@ -342,10 +359,13 @@ tasks: vars: PROJECT_NAME: "arduino-cli" DIST_DIR: "dist" - # all modules of this project except for "legacy/..." module + # all modules of this project except for "legacy/..." module and integration test DEFAULT_GO_PACKAGES: sh: | - echo $(cd {{default "./" .GO_MODULE_PATH}} && go list ./... | grep -v legacy | tr '\n' ' ' || echo '"ERROR: Unable to discover Go packages"') + echo $(cd {{default "./" .GO_MODULE_PATH}} && go list ./... | grep -v internal/integrationtest | grep -v legacy | tr '\n' ' ' || echo '"ERROR: Unable to discover Go packages"') + DEFAULT_INTEGRATIONTEST_GO_PACKAGES: + sh: | + echo $(cd {{default "./" .GO_MODULE_PATH}} && go list ./... | grep internal/integrationtest | tr '\n' ' ' || echo '"ERROR: Unable to discover Go packages"') # build vars COMMIT: sh: echo "$(git log --no-show-signature -n 1 --format=%h)" diff --git a/internal/integrationtest/board/board_list_test.go b/internal/integrationtest/board/board_list_test.go deleted file mode 100644 index 12b60497171..00000000000 --- a/internal/integrationtest/board/board_list_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2022 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 license@arduino.cc. - -package board_test - -import ( - "testing" - - "github.com/arduino/arduino-cli/internal/integrationtest" - "github.com/stretchr/testify/require" - "go.bug.st/testifyjson/requirejson" -) - -func TestCorrectBoardListOrdering(t *testing.T) { - env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) - defer env.CleanUp() - - _, _, err := cli.Run("core", "install", "arduino:avr") - require.NoError(t, err) - jsonOut, _, err := cli.Run("board", "listall", "--format", "json") - require.NoError(t, err) - requirejson.Query(t, jsonOut, "[.boards[] | .fqbn]", `[ - "arduino:avr:yun", - "arduino:avr:uno", - "arduino:avr:unomini", - "arduino:avr:diecimila", - "arduino:avr:nano", - "arduino:avr:mega", - "arduino:avr:megaADK", - "arduino:avr:leonardo", - "arduino:avr:leonardoeth", - "arduino:avr:micro", - "arduino:avr:esplora", - "arduino:avr:mini", - "arduino:avr:ethernet", - "arduino:avr:fio", - "arduino:avr:bt", - "arduino:avr:LilyPadUSB", - "arduino:avr:lilypad", - "arduino:avr:pro", - "arduino:avr:atmegang", - "arduino:avr:robotControl", - "arduino:avr:robotMotor", - "arduino:avr:gemma", - "arduino:avr:circuitplay32u4cat", - "arduino:avr:yunmini", - "arduino:avr:chiwawa", - "arduino:avr:one", - "arduino:avr:unowifi" - ]`) -} diff --git a/internal/integrationtest/board/board_test.go b/internal/integrationtest/board/board_test.go index 41777710a13..c243abd7843 100644 --- a/internal/integrationtest/board/board_test.go +++ b/internal/integrationtest/board/board_test.go @@ -29,6 +29,45 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing" ) +func TestCorrectBoardListOrdering(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + _, _, err := cli.Run("core", "install", "arduino:avr") + require.NoError(t, err) + jsonOut, _, err := cli.Run("board", "listall", "--format", "json") + require.NoError(t, err) + requirejson.Query(t, jsonOut, "[.boards[] | .fqbn]", `[ + "arduino:avr:yun", + "arduino:avr:uno", + "arduino:avr:unomini", + "arduino:avr:diecimila", + "arduino:avr:nano", + "arduino:avr:mega", + "arduino:avr:megaADK", + "arduino:avr:leonardo", + "arduino:avr:leonardoeth", + "arduino:avr:micro", + "arduino:avr:esplora", + "arduino:avr:mini", + "arduino:avr:ethernet", + "arduino:avr:fio", + "arduino:avr:bt", + "arduino:avr:LilyPadUSB", + "arduino:avr:lilypad", + "arduino:avr:pro", + "arduino:avr:atmegang", + "arduino:avr:robotControl", + "arduino:avr:robotMotor", + "arduino:avr:gemma", + "arduino:avr:circuitplay32u4cat", + "arduino:avr:yunmini", + "arduino:avr:chiwawa", + "arduino:avr:one", + "arduino:avr:unowifi" + ]`) +} + func TestBoardList(t *testing.T) { if os.Getenv("CI") != "" { t.Skip("VMs have no serial ports") diff --git a/internal/integrationtest/compile/compile_part_2_test.go b/internal/integrationtest/compile/compile_part_2_test.go deleted file mode 100644 index f3a057097c5..00000000000 --- a/internal/integrationtest/compile/compile_part_2_test.go +++ /dev/null @@ -1,162 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2022 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 license@arduino.cc. - -package compile_test - -import ( - "encoding/json" - "testing" - - "github.com/arduino/arduino-cli/internal/integrationtest" - "github.com/arduino/go-paths-helper" - "github.com/stretchr/testify/require" -) - -func TestCompileWithoutPrecompiledLibraries(t *testing.T) { - env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) - defer env.CleanUp() - - // Init the environment explicitly - url := "https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" - _, _, err := cli.Run("core", "update-index", "--additional-urls="+url) - require.NoError(t, err) - _, _, err = cli.Run("core", "install", "arduino:mbed@1.3.1", "--additional-urls="+url) - require.NoError(t, err) - - // // Precompiled version of Arduino_TensorflowLite - // _, _, err = cli.Run("lib", "install", "Arduino_LSM9DS1") - // require.NoError(t, err) - // _, _, err = cli.Run("lib", "install", "Arduino_TensorflowLite@2.1.1-ALPHA-precompiled") - // require.NoError(t, err) - - // sketchPath := cli.SketchbookDir().Join("libraries", "Arduino_TensorFlowLite", "examples", "hello_world") - // _, _, err = cli.Run("compile", "-b", "arduino:mbed:nano33ble", sketchPath.String()) - // require.NoError(t, err) - - _, _, err = cli.Run("core", "install", "arduino:samd@1.8.7", "--additional-urls="+url) - require.NoError(t, err) - // _, _, err = cli.Run("core", "install", "adafruit:samd@1.6.4", "--additional-urls="+url) - // require.NoError(t, err) - // // should work on adafruit too after https://github.com/arduino/arduino-cli/pull/1134 - // _, _, err = cli.Run("compile", "-b", "adafruit:samd:adafruit_feather_m4", sketchPath.String()) - // require.NoError(t, err) - - // // Non-precompiled version of Arduino_TensorflowLite - // _, _, err = cli.Run("lib", "install", "Arduino_TensorflowLite@2.1.0-ALPHA") - // require.NoError(t, err) - // _, _, err = cli.Run("compile", "-b", "arduino:mbed:nano33ble", sketchPath.String()) - // require.NoError(t, err) - // _, _, err = cli.Run("compile", "-b", "adafruit:samd:adafruit_feather_m4", sketchPath.String()) - // require.NoError(t, err) - - // Bosch sensor library - _, _, err = cli.Run("lib", "install", "BSEC Software Library@1.5.1474") - require.NoError(t, err) - sketchPath := cli.SketchbookDir().Join("libraries", "BSEC_Software_Library", "examples", "basic") - _, _, err = cli.Run("compile", "-b", "arduino:samd:mkr1000", sketchPath.String()) - require.NoError(t, err) - _, _, err = cli.Run("compile", "-b", "arduino:mbed:nano33ble", sketchPath.String()) - require.NoError(t, err) - - // USBBlaster library - _, _, err = cli.Run("lib", "install", "USBBlaster@1.0.0") - require.NoError(t, err) - sketchPath = cli.SketchbookDir().Join("libraries", "USBBlaster", "examples", "USB_Blaster") - _, _, err = cli.Run("compile", "-b", "arduino:samd:mkrvidor4000", sketchPath.String()) - require.NoError(t, err) -} - -func TestCompileWithCustomLibraries(t *testing.T) { - env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) - defer env.CleanUp() - - // Creates config with additional URL to install necessary core - url := "http://arduino.esp8266.com/stable/package_esp8266com_index.json" - _, _, err := cli.Run("config", "init", "--dest-dir", ".", "--additional-urls", url) - require.NoError(t, err) - - // Init the environment explicitly - _, _, err = cli.Run("update") - require.NoError(t, err) - - _, _, err = cli.Run("core", "install", "esp8266:esp8266") - require.NoError(t, err) - - sketchName := "sketch_with_multiple_custom_libraries" - sketchPath := cli.CopySketch(sketchName) - fqbn := "esp8266:esp8266:nodemcu:xtal=80,vt=heap,eesz=4M1M,wipe=none,baud=115200" - - firstLib := sketchPath.Join("libraries1") - secondLib := sketchPath.Join("libraries2") - _, _, err = cli.Run("compile", "--libraries", firstLib.String(), "--libraries", secondLib.String(), "-b", fqbn, sketchPath.String()) - require.NoError(t, err) -} - -func TestCompileWithArchivesAndLongPaths(t *testing.T) { - env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) - defer env.CleanUp() - - // Creates config with additional URL to install necessary core - url := "http://arduino.esp8266.com/stable/package_esp8266com_index.json" - _, _, err := cli.Run("config", "init", "--dest-dir", ".", "--additional-urls", url) - require.NoError(t, err) - - // Init the environment explicitly - _, _, err = cli.Run("update") - require.NoError(t, err) - - // Install core to compile - _, _, err = cli.Run("core", "install", "esp8266:esp8266@2.7.4") - require.NoError(t, err) - - // Install test library - _, _, err = cli.Run("lib", "install", "ArduinoIoTCloud") - require.NoError(t, err) - - stdout, _, err := cli.Run("lib", "examples", "ArduinoIoTCloud", "--format", "json") - require.NoError(t, err) - var libOutput []map[string]interface{} - err = json.Unmarshal(stdout, &libOutput) - require.NoError(t, err) - sketchPath := paths.New(libOutput[0]["library"].(map[string]interface{})["install_dir"].(string)) - sketchPath = sketchPath.Join("examples", "ArduinoIoTCloud-Advanced") - - _, _, err = cli.Run("compile", "-b", "esp8266:esp8266:huzzah", sketchPath.String()) - require.NoError(t, err) -} - -func TestCompileWithPrecompileLibrary(t *testing.T) { - env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) - defer env.CleanUp() - - _, _, err := cli.Run("update") - require.NoError(t, err) - - _, _, err = cli.Run("core", "install", "arduino:samd@1.8.11") - require.NoError(t, err) - fqbn := "arduino:samd:mkrzero" - - // Install precompiled library - // For more information see: - // https://arduino.github.io/arduino-cli/latest/library-specification/#precompiled-binaries - _, _, err = cli.Run("lib", "install", "BSEC Software Library@1.5.1474") - require.NoError(t, err) - sketchFolder := cli.SketchbookDir().Join("libraries", "BSEC_Software_Library", "examples", "basic") - - // Compile and verify dependencies detection for fully precompiled library is not skipped - stdout, _, err := cli.Run("compile", "-b", fqbn, sketchFolder.String(), "-v") - require.NoError(t, err) - require.NotContains(t, string(stdout), "Skipping dependencies detection for precompiled library BSEC Software Library") -} diff --git a/internal/integrationtest/compile/compile_part_3_test.go b/internal/integrationtest/compile/compile_part_3_test.go deleted file mode 100644 index c95d645cfc6..00000000000 --- a/internal/integrationtest/compile/compile_part_3_test.go +++ /dev/null @@ -1,133 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2022 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 license@arduino.cc. - -package compile_test - -import ( - "testing" - - "github.com/arduino/arduino-cli/internal/integrationtest" - "github.com/arduino/go-paths-helper" - "github.com/stretchr/testify/require" - "gopkg.in/src-d/go-git.v4" - "gopkg.in/src-d/go-git.v4/plumbing" -) - -func TestCompileWithFullyPrecompiledLibrary(t *testing.T) { - env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) - defer env.CleanUp() - - _, _, err := cli.Run("update") - require.NoError(t, err) - - _, _, err = cli.Run("core", "install", "arduino:mbed@1.3.1") - require.NoError(t, err) - fqbn := "arduino:mbed:nano33ble" - - // Create settings with library unsafe install set to true - envVar := cli.GetDefaultEnv() - envVar["ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL"] = "true" - _, _, err = cli.RunWithCustomEnv(envVar, "config", "init", "--dest-dir", ".") - require.NoError(t, err) - - // Install fully precompiled library - // For more information see: - // https://arduino.github.io/arduino-cli/latest/library-specification/#precompiled-binaries - wd, err := paths.Getwd() - require.NoError(t, err) - _, _, err = cli.Run("lib", "install", "--zip-path", wd.Parent().Join("testdata", "Arduino_TensorFlowLite-2.1.0-ALPHA-precompiled.zip").String()) - require.NoError(t, err) - sketchFolder := cli.SketchbookDir().Join("libraries", "Arduino_TensorFlowLite-2.1.0-ALPHA-precompiled", "examples", "hello_world") - - // Install example dependency - _, _, err = cli.Run("lib", "install", "Arduino_LSM9DS1") - require.NoError(t, err) - - // Compile and verify dependencies detection for fully precompiled library is skipped - stdout, _, err := cli.Run("compile", "-b", fqbn, sketchFolder.String(), "-v") - require.NoError(t, err) - require.Contains(t, string(stdout), "Skipping dependencies detection for precompiled library Arduino_TensorFlowLite") -} - -func TestCompileManuallyInstalledPlatform(t *testing.T) { - env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) - defer env.CleanUp() - - _, _, err := cli.Run("update") - require.NoError(t, err) - - sketchName := "CompileSketchManuallyInstalledPlatformUsingPlatformLocalTxt" - sketchPath := cli.SketchbookDir().Join(sketchName) - fqbn := "arduino-beta-development:avr:uno" - _, _, err = cli.Run("sketch", "new", sketchPath.String()) - require.NoError(t, err) - - // Manually installs a core in sketchbooks hardware folder - gitUrl := "https://github.com/arduino/ArduinoCore-avr.git" - repoDir := cli.SketchbookDir().Join("hardware", "arduino-beta-development", "avr") - _, err = git.PlainClone(repoDir.String(), false, &git.CloneOptions{ - URL: gitUrl, - ReferenceName: plumbing.NewTagReferenceName("1.8.3"), - }) - require.NoError(t, err) - - // Installs also the same core via CLI so all the necessary tools are installed - _, _, err = cli.Run("core", "install", "arduino:avr@1.8.3") - require.NoError(t, err) - - // Verifies compilation works without issues - _, _, err = cli.Run("compile", "--clean", "-b", fqbn, sketchPath.String()) - require.NoError(t, err) -} - -func TestCompileManuallyInstalledPlatformUsingPlatformLocalTxt(t *testing.T) { - env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) - defer env.CleanUp() - - _, _, err := cli.Run("update") - require.NoError(t, err) - - sketchName := "CompileSketchManuallyInstalledPlatformUsingPlatformLocalTxt" - sketchPath := cli.SketchbookDir().Join(sketchName) - fqbn := "arduino-beta-development:avr:uno" - _, _, err = cli.Run("sketch", "new", sketchPath.String()) - require.NoError(t, err) - - // Manually installs a core in sketchbooks hardware folder - gitUrl := "https://github.com/arduino/ArduinoCore-avr.git" - repoDir := cli.SketchbookDir().Join("hardware", "arduino-beta-development", "avr") - _, err = git.PlainClone(repoDir.String(), false, &git.CloneOptions{ - URL: gitUrl, - ReferenceName: plumbing.NewTagReferenceName("1.8.3"), - }) - require.NoError(t, err) - - // Installs also the same core via CLI so all the necessary tools are installed - _, _, err = cli.Run("core", "install", "arduino:avr@1.8.3") - require.NoError(t, err) - - // Verifies compilation works without issues - _, _, err = cli.Run("compile", "--clean", "-b", fqbn, sketchPath.String()) - require.NoError(t, err) - - // Overrides default platform compiler with an unexisting one - platformLocalTxt := repoDir.Join("platform.local.txt") - platformLocalTxt.WriteFile([]byte("compiler.c.cmd=my-compiler-that-does-not-exist")) - - // Verifies compilation now fails because compiler is not found - _, stderr, err := cli.Run("compile", "--clean", "-b", fqbn, sketchPath.String()) - require.Error(t, err) - require.Contains(t, string(stderr), "my-compiler-that-does-not-exist") -} diff --git a/internal/integrationtest/compile/compile_part_1_test.go b/internal/integrationtest/compile/compile_test.go similarity index 75% rename from internal/integrationtest/compile/compile_part_1_test.go rename to internal/integrationtest/compile/compile_test.go index ad2d8a8adb4..a349ec6b78c 100644 --- a/internal/integrationtest/compile/compile_part_1_test.go +++ b/internal/integrationtest/compile/compile_test.go @@ -27,6 +27,8 @@ import ( "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/require" "go.bug.st/testifyjson/requirejson" + "gopkg.in/src-d/go-git.v4" + "gopkg.in/src-d/go-git.v4/plumbing" ) func TestCompile(t *testing.T) { @@ -711,3 +713,247 @@ func compileUsingBoardsLocalTxt(t *testing.T, env *integrationtest.Environment, _, _, err = cli.Run("compile", "--clean", "-b", fqbn, sketchPath.String()) require.NoError(t, err) } + +func TestCompileWithoutPrecompiledLibraries(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + // Init the environment explicitly + url := "https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" + _, _, err := cli.Run("core", "update-index", "--additional-urls="+url) + require.NoError(t, err) + _, _, err = cli.Run("core", "install", "arduino:mbed@1.3.1", "--additional-urls="+url) + require.NoError(t, err) + + // // Precompiled version of Arduino_TensorflowLite + // _, _, err = cli.Run("lib", "install", "Arduino_LSM9DS1") + // require.NoError(t, err) + // _, _, err = cli.Run("lib", "install", "Arduino_TensorflowLite@2.1.1-ALPHA-precompiled") + // require.NoError(t, err) + + // sketchPath := cli.SketchbookDir().Join("libraries", "Arduino_TensorFlowLite", "examples", "hello_world") + // _, _, err = cli.Run("compile", "-b", "arduino:mbed:nano33ble", sketchPath.String()) + // require.NoError(t, err) + + _, _, err = cli.Run("core", "install", "arduino:samd@1.8.7", "--additional-urls="+url) + require.NoError(t, err) + // _, _, err = cli.Run("core", "install", "adafruit:samd@1.6.4", "--additional-urls="+url) + // require.NoError(t, err) + // // should work on adafruit too after https://github.com/arduino/arduino-cli/pull/1134 + // _, _, err = cli.Run("compile", "-b", "adafruit:samd:adafruit_feather_m4", sketchPath.String()) + // require.NoError(t, err) + + // // Non-precompiled version of Arduino_TensorflowLite + // _, _, err = cli.Run("lib", "install", "Arduino_TensorflowLite@2.1.0-ALPHA") + // require.NoError(t, err) + // _, _, err = cli.Run("compile", "-b", "arduino:mbed:nano33ble", sketchPath.String()) + // require.NoError(t, err) + // _, _, err = cli.Run("compile", "-b", "adafruit:samd:adafruit_feather_m4", sketchPath.String()) + // require.NoError(t, err) + + // Bosch sensor library + _, _, err = cli.Run("lib", "install", "BSEC Software Library@1.5.1474") + require.NoError(t, err) + sketchPath := cli.SketchbookDir().Join("libraries", "BSEC_Software_Library", "examples", "basic") + _, _, err = cli.Run("compile", "-b", "arduino:samd:mkr1000", sketchPath.String()) + require.NoError(t, err) + _, _, err = cli.Run("compile", "-b", "arduino:mbed:nano33ble", sketchPath.String()) + require.NoError(t, err) + + // USBBlaster library + _, _, err = cli.Run("lib", "install", "USBBlaster@1.0.0") + require.NoError(t, err) + sketchPath = cli.SketchbookDir().Join("libraries", "USBBlaster", "examples", "USB_Blaster") + _, _, err = cli.Run("compile", "-b", "arduino:samd:mkrvidor4000", sketchPath.String()) + require.NoError(t, err) +} + +func TestCompileWithCustomLibraries(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + // Creates config with additional URL to install necessary core + url := "http://arduino.esp8266.com/stable/package_esp8266com_index.json" + _, _, err := cli.Run("config", "init", "--dest-dir", ".", "--additional-urls", url) + require.NoError(t, err) + + // Init the environment explicitly + _, _, err = cli.Run("update") + require.NoError(t, err) + + _, _, err = cli.Run("core", "install", "esp8266:esp8266") + require.NoError(t, err) + + sketchName := "sketch_with_multiple_custom_libraries" + sketchPath := cli.CopySketch(sketchName) + fqbn := "esp8266:esp8266:nodemcu:xtal=80,vt=heap,eesz=4M1M,wipe=none,baud=115200" + + firstLib := sketchPath.Join("libraries1") + secondLib := sketchPath.Join("libraries2") + _, _, err = cli.Run("compile", "--libraries", firstLib.String(), "--libraries", secondLib.String(), "-b", fqbn, sketchPath.String()) + require.NoError(t, err) +} + +func TestCompileWithArchivesAndLongPaths(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + // Creates config with additional URL to install necessary core + url := "http://arduino.esp8266.com/stable/package_esp8266com_index.json" + _, _, err := cli.Run("config", "init", "--dest-dir", ".", "--additional-urls", url) + require.NoError(t, err) + + // Init the environment explicitly + _, _, err = cli.Run("update") + require.NoError(t, err) + + // Install core to compile + _, _, err = cli.Run("core", "install", "esp8266:esp8266@2.7.4") + require.NoError(t, err) + + // Install test library + _, _, err = cli.Run("lib", "install", "ArduinoIoTCloud") + require.NoError(t, err) + + stdout, _, err := cli.Run("lib", "examples", "ArduinoIoTCloud", "--format", "json") + require.NoError(t, err) + var libOutput []map[string]interface{} + err = json.Unmarshal(stdout, &libOutput) + require.NoError(t, err) + sketchPath := paths.New(libOutput[0]["library"].(map[string]interface{})["install_dir"].(string)) + sketchPath = sketchPath.Join("examples", "ArduinoIoTCloud-Advanced") + + _, _, err = cli.Run("compile", "-b", "esp8266:esp8266:huzzah", sketchPath.String()) + require.NoError(t, err) +} + +func TestCompileWithPrecompileLibrary(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + _, _, err := cli.Run("update") + require.NoError(t, err) + + _, _, err = cli.Run("core", "install", "arduino:samd@1.8.11") + require.NoError(t, err) + fqbn := "arduino:samd:mkrzero" + + // Install precompiled library + // For more information see: + // https://arduino.github.io/arduino-cli/latest/library-specification/#precompiled-binaries + _, _, err = cli.Run("lib", "install", "BSEC Software Library@1.5.1474") + require.NoError(t, err) + sketchFolder := cli.SketchbookDir().Join("libraries", "BSEC_Software_Library", "examples", "basic") + + // Compile and verify dependencies detection for fully precompiled library is not skipped + stdout, _, err := cli.Run("compile", "-b", fqbn, sketchFolder.String(), "-v") + require.NoError(t, err) + require.NotContains(t, string(stdout), "Skipping dependencies detection for precompiled library BSEC Software Library") +} + +func TestCompileWithFullyPrecompiledLibrary(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + _, _, err := cli.Run("update") + require.NoError(t, err) + + _, _, err = cli.Run("core", "install", "arduino:mbed@1.3.1") + require.NoError(t, err) + fqbn := "arduino:mbed:nano33ble" + + // Create settings with library unsafe install set to true + envVar := cli.GetDefaultEnv() + envVar["ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL"] = "true" + _, _, err = cli.RunWithCustomEnv(envVar, "config", "init", "--dest-dir", ".") + require.NoError(t, err) + + // Install fully precompiled library + // For more information see: + // https://arduino.github.io/arduino-cli/latest/library-specification/#precompiled-binaries + wd, err := paths.Getwd() + require.NoError(t, err) + _, _, err = cli.Run("lib", "install", "--zip-path", wd.Parent().Join("testdata", "Arduino_TensorFlowLite-2.1.0-ALPHA-precompiled.zip").String()) + require.NoError(t, err) + sketchFolder := cli.SketchbookDir().Join("libraries", "Arduino_TensorFlowLite-2.1.0-ALPHA-precompiled", "examples", "hello_world") + + // Install example dependency + _, _, err = cli.Run("lib", "install", "Arduino_LSM9DS1") + require.NoError(t, err) + + // Compile and verify dependencies detection for fully precompiled library is skipped + stdout, _, err := cli.Run("compile", "-b", fqbn, sketchFolder.String(), "-v") + require.NoError(t, err) + require.Contains(t, string(stdout), "Skipping dependencies detection for precompiled library Arduino_TensorFlowLite") +} + +func TestCompileManuallyInstalledPlatform(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + _, _, err := cli.Run("update") + require.NoError(t, err) + + sketchName := "CompileSketchManuallyInstalledPlatformUsingPlatformLocalTxt" + sketchPath := cli.SketchbookDir().Join(sketchName) + fqbn := "arduino-beta-development:avr:uno" + _, _, err = cli.Run("sketch", "new", sketchPath.String()) + require.NoError(t, err) + + // Manually installs a core in sketchbooks hardware folder + gitUrl := "https://github.com/arduino/ArduinoCore-avr.git" + repoDir := cli.SketchbookDir().Join("hardware", "arduino-beta-development", "avr") + _, err = git.PlainClone(repoDir.String(), false, &git.CloneOptions{ + URL: gitUrl, + ReferenceName: plumbing.NewTagReferenceName("1.8.3"), + }) + require.NoError(t, err) + + // Installs also the same core via CLI so all the necessary tools are installed + _, _, err = cli.Run("core", "install", "arduino:avr@1.8.3") + require.NoError(t, err) + + // Verifies compilation works without issues + _, _, err = cli.Run("compile", "--clean", "-b", fqbn, sketchPath.String()) + require.NoError(t, err) +} + +func TestCompileManuallyInstalledPlatformUsingPlatformLocalTxt(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + _, _, err := cli.Run("update") + require.NoError(t, err) + + sketchName := "CompileSketchManuallyInstalledPlatformUsingPlatformLocalTxt" + sketchPath := cli.SketchbookDir().Join(sketchName) + fqbn := "arduino-beta-development:avr:uno" + _, _, err = cli.Run("sketch", "new", sketchPath.String()) + require.NoError(t, err) + + // Manually installs a core in sketchbooks hardware folder + gitUrl := "https://github.com/arduino/ArduinoCore-avr.git" + repoDir := cli.SketchbookDir().Join("hardware", "arduino-beta-development", "avr") + _, err = git.PlainClone(repoDir.String(), false, &git.CloneOptions{ + URL: gitUrl, + ReferenceName: plumbing.NewTagReferenceName("1.8.3"), + }) + require.NoError(t, err) + + // Installs also the same core via CLI so all the necessary tools are installed + _, _, err = cli.Run("core", "install", "arduino:avr@1.8.3") + require.NoError(t, err) + + // Verifies compilation works without issues + _, _, err = cli.Run("compile", "--clean", "-b", fqbn, sketchPath.String()) + require.NoError(t, err) + + // Overrides default platform compiler with an unexisting one + platformLocalTxt := repoDir.Join("platform.local.txt") + platformLocalTxt.WriteFile([]byte("compiler.c.cmd=my-compiler-that-does-not-exist")) + + // Verifies compilation now fails because compiler is not found + _, stderr, err := cli.Run("compile", "--clean", "-b", fqbn, sketchPath.String()) + require.Error(t, err) + require.Contains(t, string(stderr), "my-compiler-that-does-not-exist") +} diff --git a/internal/integrationtest/core/core_list_test.go b/internal/integrationtest/core/core_list_test.go deleted file mode 100644 index 516d9d2133b..00000000000 --- a/internal/integrationtest/core/core_list_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2022 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 license@arduino.cc. - -package core_test - -import ( - "testing" - - "github.com/arduino/arduino-cli/internal/integrationtest" - "github.com/arduino/go-paths-helper" - "github.com/stretchr/testify/require" - "go.bug.st/testifyjson/requirejson" -) - -func TestCorrectHandlingOfPlatformVersionProperty(t *testing.T) { - // See: https://github.com/arduino/arduino-cli/issues/1823 - env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) - defer env.CleanUp() - - // Copy test platform - testPlatform := paths.New("testdata", "issue_1823", "DxCore-dev") - require.NoError(t, testPlatform.CopyDirTo(cli.SketchbookDir().Join("hardware", "DxCore-dev"))) - - // Trigger problematic call - out, _, err := cli.Run("core", "list", "--format", "json") - require.NoError(t, err) - requirejson.Contains(t, out, `[{"id":"DxCore-dev:megaavr","installed":"1.4.10","name":"DxCore"}]`) -} diff --git a/internal/integrationtest/core/core_test.go b/internal/integrationtest/core/core_test.go index c110a125760..81ecdb9f5f2 100644 --- a/internal/integrationtest/core/core_test.go +++ b/internal/integrationtest/core/core_test.go @@ -26,6 +26,21 @@ import ( "go.bug.st/testifyjson/requirejson" ) +func TestCorrectHandlingOfPlatformVersionProperty(t *testing.T) { + // See: https://github.com/arduino/arduino-cli/issues/1823 + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + // Copy test platform + testPlatform := paths.New("testdata", "issue_1823", "DxCore-dev") + require.NoError(t, testPlatform.CopyDirTo(cli.SketchbookDir().Join("hardware", "DxCore-dev"))) + + // Trigger problematic call + out, _, err := cli.Run("core", "list", "--format", "json") + require.NoError(t, err) + requirejson.Contains(t, out, `[{"id":"DxCore-dev:megaavr","installed":"1.4.10","name":"DxCore"}]`) +} + func TestCoreSearch(t *testing.T) { env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) defer env.CleanUp() diff --git a/internal/integrationtest/daemon/daemon_board_watch_test.go b/internal/integrationtest/daemon/daemon_board_watch_test.go deleted file mode 100644 index a526427b45d..00000000000 --- a/internal/integrationtest/daemon/daemon_board_watch_test.go +++ /dev/null @@ -1,82 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2022 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 license@arduino.cc. - -package daemon_test - -import ( - "context" - "fmt" - "io" - "testing" - "time" - - "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" - "github.com/stretchr/testify/require" -) - -func TestArduinoCliDaemon(t *testing.T) { - // See: https://github.com/arduino/arduino-cli/pull/1804 - - t.SkipNow() // TO BE Removed once the bug is fixed - - env, cli := createEnvForDaemon(t) - defer env.CleanUp() - - grpcInst := cli.Create() - require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { - fmt.Printf("INIT> %v\n", ir.GetMessage()) - })) - - // Run a one-shot board list - boardListResp, err := grpcInst.BoardList(time.Second) - require.NoError(t, err) - fmt.Printf("Got boardlist response with %d ports\n", len(boardListResp.GetPorts())) - - // Run a one-shot board list again (should not fail) - boardListResp, err = grpcInst.BoardList(time.Second) - require.NoError(t, err) - fmt.Printf("Got boardlist response with %d ports\n", len(boardListResp.GetPorts())) - - testWatcher := func() { - // Run watcher - watcher, err := grpcInst.BoardListWatch() - require.NoError(t, err) - ctx, cancel := context.WithCancel(context.Background()) - go func() { - defer cancel() - for { - msg, err := watcher.Recv() - if err == io.EOF { - fmt.Println("Watcher EOF") - return - } - require.Empty(t, msg.Error, "Board list watcher returned an error") - require.NoError(t, err, "BoardListWatch grpc call returned an error") - fmt.Printf("WATCH> %v\n", msg) - } - }() - time.Sleep(time.Second) - require.NoError(t, watcher.CloseSend()) - select { - case <-ctx.Done(): - // all right! - case <-time.After(time.Second): - require.Fail(t, "BoardListWatch didn't close") - } - } - - testWatcher() - testWatcher() -} diff --git a/internal/integrationtest/daemon/daemon_compile_test.go b/internal/integrationtest/daemon/daemon_compile_test.go deleted file mode 100644 index a26f4d14e1d..00000000000 --- a/internal/integrationtest/daemon/daemon_compile_test.go +++ /dev/null @@ -1,127 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2022 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 license@arduino.cc. - -package daemon_test - -import ( - "context" - "fmt" - "io" - "testing" - - "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" - "github.com/arduino/go-paths-helper" - "github.com/stretchr/testify/require" -) - -func TestDaemonCompileOptions(t *testing.T) { - // See: https://github.com/arduino/arduino-cli/issues/1614 - // See: https://github.com/arduino/arduino-cli/pull/1820 - - env, cli := 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.5", true) - require.NoError(t, err) - for { - msg, err := plInst.Recv() - if err == io.EOF { - break - } - require.NoError(t, err) - fmt.Printf("INSTALL> %v\n", msg) - } - - // Install boards.local.txt to trigger bug - platformLocalTxt := paths.New("testdata", "boards.local.txt-issue1614") - err = platformLocalTxt.CopyTo(cli.DataDir(). - Join("packages", "arduino", "hardware", "avr", "1.8.5", "boards.local.txt")) - require.NoError(t, err) - - // Re-init instance to update changes - require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { - fmt.Printf("INIT> %v\n", ir.GetMessage()) - })) - - // Build sketch (with errors) - sk := paths.New("testdata", "bare_minimum") - compile, err := grpcInst.Compile(context.Background(), "arduino:avr:uno:some_menu=bad", sk.String()) - require.NoError(t, err) - for { - msg, err := compile.Recv() - if err == io.EOF { - require.FailNow(t, "Expected compilation failure", "compilation succeeded") - break - } - if err != nil { - fmt.Println("COMPILE ERROR>", err) - break - } - if msg.ErrStream != nil { - fmt.Printf("COMPILE> %v\n", string(msg.GetErrStream())) - } - } - - // Build sketch (without errors) - compile, err = grpcInst.Compile(context.Background(), "arduino:avr:uno:some_menu=good", sk.String()) - require.NoError(t, err) - for { - msg, err := compile.Recv() - if err == io.EOF { - break - } - require.NoError(t, err) - if msg.ErrStream != nil { - fmt.Printf("COMPILE> %v\n", string(msg.GetErrStream())) - } - } -} - -func TestDaemonCompileAfterFailedLibInstall(t *testing.T) { - // See: https://github.com/arduino/arduino-cli/issues/1812 - - env, cli := createEnvForDaemon(t) - defer env.CleanUp() - - grpcInst := cli.Create() - require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { - fmt.Printf("INIT> %v\n", ir.GetMessage()) - })) - - // Build sketch (with errors) - sk := paths.New("testdata", "bare_minimum") - compile, err := grpcInst.Compile(context.Background(), "", sk.String()) - require.NoError(t, err) - for { - msg, err := compile.Recv() - if err == io.EOF { - require.FailNow(t, "Expected compilation failure", "compilation succeeded") - break - } - if err != nil { - fmt.Println("COMPILE ERROR>", err) - require.Contains(t, err.Error(), "Missing FQBN") - break - } - if msg.ErrStream != nil { - fmt.Printf("COMPILE> %v\n", string(msg.GetErrStream())) - } - } -} diff --git a/internal/integrationtest/daemon/daemon_core_test.go b/internal/integrationtest/daemon/daemon_core_test.go deleted file mode 100644 index b0ddb3435ac..00000000000 --- a/internal/integrationtest/daemon/daemon_core_test.go +++ /dev/null @@ -1,78 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2022 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 license@arduino.cc. - -package daemon_test - -import ( - "context" - "fmt" - "io" - "testing" - - "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" - "github.com/stretchr/testify/require" -) - -func TestDaemonCoreUpdateIndex(t *testing.T) { - env, cli := createEnvForDaemon(t) - defer env.CleanUp() - - grpcInst := cli.Create() - require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { - fmt.Printf("INIT> %v\n", ir.GetMessage()) - })) - - // Set extra indexes - err := cli.SetValue( - "board_manager.additional_urls", ""+ - `["http://arduino.esp8266.com/stable/package_esp8266com_index.json",`+ - ` "http://downloads.arduino.cc/package_inexistent_index.json"]`) - require.NoError(t, err) - - analyzeUpdateIndexClient := func(cl commands.ArduinoCoreService_UpdateIndexClient) (error, map[string]*commands.DownloadProgressEnd) { - analyzer := NewDownloadProgressAnalyzer(t) - for { - msg, err := cl.Recv() - // fmt.Println("DOWNLOAD>", msg) - if err == io.EOF { - return nil, analyzer.Results - } - if err != nil { - return err, analyzer.Results - } - require.NoError(t, err) - analyzer.Process(msg.GetDownloadProgress()) - } - } - - { - cl, err := grpcInst.UpdateIndex(context.Background(), true) - require.NoError(t, err) - err, res := analyzeUpdateIndexClient(cl) - require.NoError(t, err) - require.Len(t, res, 1) - require.True(t, res["https://downloads.arduino.cc/packages/package_index.tar.bz2"].Success) - } - { - cl, err := grpcInst.UpdateIndex(context.Background(), false) - require.NoError(t, err) - err, res := analyzeUpdateIndexClient(cl) - require.Error(t, err) - require.Len(t, res, 3) - require.True(t, res["https://downloads.arduino.cc/packages/package_index.tar.bz2"].Success) - require.True(t, res["http://arduino.esp8266.com/stable/package_esp8266com_index.json"].Success) - require.False(t, res["http://downloads.arduino.cc/package_inexistent_index.json"].Success) - } -} diff --git a/internal/integrationtest/daemon/daemon_lib_install_test.go b/internal/integrationtest/daemon/daemon_lib_install_test.go deleted file mode 100644 index b4ff76f2218..00000000000 --- a/internal/integrationtest/daemon/daemon_lib_install_test.go +++ /dev/null @@ -1,156 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2022 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 license@arduino.cc. - -package daemon_test - -import ( - "context" - "fmt" - "io" - "testing" - - "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" - "github.com/stretchr/testify/require" -) - -func TestDaemonBundleLibInstall(t *testing.T) { - env, cli := createEnvForDaemon(t) - defer env.CleanUp() - - grpcInst := cli.Create() - require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { - fmt.Printf("INIT> %v\n", ir.GetMessage()) - })) - - // Install libraries in bundled dir - { - instCl, err := grpcInst.LibraryInstall(context.Background(), "Arduino_BuiltIn", "", false, false, true) - require.NoError(t, err) - for { - msg, err := instCl.Recv() - if err == io.EOF { - break - } - require.NoError(t, err) - fmt.Printf("LIB INSTALL> %+v\n", msg) - } - } - - // Check if libraries are installed as expected - { - resp, err := grpcInst.LibraryList(context.Background(), "", "", true, false) - require.NoError(t, err) - libsAndLocation := map[string]commands.LibraryLocation{} - for _, lib := range resp.GetInstalledLibraries() { - libsAndLocation[lib.Library.Name] = lib.Library.Location - } - require.Contains(t, libsAndLocation, "Ethernet") - require.Contains(t, libsAndLocation, "SD") - require.Contains(t, libsAndLocation, "Firmata") - require.Equal(t, libsAndLocation["Ethernet"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) - require.Equal(t, libsAndLocation["SD"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) - require.Equal(t, libsAndLocation["Firmata"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) - } - - // Install a library in sketchbook to override bundled - { - instCl, err := grpcInst.LibraryInstall(context.Background(), "Ethernet", "", false, false, false) - require.NoError(t, err) - for { - msg, err := instCl.Recv() - if err == io.EOF { - break - } - require.NoError(t, err) - fmt.Printf("LIB INSTALL> %+v\n", msg) - } - } - - // Check if libraries are installed as expected - installedEthernetVersion := "" - { - resp, err := grpcInst.LibraryList(context.Background(), "", "", true, false) - require.NoError(t, err) - libsAndLocation := map[string]commands.LibraryLocation{} - for _, lib := range resp.GetInstalledLibraries() { - libsAndLocation[lib.Library.Name] = lib.Library.Location - if lib.Library.Name == "Ethernet" { - installedEthernetVersion = lib.Library.Version - } - } - require.Contains(t, libsAndLocation, "Ethernet") - require.Contains(t, libsAndLocation, "SD") - require.Contains(t, libsAndLocation, "Firmata") - require.Equal(t, libsAndLocation["Ethernet"], commands.LibraryLocation_LIBRARY_LOCATION_USER) - require.Equal(t, libsAndLocation["SD"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) - require.Equal(t, libsAndLocation["Firmata"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) - } - - // Remove library from sketchbook - { - uninstCl, err := grpcInst.LibraryUninstall(context.Background(), "Ethernet", installedEthernetVersion) - require.NoError(t, err) - for { - msg, err := uninstCl.Recv() - if err == io.EOF { - break - } - require.NoError(t, err) - fmt.Printf("LIB INSTALL> %+v\n", msg) - } - } - - // Check if libraries are installed as expected - { - resp, err := grpcInst.LibraryList(context.Background(), "", "", true, false) - require.NoError(t, err) - libsAndLocation := map[string]commands.LibraryLocation{} - for _, lib := range resp.GetInstalledLibraries() { - libsAndLocation[lib.Library.Name] = lib.Library.Location - } - require.Contains(t, libsAndLocation, "Ethernet") - require.Contains(t, libsAndLocation, "SD") - require.Contains(t, libsAndLocation, "Firmata") - require.Equal(t, libsAndLocation["Ethernet"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) - require.Equal(t, libsAndLocation["SD"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) - require.Equal(t, libsAndLocation["Firmata"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) - } - - // Un-Set builtin libraries dir - err := cli.SetValue("directories.builtin.libraries", `""`) - require.NoError(t, err) - - // Re-init - require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { - fmt.Printf("INIT> %v\n", ir.GetMessage()) - })) - - // Install libraries in bundled dir (should now fail) - { - instCl, err := grpcInst.LibraryInstall(context.Background(), "Arduino_BuiltIn", "", false, false, true) - require.NoError(t, err) - for { - msg, err := instCl.Recv() - if err == io.EOF { - require.FailNow(t, "LibraryInstall is supposed to fail because builtin libraries directory is not set") - } - if err != nil { - fmt.Println("LIB INSTALL ERROR:", err) - break - } - fmt.Printf("LIB INSTALL> %+v\n", msg) - } - } -} diff --git a/internal/integrationtest/daemon/daemon_test.go b/internal/integrationtest/daemon/daemon_test.go index b868483155f..8685a7c0750 100644 --- a/internal/integrationtest/daemon/daemon_test.go +++ b/internal/integrationtest/daemon/daemon_test.go @@ -16,12 +16,73 @@ package daemon_test import ( + "context" + "fmt" + "io" "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 TestArduinoCliDaemon(t *testing.T) { + // See: https://github.com/arduino/arduino-cli/pull/1804 + + t.SkipNow() // TO BE Removed once the bug is fixed + + env, cli := createEnvForDaemon(t) + defer env.CleanUp() + + grpcInst := cli.Create() + require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { + fmt.Printf("INIT> %v\n", ir.GetMessage()) + })) + + // Run a one-shot board list + boardListResp, err := grpcInst.BoardList(time.Second) + require.NoError(t, err) + fmt.Printf("Got boardlist response with %d ports\n", len(boardListResp.GetPorts())) + + // Run a one-shot board list again (should not fail) + boardListResp, err = grpcInst.BoardList(time.Second) + require.NoError(t, err) + fmt.Printf("Got boardlist response with %d ports\n", len(boardListResp.GetPorts())) + + testWatcher := func() { + // Run watcher + watcher, err := grpcInst.BoardListWatch() + require.NoError(t, err) + ctx, cancel := context.WithCancel(context.Background()) + go func() { + defer cancel() + for { + msg, err := watcher.Recv() + if err == io.EOF { + fmt.Println("Watcher EOF") + return + } + require.Empty(t, msg.Error, "Board list watcher returned an error") + require.NoError(t, err, "BoardListWatch grpc call returned an error") + fmt.Printf("WATCH> %v\n", msg) + } + }() + time.Sleep(time.Second) + require.NoError(t, watcher.CloseSend()) + select { + case <-ctx.Done(): + // all right! + case <-time.After(time.Second): + require.Fail(t, "BoardListWatch didn't close") + } + } + + testWatcher() + testWatcher() +} + // createEnvForDaemon performs the minimum required operations to start the arduino-cli daemon. // It returns a testsuite.Environment and an ArduinoCLI client to perform the integration tests. // The Environment must be disposed by calling the CleanUp method via defer. @@ -39,3 +100,285 @@ func createEnvForDaemon(t *testing.T) (*integrationtest.Environment, *integratio _ = cli.StartDaemon(false) return env, cli } + +func TestDaemonCompileOptions(t *testing.T) { + // See: https://github.com/arduino/arduino-cli/issues/1614 + // See: https://github.com/arduino/arduino-cli/pull/1820 + + env, cli := 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.5", true) + require.NoError(t, err) + for { + msg, err := plInst.Recv() + if err == io.EOF { + break + } + require.NoError(t, err) + fmt.Printf("INSTALL> %v\n", msg) + } + + // Install boards.local.txt to trigger bug + platformLocalTxt := paths.New("testdata", "boards.local.txt-issue1614") + err = platformLocalTxt.CopyTo(cli.DataDir(). + Join("packages", "arduino", "hardware", "avr", "1.8.5", "boards.local.txt")) + require.NoError(t, err) + + // Re-init instance to update changes + require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { + fmt.Printf("INIT> %v\n", ir.GetMessage()) + })) + + // Build sketch (with errors) + sk := paths.New("testdata", "bare_minimum") + compile, err := grpcInst.Compile(context.Background(), "arduino:avr:uno:some_menu=bad", sk.String()) + require.NoError(t, err) + for { + msg, err := compile.Recv() + if err == io.EOF { + require.FailNow(t, "Expected compilation failure", "compilation succeeded") + break + } + if err != nil { + fmt.Println("COMPILE ERROR>", err) + break + } + if msg.ErrStream != nil { + fmt.Printf("COMPILE> %v\n", string(msg.GetErrStream())) + } + } + + // Build sketch (without errors) + compile, err = grpcInst.Compile(context.Background(), "arduino:avr:uno:some_menu=good", sk.String()) + require.NoError(t, err) + for { + msg, err := compile.Recv() + if err == io.EOF { + break + } + require.NoError(t, err) + if msg.ErrStream != nil { + fmt.Printf("COMPILE> %v\n", string(msg.GetErrStream())) + } + } +} + +func TestDaemonCompileAfterFailedLibInstall(t *testing.T) { + // See: https://github.com/arduino/arduino-cli/issues/1812 + + env, cli := createEnvForDaemon(t) + defer env.CleanUp() + + grpcInst := cli.Create() + require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { + fmt.Printf("INIT> %v\n", ir.GetMessage()) + })) + + // Build sketch (with errors) + sk := paths.New("testdata", "bare_minimum") + compile, err := grpcInst.Compile(context.Background(), "", sk.String()) + require.NoError(t, err) + for { + msg, err := compile.Recv() + if err == io.EOF { + require.FailNow(t, "Expected compilation failure", "compilation succeeded") + break + } + if err != nil { + fmt.Println("COMPILE ERROR>", err) + require.Contains(t, err.Error(), "Missing FQBN") + break + } + if msg.ErrStream != nil { + fmt.Printf("COMPILE> %v\n", string(msg.GetErrStream())) + } + } +} + +func TestDaemonCoreUpdateIndex(t *testing.T) { + env, cli := createEnvForDaemon(t) + defer env.CleanUp() + + grpcInst := cli.Create() + require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { + fmt.Printf("INIT> %v\n", ir.GetMessage()) + })) + + // Set extra indexes + err := cli.SetValue( + "board_manager.additional_urls", ""+ + `["http://arduino.esp8266.com/stable/package_esp8266com_index.json",`+ + ` "http://downloads.arduino.cc/package_inexistent_index.json"]`) + require.NoError(t, err) + + analyzeUpdateIndexClient := func(cl commands.ArduinoCoreService_UpdateIndexClient) (map[string]*commands.DownloadProgressEnd, error) { + analyzer := NewDownloadProgressAnalyzer(t) + for { + msg, err := cl.Recv() + // fmt.Println("DOWNLOAD>", msg) + if err == io.EOF { + return analyzer.Results, nil + } + if err != nil { + return analyzer.Results, err + } + require.NoError(t, err) + analyzer.Process(msg.GetDownloadProgress()) + } + } + + { + cl, err := grpcInst.UpdateIndex(context.Background(), true) + require.NoError(t, err) + res, err := analyzeUpdateIndexClient(cl) + require.NoError(t, err) + require.Len(t, res, 1) + require.True(t, res["https://downloads.arduino.cc/packages/package_index.tar.bz2"].Success) + } + { + cl, err := grpcInst.UpdateIndex(context.Background(), false) + require.NoError(t, err) + res, err := analyzeUpdateIndexClient(cl) + require.Error(t, err) + require.Len(t, res, 3) + require.True(t, res["https://downloads.arduino.cc/packages/package_index.tar.bz2"].Success) + require.True(t, res["http://arduino.esp8266.com/stable/package_esp8266com_index.json"].Success) + require.False(t, res["http://downloads.arduino.cc/package_inexistent_index.json"].Success) + } +} + +func TestDaemonBundleLibInstall(t *testing.T) { + env, cli := createEnvForDaemon(t) + defer env.CleanUp() + + grpcInst := cli.Create() + require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { + fmt.Printf("INIT> %v\n", ir.GetMessage()) + })) + + // Install libraries in bundled dir + { + instCl, err := grpcInst.LibraryInstall(context.Background(), "Arduino_BuiltIn", "", false, false, true) + require.NoError(t, err) + for { + msg, err := instCl.Recv() + if err == io.EOF { + break + } + require.NoError(t, err) + fmt.Printf("LIB INSTALL> %+v\n", msg) + } + } + + // Check if libraries are installed as expected + { + resp, err := grpcInst.LibraryList(context.Background(), "", "", true, false) + require.NoError(t, err) + libsAndLocation := map[string]commands.LibraryLocation{} + for _, lib := range resp.GetInstalledLibraries() { + libsAndLocation[lib.Library.Name] = lib.Library.Location + } + require.Contains(t, libsAndLocation, "Ethernet") + require.Contains(t, libsAndLocation, "SD") + require.Contains(t, libsAndLocation, "Firmata") + require.Equal(t, libsAndLocation["Ethernet"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) + require.Equal(t, libsAndLocation["SD"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) + require.Equal(t, libsAndLocation["Firmata"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) + } + + // Install a library in sketchbook to override bundled + { + instCl, err := grpcInst.LibraryInstall(context.Background(), "Ethernet", "", false, false, false) + require.NoError(t, err) + for { + msg, err := instCl.Recv() + if err == io.EOF { + break + } + require.NoError(t, err) + fmt.Printf("LIB INSTALL> %+v\n", msg) + } + } + + // Check if libraries are installed as expected + installedEthernetVersion := "" + { + resp, err := grpcInst.LibraryList(context.Background(), "", "", true, false) + require.NoError(t, err) + libsAndLocation := map[string]commands.LibraryLocation{} + for _, lib := range resp.GetInstalledLibraries() { + libsAndLocation[lib.Library.Name] = lib.Library.Location + if lib.Library.Name == "Ethernet" { + installedEthernetVersion = lib.Library.Version + } + } + require.Contains(t, libsAndLocation, "Ethernet") + require.Contains(t, libsAndLocation, "SD") + require.Contains(t, libsAndLocation, "Firmata") + require.Equal(t, libsAndLocation["Ethernet"], commands.LibraryLocation_LIBRARY_LOCATION_USER) + require.Equal(t, libsAndLocation["SD"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) + require.Equal(t, libsAndLocation["Firmata"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) + } + + // Remove library from sketchbook + { + uninstCl, err := grpcInst.LibraryUninstall(context.Background(), "Ethernet", installedEthernetVersion) + require.NoError(t, err) + for { + msg, err := uninstCl.Recv() + if err == io.EOF { + break + } + require.NoError(t, err) + fmt.Printf("LIB INSTALL> %+v\n", msg) + } + } + + // Check if libraries are installed as expected + { + resp, err := grpcInst.LibraryList(context.Background(), "", "", true, false) + require.NoError(t, err) + libsAndLocation := map[string]commands.LibraryLocation{} + for _, lib := range resp.GetInstalledLibraries() { + libsAndLocation[lib.Library.Name] = lib.Library.Location + } + require.Contains(t, libsAndLocation, "Ethernet") + require.Contains(t, libsAndLocation, "SD") + require.Contains(t, libsAndLocation, "Firmata") + require.Equal(t, libsAndLocation["Ethernet"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) + require.Equal(t, libsAndLocation["SD"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) + require.Equal(t, libsAndLocation["Firmata"], commands.LibraryLocation_LIBRARY_LOCATION_BUILTIN) + } + + // Un-Set builtin libraries dir + err := cli.SetValue("directories.builtin.libraries", `""`) + require.NoError(t, err) + + // Re-init + require.NoError(t, grpcInst.Init("", "", func(ir *commands.InitResponse) { + fmt.Printf("INIT> %v\n", ir.GetMessage()) + })) + + // Install libraries in bundled dir (should now fail) + { + instCl, err := grpcInst.LibraryInstall(context.Background(), "Arduino_BuiltIn", "", false, false, true) + require.NoError(t, err) + for { + msg, err := instCl.Recv() + if err == io.EOF { + require.FailNow(t, "LibraryInstall is supposed to fail because builtin libraries directory is not set") + } + if err != nil { + fmt.Println("LIB INSTALL ERROR:", err) + break + } + fmt.Printf("LIB INSTALL> %+v\n", msg) + } + } +}