muttakin2301/ccr_train_1000 huggingface dataset:
Code review comment: Oh my bad, `Mockito.mock()` is based off a `Class`, not actual instance... In that case, it might be "cleaner" to unwrap the proxies before creating the spy, WDYT?

Code before review:
public void beforeAll(Object testInstance) {
Class<?> current = testInstance.getClass();
while (current.getSuperclass() != null) {
for (Field field : current.getDeclaredFields()) {
InjectSpy injectSpyAnnotation = field.getAnnotation(InjectSpy.class);
if (injectSpyAnnotation != null) {
Object beanInstance = getBeanInstance(testInstance, field);
Object spy = createSpyAndSetTestField(testInstance, field, beanInstance);
MockitoMocksTracker.track(testInstance, spy, beanInstance);
}
}
current = current.getSuperclass();
}
}

Line under review: while (current.getSuperclass() != null) {

Code after addressing the review:
public void beforeAll(Object testInstance) {
Class<?> current = testInstance.getClass();
while (current.getSuperclass() != null) {
for (Field field : current.getDeclaredFields()) {
InjectSpy injectSpyAnnotation = field.getAnnotation(InjectSpy.class);
if (injectSpyAnnotation != null) {
Object beanInstance = CreateMockitoMocksCallback.getBeanInstance(testInstance, field, InjectSpy.class);
Object spy = createSpyAndSetTestField(testInstance, field, beanInstance);
MockitoMocksTracker.track(testInstance, spy, beanInstance);
}
}
current = current.getSuperclass();
}
}
Code review comment: Hm, I can try to improve the readability a little bit..

Code before review:
public CompletionStage<ResultNode> resolve(SectionResolutionContext context) {
return context.resolutionContext().evaluate(iterable).thenCompose(it -> {
List<CompletionStage<ResultNode>> results = new ArrayList<>();
Iterator<?> iterator;
if (it instanceof Iterable) {
iterator = ((Iterable<?>) it).iterator();
} else if (it instanceof Iterator) {
iterator = (Iterator<?>) it;
} else if (it instanceof Map) {
iterator = ((Map<?, ?>) it).entrySet().iterator();
} else if (it instanceof Stream) {
iterator = ((Stream<?>) it).sequential().iterator();
} else if (it instanceof Integer) {
iterator = IntStream.rangeClosed(1, (Integer) it).iterator();
} else if (it != null && it.getClass().isArray()) {
iterator = Arrays.stream((Object[]) it).iterator();
} else {
throw new IllegalStateException(
String.format("Cannot iterate over [%s] resolved for [%s] in template %s on line %s", it,
iterable.toOriginalString(), iterable.origin.getTemplateId(), iterable.origin.getLine()));
}
int idx = 0;
while (iterator.hasNext()) {
results.add(nextElement(iterator.next(), idx++, iterator.hasNext(), context));
}
if (results.isEmpty()) {
return CompletableFuture.completedFuture(ResultNode.NOOP);
}
CompletableFuture<ResultNode> result = new CompletableFuture<>();
CompletableFuture<ResultNode>[] all = new CompletableFuture[results.size()];
idx = 0;
for (CompletionStage<ResultNode> r : results) {
all[idx++] = r.toCompletableFuture();
}
CompletableFuture
.allOf(all)
.whenComplete((v, t) -> {
if (t != null) {
result.completeExceptionally(t);
} else {
result.complete(new MultiResultNode(all));
}
});
return result;
});
}

Line under review: } else if (it != null && it.getClass().isArray()) {

Code after addressing the review:
public CompletionStage<ResultNode> resolve(SectionResolutionContext context) {
return context.resolutionContext().evaluate(iterable).thenCompose(it -> {
if (it == null) {
throw new TemplateException(String.format(
"Loop section error in template %s on line %s: [%s] resolved to [null] which is not iterable",
iterable.origin.getTemplateId(), iterable.origin.getLine(), iterable.toOriginalString()));
}
List<CompletionStage<ResultNode>> results = new ArrayList<>();
Iterator<?> iterator = extractIterator(it);
int idx = 0;
while (iterator.hasNext()) {
results.add(nextElement(iterator.next(), idx++, iterator.hasNext(), context));
}
if (results.isEmpty()) {
return CompletableFuture.completedFuture(ResultNode.NOOP);
}
CompletableFuture<ResultNode> result = new CompletableFuture<>();
CompletableFuture<ResultNode>[] all = new CompletableFuture[results.size()];
idx = 0;
for (CompletionStage<ResultNode> r : results) {
all[idx++] = r.toCompletableFuture();
}
CompletableFuture
.allOf(all)
.whenComplete((v, t) -> {
if (t != null) {
result.completeExceptionally(t);
} else {
result.complete(new MultiResultNode(all));
}
});
return result;
});
}
Code review comment: We skipped paging and polling operations when adding sync stack support for Key Vault, as shown [here](https://github.com/Azure/azure-sdk-for-java/blob/a90cc9a4d40f9492e76d5a4589b321e94c0aa5de/sdk/keyvault/azure-security-keyvault-secrets/src/test/java/com/azure/security/keyvault/secrets/SecretClientTest.java#L61). Has that been taken care of @g2vinay, @samvaity?

Code before review:
protected HttpClient buildAssertingClient(HttpClient httpClient) {
return new AssertingHttpClientBuilder(httpClient)
.skipRequest((ignored1, ignored2) -> false)
.assertAsync()
.build();
}

Line under review: .build();

Code after addressing the review:
protected HttpClient buildAssertingClient(HttpClient httpClient) {
return new AssertingHttpClientBuilder(httpClient)
.skipRequest((ignored1, ignored2) -> false)
.assertAsync()
.build();
}
Code review comment: It's same, the queue `poll` may return null ```     /**      * Retrieves and removes the head of this queue, waiting up to the      * specified wait time if necessary for an element to become available.      *      * @param timeout how long to wait before giving up, in units of      *        {@code unit}      * @param unit a {@code TimeUnit} determining how to interpret the      *        {@code timeout} parameter      * @return the head of this queue, or {@code null} if the      *         specified waiting time elapses before an element is available      * @throws InterruptedException if interrupted while waiting      */     E poll(long timeout, TimeUnit unit)         throws InterruptedException;  ```

Code before review:
protected void runBlocking() {
client.connect();
client.subscribe(binlogPosition.getFilename(), binlogPosition.getPosition());
while (isRunning()) {
List<AbstractBinlogEvent> events = client.poll();
if (null == events) {
continue;
}
handleEvent(events);
}
channel.pushRecords(Collections.singletonList(new FinishedRecord(new FinishedPosition())));
}

Line under review: }

Code after addressing the review:
protected void runBlocking() {
client.connect();
client.subscribe(binlogPosition.getFilename(), binlogPosition.getPosition());
while (isRunning()) {
List<AbstractBinlogEvent> events = client.poll();
if (events.isEmpty()) {
continue;
}
handleEvents(events);
}
channel.pushRecords(Collections.singletonList(new FinishedRecord(new FinishedPosition())));
}
Code review comment: Yes, and using .single() would force it to throw if there was more than one element in the flux. why not use `.next()` rather than `.last()` then? If the stream had 10000 elements, this would not complete until 9999 elements had been emitted.

Code before review:
public Mono<Instant> renewMessageLock(UUID lockToken) {
return renewMessageLock(new UUID[]{lockToken})
.last()
.publishOn(scheduler);
}

Line under review: .last()

Code after addressing the review:
public Mono<Instant> renewMessageLock(UUID lockToken) {
return renewMessageLock(new UUID[]{lockToken})
.next()
.publishOn(scheduler);
}
Code review comment: The params is a lambda expression

Code before review:
public static Schema toIcebergApiSchema(List<Column> columns) {
List<Types.NestedField> icebergColumns = new ArrayList<>();
for (Column column : columns) {
int index = icebergColumns.size();
org.apache.iceberg.types.Type type = toIcebergColumnType(column.getType());
Types.NestedField field = Types.NestedField.of(
index, column.isAllowNull(), column.getName(), type, column.getComment());
icebergColumns.add(field);
}
org.apache.iceberg.types.Type icebergSchema = Types.StructType.of(icebergColumns);
AtomicInteger nextFieldId = new AtomicInteger(1);
icebergSchema = TypeUtil.assignFreshIds(icebergSchema, nextFieldId::getAndIncrement);
return new Schema(icebergSchema.asStructType().fields());
}

Line under review: AtomicInteger nextFieldId = new AtomicInteger(1);

Code after addressing the review:
public static Schema toIcebergApiSchema(List<Column> columns) {
List<Types.NestedField> icebergColumns = new ArrayList<>();
for (Column column : columns) {
int index = icebergColumns.size();
org.apache.iceberg.types.Type type = toIcebergColumnType(column.getType());
Types.NestedField field = Types.NestedField.of(
index, column.isAllowNull(), column.getName(), type, column.getComment());
icebergColumns.add(field);
}
org.apache.iceberg.types.Type icebergSchema = Types.StructType.of(icebergColumns);
AtomicInteger nextFieldId = new AtomicInteger(1);
icebergSchema = TypeUtil.assignFreshIds(icebergSchema, nextFieldId::getAndIncrement);
return new Schema(icebergSchema.asStructType().fields());
}
Code review comment: Shall we take 4 to a meaningful constant??

Code before review:
public void process(ServiceNode serviceNode, List<AnnotationAttachmentNode> annotations) {
List<BLangFunction> resources = (List<BLangFunction>) serviceNode.getResources();
resources.forEach(res -> validate(serviceNode.getName().getValue(), res, this.diagnosticLog));
if (resourceCount != 4) {
String errorMsg = "Service needs to have all 4 resources "
+ "[(%s (Listener) or %s (CallBackService)), %s, %s, %s].";
String msg = String.format(errorMsg, RESOURCE_ON_ACCEPT, RESOURCE_ON_CONNECT, RESOURCE_ON_READ_READY,
RESOURCE_ON_CLOSE, RESOURCE_ON_ERROR);
diagnosticLog.logDiagnostic(ERROR, serviceNode.getPosition(), msg);
}
}

Line under review: if (resourceCount != 4) {

Code after addressing the review:
public void process(ServiceNode serviceNode, List<AnnotationAttachmentNode> annotations) {
int resourceCount = 0;
int mandatoryResourceCount = 4;
List<BLangFunction> resources = (List<BLangFunction>) serviceNode.getResources();
for (BLangFunction resource : resources) {
resourceCount += validate(serviceNode.getName().getValue(), resource, this.diagnosticLog);
}
if (resourceCount != mandatoryResourceCount) {
String errorMsg = "Service needs to have all 4 resources "
+ "[(%s (Listener) or %s (CallBackService)), %s, %s, %s].";
String msg = String.format(errorMsg, RESOURCE_ON_ACCEPT, RESOURCE_ON_CONNECT, RESOURCE_ON_READ_READY,
RESOURCE_ON_CLOSE, RESOURCE_ON_ERROR);
diagnosticLog.logDiagnostic(ERROR, serviceNode.getPosition(), msg);
}
}
Code review comment: based on above suggestion, I am making it not nullable.

Code before review:
public RequestIdPolicy(Supplier<HttpHeaders> requestIdSupplier) {
this.requestIdSupplier = requestIdSupplier;
}

Line under review: this.requestIdSupplier = requestIdSupplier;

Code after addressing the review:
public RequestIdPolicy(Supplier<HttpHeaders> requestIdSupplier) {
this.requestIdSupplier = Objects.requireNonNull(requestIdSupplier, "'requestIdSupplier' must not be null");
}
Code review comment: There's a CheckUtil method you used in the same file that gives you the modifier. `final AccessModifier accessModifier = CheckUtil.getAccessModifierFromModifiersToken(modifiersToken);`

Code before review:
public void visitToken(DetailAST token) {
switch (token.getType()) {
case TokenTypes.IMPORT:
final String importClassPath = FullIdent.createFullIdentBelow(token).getText();
final String className = importClassPath.substring(importClassPath.lastIndexOf(".") + 1);
simpleClassNameToQualifiedNameMap.put(className, importClassPath);
break;
case TokenTypes.CLASS_DEF:
final DetailAST modifiersToken = token.findFirstToken(TokenTypes.MODIFIERS);
isPublicClass = modifiersToken.branchContains(TokenTypes.LITERAL_PUBLIC);
break;
case TokenTypes.METHOD_DEF:
if (!isPublicClass) {
return;
}
checkNoExternalDependencyExposed(token);
break;
default:
break;
}
}

Line under review: final DetailAST modifiersToken = token.findFirstToken(TokenTypes.MODIFIERS);

Code after addressing the review:
public void visitToken(DetailAST token) {
switch (token.getType()) {
case TokenTypes.IMPORT:
final String importClassPath = FullIdent.createFullIdentBelow(token).getText();
final String className = importClassPath.substring(importClassPath.lastIndexOf(".") + 1);
simpleClassNameToQualifiedNameMap.put(className, importClassPath);
break;
case TokenTypes.CLASS_DEF:
final AccessModifier accessModifier = CheckUtil.getAccessModifierFromModifiersToken(
token.findFirstToken(TokenTypes.MODIFIERS));
isPublicClass = accessModifier.equals(AccessModifier.PUBLIC);
break;
case TokenTypes.METHOD_DEF:
if (!isPublicClass) {
return;
}
checkNoExternalDependencyExposed(token);
break;
default:
break;
}
}
Code review comment: > Should be covered with one test case.  sure, will add one later.

Code before review:
public static Properties flatten(Properties config) {
final Properties flattenProperties = new Properties();
Collections.list(config.propertyNames()).stream().forEach(
name -> {
Preconditions.checkArgument(name instanceof String);
flattenProperties.setProperty((String) name, config.getProperty((String) name));
}
);
return flattenProperties;
}

Line under review: final Properties flattenProperties = new Properties();

Code after addressing the review:
public static Properties flatten(Properties config) {
final Properties flattenProperties = new Properties();
Collections.list(config.propertyNames()).stream().forEach(
name -> {
Preconditions.checkArgument(name instanceof String);
flattenProperties.setProperty((String) name, config.getProperty((String) name));
}
);
return flattenProperties;
}
Code review comment: No, this would not happen. If the finally block throws an exception it would either throw this exception if the try block has not thrown an exception or add the finally exception as a suppressed exception to the try exception.

Code before review:
protected void runTest(RunnableWithException test) {
Throwable testFailure = null;
try {
test.run();
} catch (Throwable t) {
testFailure = t;
}
try {
Deadline deadline = Deadline.now().plus(Duration.ofSeconds(10));
boolean isAnyJobRunning = yarnClient.getApplications().stream()
.anyMatch(YarnTestBase::isApplicationRunning);
while (deadline.hasTimeLeft() && isAnyJobRunning) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Assert.fail("Should not happen");
}
isAnyJobRunning = yarnClient.getApplications().stream()
.anyMatch(YarnTestBase::isApplicationRunning);
}
if (isAnyJobRunning) {
final List<String> runningApps = yarnClient.getApplications().stream()
.filter(YarnTestBase::isApplicationRunning)
.map(app -> "App " + app.getApplicationId() + " is in state " + app.getYarnApplicationState() + '.')
.collect(Collectors.toList());
if (!runningApps.isEmpty()) {
Assert.fail("There is at least one application on the cluster that is not finished." + runningApps);
}
}
} catch (Throwable t) {
throw new AssertionError(ExceptionUtils.firstOrSuppressed(t, testFailure));
}
}

