Skip to content

validate MeterValue timestamps against transaction time window and chronological order#1988

Merged
goekay merged 7 commits intosteve-community:masterfrom
rishabhvaish:fix/meter-values-timestamp-and-order-validation
Mar 25, 2026
Merged

validate MeterValue timestamps against transaction time window and chronological order#1988
goekay merged 7 commits intosteve-community:masterfrom
rishabhvaish:fix/meter-values-timestamp-and-order-validation

Conversation

@rishabhvaish
Copy link
Contributor

The existing validateMeterValuesInternal checked that timestamps aren't in the future and don't exceed the stop timestamp, but it didn't verify that they fall within the transaction's time window or arrive in order.

I've added two checks:

  1. Transaction time window — when called from validateStop, the method now receives startTimestamp and rejects any MeterValue whose timestamp is before the transaction started. This catches late-arriving meter data from a previous session or clock-drift replays.
  2. Chronological ordering — timestamps in the MeterValue list must be non-decreasing. Out-of-order entries suggest clock issues or message replays and are now flagged.
    Both checks follow the existing pattern of returning a SteveException without throwing, so the caller decides how to handle it.

Tests cover: before-start rejection, at-start acceptance, out-of-order rejection, in-order acceptance, and equal-timestamp acceptance.

Partial fix for #1962.

@qodo-free-for-open-source-projects

Review Summary by Qodo

Validate MeterValue timestamps against transaction window and order

🐞 Bug fix 🧪 Tests

Grey Divider

Walkthroughs

Description
• Validate MeterValue timestamps fall within transaction time window
• Enforce chronological ordering of MeterValue timestamps
• Add comprehensive test coverage for new validations
• Refactor timestamp extraction to support multiple validation checks
Diagram
flowchart LR
  MV["MeterValue List"]
  Extract["Extract Timestamps"]
  FutureCheck["Check Future Timestamps"]
  WindowCheck["Check Time Window<br/>start ≤ ts ≤ stop"]
  OrderCheck["Check Chronological<br/>Order"]
  Result["Validation Result"]
  
  MV --> Extract
  Extract --> FutureCheck
  FutureCheck --> WindowCheck
  WindowCheck --> OrderCheck
  OrderCheck --> Result
Loading

Grey Divider

File Changes

1. src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_ServiceValidator.java 🐞 Bug fix +25/-8

Add transaction window and chronological order validation

• Added startTimestamp parameter to validateMeterValuesInternal method to validate against
 transaction start time
• Refactored timestamp extraction to collect all timestamps in a list for multiple validation passes
• Added validation to reject MeterValues with timestamps before transaction start time
• Added chronological ordering check to ensure timestamps are non-decreasing
• Removed unused import AbstractInstant and added Comparator import

src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_ServiceValidator.java


2. src/test/java/de/rwth/idsg/steve/service/CentralSystemService16ServiceValidatorTest.java 🧪 Tests +53/-0

Add timestamp validation test coverage

• Added test for MeterValue timestamp before start time rejection
• Added test for MeterValue timestamp at start time acceptance
• Added test for out-of-order timestamps rejection
• Added test for in-order timestamps acceptance
• Added test for equal timestamps acceptance

src/test/java/de/rwth/idsg/steve/service/CentralSystemService16ServiceValidatorTest.java


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link

qodo-free-for-open-source-projects bot commented Mar 19, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. Null MeterValue not handled📘 Rule violation ✓ Correctness
Description
meterValues is streamed and dereferenced via MeterValue::getTimestamp without filtering out
possible null elements, which can cause an NPE instead of a clear validation error. Additionally,
null timestamps are silently dropped (unless all are null), allowing invalid external input to
bypass validation logic.
Code

src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_ServiceValidator.java[R115-118]

+        List<DateTime> timestamps = meterValues.stream()
        .map(MeterValue::getTimestamp)
        .filter(java.util.Objects::nonNull)
-            .max(AbstractInstant::compareTo)
-            .orElse(null);
+            .toList();
Evidence
PR Compliance ID 5 requires externally supplied collections to be sanitized (treat null as empty and
filter null elements) and to fail fast with clear exceptions, rather than risking NPEs or implicitly
ignoring invalid items. The changed code dereferences elements without null-element filtering and
drops null timestamps via filter(Objects::nonNull) instead of rejecting them.

src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_ServiceValidator.java[115-118]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`validateMeterValuesInternal` can throw an NPE because it calls `MeterValue::getTimestamp` on elements of an externally supplied list without filtering out null elements first. It also silently ignores null timestamps (unless *all* timestamps are null), which lets invalid external input bypass validation.
## Issue Context
Compliance requires sanitizing externally supplied collections (treat null as empty, filter null elements) and failing fast with clear/semantically correct validation errors.
## Fix Focus Areas
- src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_ServiceValidator.java[115-123]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

rishabhvaish and others added 3 commits March 19, 2026 01:01
Filter null elements from the meterValues list before calling
MeterValue::getTimestamp to prevent NPE. Add tests for lists
containing null elements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@goekay
Copy link
Member

goekay commented Mar 23, 2026

hey @rishabhvaish, thanks for your contribution.

the code makes, in worst-case scenario, 4 passes over the MeterValues. this can be inefficient with long-running transactions and therefore a long list of MeterValues entries. i think, this number can be reduced to 2 without sacrificing anything. or even 1 (but maybe in this case it will harm the readability and compactness). can you explore an improvement in this area?

Track earliest, latest timestamps and chronological order in a single
loop instead of separate stream operations. Removes the intermediate
list allocation and redundant Comparator import.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@rishabhvaish
Copy link
Contributor Author

@goekay — Good catch. Refactored validateMeterValuesInternal from 4 passes to 1.

Before: stream → list of timestamps, stream → max, stream → min, loop → order check
After: single for loop tracking earliest, latest, and outOfOrder in one pass. Also removes the intermediate List<DateTime> allocation and the unused Comparator import.

All existing tests are unchanged — they exercise the same public API and error messages.

- early exit when not in chronological order. no need to track another variable
- init earliest/latest/previous with sensible values such that null-checks are not needed
@goekay goekay merged commit 08cfad5 into steve-community:master Mar 25, 2026
11 checks passed
@goekay
Copy link
Member

goekay commented Mar 25, 2026

@rishabhvaish i will revert this PR partially, because of #1992

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.

2 participants