aliehsaeedii commented on code in PR #22901:
URL: https://github.com/apache/kafka/pull/22901#discussion_r3712790482


##########
streams/integration-tests/src/test/java/org/apache/kafka/streams/integration/HeadersStoreUpgradeIntegrationTest.java:
##########
@@ -135,6 +137,117 @@ private void buildAndStart(final StoreBuilder<?> 
storeBuilder,
         IntegrationTestUtils.startApplicationAndWaitUntilRunning(kafkaStreams);
     }
 
+    /**
+     * Produces a single record (no explicit timestamp) into the input stream. 
Keys and values are
+     * always {@link String}, matching the {@link StringSerializer} used below.
+     */
+    private void produce(final String key, final String value) {
+        IntegrationTestUtils.produceKeyValuesSynchronously(
+            inputStream,
+            singletonList(KeyValue.pair(key, value)),
+            TestUtils.producerConfig(CLUSTER.bootstrapServers(), 
StringSerializer.class, StringSerializer.class),
+            CLUSTER.time,
+            false);
+    }
+
+    /**
+     * Produces a single record with an explicit timestamp into the input 
stream.
+     */
+    private void produce(final String key, final String value, final long 
timestamp) {
+        IntegrationTestUtils.produceKeyValuesSynchronouslyWithTimestamp(
+            inputStream,
+            singletonList(KeyValue.pair(key, value)),
+            TestUtils.producerConfig(CLUSTER.bootstrapServers(), 
StringSerializer.class, StringSerializer.class),
+            timestamp,
+            false);
+    }
+
+    /**
+     * Produces a single record with an explicit timestamp and headers into 
the input stream.
+     */
+    private void produce(final String key, final String value, final long 
timestamp, final Headers headers) {
+        IntegrationTestUtils.produceKeyValuesSynchronouslyWithTimestamp(
+            inputStream,
+            singletonList(KeyValue.pair(key, value)),
+            TestUtils.producerConfig(CLUSTER.bootstrapServers(), 
StringSerializer.class, StringSerializer.class),
+            headers,
+            timestamp,
+            false);
+    }
+
+    /**
+     * Shared skeleton for the process-and-verify / verify helpers: waits 
until the named store is
+     * queryable and the supplied condition holds. The store lookup is retried 
until the condition
+     * passes or the timeout elapses; transient query {@link Exception}s (e.g. 
store not yet ready)
+     * are swallowed and treated as "not ready". {@link AssertionError} thrown 
by a condition that
+     * uses {@code assertX(...)} is intentionally NOT caught here, so those 
helpers still fail fast.
+     */
+    private <S> void awaitStore(final String storeName,
+                                final QueryableStoreType<S> storeType,
+                                final Predicate<S> condition,
+                                final String message) throws Exception {
+        TestUtils.waitForCondition(() -> {
+            try {
+                return condition.test(IntegrationTestUtils.getStore(storeName, 
kafkaStreams, storeType));
+            } catch (final Exception swallow) {
+                LOG.error("Error while checking store result", swallow);
+                return false;
+            }
+        }, DEFAULT_STORE_TIMEOUT_MS, message);
+    }
+
+    /**
+     * Computes the start of the window that {@code timestamp} falls into for 
the fixed
+     * {@link #WINDOW_SIZE_MS} window size.
+     */
+    private static long windowStart(final long timestamp) {
+        return timestamp - (timestamp % WINDOW_SIZE_MS);
+    }
+
+    /**
+     * Finds the entry stored for {@code key} in the window that {@code 
timestamp} falls into, by
+     * scanning {@link ReadOnlyWindowStore#all()} and matching on key and 
window start. Returns the
+     * matched {@link KeyValue} so an empty result means "no such entry" and 
is not conflated with a
+     * matched entry that happens to have a {@code null} value — callers can 
assert on the value.
+     */
+    private static Optional<KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>>> findWindowedValue(
+        final ReadOnlyWindowStore<String, ValueTimestampHeaders<String>> store,
+        final String key,
+        final long timestamp) {
+        final long start = windowStart(timestamp);
+        try (final KeyValueIterator<Windowed<String>, 
ValueTimestampHeaders<String>> iterator = store.all()) {
+            while (iterator.hasNext()) {
+                final KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>> kv = iterator.next();
+                if (kv.key.key().equals(key) && kv.key.window().start() == 
start) {
+                    return Optional.of(kv);
+                }
+            }
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * Finds the entry stored for {@code key} in the session whose window 
starts at {@code timestamp},
+     * by scanning {@link ReadOnlySessionStore#fetch(Object)}. Sessions in 
this test are always
+     * created as {@code SessionWindow(ts, ts)}, so matching on window start 
is equivalent to matching
+     * both start and end. Returns the matched {@link KeyValue} so an empty 
result means "no such
+     * entry" and is not conflated with a matched entry that happens to have a 
{@code null} value.
+     */
+    private static Optional<KeyValue<Windowed<String>, 
AggregationWithHeaders<String>>> findSessionValue(
+        final ReadOnlySessionStore<String, AggregationWithHeaders<String>> 
store,
+        final String key,
+        final long timestamp) {
+        try (final KeyValueIterator<Windowed<String>, 
AggregationWithHeaders<String>> iterator = store.fetch(key)) {
+            while (iterator.hasNext()) {
+                final KeyValue<Windowed<String>, 
AggregationWithHeaders<String>> kv = iterator.next();
+                if (kv.key.key().equals(key) && kv.key.window().start() == 
timestamp) {

Review Comment:
   The old session verifiers also required `kv.key.window().end() == 
timestamp`. Dropping it means a migration bug that mangles a session's end 
boundary no longer fails the test — please add the end check back.



##########
streams/integration-tests/src/test/java/org/apache/kafka/streams/integration/HeadersStoreUpgradeIntegrationTest.java:
##########
@@ -135,6 +137,117 @@ private void buildAndStart(final StoreBuilder<?> 
storeBuilder,
         IntegrationTestUtils.startApplicationAndWaitUntilRunning(kafkaStreams);
     }
 
+    /**
+     * Produces a single record (no explicit timestamp) into the input stream. 
Keys and values are
+     * always {@link String}, matching the {@link StringSerializer} used below.
+     */
+    private void produce(final String key, final String value) {
+        IntegrationTestUtils.produceKeyValuesSynchronously(
+            inputStream,
+            singletonList(KeyValue.pair(key, value)),
+            TestUtils.producerConfig(CLUSTER.bootstrapServers(), 
StringSerializer.class, StringSerializer.class),
+            CLUSTER.time,
+            false);
+    }
+
+    /**
+     * Produces a single record with an explicit timestamp into the input 
stream.
+     */
+    private void produce(final String key, final String value, final long 
timestamp) {
+        IntegrationTestUtils.produceKeyValuesSynchronouslyWithTimestamp(
+            inputStream,
+            singletonList(KeyValue.pair(key, value)),
+            TestUtils.producerConfig(CLUSTER.bootstrapServers(), 
StringSerializer.class, StringSerializer.class),
+            timestamp,
+            false);
+    }
+
+    /**
+     * Produces a single record with an explicit timestamp and headers into 
the input stream.
+     */
+    private void produce(final String key, final String value, final long 
timestamp, final Headers headers) {
+        IntegrationTestUtils.produceKeyValuesSynchronouslyWithTimestamp(
+            inputStream,
+            singletonList(KeyValue.pair(key, value)),
+            TestUtils.producerConfig(CLUSTER.bootstrapServers(), 
StringSerializer.class, StringSerializer.class),
+            headers,
+            timestamp,
+            false);
+    }
+
+    /**
+     * Shared skeleton for the process-and-verify / verify helpers: waits 
until the named store is
+     * queryable and the supplied condition holds. The store lookup is retried 
until the condition
+     * passes or the timeout elapses; transient query {@link Exception}s (e.g. 
store not yet ready)
+     * are swallowed and treated as "not ready". {@link AssertionError} thrown 
by a condition that
+     * uses {@code assertX(...)} is intentionally NOT caught here, so those 
helpers still fail fast.

Review Comment:
   `waitForCondition` does catch `AssertionError` and retries until the timeout 
(`TestUtils.retryOnExceptionWithTimeout`), so these helpers don't fail fast — 
they retry for 60s and then rethrow the assert. The doc needs fixing.



##########
streams/integration-tests/src/test/java/org/apache/kafka/streams/integration/HeadersStoreUpgradeIntegrationTest.java:
##########
@@ -1586,146 +1359,66 @@ public void 
shouldSuccessfullyDowngradeFromSessionStoreWithHeadersToSessionStore
     private void processSessionKeyValueAndVerify(final String key,
                                                   final String value,
                                                   final long timestamp) throws 
Exception {
-        IntegrationTestUtils.produceKeyValuesSynchronouslyWithTimestamp(
-            inputStream,
-            singletonList(KeyValue.pair(key, value)),
-            TestUtils.producerConfig(CLUSTER.bootstrapServers(),
-                StringSerializer.class,
-                StringSerializer.class),
-            timestamp,
-            false);
-
-        TestUtils.waitForCondition(() -> {
-            try {
-                final ReadOnlySessionStore<String, String> store =
-                    IntegrationTestUtils.getStore(SESSION_STORE_NAME, 
kafkaStreams, QueryableStoreTypes.sessionStore());
-
-                if (store == null) {
-                    return false;
-                }
+        produce(key, value, timestamp);
 
+        awaitStore(SESSION_STORE_NAME, QueryableStoreTypes.<String, 
String>sessionStore(),
+            store -> {
                 try (final KeyValueIterator<Windowed<String>, String> iterator 
= store.fetch(key)) {

Review Comment:
   This hand-rolls the scan that `findSessionValue` already does. Making 
`findSessionValue` generic in the value type would let this reuse it.



##########
streams/integration-tests/src/test/java/org/apache/kafka/streams/integration/HeadersStoreUpgradeIntegrationTest.java:
##########
@@ -814,261 +797,89 @@ public void 
shouldProxyTimestampedWindowStoreToTimestampedWindowStoreWithHeaders
     private void processPlainWindowedKeyValueAndVerify(final String key,
                                                        final String value,
                                                        final long timestamp) 
throws Exception {
-        IntegrationTestUtils.produceKeyValuesSynchronouslyWithTimestamp(
-            inputStream,
-            List.of(KeyValue.pair(key, value)),
-            TestUtils.producerConfig(CLUSTER.bootstrapServers(),
-                StringSerializer.class,
-                StringSerializer.class),
-            timestamp,
-            false);
-
-        TestUtils.waitForCondition(() -> {
-            try {
-                final ReadOnlyWindowStore<String, String> store =
-                    IntegrationTestUtils.getStore(WINDOW_STORE_NAME, 
kafkaStreams, QueryableStoreTypes.windowStore());
-
-                if (store == null) {
-                    return false;
-                }
-
-                final long windowStart = timestamp - (timestamp % 
WINDOW_SIZE_MS);
-                final String result = store.fetch(key, windowStart);
+        produce(key, value, timestamp);
 
+        awaitStore(WINDOW_STORE_NAME, QueryableStoreTypes.<String, 
String>windowStore(),
+            store -> {
+                final String result = store.fetch(key, windowStart(timestamp));
                 return result != null && result.equals(value);
-            } catch (final Exception e) {
-                return false;
-            }
-        }, 60_000L, "Could not verify plain window value in time.");
+            },
+            "Could not verify plain window value in time.");
     }
 
     private void verifyPlainWindowValueWithEmptyHeadersAndTimestamp(final 
String key,
                                                                     final 
String value,
                                                                     final long 
windowTimestamp,
                                                                     final long 
expectedTimestamp) throws Exception {
-        TestUtils.waitForCondition(() -> {
-            try {
-                final ReadOnlyWindowStore<String, 
ValueTimestampHeaders<String>> store =
-                    IntegrationTestUtils.getStore(WINDOW_STORE_NAME, 
kafkaStreams, QueryableStoreTypes.timestampedWindowStoreWithHeaders());
-
-                if (store == null) {
-                    return false;
-                }
-
-                final long windowStart = windowTimestamp - (windowTimestamp % 
WINDOW_SIZE_MS);
-
-                final List<KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>>> results = new LinkedList<>();
-                try (final KeyValueIterator<Windowed<String>, 
ValueTimestampHeaders<String>> iterator = store.all()) {
-                    while (iterator.hasNext()) {
-                        final KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>> kv = iterator.next();
-                        if (kv.key.key().equals(key) && 
kv.key.window().start() == windowStart) {
-                            results.add(kv);
-                        }
-                    }
-                }
-
-                if (results.isEmpty()) {
+        awaitStore(WINDOW_STORE_NAME, QueryableStoreTypes.<String, 
String>timestampedWindowStoreWithHeaders(),
+            store -> {
+                final Optional<KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>>> result =
+                    findWindowedValue(store, key, windowTimestamp);
+                if (result.isEmpty()) {
                     return false;
                 }
 
-                final ValueTimestampHeaders<String> result = 
results.get(0).value;
-                assertNotNull(result, "Result should not be null");
-                assertEquals(value, result.value(), "Value should match");
-                assertEquals(expectedTimestamp, result.timestamp(), "Timestamp 
should be " + expectedTimestamp + " for plain store migration");
+                final ValueTimestampHeaders<String> actual = 
result.get().value;
+                assertNotNull(actual, "Stored value should not be null");
+                assertEquals(value, actual.value(), "Value should match");
+                assertEquals(expectedTimestamp, actual.timestamp(), "Timestamp 
should be " + expectedTimestamp + " for plain store migration");

Review Comment:
   This says "for plain store migration", but the timestamped-store migration 
and proxy tests now call this method too. Same for the `Plain` in the method 
name — worth dropping both.



##########
streams/integration-tests/src/test/java/org/apache/kafka/streams/integration/HeadersStoreUpgradeIntegrationTest.java:
##########
@@ -135,6 +137,117 @@ private void buildAndStart(final StoreBuilder<?> 
storeBuilder,
         IntegrationTestUtils.startApplicationAndWaitUntilRunning(kafkaStreams);
     }
 
+    /**
+     * Produces a single record (no explicit timestamp) into the input stream. 
Keys and values are
+     * always {@link String}, matching the {@link StringSerializer} used below.
+     */
+    private void produce(final String key, final String value) {
+        IntegrationTestUtils.produceKeyValuesSynchronously(
+            inputStream,
+            singletonList(KeyValue.pair(key, value)),
+            TestUtils.producerConfig(CLUSTER.bootstrapServers(), 
StringSerializer.class, StringSerializer.class),
+            CLUSTER.time,
+            false);
+    }
+
+    /**
+     * Produces a single record with an explicit timestamp into the input 
stream.
+     */
+    private void produce(final String key, final String value, final long 
timestamp) {
+        IntegrationTestUtils.produceKeyValuesSynchronouslyWithTimestamp(
+            inputStream,
+            singletonList(KeyValue.pair(key, value)),
+            TestUtils.producerConfig(CLUSTER.bootstrapServers(), 
StringSerializer.class, StringSerializer.class),
+            timestamp,
+            false);
+    }
+
+    /**
+     * Produces a single record with an explicit timestamp and headers into 
the input stream.
+     */
+    private void produce(final String key, final String value, final long 
timestamp, final Headers headers) {
+        IntegrationTestUtils.produceKeyValuesSynchronouslyWithTimestamp(
+            inputStream,
+            singletonList(KeyValue.pair(key, value)),
+            TestUtils.producerConfig(CLUSTER.bootstrapServers(), 
StringSerializer.class, StringSerializer.class),
+            headers,
+            timestamp,
+            false);
+    }
+
+    /**
+     * Shared skeleton for the process-and-verify / verify helpers: waits 
until the named store is
+     * queryable and the supplied condition holds. The store lookup is retried 
until the condition
+     * passes or the timeout elapses; transient query {@link Exception}s (e.g. 
store not yet ready)
+     * are swallowed and treated as "not ready". {@link AssertionError} thrown 
by a condition that
+     * uses {@code assertX(...)} is intentionally NOT caught here, so those 
helpers still fail fast.
+     */
+    private <S> void awaitStore(final String storeName,
+                                final QueryableStoreType<S> storeType,
+                                final Predicate<S> condition,
+                                final String message) throws Exception {
+        TestUtils.waitForCondition(() -> {
+            try {
+                return condition.test(IntegrationTestUtils.getStore(storeName, 
kafkaStreams, storeType));
+            } catch (final Exception swallow) {
+                LOG.error("Error while checking store result", swallow);

Review Comment:
   Add `storeName` to this log line — now that every helper shares it, the log 
no longer says which check failed.



##########
streams/integration-tests/src/test/java/org/apache/kafka/streams/integration/HeadersStoreUpgradeIntegrationTest.java:
##########
@@ -814,261 +797,89 @@ public void 
shouldProxyTimestampedWindowStoreToTimestampedWindowStoreWithHeaders
     private void processPlainWindowedKeyValueAndVerify(final String key,
                                                        final String value,
                                                        final long timestamp) 
throws Exception {
-        IntegrationTestUtils.produceKeyValuesSynchronouslyWithTimestamp(
-            inputStream,
-            List.of(KeyValue.pair(key, value)),
-            TestUtils.producerConfig(CLUSTER.bootstrapServers(),
-                StringSerializer.class,
-                StringSerializer.class),
-            timestamp,
-            false);
-
-        TestUtils.waitForCondition(() -> {
-            try {
-                final ReadOnlyWindowStore<String, String> store =
-                    IntegrationTestUtils.getStore(WINDOW_STORE_NAME, 
kafkaStreams, QueryableStoreTypes.windowStore());
-
-                if (store == null) {
-                    return false;
-                }
-
-                final long windowStart = timestamp - (timestamp % 
WINDOW_SIZE_MS);
-                final String result = store.fetch(key, windowStart);
+        produce(key, value, timestamp);
 
+        awaitStore(WINDOW_STORE_NAME, QueryableStoreTypes.<String, 
String>windowStore(),
+            store -> {
+                final String result = store.fetch(key, windowStart(timestamp));
                 return result != null && result.equals(value);
-            } catch (final Exception e) {
-                return false;
-            }
-        }, 60_000L, "Could not verify plain window value in time.");
+            },
+            "Could not verify plain window value in time.");
     }
 
     private void verifyPlainWindowValueWithEmptyHeadersAndTimestamp(final 
String key,
                                                                     final 
String value,
                                                                     final long 
windowTimestamp,
                                                                     final long 
expectedTimestamp) throws Exception {
-        TestUtils.waitForCondition(() -> {
-            try {
-                final ReadOnlyWindowStore<String, 
ValueTimestampHeaders<String>> store =
-                    IntegrationTestUtils.getStore(WINDOW_STORE_NAME, 
kafkaStreams, QueryableStoreTypes.timestampedWindowStoreWithHeaders());
-
-                if (store == null) {
-                    return false;
-                }
-
-                final long windowStart = windowTimestamp - (windowTimestamp % 
WINDOW_SIZE_MS);
-
-                final List<KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>>> results = new LinkedList<>();
-                try (final KeyValueIterator<Windowed<String>, 
ValueTimestampHeaders<String>> iterator = store.all()) {
-                    while (iterator.hasNext()) {
-                        final KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>> kv = iterator.next();
-                        if (kv.key.key().equals(key) && 
kv.key.window().start() == windowStart) {
-                            results.add(kv);
-                        }
-                    }
-                }
-
-                if (results.isEmpty()) {
+        awaitStore(WINDOW_STORE_NAME, QueryableStoreTypes.<String, 
String>timestampedWindowStoreWithHeaders(),
+            store -> {
+                final Optional<KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>>> result =
+                    findWindowedValue(store, key, windowTimestamp);
+                if (result.isEmpty()) {
                     return false;
                 }
 
-                final ValueTimestampHeaders<String> result = 
results.get(0).value;
-                assertNotNull(result, "Result should not be null");
-                assertEquals(value, result.value(), "Value should match");
-                assertEquals(expectedTimestamp, result.timestamp(), "Timestamp 
should be " + expectedTimestamp + " for plain store migration");
+                final ValueTimestampHeaders<String> actual = 
result.get().value;
+                assertNotNull(actual, "Stored value should not be null");
+                assertEquals(value, actual.value(), "Value should match");
+                assertEquals(expectedTimestamp, actual.timestamp(), "Timestamp 
should be " + expectedTimestamp + " for plain store migration");
 
                 // Verify headers exist but are empty (migrated from plain 
store without headers or timestamps)
-                assertNotNull(result.headers(), "Headers should not be null 
for migrated data");
-                assertEquals(0, result.headers().toArray().length, "Headers 
should be empty for migrated data");
+                assertNotNull(actual.headers(), "Headers should not be null 
for migrated data");
+                assertEquals(0, actual.headers().toArray().length, "Headers 
should be empty for migrated data");
 
                 return true;
-            } catch (final Exception e) {
-                LOG.error("Error while verifying plain window value with empty 
headers and timestamp", e);
-                return false;
-            }
-        }, 60_000L, "Could not verify plain window value with empty headers 
and timestamp in time.");
-    }
-
-    private void processPlainWindowedKeyValueWithHeadersAndVerify(final String 
key,
-                                                                  final String 
value,
-                                                                  final long 
timestamp,
-                                                                  final 
Headers headers,
-                                                                  final 
Headers expectedHeaders) throws Exception {
-        IntegrationTestUtils.produceKeyValuesSynchronouslyWithTimestamp(
-            inputStream,
-            List.of(KeyValue.pair(key, value)),
-            TestUtils.producerConfig(CLUSTER.bootstrapServers(),
-                StringSerializer.class,
-                StringSerializer.class),
-            headers,
-            timestamp,
-            false);
-
-        TestUtils.waitForCondition(() -> {
-            try {
-                final ReadOnlyWindowStore<String, 
ValueTimestampHeaders<String>> store =
-                    IntegrationTestUtils.getStore(WINDOW_STORE_NAME, 
kafkaStreams, QueryableStoreTypes.timestampedWindowStoreWithHeaders());
-
-                if (store == null) {
-                    return false;
-                }
-
-                final long windowStart = timestamp - (timestamp % 
WINDOW_SIZE_MS);
-
-                final List<KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>>> results = new LinkedList<>();
-                try (final KeyValueIterator<Windowed<String>, 
ValueTimestampHeaders<String>> iterator = store.all()) {
-                    while (iterator.hasNext()) {
-                        final KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>> kv = iterator.next();
-                        if (kv.key.key().equals(key) && 
kv.key.window().start() == windowStart) {
-                            results.add(kv);
-                        }
-                    }
-                }
-
-                if (results.isEmpty()) {
-                    return false;
-                }
-
-                final ValueTimestampHeaders<String> result = 
results.get(0).value;
-                // For plain window stores, timestamp is always -1 since it's 
not preserved
-                return result != null
-                    && result.value().equals(value)
-                    && result.timestamp() == -1L
-                    && result.headers().equals(expectedHeaders);
-            } catch (final Exception e) {
-                e.printStackTrace();
-                return false;
-            }
-        }, 60_000L, "Could not verify plain windowed value with headers in 
time.");
+            },
+            "Could not verify plain window value with empty headers and 
timestamp in time.");
     }
 
     private void processWindowedKeyValueAndVerifyTimestamped(final String key,
                                                              final String 
value,
                                                              final long 
timestamp) throws Exception {
-        IntegrationTestUtils.produceKeyValuesSynchronouslyWithTimestamp(
-            inputStream,
-            singletonList(KeyValue.pair(key, value)),
-            TestUtils.producerConfig(CLUSTER.bootstrapServers(),
-                StringSerializer.class,
-                StringSerializer.class),
-            timestamp,
-            false);
-
-        TestUtils.waitForCondition(() -> {
-            try {
-                final ReadOnlyWindowStore<String, ValueAndTimestamp<String>> 
store =
-                    IntegrationTestUtils.getStore(WINDOW_STORE_NAME, 
kafkaStreams, QueryableStoreTypes.timestampedWindowStore());
-
-                if (store == null) {
-                    return false;
-                }
-
-                final long windowStart = timestamp - (timestamp % 
WINDOW_SIZE_MS);
-                final ValueAndTimestamp<String> result = store.fetch(key, 
windowStart);
+        produce(key, value, timestamp);
 
+        awaitStore(WINDOW_STORE_NAME, QueryableStoreTypes.<String, 
String>timestampedWindowStore(),
+            store -> {
+                final ValueAndTimestamp<String> result = store.fetch(key, 
windowStart(timestamp));
                 return result != null
                     && result.value().equals(value)
                     && result.timestamp() == timestamp;
-            } catch (final Exception e) {
-                return false;
-            }
-        }, 60_000L, "Could not verify timestamped value in time.");
+            },
+            "Could not verify timestamped value in time.");
     }
 
     private void processWindowedKeyValueWithHeadersAndVerify(final String key,
                                                              final String 
value,
                                                              final long 
timestamp,
                                                              final Headers 
headers,
                                                              final Headers 
expectedHeaders) throws Exception {
-        IntegrationTestUtils.produceKeyValuesSynchronouslyWithTimestamp(
-            inputStream,
-            singletonList(KeyValue.pair(key, value)),
-            TestUtils.producerConfig(CLUSTER.bootstrapServers(),
-                StringSerializer.class,
-                StringSerializer.class),
-            headers,
-            timestamp,
-            false);
-
-        TestUtils.waitForCondition(() -> {
-            try {
-                final ReadOnlyWindowStore<String, 
ValueTimestampHeaders<String>> store =
-                    IntegrationTestUtils.getStore(WINDOW_STORE_NAME, 
kafkaStreams, QueryableStoreTypes.timestampedWindowStoreWithHeaders());
-
-                if (store == null) {
-                    return false;
-                }
-
-                final long windowStart = timestamp - (timestamp % 
WINDOW_SIZE_MS);
-
-                final List<KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>>> results = new LinkedList<>();
-                try (final KeyValueIterator<Windowed<String>, 
ValueTimestampHeaders<String>> iterator = store.all()) {
-                    while (iterator.hasNext()) {
-                        final KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>> kv = iterator.next();
-                        if (kv.key.key().equals(key) && 
kv.key.window().start() == windowStart) {
-                            results.add(kv);
-                        }
-                    }
-                }
-
-                if (results.isEmpty()) {
-                    return false;
-                }
-
-                final ValueTimestampHeaders<String> result = 
results.get(0).value;
-                return result != null
-                    && result.value().equals(value)
-                    && result.timestamp() == timestamp
-                    && result.headers().equals(expectedHeaders);
-            } catch (final Exception e) {
-                LOG.error("Error while verifying windowed value with headers", 
e);
-                return false;
-            }
-        }, 60_000L, "Could not verify windowed value with headers in time.");
+        processWindowedKeyValueWithHeadersAndVerify(key, value, timestamp, 
timestamp, headers, expectedHeaders);
     }
 
-    private void verifyWindowValueWithEmptyHeaders(final String key,
-                                                   final String value,
-                                                   final long timestamp) 
throws Exception {
-        TestUtils.waitForCondition(() -> {
-            try {
-                final ReadOnlyWindowStore<String, 
ValueTimestampHeaders<String>> store =
-                    IntegrationTestUtils.getStore(WINDOW_STORE_NAME, 
kafkaStreams, QueryableStoreTypes.timestampedWindowStoreWithHeaders());
-
-                if (store == null) {
-                    return false;
-                }
-
-                final long windowStart = timestamp - (timestamp % 
WINDOW_SIZE_MS);
-
-                final List<KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>>> results = new LinkedList<>();
-                try (final KeyValueIterator<Windowed<String>, 
ValueTimestampHeaders<String>> iterator = store.all()) {
-                    while (iterator.hasNext()) {
-                        final KeyValue<Windowed<String>, 
ValueTimestampHeaders<String>> kv = iterator.next();
-                        if (kv.key.key().equals(key) && 
kv.key.window().start() == windowStart) {
-                            results.add(kv);
-                        }
-                    }
-                }
-
-                if (results.isEmpty()) {
-                    return false;
-                }
-
-                final ValueTimestampHeaders<String> result = 
results.get(0).value;
-                assertNotNull(result, "Result should not be null");
-                assertEquals(value, result.value(), "Value should match");
-                assertEquals(timestamp, result.timestamp(), "Timestamp should 
match");
-
-                // Verify headers exist but are empty (migrated from 
timestamped store without headers)
-                assertNotNull(result.headers(), "Headers should not be null 
for migrated data");
-                assertEquals(0, result.headers().toArray().length, "Headers 
should be empty for migrated data");
-
-                return true;
-            } catch (final Exception e) {
-                LOG.error("Error while verifying legacy value with empty 
headers", e);
-                return false;
-            }
-        }, 60_000L, "Could not verify legacy value with empty headers in 
time.");
+    /**
+     * Produces a windowed record with headers and verifies the stored 
value/headers, expecting
+     * {@code expectedTimestamp} in the store. For a plain window store (no 
timestamp preserved)
+     * pass {@code expectedTimestamp == -1L}; otherwise pass the produced 
{@code timestamp}.
+     */
+    private void processWindowedKeyValueWithHeadersAndVerify(final String key,
+                                                             final String 
value,
+                                                             final long 
timestamp,
+                                                             final long 
expectedTimestamp,
+                                                             final Headers 
headers,
+                                                             final Headers 
expectedHeaders) throws Exception {
+        produce(key, value, timestamp, headers);
+
+        awaitStore(WINDOW_STORE_NAME, QueryableStoreTypes.<String, 
String>timestampedWindowStoreWithHeaders(),

Review Comment:
   `verifyPlainWindowValueWithEmptyHeadersAndTimestamp` checks the same fields 
with `expectedHeaders` fixed to empty. Giving that verifier an 
`expectedHeaders` parameter and making this `produce(...)` plus a call to it 
would keep the find-and-check logic in one place. Same duplication between 
`verifyLegacyValuesWithEmptyHeaders` and the 6-arg 
`processKeyValueWithTimestampAndHeadersAndVerify`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to