Line under review: testFailure = t;

Code after addressing the review:
protected void runTest(RunnableWithException test) throws Exception {
try (final CleanupYarnApplication ignored = new CleanupYarnApplication()) {
test.run();
}
}
Code review comment: Added a const value with https://github.com/ballerina-platform/ballerina-lang/pull/14163/commits/b58dcf2630d4aacb53767112899c20e0e564323c.

Code before review:
public void exitArrayTypeNameLabel(BallerinaParser.ArrayTypeNameLabelContext ctx) {
if (isInErrorState) {
return;
}
int index = 1;
int dimensions = 0;
List<Integer> sizes = new ArrayList<>();
List<ParseTree> children = ctx.children;
while (index < children.size()) {
if (children.get(index).getText().equals("[")) {
if (children.get(index + 1).getText().equals("]")) {
sizes.add(UNSEALED_ARRAY_INDICATOR);
index += 2;
} else if (children.get(index + 1).getText().equals("*")) {
sizes.add(OPEN_SEALED_ARRAY_INDICATOR);
index += 1;
} else {
sizes.add(Integer.parseInt(children.get(index + 1).getText()));
index += 1;
}
dimensions++;
} else {
index++;
}
}
Collections.reverse(sizes);
this.pkgBuilder.addArrayType(
getCurrentPos(ctx), getWS(ctx), dimensions, sizes.stream().mapToInt(val -> val).toArray());
}

