Skip to content

Commit f872b0f

Browse files
Add tests for the changes
1 parent 797981d commit f872b0f

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

arduino/libraries/libraries_test.go

+89
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ package libraries
1717

1818
import (
1919
"encoding/json"
20+
"os"
2021
"testing"
22+
"time"
2123

2224
paths "github.com/arduino/go-paths-helper"
25+
"github.com/stretchr/testify/assert"
2326
"github.com/stretchr/testify/require"
2427
)
2528

@@ -85,3 +88,89 @@ func TestLibrariesLoader(t *testing.T) {
8588
require.True(t, lib.IsLegacy)
8689
}
8790
}
91+
92+
func TestSymlinkLoop(t *testing.T) {
93+
// Set up directory structure of test library.
94+
libraryPath := paths.New("testdata", "TestLib")
95+
tempLibPath, err := paths.TempDir().MkTempDir("TestSymlinkLoop")
96+
require.NoError(t, err)
97+
defer tempLibPath.RemoveAll() // Clean up after the test.
98+
testLib := tempLibPath.Join("TestLib")
99+
require.NoError(t, libraryPath.CopyDirTo(testLib))
100+
examplesPath := testLib.Join("examples")
101+
require.NoError(t, examplesPath.Mkdir())
102+
103+
// It's probably most friendly for contributors using Windows to create the symlinks needed for the test on demand.
104+
err = os.Symlink(examplesPath.Join("..").String(), examplesPath.Join("UpGoer1").String())
105+
require.NoError(t, err, "This test must be run as administrator on Windows to have symlink creation privilege.")
106+
// It's necessary to have multiple symlinks to a parent directory to create the loop.
107+
err = os.Symlink(examplesPath.Join("..").String(), examplesPath.Join("UpGoer2").String())
108+
require.NoError(t, err)
109+
110+
// The failure condition is Load() never returning, testing for which requires setting up a timeout.
111+
done := make(chan bool)
112+
go func() {
113+
_, err = Load(testLib, User)
114+
done <- true
115+
}()
116+
117+
noHang := assert.Eventually(
118+
t,
119+
func() bool {
120+
select {
121+
case <-done:
122+
return true
123+
default:
124+
return false
125+
}
126+
},
127+
20*time.Second,
128+
10*time.Millisecond,
129+
"Infinite symlink loop while loading library",
130+
)
131+
require.True(t, noHang)
132+
require.Error(t, err)
133+
}
134+
135+
func TestLegacySymlinkLoop(t *testing.T) {
136+
// Set up directory structure of test library.
137+
libraryPath, err := paths.TempDir().MkTempDir("TestSymlinkLoop")
138+
defer libraryPath.RemoveAll() // Clean up after the test.
139+
require.NoError(t, err)
140+
err = libraryPath.Join("TestSymlinkLoop.h").WriteFile([]byte{})
141+
require.NoError(t, err)
142+
examplesPath := libraryPath.Join("examples")
143+
err = examplesPath.Mkdir()
144+
require.NoError(t, err)
145+
146+
// It's probably most friendly for contributors using Windows to create the symlinks needed for the test on demand.
147+
err = os.Symlink(examplesPath.Join("..").String(), examplesPath.Join("UpGoer1").String())
148+
require.NoError(t, err, "This test must be run as administrator on Windows to have symlink creation privilege.")
149+
// It's necessary to have multiple symlinks to a parent directory to create the loop.
150+
err = os.Symlink(examplesPath.Join("..").String(), examplesPath.Join("UpGoer2").String())
151+
require.NoError(t, err)
152+
153+
// The failure condition is Load() never returning, testing for which requires setting up a timeout.
154+
done := make(chan bool)
155+
go func() {
156+
_, err = Load(libraryPath, User)
157+
done <- true
158+
}()
159+
160+
noHang := assert.Eventually(
161+
t,
162+
func() bool {
163+
select {
164+
case <-done:
165+
return true
166+
default:
167+
return false
168+
}
169+
},
170+
20*time.Second,
171+
10*time.Millisecond,
172+
"Infinite symlink loop while loading library",
173+
)
174+
require.True(t, noHang)
175+
require.Error(t, err)
176+
}

0 commit comments

Comments
 (0)