@@ -4,16 +4,18 @@ import (
44 "strings"
55 "testing"
66
7+ "errors"
8+ "fmt"
9+
710 "github.com/eraser-dev/eraser/api/unversioned"
11+
12+ "github.com/stretchr/testify/assert"
813)
914
1015const ref = "image:tag"
1116
1217var testDuration = unversioned .Duration (100000000000 )
1318
14- func init () {
15- }
16-
1719func TestCLIArgs (t * testing.T ) {
1820 type testCell struct {
1921 desc string
@@ -168,3 +170,157 @@ func TestCLIArgs(t *testing.T) {
168170 })
169171 }
170172}
173+
174+ // TestImageScanner_findTrivyExecutable tests the findTrivyExecutable method in isolation.
175+ func TestImageScanner_findTrivyExecutable (t * testing.T ) {
176+ // Store original function to restore after tests
177+ originalLookPath := currentExecutingLookPath
178+ defer func () { currentExecutingLookPath = originalLookPath }()
179+
180+ scanner := & ImageScanner {}
181+
182+ testCases := []struct {
183+ name string
184+ lookPathSetup func ()
185+ expectedPath string
186+ expectedError bool
187+ expectedErrorMatch string
188+ }{
189+ {
190+ name : "Trivy found in PATH only" ,
191+ lookPathSetup : func () {
192+ currentExecutingLookPath = func (file string ) (string , error ) {
193+ if file == "trivy" {
194+ return "/usr/bin/trivy" , nil
195+ }
196+ return "" , errors .New ("not found" )
197+ }
198+ },
199+ expectedPath : "/usr/bin/trivy" ,
200+ expectedError : false ,
201+ },
202+ {
203+ name : "Trivy not found anywhere" ,
204+ lookPathSetup : func () {
205+ currentExecutingLookPath = func (file string ) (string , error ) {
206+ return "" , errors .New ("executable file not found in $PATH" )
207+ }
208+ },
209+ expectedPath : "" ,
210+ expectedError : true ,
211+ expectedErrorMatch : "trivy executable not found at /trivy and not found in PATH" ,
212+ },
213+ }
214+
215+ for _ , tc := range testCases {
216+ t .Run (tc .name , func (t * testing.T ) {
217+ tc .lookPathSetup ()
218+
219+ path , err := scanner .findTrivyExecutable ()
220+
221+ if tc .expectedError {
222+ assert .Error (t , err )
223+ assert .Contains (t , err .Error (), tc .expectedErrorMatch )
224+ assert .Empty (t , path )
225+ } else {
226+ assert .NoError (t , err )
227+ assert .Equal (t , tc .expectedPath , path )
228+ }
229+ })
230+ }
231+ }
232+
233+ // TestImageScanner_Scan_TrivyPathLookup tests the logic for finding the trivy executable.
234+ func TestImageScanner_Scan_TrivyPathLookup (t * testing.T ) {
235+ // Store original function to restore after tests
236+ originalLookPath := currentExecutingLookPath
237+ defer func () { currentExecutingLookPath = originalLookPath }()
238+
239+ // Base configuration for the scanner
240+ baseConfig := DefaultConfig ()
241+ scanner := & ImageScanner {
242+ config : * baseConfig ,
243+ }
244+ // Dummy image for testing
245+ img := unversioned.Image {ImageID : "test-image-id" , Names : []string {"test-image:latest" }}
246+
247+ // Expected error message prefix when trivy is not found
248+ expectedNotFoundErrorMsgPrefix := fmt .Sprintf ("trivy executable not found at %s" , trivyCommandName )
249+
250+ testCases := []struct {
251+ name string
252+ lookPathSetup func () // Sets up the mock for exec.LookPath
253+ expectedStatus ScanStatus
254+ expectNotFoundError bool // True if we expect the specific "trivy not found by LookPath" error
255+ expectedErrorMsgContains string // The prefix for the "not found" error message
256+ }{
257+ {
258+ name : "Trivy found at hardcoded path /trivy" ,
259+ lookPathSetup : func () {
260+ currentExecutingLookPath = func (file string ) (string , error ) {
261+ if file == "trivy" {
262+ return "/usr/bin/trivy" , nil // Found in PATH
263+ }
264+ return originalLookPath (file ) // Fallback for any other calls
265+ }
266+ },
267+ // Scan will likely still fail due to inability to run actual scan in test,
268+ // but it should not be the "trivy not found by LookPath" error.
269+ expectedStatus : StatusFailed ,
270+ expectNotFoundError : false ,
271+ },
272+ {
273+ name : "Trivy found in $PATH, not at /trivy" ,
274+ lookPathSetup : func () {
275+ currentExecutingLookPath = func (file string ) (string , error ) {
276+ if file == "trivy" {
277+ return "/usr/bin/trivy" , nil // Found in $PATH
278+ }
279+ return originalLookPath (file )
280+ }
281+ },
282+ expectedStatus : StatusFailed , // Similar to above, subsequent scan steps will fail.
283+ expectNotFoundError : false ,
284+ },
285+ {
286+ name : "Trivy not found anywhere" ,
287+ lookPathSetup : func () {
288+ currentExecutingLookPath = func (file string ) (string , error ) {
289+ if file == "trivy" {
290+ return "" , errors .New ("mock: trivy not in $PATH" )
291+ }
292+ return originalLookPath (file )
293+ }
294+ },
295+ expectedStatus : StatusFailed ,
296+ expectNotFoundError : true ,
297+ expectedErrorMsgContains : expectedNotFoundErrorMsgPrefix ,
298+ },
299+ }
300+
301+ for _ , tc := range testCases {
302+ t .Run (tc .name , func (t * testing.T ) {
303+ tc .lookPathSetup ()
304+
305+ status , err := scanner .Scan (img )
306+
307+ if tc .expectNotFoundError {
308+ assert .Error (t , err , "Expected an error when trivy is not found" )
309+ if err != nil { // Check prefix only if error is not nil
310+ assert .True (t , strings .HasPrefix (err .Error (), tc .expectedErrorMsgContains ),
311+ "Error message should start with '%s'. Got: %s" , tc .expectedErrorMsgContains , err .Error ())
312+ }
313+ assert .Equal (t , tc .expectedStatus , status , "ScanStatus should be StatusFailed" )
314+ } else {
315+ // If trivy was "found" by LookPath, any error should be from subsequent operations (e.g., cmd.Run, JSON unmarshal),
316+ // not the specific "trivy executable not found by LookPath..." error.
317+ if err != nil {
318+ assert .False (t , strings .HasPrefix (err .Error (), expectedNotFoundErrorMsgPrefix ),
319+ "Error should not be the 'trivy not found by LookPath' error. Got: %s" , err .Error ())
320+ }
321+ // The status might still be StatusFailed due to these subsequent errors,
322+ // which is acceptable for this test's focus on path lookup.
323+ }
324+ })
325+ }
326+ }
0 commit comments