Line under review: } else if (children.get(index + 1).getText().equals("*")) {

Code after addressing the review:
public void exitArrayTypeNameLabel(BallerinaParser.ArrayTypeNameLabelContext ctx) {
if (isInErrorState) {
return;
}
int index = 1;
int dimensions = 0;
List<Integer> sizes = new ArrayList<>();
List<ParseTree> children = ctx.children;
while (index < children.size()) {
if (children.get(index).getText().equals("[")) {
if (children.get(index + 1).getText().equals("]")) {
sizes.add(UNSEALED_ARRAY_INDICATOR);
index += 2;
} else if (children.get(index + 1).getText().equals(OPEN_SEALED_ARRAY)) {
sizes.add(OPEN_SEALED_ARRAY_INDICATOR);
index += 1;
} else {
sizes.add(Integer.parseInt(children.get(index + 1).getText()));
index += 1;
}
dimensions++;
} else {
index++;
}
}
Collections.reverse(sizes);
this.pkgBuilder.addArrayType(
getCurrentPos(ctx), getWS(ctx), dimensions, sizes.stream().mapToInt(val -> val).toArray());
}
Code review comment: Can this ever be null? From the current code, it doesn't look like so. 

Code before review:
public String getUserAgent() {
String userAgent = null;
if (this.feedResponseDiagnostics != null) {
userAgent = this.feedResponseDiagnostics.getUserAgent();
} else if (this.clientSideRequestStatistics != null) {
userAgent = this.clientSideRequestStatistics.getUserAgent();
}
if (userAgent != null) {
return userAgent;
}
return "";
}

Line under review: if (userAgent != null) {

Code after addressing the review:
public String getUserAgent() {
if (this.feedResponseDiagnostics != null) {
return this.feedResponseDiagnostics.getUserAgent();
}
return this.clientSideRequestStatistics.getUserAgent();
}
Code review comment: Here exists following case we don't support:  1. the target table is temporary table 2. Specify the columns explicitly 3. Specify the watermark explicitly 4. Specify the constraint explicitly  Regarding to partition key, we think we should support it, see [spark](https://spark.apache.org/docs/latest/sql-ref-syntax-ddl-create-table-datasource.html) also support it. 

Code before review:
public void validate() throws SqlValidateException {
List<SqlTableConstraint> constraints =
getFullConstraints().stream()
.filter(SqlTableConstraint::isPrimaryKey)
.collect(Collectors.toList());
if (constraints.size() > 1) {
throw new SqlValidateException(
constraints.get(1).getParserPosition(), "Duplicate primary key definition");
} else if (constraints.size() == 1) {
Set<String> primaryKeyColumns =
Arrays.stream(constraints.get(0).getColumnNames()).collect(Collectors.toSet());
for (SqlNode column : columnList) {
SqlTableColumn tableColumn = (SqlTableColumn) column;
if (tableColumn instanceof SqlRegularColumn
&& primaryKeyColumns.contains(tableColumn.getName().getSimple())) {
SqlRegularColumn regularColumn = (SqlRegularColumn) column;
SqlDataTypeSpec notNullType = regularColumn.getType().withNullable(false);
regularColumn.setType(notNullType);
}
}
}
if (tableLike != null) {
tableLike.validate();
}
if (query != null
&& (columnList.size() > 0
|| constraints.size() > 0
|| partitionKeyList.size() > 0)) {
throw new SqlValidateException(
pos,
"CREATE TABLE AS SELECT syntax does not yet support to specific Column/Partition/Constraints.");
}
}

Line under review: || constraints.size() > 0

Code after addressing the review:
public void validate() throws SqlValidateException {
List<SqlTableConstraint> constraints =
getFullConstraints().stream()
.filter(SqlTableConstraint::isPrimaryKey)
.collect(Collectors.toList());
if (constraints.size() > 1) {
throw new SqlValidateException(
constraints.get(1).getParserPosition(), "Duplicate primary key definition");
} else if (constraints.size() == 1) {
Set<String> primaryKeyColumns =
Arrays.stream(constraints.get(0).getColumnNames()).collect(Collectors.toSet());
for (SqlNode column : columnList) {
SqlTableColumn tableColumn = (SqlTableColumn) column;
if (tableColumn instanceof SqlRegularColumn
&& primaryKeyColumns.contains(tableColumn.getName().getSimple())) {
SqlRegularColumn regularColumn = (SqlRegularColumn) column;
SqlDataTypeSpec notNullType = regularColumn.getType().withNullable(false);
regularColumn.setType(notNullType);
}
}
}
}
Code review comment: Hey @michalvavrik I've missed all your recent comments, well, I was aware this PR was still open :-), but could not find the proper time to review.  So let me ask: do you agree this particular issue, how to manage HTTP Security Policy alongside annotation based authentication requirements like `@Authenticated`, `@CodeFlow`, etc, is an additional concern, and we can handle it in a follow up PR ? IMHO it would simplify the current PR significantly, and will let us focus better on this important problem better later

Code before review:
static void selectAuthMechanism(RoutingContext routingContext, String authMechanism) {
if (requestAlreadyAuthenticated(routingContext)) {
throw new AuthenticationFailedException("Request has been authenticated before the '" + authMechanism
+ "' authentication mechanism was selected with an annotation. Most often, this will happen when "
+ "you configure HTTPSecurityPolicy that requires authentication (like 'roles-allowed' policy). "
+ "Please revise your 'quarkus.http.auth.permission.*' configuration properties");
}
routingContext.put(AUTH_MECHANISM, authMechanism);
}

Line under review: throw new AuthenticationFailedException("Request has been authenticated before the '" + authMechanism

Code after addressing the review:
static void selectAuthMechanism(RoutingContext routingContext, String authMechanism) {
if (requestAlreadyAuthenticated(routingContext, authMechanism)) {
throw new AuthenticationFailedException("""
The '%1$s' authentication mechanism is required to authenticate the request but it was already
authenticated with the '%2$s' authentication mechanism. It can happen if the '%1$s' is selected with
an annotation but '%2$s' is activated by the HTTP security policy which is enforced before
the JAX-RS chain is run. In such cases, please set the
'quarkus.http.auth.permission."permissions".applies-to=JAXRS' to all HTTP security policies
which secure the same REST endpoints as the ones secured by the '%1$s' authentication mechanism
selected with the annotation.
""".formatted(authMechanism, routingContext.get(AUTH_MECHANISM)));
}
routingContext.put(AUTH_MECHANISM, authMechanism);
}
Code review comment: I reuse the `parseListeners()` here which has the following definition. `<code>expression-list := expression (, expression)*</code>`  Shall I refactor its name to `parseExpressionsList()` and corresponding `LISTNERS_LIST` ctx name to `EXPRESSIONS_LIST` in error handler.  Or Let's keep keep those names intact ? 

Code before review:
private STNode parseOptionalExpressionsList() {
STToken nextToken = peek();
if (isEndOfListenersList(nextToken.kind)) {
return STNodeFactory.createNodeList(new ArrayList<>());
}
return parseListeners();
}

Line under review: return parseListeners();

Code after addressing the review:
private STNode parseOptionalExpressionsList() {
List<STNode> expressions = new ArrayList<>();
STToken nextToken = peek();
if (isEndOfExpressionsList(nextToken.kind)) {
return STNodeFactory.createNodeList(new ArrayList<>());
}
STNode expr = parseExpression();
expressions.add(expr);
nextToken = peek();
STNode leadingComma;
while (!isEndOfExpressionsList(nextToken.kind)) {
leadingComma = parseComma();
expressions.add(leadingComma);
expr = parseExpression();
expressions.add(expr);
nextToken = peek();
}
return STNodeFactory.createNodeList(expressions);
}
Code review comment: Consider adding an assert for the number of dispatchers to ensure that we actually check something in the loop.

Code before review:
public void requireThatDispatchTuningIsApplied() throws ParseException {
ContentCluster cluster = newContentCluster(joinLines("<search>", "</search>"),
joinLines("<tuning>",
"</tuning>"));
for (Dispatch tld : cluster.getSearch().getIndexed().getTLDs()) {
PartitionsConfig.Builder builder = new PartitionsConfig.Builder();
tld.getConfig(builder);
PartitionsConfig config = new PartitionsConfig(builder);
assertEquals(2, config.dataset(0).searchablecopies());
assertTrue(config.dataset(0).useroundrobinforfixedrow());
}
}

Line under review: for (Dispatch tld : cluster.getSearch().getIndexed().getTLDs()) {

Code after addressing the review:
public void requireThatDispatchTuningIsApplied() throws ParseException {
ContentCluster cluster = newContentCluster(joinLines("<search>", "</search>"),
joinLines("<tuning>",
"</tuning>"));
assertEquals(1, cluster.getSearch().getIndexed().getTLDs().size());
for (Dispatch tld : cluster.getSearch().getIndexed().getTLDs()) {
PartitionsConfig.Builder builder = new PartitionsConfig.Builder();
tld.getConfig(builder);
PartitionsConfig config = new PartitionsConfig(builder);
assertEquals(2, config.dataset(0).searchablecopies());
assertTrue(config.dataset(0).useroundrobinforfixedrow());
}
}
Code review comment: non-nullity asserted already, some lines up

Code before review:
public Endpoint in(SystemName system) {
if (system.isPublic() && routingMethod != RoutingMethod.exclusive) {
throw new IllegalArgumentException("Public system only supports routing method " + RoutingMethod.exclusive);
}
if (routingMethod.isDirect() && !port.isDefault()) {
throw new IllegalArgumentException("Routing method " + routingMethod + " can only use default port");
}
URI url = createUrl(endpointOrClusterAsString(endpointId, cluster),
Objects.requireNonNull(application, "application must be non-null"),
Objects.requireNonNull(instance, "instance must be non-null"),
Objects.requireNonNull(targets, "targets must be non-null"),
Objects.requireNonNull(scope, "scope must be non-null"),
Objects.requireNonNull(system, "system must be non-null"),
Objects.requireNonNull(port, "port must be non-null"),
legacy);
return new Endpoint(application,
instance,
endpointId,
cluster,
url,
targets,
scope,
port,
legacy,
routingMethod,
certificateName);
}

Line under review: instance,

Code after addressing the review:
public Endpoint in(SystemName system) {
if (system.isPublic() && routingMethod != RoutingMethod.exclusive) {
throw new IllegalArgumentException("Public system only supports routing method " + RoutingMethod.exclusive);
}
if (routingMethod.isDirect() && !port.isDefault()) {
throw new IllegalArgumentException("Routing method " + routingMethod + " can only use default port");
}
URI url = createUrl(endpointOrClusterAsString(endpointId, cluster),
Objects.requireNonNull(application, "application must be non-null"),
Objects.requireNonNull(instance, "instance must be non-null"),
Objects.requireNonNull(targets, "targets must be non-null"),
Objects.requireNonNull(scope, "scope must be non-null"),
Objects.requireNonNull(system, "system must be non-null"),
Objects.requireNonNull(port, "port must be non-null"),
legacy);
return new Endpoint(application,
instance,
endpointId,
cluster,
url,
targets,
scope,
port,
legacy,
routingMethod,
certificateName);
}
Code review comment: I don't have a preference except that it should be consistent, we can extract it as a separate matcher if having good error messages is something that we want.

Code before review:
public void testAvroSchemaFromBeamSchemaCanBeParsed() {
String stringSchema = AvroUtils.toAvroSchema(getBeamSchema()).toString();
org.apache.avro.Schema schema = new org.apache.avro.Schema.Parser().parse(stringSchema);
assertEquals(stringSchema, schema.toString());
}

Line under review: assertEquals(stringSchema, schema.toString());

Code after addressing the review:
public void testAvroSchemaFromBeamSchemaCanBeParsed() {
org.apache.avro.Schema convertedSchema = AvroUtils.toAvroSchema(getBeamSchema());
org.apache.avro.Schema validatedSchema =
new org.apache.avro.Schema.Parser().parse(convertedSchema.toString());
assertEquals(convertedSchema, validatedSchema);
}
Code review comment:  We should have tests that cover each one of the classes being instrumented...

Code before review:
public void testNettyEventExecutorMetrics() {
testNettyMetrics(2L, NettyEventExecutorMetrics.class);
}

Line under review: testNettyMetrics(2L, NettyEventExecutorMetrics.class);

Code after addressing the review:
public void testNettyEventExecutorMetrics() {
testNettyMetrics(2L, NettyEventExecutorMetrics.class);
}
Code review comment: ```suggestion                     "Detected platform dependencies with provided scope. Redistribution is not " + ```

Code before review:
private void addProvidedDependencyWarning(List<Diagnostic> emitResultDiagnostics) {
if (!jarResolver.providedPlatformLibs().isEmpty()) {
DiagnosticInfo diagnosticInfo = new DiagnosticInfo(
ProjectDiagnosticErrorCode.PROVIDED_PLATFORM_JAR_IN_EXECUTABLE.diagnosticId(),
"Detected platform dependencies with provided scope; redistribution is not " +
"recommended due to potential license restrictions\n",
DiagnosticSeverity.WARNING);
emitResultDiagnostics.add(new PackageDiagnostic(diagnosticInfo,
this.packageContext().descriptor().name().toString()));
}
}

Line under review: "Detected platform dependencies with provided scope; redistribution is not " +

Code after addressing the review:
private void addProvidedDependencyWarning(List<Diagnostic> emitResultDiagnostics) {
if (!jarResolver.providedPlatformLibs().isEmpty()) {
DiagnosticInfo diagnosticInfo = new DiagnosticInfo(
ProjectDiagnosticErrorCode.PROVIDED_PLATFORM_JAR_IN_EXECUTABLE.diagnosticId(),
String.format("Detected platform dependencies with '%s' scope. Redistribution is discouraged" +
" due to potential license restrictions%n", PlatformLibraryScope.PROVIDED.getStringValue()),
DiagnosticSeverity.WARNING);
emitResultDiagnostics.add(new PackageDiagnostic(diagnosticInfo,
this.packageContext().descriptor().name().toString()));
}
}
Code review comment: I suppose you could get back to using `arc` now? I had to change it because of a conflict with `hibernate-search-elasticsearch`.

Code before review:
void addSomeValidExtensions() throws IOException {
final File pom = new File("target/extensions-test", "pom.xml");
CreateProjectTest.delete(pom.getParentFile());
new CreateProject(new FileProjectWriter(pom.getParentFile()))
.groupId("org.acme")
.artifactId("add-extension-test")
.version("0.0.1-SNAPSHOT")
.doCreateProject(new HashMap<>());
File pomFile = new File(pom.getAbsolutePath());
new AddExtensions(new FileProjectWriter(pomFile.getParentFile()), pomFile.getName())
.addExtensions(new HashSet<>(asList("jdbc-postgre", "agroal", "quarkus-arc", " hibernate-validator",
"commons-io:commons-io:2.6")));
Model model = MojoUtils.readPom(pom);
hasDependency(model, "quarkus-agroal");
hasDependency(model, "quarkus-arc");
hasDependency(model, "quarkus-hibernate-validator");
hasDependency(model, "commons-io", "commons-io", "2.6");
doesNotHaveDependency(model, "quarkus-jdbc-postgresql");
}

Line under review: Model model = MojoUtils.readPom(pom);

Code after addressing the review:
void addSomeValidExtensions() throws IOException {
final File pom = new File("target/extensions-test", "pom.xml");
CreateProjectTest.delete(pom.getParentFile());
new CreateProject(new FileProjectWriter(pom.getParentFile()))
.groupId("org.acme")
.artifactId("add-extension-test")
.version("0.0.1-SNAPSHOT")
.doCreateProject(new HashMap<>());
File pomFile = new File(pom.getAbsolutePath());
new AddExtensions(new FileProjectWriter(pomFile.getParentFile()), pomFile.getName())
.addExtensions(new HashSet<>(asList("jdbc-postgre", "agroal", "quarkus-arc", " hibernate-validator",
"commons-io:commons-io:2.6")));
Model model = MojoUtils.readPom(pom);
hasDependency(model, "quarkus-agroal");
hasDependency(model, "quarkus-arc");
hasDependency(model, "quarkus-hibernate-validator");
hasDependency(model, "commons-io", "commons-io", "2.6");
hasDependency(model, "quarkus-jdbc-postgresql");
}
Code review comment: Not sure on this style of returning a string error. Maybe another reviewer can comment.

Code before review:
public CounterUpdate transform(MonitoringInfo monitoringInfo) {
Optional<String> validationResult = validate(monitoringInfo);
if (validationResult.isPresent()) {
LOG.info(validationResult.get());
return null;
}
long value = monitoringInfo.getMetric().getCounterData().getInt64Value();
String urn = monitoringInfo.getUrn();
final String ptransform = monitoringInfo.getLabelsMap().get("PTRANSFORM");
DataflowStepContext stepContext = transformIdMapping.get(ptransform);
String counterName = urnToCounterNameMapping.get(urn);
CounterStructuredNameAndMetadata name = new CounterStructuredNameAndMetadata();
name.setName(
new CounterStructuredName()
.setOrigin("SYSTEM")
.setName(counterName)
.setOriginalStepName(stepContext.getNameContext().originalName())
.setExecutionStepName(stepContext.getNameContext().stageName()))
.setMetadata(new CounterMetadata().setKind("SUM"));
return new CounterUpdate()
.setStructuredNameAndMetadata(name)
.setCumulative(true)
.setInteger(DataflowCounterUpdateExtractor.longToSplitInt(value));
}

Line under review: Optional<String> validationResult = validate(monitoringInfo);

Code after addressing the review:
public CounterUpdate transform(MonitoringInfo monitoringInfo) {
Optional<String> validationResult = validate(monitoringInfo);
if (validationResult.isPresent()) {
LOG.info(validationResult.get());
return null;
}
long value = monitoringInfo.getMetric().getCounterData().getInt64Value();
String urn = monitoringInfo.getUrn();
final String ptransform = monitoringInfo.getLabelsMap().get("PTRANSFORM");
DataflowStepContext stepContext = transformIdMapping.get(ptransform);
String counterName = urnToCounterNameMapping.get(urn);
CounterStructuredNameAndMetadata name = new CounterStructuredNameAndMetadata();
name.setName(
new CounterStructuredName()
.setOrigin("SYSTEM")
.setName(counterName)
.setOriginalStepName(stepContext.getNameContext().originalName())
.setExecutionStepName(stepContext.getNameContext().stageName()))
.setMetadata(new CounterMetadata().setKind("SUM"));
return new CounterUpdate()
.setStructuredNameAndMetadata(name)
.setCumulative(true)
.setInteger(DataflowCounterUpdateExtractor.longToSplitInt(value));
}
Code review comment: This behaviour is not expected by TCKs, see for instance https://github.com/eclipse/microprofile-context-propagation/blob/master/tck/src/main/java/org/eclipse/microprofile/context/tck/ManagedExecutorTest.java#L1737

Code before review:
void initialize(ExecutorService executorService) {
managedExecutor = new ManagedExecutorImpl(-1, -1, (ThreadContextImpl) getAllThreadContext(), executorService, "no-ip") {
@Override
public void shutdown() {
throw new IllegalStateException("This executor is managed by the container and cannot be shut down.");
}
@Override
public List<Runnable> shutdownNow() {
throw new IllegalStateException("This executor is managed by the container and cannot be shut down.");
}
};
}

Line under review: throw new IllegalStateException("This executor is managed by the container and cannot be shut down.");

Code after addressing the review:
void initialize(ExecutorService executorService) {
managedExecutor = new SmallRyeManagedExecutor(-1, -1, (SmallRyeThreadContext) getAllThreadContext(), executorService,
"no-ip") {
@Override
public void shutdown() {
throw new IllegalStateException("This executor is managed by the container and cannot be shut down.");
}
@Override
public List<Runnable> shutdownNow() {
throw new IllegalStateException("This executor is managed by the container and cannot be shut down.");
}
};
}
Code review comment: @tsreaper - I've changed the parallelism to 1 and now the output is in the same order as you had mentioned.  I've also added table output recommended by @JingsongLi. Please let me know if you have any other recommendations.  Thanks

Code before review:
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
StreamTableEnvironment tEnv = StreamTableEnvironment.create(env);
String contents =
"1,beer,3,2019-12-12 00:00:01\n"
+ "1,diaper,4,2019-12-12 00:00:02\n"
+ "2,pen,3,2019-12-12 00:00:04\n"
+ "2,rubber,3,2019-12-12 00:00:06\n"
+ "3,rubber,2,2019-12-12 00:00:05\n"
+ "4,beer,1,2019-12-12 00:00:08";
String path = createTempFile(contents);
String ddl =
"CREATE TABLE orders (\n"
+ "  user_id INT,\n"
+ "  product STRING,\n"
+ "  amount INT,\n"
+ "  ts TIMESTAMP(3),\n"
+ "  WATERMARK FOR ts AS ts - INTERVAL '3' SECOND\n"
+ ") WITH (\n"
+ "  'connector.type' = 'filesystem',\n"
+ "  'connector.path' = '"
+ path
+ "',\n"
+ "  'format.type' = 'csv'\n"
+ ")";
tEnv.executeSql(ddl);
String query =
"SELECT\n"
+ "  CAST(TUMBLE_START(ts, INTERVAL '5' SECOND) AS STRING) window_start,\n"
+ "  COUNT(*) order_num,\n"
+ "  SUM(amount) total_amount,\n"
+ "  COUNT(DISTINCT product) unique_products\n"
+ "FROM orders\n"
+ "GROUP BY TUMBLE(ts, INTERVAL '5' SECOND)";
Table result = tEnv.sqlQuery(query);
tEnv.toAppendStream(result, Row.class).print();
env.execute("Streaming Window SQL Job");
}


Code after addressing the review:
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
StreamTableEnvironment tEnv = StreamTableEnvironment.create(env);
String contents =
"1,beer,3,2019-12-12 00:00:01\n"
+ "1,diaper,4,2019-12-12 00:00:02\n"
+ "2,pen,3,2019-12-12 00:00:04\n"
+ "2,rubber,3,2019-12-12 00:00:06\n"
+ "3,rubber,2,2019-12-12 00:00:05\n"
+ "4,beer,1,2019-12-12 00:00:08";
String path = createTempFile(contents);
String ddl =
"CREATE TABLE orders (\n"
+ "  user_id INT,\n"
+ "  product STRING,\n"
+ "  amount INT,\n"
+ "  ts TIMESTAMP(3),\n"
+ "  WATERMARK FOR ts AS ts - INTERVAL '3' SECOND\n"
+ ") WITH (\n"
+ "  'connector.type' = 'filesystem',\n"
+ "  'connector.path' = '"
+ path
+ "',\n"
+ "  'format.type' = 'csv'\n"
+ ")";
tEnv.executeSql(ddl);
String query =
"SELECT\n"
+ "  CAST(TUMBLE_START(ts, INTERVAL '5' SECOND) AS STRING) window_start,\n"
+ "  COUNT(*) order_num,\n"
+ "  SUM(amount) total_amount,\n"
+ "  COUNT(DISTINCT product) unique_products\n"
+ "FROM orders\n"
+ "GROUP BY TUMBLE(ts, INTERVAL '5' SECOND)";
tEnv.executeSql(query).print();
}
Code review comment: > only private ctor is enough, why add the exception?  As suggestion by Sonar, this makes it more readable, and I accept it.

Code before review:
private SerializerUtils(){
throw new IllegalStateException("Utility class");
}

Line under review: throw new IllegalStateException("Utility class");

Code after addressing the review:
private SerializerUtils() {
}
Code review comment: dockerImage is the full string e.g. "docker-registry.ops.yahoo.com:4443/vespa/ci:6.96.12", so you need to parse it

Code before review:
private static ClusterMembership readMembership(Inspector object) {
return ClusterMembership.from(object.field(hostSpecMembership).asString(),
object.field(hostSpecVespaVersion).valid() ?
com.yahoo.component.Version.fromString(object.field(hostSpecVespaVersion).asString()) :
( object.field(dockerImage).valid() ? com.yahoo.component.Version.fromString(object.field(dockerImage).asString()) : Vtag.currentVersion));
}

Line under review: }

Code after addressing the review:
private static ClusterMembership readMembership(Inspector object) {
return ClusterMembership.from(object.field(hostSpecMembership).asString(),
object.field(hostSpecVespaVersion).valid() ?
com.yahoo.component.Version.fromString(object.field(hostSpecVespaVersion).asString()) :
( object.field(dockerImage).valid() ? new DockerImage(object.field(dockerImage).asString()).tagAsVersion() : Vtag.currentVersion));
}
Code review comment: can replace `types.get(i)` with `node`. 

Code before review:
public BLangNode transform(TupleTypeDescriptorNode tupleTypeDescriptorNode) {
BLangTupleTypeNode tupleTypeNode = (BLangTupleTypeNode) TreeBuilder.createTupleTypeNode();
SeparatedNodeList<Node> types = tupleTypeDescriptorNode.memberTypeDesc();
for (int i = 0; i < types.size(); i++) {
Node node = types.get(i);
if (node.kind() == SyntaxKind.REST_TYPE) {
tupleTypeNode.restParamType = createTypeNode(types.get(i));
} else {
tupleTypeNode.memberTypeNodes.add(createTypeNode(types.get(i)));
}
}
tupleTypeNode.pos = getPosition(tupleTypeDescriptorNode);
return tupleTypeNode;
}

Line under review: tupleTypeNode.memberTypeNodes.add(createTypeNode(types.get(i)));

Code after addressing the review:
public BLangNode transform(TupleTypeDescriptorNode tupleTypeDescriptorNode) {
BLangTupleTypeNode tupleTypeNode = (BLangTupleTypeNode) TreeBuilder.createTupleTypeNode();
SeparatedNodeList<Node> types = tupleTypeDescriptorNode.memberTypeDesc();
for (int i = 0; i < types.size(); i++) {
Node node = types.get(i);
if (node.kind() == SyntaxKind.REST_TYPE) {
RestDescriptorNode restDescriptor = (RestDescriptorNode) node;
tupleTypeNode.restParamType = createTypeNode(restDescriptor.typeDescriptor());
} else {
tupleTypeNode.memberTypeNodes.add(createTypeNode(node));
}
}
tupleTypeNode.pos = getPosition(tupleTypeDescriptorNode);
return tupleTypeNode;
}
Code review comment: > sessionTokenApplicable: In java V4: we also skip applying the session token when Eventual Consistency is explicitly requested on request-level for data plane operations. This is not included in V2 and .net SDK.  If consistency is eventual there is no need to set session token. This is intentional.   Does this PR change this behaviour?

Code before review:
private void applySessionToken(RxDocumentServiceRequest request) {
Map<String, String> headers = request.getHeaders();
Objects.requireNonNull(headers, "RxDocumentServiceRequest::headers is required and cannot be null");
String requestConsistencyLevel = headers.get(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL);
boolean sessionTokenApplicable =
Strings.areEqual(requestConsistencyLevel, ConsistencyLevel.SESSION.toString()) ||
(this.defaultConsistencyLevel == ConsistencyLevel.SESSION &&
(!request.isReadOnlyRequest() ||
request.getResourceType() != ResourceType.Document ||
!Strings.areEqual(requestConsistencyLevel, ConsistencyLevel.EVENTUAL.toString())));
if (!Strings.isNullOrEmpty(request.getHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN))) {
if (!sessionTokenApplicable || isMasterOperation(request.getResourceType(), request.getOperationType())) {
request.getHeaders().remove(HttpConstants.HttpHeaders.SESSION_TOKEN);
}
return;
}
if (!sessionTokenApplicable || isMasterOperation(request.getResourceType(), request.getOperationType())) {
return;
}
String sessionToken = this.sessionContainer.resolveGlobalSessionToken(request);
if (!Strings.isNullOrEmpty(sessionToken)) {
headers.put(HttpConstants.HttpHeaders.SESSION_TOKEN, sessionToken);
}
}

