Skip to content

Conversation

@ManojTestsigma
Copy link
Contributor

@ManojTestsigma ManojTestsigma commented Sep 5, 2025

Jira

https://testsigma.atlassian.net/browse/TE-29364

Addon Name : Get Status Code from Network Logs
Jarvis Account : https://jarvis.testsigma.com/ui/tenants/2817/addons

fix

added a class to track the status code.
one more class to fetch the status code.

Summary by CodeRabbit

  • New Features
    • Added actions to start tracking browser network requests and capture HTTP status codes for matching URLs/methods.
    • Added an action to fetch the captured status code and store it in a runtime variable for use in test steps and validations.
  • Chores
    • Introduced a new module packaged as a shaded JAR with attached sources and standardized dependency versions.
    • Added configuration resources required for SDK integration.

@coderabbitai
Copy link

coderabbitai bot commented Sep 5, 2025

Walkthrough

Adds a new addon module to capture HTTP status codes from browser network logs using Selenium DevTools. Introduces two WebActions: one starts tracking and stores the status code per run; the other retrieves it into a runtime variable. Includes utility classes for Base64/JSON file-backed persistence and Maven module setup.

Changes

Cohort / File(s) Summary
Module setup
get_status_code_from_network_logs/pom.xml, get_status_code_from_network_logs/src/main/resources/testsigma-sdk.properties
New Maven module with shading and SDK/test dependencies; adds SDK properties file with API key.
Web actions
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/StartTracking.java, .../web/GetStatusCode.java
New WebActions: StartTracking configures Selenium DevTools Network listeners to capture status code for matching URL/method and persist it; GetStatusCode reads stored status code and writes it to a runtime variable.
Persistence utilities
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/utilities/ResponseDataUtilities.java, .../utilities/FileUtilities.java
Adds utilities to encode/decode JSON via Base64 and read/write per-run data to files under /tmp/ntuc_data; exposes add/get status code APIs.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Tester
  participant StartTracking as StartTracking Action
  participant WebDriver as Selenium WebDriver
  participant DevTools as Chrome DevTools
  participant RespUtil as ResponseDataUtilities
  participant Files as FileUtilities

  Tester->>StartTracking: execute()
  StartTracking->>WebDriver: augment() + getDevTools()
  StartTracking->>DevTools: createSession() + Network.enable()
  note over DevTools: Listeners registered
  DevTools-->>StartTracking: requestWillBeSent(request)
  alt URL contains url_value AND method==method_value
    StartTracking->>DevTools: store RequestId
  end
  DevTools-->>StartTracking: responseReceived(response)
  alt Response matches stored RequestId
    StartTracking->>RespUtil: addStatusCodeData(runId, status)
    RespUtil->>Files: writeToFile(runId, Base64(JSON{statusCode}))
    Files-->>RespUtil: ok
    RespUtil-->>StartTracking: ok
  end
  StartTracking-->>Tester: Result.SUCCESS
Loading
sequenceDiagram
  autonumber
  actor Tester
  participant GetStatus as GetStatusCode Action
  participant RespUtil as ResponseDataUtilities
  participant Files as FileUtilities
  participant Runtime as Runtime Var Store

  Tester->>GetStatus: execute()
  GetStatus->>RespUtil: getStatusCode(runId)
  RespUtil->>Files: readFromFile(runId)
  Files-->>RespUtil: Base64(JSON)
  RespUtil-->>GetStatus: statusCode
  GetStatus->>Runtime: set(status_code, value)
  GetStatus-->>Tester: Result.SUCCESS
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Ganesh-Testsigma
  • vigneshtestsigma

Poem

In chrome-lit burrows, I listen for hops,
Packets thump softly—status code drops.
I stash the digits where runtimes dwell,
Base64 whispers the tale to tell.
Click, scurry, fetch—logs in a row,
A rabbit nods: 2️⃣0️⃣0️⃣—good to go! 🐇✨

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch TE-29364

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (14)
get_status_code_from_network_logs/pom.xml (3)

