2222 */
2323package com .scanoss ;
2424
25+ import com .google .gson .Gson ;
26+ import com .scanoss .dto .ScanFileDetails ;
27+ import com .scanoss .dto .ScanFileResult ;
28+ import com .scanoss .dto .ServerDetails ;
29+ import com .scanoss .dto .enums .MatchType ;
2530import com .scanoss .exceptions .ScannerException ;
2631import com .scanoss .filters .FilterConfig ;
2732import com .scanoss .settings .ScanossSettings ;
2833import com .scanoss .utils .JsonUtils ;
34+ import com .scanoss .utils .WinnowingUtils ;
2935import lombok .extern .slf4j .Slf4j ;
36+ import okhttp3 .mockwebserver .Dispatcher ;
37+ import okhttp3 .mockwebserver .MockResponse ;
38+ import okhttp3 .mockwebserver .MockWebServer ;
39+ import okhttp3 .mockwebserver .RecordedRequest ;
40+ import org .jetbrains .annotations .NotNull ;
41+ import org .junit .After ;
3042import org .junit .Before ;
3143import org .junit .Test ;
3244
45+ import java .io .File ;
3346import java .io .FileWriter ;
3447import java .io .IOException ;
35- import java .util .ArrayList ;
36- import java .util .Arrays ;
37- import java .util .List ;
48+ import java .nio .file .*;
49+ import java .nio .file .attribute .BasicFileAttributes ;
50+ import java .util .*;
51+ import java .util .concurrent .*;
52+ import java .util .stream .Collectors ;
3853
3954import static org .junit .Assert .*;
4055
4156@ Slf4j
4257public class TestScanner {
58+ private MockWebServer server ;
59+
60+
4361 @ Before
44- public void Setup () {
62+ public void Setup () throws IOException {
4563 log .info ("Starting Scanner test cases..." );
4664 log .debug ("Logging debug enabled" );
4765 log .trace ("Logging trace enabled" );
66+ log .info ("Starting Mock Server..." );
67+ server = new MockWebServer ();
68+ server .start ();
69+ }
70+
71+ @ After
72+ public void Finish () {
73+ log .info ("Shutting down mock server." );
74+ try {
75+ server .close ();
76+ server .shutdown ();
77+ } catch (IOException e ) {
78+ log .warn ("Some issue shutting down mock server: {}" , e .getLocalizedMessage ());
79+ }
4880 }
4981
5082 @ Test
@@ -409,4 +441,116 @@ public void TestScannerCustomFilterConfig() {
409441
410442 log .info ("Finished {} -->" , methodName );
411443 }
412- }
444+
445+ /**
446+ * Test that we can scan a folder with obfuscation enabled using a mock server.
447+ * This test focuses on the path obfuscation/deobfuscation functionality in a multi-threaded environment.
448+ * The dispatcher supports handling multiple files in a single request.
449+ */
450+ @ Test
451+ public void testConcurrentScanWithObfuscation () throws IOException {
452+ final String folderToScan = "src/test" ;
453+
454+ // Set to capture all paths received by the server
455+ final Set <String > receivedPaths = ConcurrentHashMap .newKeySet ();
456+
457+ // Collect all files in the src/test folder before scanning
458+ final Set <String > allSourceFilePaths = Files .walk (Paths .get (folderToScan ))
459+ .filter (path -> !Files .isDirectory (path ))
460+ .map (path -> {
461+ // Convert to relative path with forward slashes
462+ String relativePath = Paths .get (folderToScan ).relativize (path ).toString ();
463+ return relativePath .replace (File .separatorChar , '/' );
464+ })
465+ .collect (Collectors .toSet ());
466+
467+ log .info ("Found {} files in source directory" , allSourceFilePaths .size ());
468+
469+
470+
471+
472+
473+ // Configure the MockWebServer to return a 'no match' response for any request.
474+ // This is important for testing without depending on actual scan results.
475+ //TODO: Extend the mock webserver to other tests.
476+ final Dispatcher dispatcher = new Dispatcher () {
477+ @ NotNull
478+ @ Override
479+ public MockResponse dispatch (RecordedRequest request ) {
480+ // Extract the WFP from the request and parse all obfuscated paths
481+ String requestBody = request .getBody ().readUtf8 ();
482+ Set <String > paths = WinnowingUtils .extractFilePathsFromWFPBlock (requestBody );
483+
484+ // Store all received paths for later verification
485+ receivedPaths .addAll (paths );
486+
487+
488+ for (String path : paths ) {
489+ log .debug ("Server received obfuscated path: {}" , path );
490+ }
491+
492+ if (paths .isEmpty ()) {
493+ return new MockResponse ()
494+ .setResponseCode (400 )
495+ .setBody ("error: Bad Request - No valid obfuscated paths found" );
496+ }
497+
498+ // Create response objects using the DTO classes
499+ Map <String , List <ScanFileDetails >> responseMap = new HashMap <>();
500+
501+ // Create server details object (same for all responses)
502+ ServerDetails .KbVersion kbVersion = new ServerDetails .KbVersion ("25.05" , "21.05.21" );
503+ ServerDetails serverDetails = new ServerDetails ("5.4.10" , kbVersion );
504+
505+ // Create a "none" match result for each path
506+ for (String path : paths ) {
507+ ScanFileDetails noMatchResult = ScanFileDetails .builder ()
508+ .matchType (MatchType .none )
509+ .serverDetails (serverDetails )
510+ .build ();
511+
512+ responseMap .put (path , Collections .singletonList (noMatchResult ));
513+ }
514+
515+ // Convert to JSON
516+ Gson gson = new Gson ();
517+ String responseJson = gson .toJson (responseMap );
518+
519+ return new MockResponse ()
520+ .setResponseCode (200 )
521+ .setBody (responseJson );
522+ }
523+ };
524+ server .setDispatcher (dispatcher );
525+
526+ // Create a scanner with obfuscation enabled and multiple threads
527+ Scanner scanner = Scanner .builder ()
528+ .obfuscate (true )
529+ .numThreads (8 ) // Use multiple threads to process files
530+ .url (server .url ("/api/scan/direct" ).toString ()) // Use our mock server
531+ .build ();
532+
533+ // Scan the files to test the full obfuscation/deobfuscation cycle
534+ List <String > results = scanner .scanFolder (folderToScan );
535+
536+
537+ // Verify we got scan results
538+ assertNotNull ("Should have scan results" , results );
539+ assertFalse ("Should have result non empty" , results .isEmpty ());
540+ log .info ("Received {} scan results" , results .size ());
541+
542+ // Verify paths received by the server are obfuscated (not matching any source file paths)
543+ for (String receivedPath : receivedPaths ) {
544+ assertFalse ("Path should be obfuscated and not match any source path: " + receivedPath ,
545+ allSourceFilePaths .contains (receivedPath ));
546+ }
547+
548+ List <ScanFileResult > resultsDto = JsonUtils .toScanFileResults (results );
549+ // Verify (deobfuscation) that all results from scanFolder are valid file paths from our source directory
550+ for (ScanFileResult r : resultsDto ) {
551+ assertTrue ("Result should be a valid source file path: " + r .getFilePath (),
552+ allSourceFilePaths .contains (r .getFilePath ()));
553+ }
554+
555+ }
556+ }
0 commit comments