Line under review: if (!sessionTokenApplicable || isMasterOperation(request.getResourceType(), request.getOperationType())) {

Code after addressing the review:
private void applySessionToken(RxDocumentServiceRequest request) {
Map<String, String> headers = request.getHeaders();
Objects.requireNonNull(headers, "RxDocumentServiceRequest::headers is required and cannot be null");
String requestConsistencyLevel = headers.get(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL);
boolean sessionTokenApplicable =
Strings.areEqual(requestConsistencyLevel, ConsistencyLevel.SESSION.toString()) ||
(this.defaultConsistencyLevel == ConsistencyLevel.SESSION &&
(!request.isReadOnlyRequest() ||
request.getResourceType() != ResourceType.Document ||
!Strings.areEqual(requestConsistencyLevel, ConsistencyLevel.EVENTUAL.toString())));
if (!Strings.isNullOrEmpty(request.getHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN))) {
if (!sessionTokenApplicable || isMasterOperation(request.getResourceType(), request.getOperationType())) {
request.getHeaders().remove(HttpConstants.HttpHeaders.SESSION_TOKEN);
}
return;
}
if (!sessionTokenApplicable || isMasterOperation(request.getResourceType(), request.getOperationType())) {
return;
}
String sessionToken = this.sessionContainer.resolveGlobalSessionToken(request);
if (!Strings.isNullOrEmpty(sessionToken)) {
headers.put(HttpConstants.HttpHeaders.SESSION_TOKEN, sessionToken);
}
}
Code review comment: One advantage of being explicit is that the program will fail at pipeline creation time if the option is accidentally forgotten about.  Otherwise they could get a NPE.   But not sure if that protection is valuable enough, or if the simplification of the API is better? 