47-58: Validate Selenium/Appium versions vs. platform support.

Ensure these versions are supported by the Testsigma runtime. If Appium isn’t used by this addon, drop it.


12-22: Consider aligning Java and plugin versions with org standards.

Java 11 is fine; if the org has moved to 17, update source/target here to match.


24-47: Trim unused test frameworks and libs to reduce jar size and surface area.

Both JUnit and TestNG are declared; keep only the one you use. Likewise, Lombok, Jackson-annotations, and org.json are not used in the provided sources.

Quick check for usage:

#!/bin/bash
rg -nP 'import\s+lombok' -g '!**/target/**'
rg -nP 'import\s+com\.fasterxml\.jackson\.annotation' -g '!**/target/**'
rg -nP 'import\s+org\.json\.' -g '!**/target/**'
rg -nP 'import\s+org\.testng\.' -g '!**/target/**'
rg -nP 'import\s+org\.junit\.jupiter\.' -g '!**/target/**'
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/utilities/FileUtilities.java (3)

15-19: Avoid hard-coded absolute path; use OS temp dir.

Hard-coding /tmp/ntuc_data is brittle and platform-specific.

-    private static final String folderPath = "/tmp/ntuc_data";
+    private static final String folderPath =
+        System.getProperty("java.io.tmpdir") + File.separator + "testsigma_network";

9-12: Remove unused imports.

-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.UUID;

47-55: Propagate or log read failures.

Currently returns null silently; at least log the exception to aid debugging.

-        } catch (IOException e) {
-            return null;
-        }
+        } catch (IOException e) {
+            // optional: use a logger if available
+            return null;
+        }
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/GetStatusCode.java (2)

14-16: Action description references "StartTrackingV3" — mismatch.

If the paired action class is named differently (e.g., StartTracking), update the description to avoid user confusion.


31-39: Minor: streamline return and guard runtime variable key.

Return Result.SUCCESS directly; defensively handle null variable name to avoid NPE if misconfigured.

-            Result result = Result.SUCCESS;
             logger.info("Retrieving status code for test case ID: " + testCaseResult.getId());
             int statusCodeFromFile = getStatusCode(testCaseResult.getId(), logger);
             logger.info("Status code retrieved: " + statusCodeFromFile);
             
             // Store the status code in the runtime variable
-            runTimeData.setKey(statusCodeVariable.getValue().toString());
+            if (statusCodeVariable.getValue() == null) {
+                setErrorMessage("Runtime variable name (status_code) is not set.");
+                return Result.FAILED;
+            }
+            runTimeData.setKey(statusCodeVariable.getValue().toString());
             runTimeData.setValue(String.valueOf(statusCodeFromFile));
             setSuccessMessage("Status code retrieved successfully: " + statusCodeFromFile);
-            return result;
+            return Result.SUCCESS;
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/utilities/ResponseDataUtilities.java (3)

3-6: Remove unused imports (JsonArray).

-import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;

21-24: Improve logging level and exception propagation.

Use warn/error and avoid wrapping with generic Exception unless required by callers.


53-55: Consider returning a clearer exception type or message.

"Failed to get any status code" could include the runId and known causes (e.g., tracker not started).

get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/StartTracking.java (3)

55-56: Avoid oversized network buffer

100MB buffer is excessive and can inflate memory use. Let Selenium/Chrome choose defaults unless you have a measured need.

-            devTool.send(Network.enable(Optional.empty(),
-                    Optional.empty(), Optional.of(100000000)));
+            devTool.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));

64-71: Downgrade verbose request/response logs to debug and avoid logging full URLs in info

URLs can contain tokens/PII. Keep them at debug level and prefer structured logging placeholders.

