Skip to content

Commit ffd1152

Browse files
committed
Add test for project discovery handling of symlink loops
1 parent 85638b8 commit ffd1152

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

internal/project/project_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ import (
2020
"os"
2121
"reflect"
2222
"testing"
23+
"time"
2324

2425
"github.com/arduino/arduino-lint/internal/configuration"
2526
"github.com/arduino/arduino-lint/internal/project/projecttype"
2627
"github.com/arduino/arduino-lint/internal/util/test"
2728
"github.com/arduino/go-paths-helper"
2829
"github.com/stretchr/testify/assert"
30+
"github.com/stretchr/testify/require"
2931
)
3032

3133
var testDataPath *paths.Path
@@ -38,6 +40,50 @@ func init() {
3840
testDataPath = paths.New(workingDirectory, "testdata")
3941
}
4042

43+
func TestSymlinkLoop(t *testing.T) {
44+
// Set up directory structure of test library.
45+
libraryPath, err := paths.TempDir().MkTempDir("TestSymlinkLoop")
46+
defer libraryPath.RemoveAll() // Clean up after the test.
47+
require.Nil(t, err)
48+
err = libraryPath.Join("TestSymlinkLoop.h").WriteFile([]byte{})
49+
require.Nil(t, err)
50+
examplesPath := libraryPath.Join("examples")
51+
err = examplesPath.Mkdir()
52+
require.Nil(t, err)
53+
54+
// It's probably most friendly for contributors using Windows to create the symlinks needed for the test on demand.
55+
err = os.Symlink(examplesPath.Join("..").String(), examplesPath.Join("UpGoer1").String())
56+
require.Nil(t, err, "This test must be run as administrator on Windows to have symlink creation privilege.")
57+
// It's necessary to have multiple symlinks to a parent directory to create the loop.
58+
err = os.Symlink(examplesPath.Join("..").String(), examplesPath.Join("UpGoer2").String())
59+
require.Nil(t, err)
60+
61+
configuration.Initialize(test.ConfigurationFlags(), []string{libraryPath.String()})
62+
63+
// The failure condition is FindProjects() never returning, testing for which requires setting up a timeout.
64+
done := make(chan bool)
65+
go func() {
66+
_, err = FindProjects()
67+
done <- true
68+
}()
69+
70+
assert.Eventually(
71+
t,
72+
func() bool {
73+
select {
74+
case <-done:
75+
return true
76+
default:
77+
return false
78+
}
79+
},
80+
20*time.Second,
81+
10*time.Millisecond,
82+
"Infinite symlink loop during project discovery",
83+
)
84+
require.Nil(t, err)
85+
}
86+
4187
func TestFindProjects(t *testing.T) {
4288
sketchPath := testDataPath.Join("Sketch")
4389
libraryPath := testDataPath.Join("Library")

0 commit comments

Comments
 (0)