Code before review:
public void processElement(ProcessContext context) {
try {
context.output(jsonToRow(objectMapper(), context.element()));
} catch (Exception ex) {
if (withExtendedErrorInfo) {
context.output(
PARSE_ERROR_LINE_WITH_MSG,
Row.withSchema(ERROR_ROW_WITH_ERR_MSG_SCHEMA)
.addValue(context.element())
.addValue(ex.getMessage())
.build());
} else {
context.output(
PARSE_ERROR_LINE,
Row.withSchema(ERROR_ROW_SCHEMA).addValue(context.element()).build());
}
}
}

Line under review: PARSE_ERROR_LINE_WITH_MSG,

Code after addressing the review:
public void processElement(ProcessContext context) {
context.output(jsonToRow(objectMapper(), context.element()));
}
Code review comment: Adding it but it would be good to understand that do heartbeat services need to do the same or they're somehow different? 

Code before review:
private void stopResourceManagerServices() throws Exception {
Exception exception = null;
try {
terminate();
} catch (Exception e) {
exception =
new ResourceManagerException("Error while shutting down resource manager", e);
}
delegationTokenManager.ifPresent(DelegationTokenManager::stop);
stopHeartbeatServices();
try {
slotManager.close();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
try {
jobLeaderIdService.stop();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
resourceManagerMetricGroup.close();
clearStateInternal();
ExceptionUtils.tryRethrowException(exception);
}

Line under review: delegationTokenManager.ifPresent(DelegationTokenManager::stop);

Code after addressing the review:
private void stopResourceManagerServices() throws Exception {
Exception exception = null;
try {
terminate();
} catch (Exception e) {
exception =
new ResourceManagerException("Error while shutting down resource manager", e);
}
try {
delegationTokenManager.stop();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
stopHeartbeatServices();
try {
slotManager.close();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
try {
jobLeaderIdService.stop();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
resourceManagerMetricGroup.close();
clearStateInternal();
ExceptionUtils.tryRethrowException(exception);
}
Code review comment: Thanks @iemejia . Do suggest if there any other changes needed.

Code before review:
public void finishBundle(FinishBundleContext context) throws Exception {
Multimap<BoundedWindow, KV<String, String>> kvs = fetchAndFlush();
for (BoundedWindow w : kvs.keySet()) {
for (KV<String, String> kv : kvs.get(w)) {
context.output(kv, w.maxTimestamp(), w);
}
}
}

Line under review: Multimap<BoundedWindow, KV<String, String>> kvs = fetchAndFlush();

Code after addressing the review:
public void finishBundle(FinishBundleContext context) throws Exception {
Multimap<BoundedWindow, KV<String, String>> kvs = fetchAndFlush();
for (BoundedWindow w : kvs.keySet()) {
for (KV<String, String> kv : kvs.get(w)) {
context.output(kv, w.maxTimestamp(), w);
}
}
}
Code review comment: Got it. I have changed the implementation of testTotalAttemptsPerUpload, and updated the pr.

Code before review:
public UploadTasksResult upload(Collection<UploadTask> tasks) throws IOException {
Map<UploadTask, Map<StateChangeSet, Long>> map = new HashMap<>();
try {
TimeUnit.MILLISECONDS.sleep(latency);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
for (UploadTask uploadTask : tasks) {
map.put(
uploadTask,
uploadTask.changeSets.stream()
.collect(Collectors.toMap(Function.identity(), ign -> 0L)));
}
return new UploadTasksResult(map, new EmptyStreamStateHandle());
}

Line under review: TimeUnit.MILLISECONDS.sleep(latency);

Code after addressing the review:
public UploadTasksResult upload(Collection<UploadTask> tasks) throws IOException {
Map<UploadTask, Map<StateChangeSet, Long>> map = new HashMap<>();
for (UploadTask uploadTask : tasks) {
int currentAttempt = 1 + attemptsPerTask.getOrDefault(uploadTask, 0);
if (currentAttempt == maxAttempts) {
attemptsPerTask.remove(uploadTask);
map.put(
uploadTask,
uploadTask.changeSets.stream()
.collect(Collectors.toMap(Function.identity(), ign -> 0L)));
} else {
attemptsPerTask.put(uploadTask, currentAttempt);
throw new IOException();
}
}
return new UploadTasksResult(map, new EmptyStreamStateHandle());
}