-
Notifications
You must be signed in to change notification settings - Fork 133
chore(x-goog-spanner-request-id): setup expectations for end-to-end request-id checks #3932
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bf94ef7
ffcf3f5
abb5f5d
aa2cf65
e33cf68
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,8 @@ | |
import io.grpc.ServerInterceptor; | ||
import io.grpc.Status; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Comparator; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
@@ -41,6 +43,7 @@ | |
|
||
@RunWith(JUnit4.class) | ||
public class XGoogSpannerRequestIdTest { | ||
public static long NON_DETERMINISTIC = -1; | ||
|
||
@Test | ||
public void testEquals() { | ||
|
@@ -157,40 +160,83 @@ private void assertMonotonicityOfIds(String prefix, List<XGoogSpannerRequestId> | |
+ String.join("\n\t", violations.toArray(new String[0]))); | ||
} | ||
|
||
public static class methodAndRequestId { | ||
String method; | ||
String requestId; | ||
|
||
public methodAndRequestId(String method, String requestId) { | ||
this.method = method; | ||
this.requestId = requestId; | ||
} | ||
|
||
public String toString() { | ||
return "{" + this.method + ":" + this.requestId + "}"; | ||
} | ||
} | ||
|
||
public methodAndRequestId[] accumulatedUnaryValues() { | ||
List<methodAndRequestId> accumulated = new ArrayList(); | ||
public MethodAndRequestId[] accumulatedUnaryValues() { | ||
List<MethodAndRequestId> accumulated = new ArrayList(); | ||
this.unaryResults.forEach( | ||
(String method, CopyOnWriteArrayList<XGoogSpannerRequestId> values) -> { | ||
for (int i = 0; i < values.size(); i++) { | ||
accumulated.add(new methodAndRequestId(method, values.get(i).toString())); | ||
accumulated.add(new MethodAndRequestId(method, values.get(i))); | ||
} | ||
}); | ||
return accumulated.toArray(new methodAndRequestId[0]); | ||
return accumulated.toArray(new MethodAndRequestId[0]); | ||
} | ||
|
||
public methodAndRequestId[] accumulatedStreamingValues() { | ||
List<methodAndRequestId> accumulated = new ArrayList(); | ||
public MethodAndRequestId[] accumulatedStreamingValues() { | ||
List<MethodAndRequestId> accumulated = new ArrayList(); | ||
this.streamingResults.forEach( | ||
(String method, CopyOnWriteArrayList<XGoogSpannerRequestId> values) -> { | ||
for (int i = 0; i < values.size(); i++) { | ||
accumulated.add(new methodAndRequestId(method, values.get(i).toString())); | ||
accumulated.add(new MethodAndRequestId(method, values.get(i))); | ||
} | ||
}); | ||
return accumulated.toArray(new methodAndRequestId[0]); | ||
return accumulated.toArray(new MethodAndRequestId[0]); | ||
} | ||
|
||
public void checkExpectedUnaryXGoogRequestIds(MethodAndRequestId... wantUnaryValues) { | ||
MethodAndRequestId[] gotUnaryValues = this.accumulatedUnaryValues(); | ||
sortValues(gotUnaryValues); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it correct that we are sorting these accumulated values here? Doesn't that mean that if we receive the request-ids out of the expected order on the (mock) server, this sort action hides any potential test failures due to the request-ids having been out of order? |
||
for (int i = 0; i < gotUnaryValues.length && false; i++) { | ||
System.out.println("\033[33misUnary: #" + i + ":: " + gotUnaryValues[i] + "\033[00m"); | ||
} | ||
Comment on lines
+188
to
+190
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand that this is not being printed due to the |
||
assertEquals(wantUnaryValues, gotUnaryValues); | ||
} | ||
|
||
public void checkAtLeastHasExpectedUnaryXGoogRequestIds(MethodAndRequestId... wantUnaryValues) { | ||
MethodAndRequestId[] gotUnaryValues = this.accumulatedUnaryValues(); | ||
sortValues(gotUnaryValues); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here regarding sorting the accumulated values as above. |
||
for (int i = 0; i < gotUnaryValues.length && false; i++) { | ||
System.out.println("\033[33misUnary: #" + i + ":: " + gotUnaryValues[i] + "\033[00m"); | ||
} | ||
if (wantUnaryValues.length < gotUnaryValues.length) { | ||
MethodAndRequestId[] gotSliced = | ||
Arrays.copyOfRange(gotUnaryValues, 0, wantUnaryValues.length); | ||
assertEquals(wantUnaryValues, gotSliced); | ||
} else { | ||
assertEquals(wantUnaryValues, gotUnaryValues); | ||
} | ||
} | ||
|
||
public void checkExpectedUnaryXGoogRequestIdsAsSuffixes(MethodAndRequestId... wantUnaryValues) { | ||
MethodAndRequestId[] gotUnaryValues = this.accumulatedUnaryValues(); | ||
sortValues(gotUnaryValues); | ||
for (int i = 0; i < gotUnaryValues.length && false; i++) { | ||
System.out.println("\033[33misUnary: #" + i + ":: " + gotUnaryValues[i] + "\033[00m"); | ||
} | ||
if (wantUnaryValues.length < gotUnaryValues.length) { | ||
MethodAndRequestId[] gotSliced = | ||
Arrays.copyOfRange( | ||
gotUnaryValues, | ||
gotUnaryValues.length - wantUnaryValues.length, | ||
gotUnaryValues.length); | ||
assertEquals(wantUnaryValues, gotSliced); | ||
} else { | ||
assertEquals(wantUnaryValues, gotUnaryValues); | ||
} | ||
} | ||
|
||
private void sortValues(MethodAndRequestId[] values) { | ||
massageValues(values); | ||
Arrays.sort(values, new MethodAndRequestIdComparator()); | ||
} | ||
|
||
public void checkExpectedStreamingXGoogRequestIds(MethodAndRequestId... wantStreamingValues) { | ||
MethodAndRequestId[] gotStreamingValues = this.accumulatedStreamingValues(); | ||
for (int i = 0; i < gotStreamingValues.length && false; i++) { | ||
System.out.println( | ||
"\033[32misStreaming: #" + i + ":: " + gotStreamingValues[i] + "\033[00m"); | ||
} | ||
sortValues(gotStreamingValues); | ||
assertEquals(wantStreamingValues, gotStreamingValues); | ||
} | ||
|
||
public void reset() { | ||
|
@@ -199,4 +245,80 @@ public void reset() { | |
this.streamingResults.clear(); | ||
} | ||
} | ||
|
||
public static class MethodAndRequestId { | ||
String method; | ||
XGoogSpannerRequestId requestId; | ||
|
||
public MethodAndRequestId(String method, XGoogSpannerRequestId requestId) { | ||
this.method = method; | ||
this.requestId = requestId; | ||
} | ||
|
||
public String toString() { | ||
return "{" + this.method + ":" + this.requestId.debugToString() + "}"; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (!(o instanceof MethodAndRequestId)) { | ||
return false; | ||
} | ||
MethodAndRequestId other = (MethodAndRequestId) o; | ||
return Objects.equals(this.method, other.method) | ||
&& Objects.equals(this.requestId, other.requestId); | ||
} | ||
} | ||
|
||
static class MethodAndRequestIdComparator implements Comparator<MethodAndRequestId> { | ||
@Override | ||
public int compare(MethodAndRequestId mr1, MethodAndRequestId mr2) { | ||
int cmpMethod = mr1.method.compareTo(mr2.method); | ||
if (cmpMethod != 0) { | ||
return cmpMethod; | ||
} | ||
|
||
if (Objects.equals(mr1.requestId, mr2.requestId)) { | ||
return 0; | ||
} | ||
if (mr1.requestId.isGreaterThan(mr2.requestId)) { | ||
return +1; | ||
} | ||
return -1; | ||
} | ||
} | ||
|
||
static void massageValues(MethodAndRequestId[] mreqs) { | ||
for (int i = 0; i < mreqs.length; i++) { | ||
MethodAndRequestId mreq = mreqs[i]; | ||
// BatchCreateSessions is so hard to control as the round-robin doling out | ||
// hence we might need to be able to scrub the nth_request that won't match | ||
// nth_req in consecutive order of nth_client. | ||
if (mreq.method.compareTo("google.spanner.v1.Spanner/BatchCreateSessions") == 0) { | ||
mreqs[i] = | ||
new MethodAndRequestId( | ||
mreq.method, | ||
mreq.requestId | ||
.withNthRequest(NON_DETERMINISTIC) | ||
.withChannelId(NON_DETERMINISTIC) | ||
.withNthClientId(NON_DETERMINISTIC)); | ||
} else if (mreq.method.compareTo("google.spanner.v1.Spanner/BeginTransaction") == 0 | ||
|| mreq.method.compareTo("google.spanner.v1.Spanner/ExecuteStreamingSql") == 0 | ||
|| mreq.method.compareTo("google.spanner.v1.Spanner/ExecuteSql") == 0 | ||
|| mreq.method.compareTo("google.spanner.v1.Spanner/CreateSession") == 0 | ||
|| mreq.method.compareTo("google.spanner.v1.Spanner/Commit") == 0) { | ||
mreqs[i] = | ||
new MethodAndRequestId(mreq.method, mreq.requestId.withNthClientId(NON_DETERMINISTIC)); | ||
} | ||
} | ||
} | ||
|
||
public static MethodAndRequestId ofMethodAndRequestId(String method, String reqId) { | ||
return new MethodAndRequestId(method, XGoogSpannerRequestId.of(reqId)); | ||
} | ||
|
||
public static MethodAndRequestId ofMethodAndRequestId( | ||
String method, XGoogSpannerRequestId reqId) { | ||
return new MethodAndRequestId(method, reqId); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact that we can make this change without any tests failing (or needing to be changed) seems to indicate that we have a test gap. Will that be covered by the tests that are being added in this PR, but that are currently not verifying anything, as all verifications are in
if (false)
blocks? If not, can we add tests that cover this in a follow-up PR?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@olavloite I had made a much larger PR #3915 in which tests were all updated but deemed too large to get in at once hence I carved this one out. Indeed @tharoldD is sending a follow-up PR to remove all the false conditions and then more tests too.