Skip to content

SONARJAVA-6330: Implement S8692 - The system clock should not be used in tests#5611

Open
aurelien-coet-sonarsource wants to merge 7 commits into
masterfrom
ac/SONARJAVA-6330
Open

SONARJAVA-6330: Implement S8692 - The system clock should not be used in tests#5611
aurelien-coet-sonarsource wants to merge 7 commits into
masterfrom
ac/SONARJAVA-6330

Conversation

@aurelien-coet-sonarsource
Copy link
Copy Markdown
Contributor

No description provided.

@sonar-review-alpha
Copy link
Copy Markdown
Contributor

sonar-review-alpha Bot commented May 8, 2026

Summary

Implements S8692: a new static analysis rule that detects direct use of the system clock in unit tests. The rule flags calls to .now() methods on java.time types (without parameters or with ZoneId), Clock.system*() methods, and System.currentTimeMillis().

Tests should use fixed or mocked clocks via dependency injection to remain deterministic and reproducible. The PR includes the check implementation, comprehensive unit test samples showing compliant and noncompliant patterns, rule documentation explaining the problem and solutions, and baseline expectations from real-world projects (commons-beanutils, eclipse-jetty, sonar-server).

What reviewers should know

Check implementation: SystemClockCheck.java uses MethodMatchers to detect three groups of invocations: parameterless .now() calls, .now(ZoneId) calls on java.time types; Clock.system*() methods; and System.currentTimeMillis(). Straightforward pattern-based detection with no complex logic.

Test coverage: SystemClockCheckSample.java demonstrates the rule in action—start here to see what triggers and what's compliant (fixed clocks, mocked clocks, nanoTime).

Documentation: S8692.html provides clear rationale (test flakiness/non-determinism) and two solution patterns (fixed clocks, injected mocks). Good reference for reviewers unfamiliar with clock testing patterns.

Ruling baselines: Four JSON files contain expected findings from the autoscan and ruling test suites. These are critical for integration testing—verify they align with actual scan results. Minor note: S3577 false negatives increased by 1, likely a side effect of test file scanning changes.

Profile integration: Added to Sonar_way_profile.json, so it's active in the default quality gate.


  • Generate Walkthrough
  • Generate Diagram

🗣️ Give feedback


@Override
protected void onMethodInvocationFound(MethodInvocationTree mit) {
reportIssue(mit, "Replace this use of the system clock with a fixed clock.");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's keep the message generic, so it also covers reading the clock to measure elapsed time..

sonar-review-alpha[bot]

This comment was marked as resolved.

@sonarqube-next
Copy link
Copy Markdown

sonarqube-next Bot commented May 8, 2026

sonar-review-alpha[bot]

This comment was marked as outdated.

}

@Test
void testSystemClockInstants() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Instant.ofEpochMilli(System.currentTimeMillis()); is compliant. Should this rule catch it too? (There is also System.nanoTime())

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, I think that in the first example, we should probably raise an issue on System.currentTimeMillis() (rather than Instant.ofEpochMilli(), since it doesn't have anything to do with the system clock). System.nanoTime() doesn't read the system clock and is very commonly used to measure elapsed time, so I don't think we should raise on it either.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Even if System.nanoTime doesn't read the wall-clock system time, it still uses the hardware to measure time (which still makes the tests non deterministic), so I think it could be targeted by the rule too

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, however my issue with including System.nanoTime is that it is often one of the recommended ways to measure elapsed time between two points in tests. It is not a problem to read System.nanoTime in a test because it does not depend on the system clock (which could change between runs or even during a run). As specified in the doc: "This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time".

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok, you're right, it seems to be out of scope for this rule

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 19, 2026

Agentic Analysis: Early Results

Agentic Analysis and Context Augmentation are available on your project. Here are some issues that could have been prevented. Follow the links to learn how to put them into action.

15 issue(s) found across 1 file(s):

Rule File Line Message
java:S125 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 34 This block of commented-out lines of code should be removed.
java:S139 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 34 Move this trailing comment on the previous empty line.
java:S125 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 36 This block of commented-out lines of code should be removed.
java:S139 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 36 Move this trailing comment on the previous empty line.
java:S125 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 43 This block of commented-out lines of code should be removed.
java:S139 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 43 Move this trailing comment on the previous empty line.
java:S125 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 45 This block of commented-out lines of code should be removed.
java:S139 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 45 Move this trailing comment on the previous empty line.
java:S125 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 52 This block of commented-out lines of code should be removed.
java:S139 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 52 Move this trailing comment on the previous empty line.
java:S125 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 54 This block of commented-out lines of code should be removed.
java:S139 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 54 Move this trailing comment on the previous empty line.
java:S125 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 60 This block of commented-out lines of code should be removed.
java:S139 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 60 Move this trailing comment on the previous empty line.
java:S139 java-checks-test-sources/default/src/test/java/checks/tests/SystemClockCheckSample.java 62 Move this trailing comment on the previous empty line.

Analyzed by SonarQube Agentic Analysis in 6.1 s

sonar-review-alpha[bot]

This comment was marked as outdated.

sonar-review-alpha[bot]

This comment was marked as resolved.

"datetime",
"tests"
],
"defaultSeverity": "Major",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should probably update the RSPEC because the default severity doesn't match the highest impact severity

sonar-review-alpha[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@sonar-review-alpha sonar-review-alpha Bot left a comment

Choose a reason for hiding this comment

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

The highlighting inconsistency flagged in the previous review round is still open — no other new issues found.

🗣️ Give feedback

@sonarqube-next
Copy link
Copy Markdown

long currentTimeMillis = System.currentTimeMillis(); // Noncompliant {{Do not use the system clock in tests.}}
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
long currentTimeNanos = System.nanoTime(); // Compliant: nanoTime is typically used to measure elapsed time in tests
assertTrue(currentTimeMillis < currentTimeNanos);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Here is an idea for another rule: if you use a suffix such as millis or nanos, don't mix them up :) It may not be straightfoward to implement though.

.build(),
MethodMatchers.create()
.ofTypes("java.lang.System")
.names("currentTimeMillis")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It just occured to me that new java.util.Date() is another way to read the system clock and I think it is used frequently. I know that is class should not be used, and we probably have a rule for that, but this is an orthogonal concern - someone may allow using java.util.Date in their code (compatibility with 3rd party code is a good reason to do so) and still want to have an issue about reading system clock in tests.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right, I'll add calls to the Date constructors to the nodes we should raise the issue on.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I assume you reviewed all these sources.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, these are all occurrences of System.currentTimeMillis in tests !

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