-                logger.info("Intercepted request URL: " + requestUrl);
+                logger.debug("Intercepted request URL: {}", requestUrl);
-                    logger.info("Matching request found with URL: " + requestUrl + " and method: "
-                            + methodValue.getValue());
+                    logger.debug("Matching request found: url={}, method={}", requestUrl, method);
-                    logger.info("Matching response found for URL: " + response.getResponse().getUrl());
+                    logger.debug("Matching response for URL: {}", response.getResponse().getUrl());
-                        logger.info("Storing status code " + statusCode + " in test case result...");
+                        logger.debug("Storing status code {}", statusCode);

Also applies to: 80-85


61-63: Listener accumulation across repeated runs

If StartTracking is executed multiple times in the same browser session, listeners may accumulate. Consider idempotency or clearing your own listeners, or provide a StopTracking action to detach/disable.

Also applies to: 75-77

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 604d28c and 6d2a0ef.

📒 Files selected for processing (6)
  • get_status_code_from_network_logs/pom.xml (1 hunks)
  • get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/GetStatusCode.java (1 hunks)
  • get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/StartTracking.java (1 hunks)
  • get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/utilities/FileUtilities.java (1 hunks)
  • get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/utilities/ResponseDataUtilities.java (1 hunks)
  • get_status_code_from_network_logs/src/main/resources/testsigma-sdk.properties (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/GetStatusCode.java (1)
store_network_logs_data/src/main/java/com/testsigma/addons/web/GetStatusCode.java (1)
  • Data (14-49)
🔇 Additional comments (3)
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/StartTracking.java (3)

21-27: Action metadata reads well

Action text/description and WEB scoping look good.


101-105: Happy path completion

Clear success message and Result.SUCCESS are appropriate after setup.


13-15: CDP version pinning: verify compatibility with your Selenium/Chrome versions

Importing v137 ties you to specific Chrome versions. Ensure your pom.xml includes a matching selenium-devtools artifact or switch to the “idealized” DevTools API if supported in your stack.

Run to confirm versions:

#!/bin/bash
fd -a pom.xml | while read -r p; do
  echo "==> $p"
  rg -n -C2 -e 'selenium.*(java|devtools)' "$p"
done

Comment on lines +91 to +103
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

❓ Verification inconclusive

Shading without relocations may cause runtime conflicts.

Shading Selenium/Gson/etc. into the addon can clash with platform-provided versions. Either avoid shading or add relocations for conflicting packages, after confirming platform guidance.

Example relocation (adjust per platform policy):

             <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-shade-plugin</artifactId>
               <version>3.2.4</version>
               <executions>
                 <execution>
                   <phase>package</phase>
                   <goals>
                     <goal>shade</goal>
                   </goals>
+                  <configuration>
+                    <relocations>
+                      <relocation>
+                        <pattern>com.google.gson</pattern>
+                        <shadedPattern>com.testsigma.addons.shaded.gson</shadedPattern>
+                      </relocation>
+                      <relocation>
+                        <pattern>org.apache.commons.io</pattern>
+                        <shadedPattern>com.testsigma.addons.shaded.commons.io</shadedPattern>
+                      </relocation>
+                    </relocations>
+                  </configuration>
                 </execution>
               </executions>
             </plugin>

Add relocations to the Maven Shade plugin or disable shading
Shading third-party libraries without relocations can cause runtime conflicts with platform-provided versions (e.g. Selenium, Gson). In get_status_code_from_network_logs/pom.xml (lines 91–103), either remove the shade execution or add a <configuration><relocations>…</relocations></configuration> block to relocate any bundled packages.

🤖 Prompt for AI Agents
In get_status_code_from_network_logs/pom.xml around lines 91 to 103 the
maven-shade-plugin is executed without relocations which can cause runtime
conflicts; either remove the <execution> block for the shade goal (so shading is
disabled) or add a <configuration> section containing a <relocations> block that
lists package relocations for all third-party packages you bundle (for example
relocate com.google.gson, org.openqa.selenium and other vendor packages to a
project-specific namespace), ensuring each <relocation> includes <pattern> and
<shadedPattern> entries; update the plugin element accordingly and run mvn
package to verify no classpath conflicts.

Comment on lines +45 to +51
driver = new Augmenter().augment(driver);

// Initialize DevTools and create a session
logger.info("Initializing DevTools...");
DevTools devTool = ((HasDevTools) driver).getDevTools();
devTool.createSessionIfThereIsNotOne();
logger.info("DevTools session successfully created.");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Guard for non-Chromium drivers to avoid ClassCastException

If the driver doesn’t support DevTools, the cast to HasDevTools will fail. Check support after augmenting and fail gracefully.

             logger.info("Augmenting driver to support DevTools...");
             driver = new Augmenter().augment(driver);

             // Initialize DevTools and create a session
             logger.info("Initializing DevTools...");
-            DevTools devTool = ((HasDevTools) driver).getDevTools();
+            if (!(driver instanceof HasDevTools)) {
+                setErrorMessage("DevTools not supported by this browser/driver. Use a Chromium-based browser (Chrome/Edge).");
+                return Result.FAILED;
+            }
+            DevTools devTool = ((HasDevTools) driver).getDevTools();
             devTool.createSessionIfThereIsNotOne();
             logger.info("DevTools session successfully created.");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
driver = new Augmenter().augment(driver);
// Initialize DevTools and create a session
logger.info("Initializing DevTools...");
DevTools devTool = ((HasDevTools) driver).getDevTools();
devTool.createSessionIfThereIsNotOne();
logger.info("DevTools session successfully created.");
logger.info("Augmenting driver to support DevTools...");
driver = new Augmenter().augment(driver);
// Initialize DevTools and create a session
logger.info("Initializing DevTools...");
if (!(driver instanceof HasDevTools)) {
setErrorMessage("DevTools not supported by this browser/driver. Use a Chromium-based browser (Chrome/Edge).");
return Result.FAILED;
}
DevTools devTool = ((HasDevTools) driver).getDevTools();
devTool.createSessionIfThereIsNotOne();
logger.info("DevTools session successfully created.");
🤖 Prompt for AI Agents
In
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/StartTracking.java
around lines 45 to 51, the code unconditionally casts the augmented driver to
HasDevTools which will throw ClassCastException for non‑Chromium drivers; after
augmenting the driver, check if (driver instanceof HasDevTools) before casting,
obtain DevTools only in that branch, and otherwise log a clear warning/error and
fail gracefully (e.g., return, throw a descriptive exception, or skip DevTools
initialization) so non‑Chromium drivers are handled safely.

Comment on lines +51 to +56
logger.info("DevTools session successfully created.");

// Enable network interception with high buffer size
logger.info("Enabling network interception...");
devTool.send(Network.enable(Optional.empty(),
Optional.empty(), Optional.of(100000000)));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Validate inputs early and compute once for thread-safe capture

Avoid NPEs and repeated TestData.getValue() calls inside listeners. Precompute and validate.

             devTool.createSessionIfThereIsNotOne();
             logger.info("DevTools session successfully created.");
 
-            // Enable network interception with high buffer size
+            // Resolve and validate inputs
+            final String urlPattern = java.util.Objects.toString(urlValue != null ? urlValue.getValue() : null, "").trim();
+            final String method = java.util.Objects.toString(methodValue != null ? methodValue.getValue() : null, "").trim();
+            if (urlPattern.isBlank() || method.isBlank()) {
+                setErrorMessage("Both 'url_value' and 'method_value' are required and cannot be blank.");
+                return Result.FAILED;
+            }
+
+            // Enable network interception with sane defaults
             logger.info("Enabling network interception...");
-            devTool.send(Network.enable(Optional.empty(),
-                    Optional.empty(), Optional.of(100000000)));
+            devTool.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
logger.info("DevTools session successfully created.");
// Enable network interception with high buffer size
logger.info("Enabling network interception...");
devTool.send(Network.enable(Optional.empty(),
Optional.empty(), Optional.of(100000000)));
devTool.createSessionIfThereIsNotOne();
logger.info("DevTools session successfully created.");
// Resolve and validate inputs
final String urlPattern = java.util.Objects.toString(
urlValue != null ? urlValue.getValue() : null, ""
).trim();
final String method = java.util.Objects.toString(
methodValue != null ? methodValue.getValue() : null, ""
).trim();
if (urlPattern.isBlank() || method.isBlank()) {
setErrorMessage(
"Both 'url_value' and 'method_value' are required and cannot be blank."
);
return Result.FAILED;
}
// Enable network interception with sane defaults
logger.info("Enabling network interception...");
devTool.send(Network.enable(
Optional.empty(),
Optional.empty(),
Optional.empty()
));
🤖 Prompt for AI Agents
In
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/StartTracking.java
around lines 51 to 56, avoid calling TestData.getValue() repeatedly inside
listeners and prevent possible NPEs by reading and validating the value once
before creating the DevTools listeners; compute the value into a final local
variable, check for null/empty and log or throw an informative error if invalid,
then capture that final variable inside the listener so the listener uses the
precomputed, thread-safe value instead of calling TestData.getValue() multiple
times.

Comment on lines +58 to +73
final RequestId[] requestIds = new RequestId[1];

// Listener to intercept network requests
logger.info("Adding listener for network requests...");
devTool.addListener(Network.requestWillBeSent(), request -> {
String requestUrl = request.getRequest().getUrl();
logger.info("Intercepted request URL: " + requestUrl);

// Check if the URL and method match the specified criteria
if (requestUrl.contains(urlValue.getValue().toString()) &&
request.getRequest().getMethod().equalsIgnoreCase(methodValue.getValue().toString())) {
logger.info("Matching request found with URL: " + requestUrl + " and method: "
+ methodValue.getValue());
requestIds[0] = request.getRequestId();
}
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix request/response pairing to avoid races and missed matches

Tracking only a single mutable RequestId causes lost/mismatched captures when multiple matching requests are in flight. Use a thread-safe set of requestIds and capture exactly once, atomically, on the first matching response.

Apply:

-            final RequestId[] requestIds = new RequestId[1];
+            final java.util.Set<RequestId> matchingIds = java.util.concurrent.ConcurrentHashMap.newKeySet();
+            final java.util.concurrent.atomic.AtomicBoolean captured = new java.util.concurrent.atomic.AtomicBoolean(false);

             // Listener to intercept network requests
             logger.info("Adding listener for network requests...");
             devTool.addListener(Network.requestWillBeSent(), request -> {
                 String requestUrl = request.getRequest().getUrl();
-                logger.info("Intercepted request URL: " + requestUrl);
+                logger.debug("Intercepted request URL: {}", requestUrl);

                 // Check if the URL and method match the specified criteria
-                if (requestUrl.contains(urlValue.getValue().toString()) &&
-                        request.getRequest().getMethod().equalsIgnoreCase(methodValue.getValue().toString())) {
-                    logger.info("Matching request found with URL: " + requestUrl + " and method: "
-                            + methodValue.getValue());
-                    requestIds[0] = request.getRequestId();
+                if (requestUrl.contains(urlPattern) &&
+                        request.getRequest().getMethod().equalsIgnoreCase(method)) {
+                    logger.debug("Matching request: url={}, method={}", requestUrl, method);
+                    matchingIds.add(request.getRequestId());
                 }
             });

             // Listener to intercept network responses
             logger.info("Adding listener for network responses...");
             devTool.addListener(Network.responseReceived(), response -> {
-                if (response.getResponse().getUrl().contains(urlValue.getValue().toString()) &&
-                        requestIds[0] != null && requestIds[0].toString().equals(response.getRequestId().toString())) {
-                    logger.info("Matching response found for URL: " + response.getResponse().getUrl());
+                if (!captured.get()
+                        && response.getResponse().getUrl().contains(urlPattern)
+                        && matchingIds.remove(response.getRequestId())) {
+                    logger.debug("Matching response for URL: {}", response.getResponse().getUrl());
                     try {
                         // Retrieve the status code from the response
                         int statusCode = response.getResponse().getStatus();
-                        logger.info("Storing status code " + statusCode + " in test case result...");
-                        addStatusCodeData(testCaseResult.getId(), statusCode, logger);
+                        if (captured.compareAndSet(false, true)) {
+                            logger.debug("Storing status code {}", statusCode);
+                            addStatusCodeData(testCaseResult.getId(), statusCode, logger);
+                        }
                         logger.info("Status code successfully stored.");
                     } catch (Exception e) {
                         logger.warn("Error while storing status code: " + ExceptionUtils.getStackTrace(e));
                     }
                 }
             });

Also applies to: 75-91

🤖 Prompt for AI Agents
In
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/StartTracking.java
around lines 58-73 (and similarly for lines 75-91), the code uses a single
mutable RequestId array which races and drops/mismatches captures when multiple
matching requests occur; replace that with a thread-safe collection (e.g.,
ConcurrentLinkedQueue or ConcurrentHashMap key set) to store all matching
RequestIds from the Network.requestWillBeSent listener, and in the corresponding
response listener consume them atomically (remove or poll the first entry) so
each response is paired to exactly one stored request id; ensure all access is
thread-safe and only capture the match once per requestId to avoid duplicate
processing.

Comment on lines +21 to +45
public static void writeToFile(Long runId, String content) throws Exception {
String fileName = getFileName(runId);
File file = new File(fileName);
try {
// Ensure the parent directory exists without overwriting it
File parentDir = file.getParentFile();
if (parentDir != null && !parentDir.exists()) {
if (!parentDir.mkdirs()) {
throw new IOException("Failed to create directory: " + parentDir);
}
}
// Check if file exists, delete if it does
if (file.exists()) {
if (!file.delete()) {
throw new IOException("Failed to delete existing file: " + file);
}
}
// Write the content to the file
FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8);
// Write the JSON content to the file
FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new Exception(e);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Make writes atomic and simplify error handling.

Use a temp file + atomic move to prevent readers from seeing partial content; prefer throwing IOException.

-    public static void writeToFile(Long runId, String content) throws Exception {
-        String fileName = getFileName(runId);
-        File file = new File(fileName);
-        try {
-            // Ensure the parent directory exists without overwriting it
-            File parentDir = file.getParentFile();
-            if (parentDir != null && !parentDir.exists()) {
-                if (!parentDir.mkdirs()) {
-                    throw new IOException("Failed to create directory: " + parentDir);
-                }
-            }
-            // Check if file exists, delete if it does
-            if (file.exists()) {
-                if (!file.delete()) {
-                    throw new IOException("Failed to delete existing file: " + file);
-                }
-            }
-            // Write the content to the file
-            FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8);
-        } catch (IOException e) {
-            throw new Exception(e);
-        }
-    }
+    public static void writeToFile(Long runId, String content) throws IOException {
+        File file = new File(getFileName(runId));
+        File parentDir = file.getParentFile();
+        if (parentDir != null && !parentDir.exists() && !parentDir.mkdirs()) {
+            throw new IOException("Failed to create directory: " + parentDir);
+        }
+        File tmp = File.createTempFile(runId + "-", ".tmp", parentDir);
+        FileUtils.writeStringToFile(tmp, content, StandardCharsets.UTF_8);
+        if (!tmp.renameTo(file)) { // fallback if atomic move unsupported
+            FileUtils.copyFile(tmp, file);
+            if (!tmp.delete()) {
+                // best effort
+            }
+        }
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public static void writeToFile(Long runId, String content) throws Exception {
String fileName = getFileName(runId);
File file = new File(fileName);
try {
// Ensure the parent directory exists without overwriting it
File parentDir = file.getParentFile();
if (parentDir != null && !parentDir.exists()) {
if (!parentDir.mkdirs()) {
throw new IOException("Failed to create directory: " + parentDir);
}
}
// Check if file exists, delete if it does
if (file.exists()) {
if (!file.delete()) {
throw new IOException("Failed to delete existing file: " + file);
}
}
// Write the content to the file
FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8);
// Write the JSON content to the file
FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new Exception(e);
}
}
public static void writeToFile(Long runId, String content) throws IOException {
File file = new File(getFileName(runId));
File parentDir = file.getParentFile();
if (parentDir != null && !parentDir.exists() && !parentDir.mkdirs()) {
throw new IOException("Failed to create directory: " + parentDir);
}
// Write to a temp file first for atomicity
File tmp = File.createTempFile(runId + "-", ".tmp", parentDir);
FileUtils.writeStringToFile(tmp, content, StandardCharsets.UTF_8);
// Atomically replace target; if rename unsupported, fall back to copy
if (!tmp.renameTo(file)) {
FileUtils.copyFile(tmp, file);
if (!tmp.delete()) {
// best effort cleanup
}
}
}
🤖 Prompt for AI Agents
In
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/utilities/FileUtilities.java
around lines 21 to 45, the current method writes directly (twice) to the target
file and wraps IOExceptions in a generic Exception; change it to write to a
temporary file in the same directory, flush and close it, then perform an atomic
move/rename to the final file (using Files.move with ATOMIC_MOVE when supported)
to avoid readers seeing partial content, remove the duplicate write, and let the
method throw IOException directly instead of wrapping it so callers can handle
IO errors precisely.

Comment on lines +39 to +41
FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8);
// Write the JSON content to the file
FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Duplicate writes to the same file — remove redundant write.

Writing twice risks partial/overlapping writes under concurrency.

-            // Write the content to the file
-            FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8);
-            // Write the JSON content to the file
-            FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8);
+            // Write the content to the file
+            FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/utilities/FileUtilities.java
around lines 39 to 41, the code writes the same content to the same file twice
which is redundant and can cause partial/overlapping writes; remove the
duplicate FileUtils.writeStringToFile(...) call so the content is written only
once, keeping the single, correctly parameterized write operation and ensure any
necessary exception handling/logging remains intact.

Comment on lines +19 to +21
String encodedData = Base64.getEncoder().encodeToString(json.getBytes());
FileUtilities.writeToFile(runId, encodedData);
} catch (Exception e) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Specify UTF-8 explicitly when Base64-encoding JSON.

Avoid platform-default charset to ensure consistent serialization.

-            String encodedData = Base64.getEncoder().encodeToString(json.getBytes());
+            String encodedData = Base64.getEncoder().encodeToString(json.getBytes(java.nio.charset.StandardCharsets.UTF_8));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
String encodedData = Base64.getEncoder().encodeToString(json.getBytes());
FileUtilities.writeToFile(runId, encodedData);
} catch (Exception e) {
String encodedData = Base64.getEncoder().encodeToString(
json.getBytes(java.nio.charset.StandardCharsets.UTF_8)
);
FileUtilities.writeToFile(runId, encodedData);
} catch (Exception e) {
🤖 Prompt for AI Agents
In
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/utilities/ResponseDataUtilities.java
around lines 19 to 21, the code uses json.getBytes() which relies on the
platform default charset; change it to json.getBytes(StandardCharsets.UTF_8) and
add the import java.nio.charset.StandardCharsets so Base64 encoding always uses
UTF-8 for consistent serialization; ensure imports compile and run unit tests.

Comment on lines +41 to +43
String json = new String(Base64.getDecoder().decode(encodedData));
try {
JsonObject data = gson.fromJson(json, JsonObject.class);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Specify UTF-8 when decoding Base64 payload to String.

-        String json = new String(Base64.getDecoder().decode(encodedData));
+        String json = new String(Base64.getDecoder().decode(encodedData), java.nio.charset.StandardCharsets.UTF_8);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
String json = new String(Base64.getDecoder().decode(encodedData));
try {
JsonObject data = gson.fromJson(json, JsonObject.class);
String json = new String(Base64.getDecoder().decode(encodedData), java.nio.charset.StandardCharsets.UTF_8);
try {
JsonObject data = gson.fromJson(json, JsonObject.class);
🤖 Prompt for AI Agents
In
get_status_code_from_network_logs/src/main/java/com/testsigma/addons/web/utilities/ResponseDataUtilities.java
around lines 41 to 43, the Base64-decoded bytes are converted to a String
without specifying a charset; change the conversion to explicitly use UTF-8
(e.g., new String(decodedBytes, StandardCharsets.UTF_8)) and add the required
import for StandardCharsets so the JSON is parsed from a well-defined UTF-8
string.

@@ -0,0 +1 @@
testsigma-sdk.api.key=eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIyNDBkMjhiNS0xNmUwLThlNmYtOWQ0ZS05MjYxMGNiZTcyYzciLCJ1bmlxdWVJZCI6IjUzMjciLCJpZGVudGl0eUFjY291bnRVVUlkIjoiMzUifQ.cRlkeixKWH21RyjaJRzI-hZHjnfQPoNkpkNE6o1MmIKwrCjXrZvWPhW7yO62ameRC8D2SOTWzPIjMNTNMGhmyg No newline at end of file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Critical: Secret/API key committed to repo — remove, rotate immediately.

This appears to be a real JWT-like API key. Committing credentials is a severe security risk. Remove the secret from Git history, rotate the key, and load it via environment/CI secrets or vault. Keep only a template file in VCS.

Apply either minimal redaction or env-driven placeholder:

-testsigma-sdk.api.key=eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIyNDBkMjhiNS0xNmUwLThlNmYtOWQ0ZS05MjYxMGNiZTcyYzciLCJ1bmlxdWVJZCI6IjUzMjciLCJpZGVudGl0eUFjY291bnRVVUlkIjoiMzUifQ.cRlkeixKWH21RyjaJRzI-hZHjnfQPoNkpkNE6o1MmIKwrCjXrZvWPhW7yO62ameRC8D2SOTWzPIjMNTNMGhmyg
+testsigma-sdk.api.key=${TESTSIGMA_SDK_API_KEY}

Add to .gitignore (outside this diff):

get_status_code_from_network_logs/src/main/resources/testsigma-sdk.properties

To locate any other leaked secrets:

#!/bin/bash
rg -n --hidden -S -C2 $'testsigma-sdk.api.key\s*='
rg -n --hidden -C2 '(api[_-]?key|secret|token)\s*=' --glob '!**/*.png' --glob '!**/*.jpg'
🤖 Prompt for AI Agents
In get_status_code_from_network_logs/src/main/resources/testsigma-sdk.properties
around line 1 there is a committed real API/JWT secret; remove the secret from
the file and replace it with a non-sensitive placeholder or an env-var reference
(e.g. TESTSIGMA_API_KEY=${TESTSIGMA_API_KEY}) so the repo contains no actual
credentials; add this properties file path to .gitignore (or keep only a
template file like testsigma-sdk.properties.example checked in) and instruct
CI/deploy to read the real key from environment/secret store; rotate/revoke the
exposed key immediately; purge the secret from git history using a
history-rewrite tool (git filter-repo or BFG) and force-push the cleaned branch,
then run the provided repository-wide secret search commands and notify
security/ops of the leak and rotation.

@ManojTestsigma ManojTestsigma merged commit 79a306a into dev Sep 8, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants