2828import io .grpc .ServerInterceptor ;
2929import io .grpc .Status ;
3030import java .util .ArrayList ;
31+ import java .util .Arrays ;
32+ import java .util .Comparator ;
3133import java .util .List ;
3234import java .util .Map ;
3335import java .util .Objects ;
4143
4244@ RunWith (JUnit4 .class )
4345public class XGoogSpannerRequestIdTest {
46+ public static long NON_DETERMINISTIC = -1 ;
4447
4548 @ Test
4649 public void testEquals () {
@@ -157,40 +160,83 @@ private void assertMonotonicityOfIds(String prefix, List<XGoogSpannerRequestId>
157160 + String .join ("\n \t " , violations .toArray (new String [0 ])));
158161 }
159162
160- public static class methodAndRequestId {
161- String method ;
162- String requestId ;
163-
164- public methodAndRequestId (String method , String requestId ) {
165- this .method = method ;
166- this .requestId = requestId ;
167- }
168-
169- public String toString () {
170- return "{" + this .method + ":" + this .requestId + "}" ;
171- }
172- }
173-
174- public methodAndRequestId [] accumulatedUnaryValues () {
175- List <methodAndRequestId > accumulated = new ArrayList ();
163+ public MethodAndRequestId [] accumulatedUnaryValues () {
164+ List <MethodAndRequestId > accumulated = new ArrayList ();
176165 this .unaryResults .forEach (
177166 (String method , CopyOnWriteArrayList <XGoogSpannerRequestId > values ) -> {
178167 for (int i = 0 ; i < values .size (); i ++) {
179- accumulated .add (new methodAndRequestId (method , values .get (i ). toString ( )));
168+ accumulated .add (new MethodAndRequestId (method , values .get (i )));
180169 }
181170 });
182- return accumulated .toArray (new methodAndRequestId [0 ]);
171+ return accumulated .toArray (new MethodAndRequestId [0 ]);
183172 }
184173
185- public methodAndRequestId [] accumulatedStreamingValues () {
186- List <methodAndRequestId > accumulated = new ArrayList ();
174+ public MethodAndRequestId [] accumulatedStreamingValues () {
175+ List <MethodAndRequestId > accumulated = new ArrayList ();
187176 this .streamingResults .forEach (
188177 (String method , CopyOnWriteArrayList <XGoogSpannerRequestId > values ) -> {
189178 for (int i = 0 ; i < values .size (); i ++) {
190- accumulated .add (new methodAndRequestId (method , values .get (i ). toString ( )));
179+ accumulated .add (new MethodAndRequestId (method , values .get (i )));
191180 }
192181 });
193- return accumulated .toArray (new methodAndRequestId [0 ]);
182+ return accumulated .toArray (new MethodAndRequestId [0 ]);
183+ }
184+
185+ public void checkExpectedUnaryXGoogRequestIds (MethodAndRequestId ... wantUnaryValues ) {
186+ MethodAndRequestId [] gotUnaryValues = this .accumulatedUnaryValues ();
187+ sortValues (gotUnaryValues );
188+ for (int i = 0 ; i < gotUnaryValues .length && false ; i ++) {
189+ System .out .println ("\033 [33misUnary: #" + i + ":: " + gotUnaryValues [i ] + "\033 [00m" );
190+ }
191+ assertEquals (wantUnaryValues , gotUnaryValues );
192+ }
193+
194+ public void checkAtLeastHasExpectedUnaryXGoogRequestIds (MethodAndRequestId ... wantUnaryValues ) {
195+ MethodAndRequestId [] gotUnaryValues = this .accumulatedUnaryValues ();
196+ sortValues (gotUnaryValues );
197+ for (int i = 0 ; i < gotUnaryValues .length && false ; i ++) {
198+ System .out .println ("\033 [33misUnary: #" + i + ":: " + gotUnaryValues [i ] + "\033 [00m" );
199+ }
200+ if (wantUnaryValues .length < gotUnaryValues .length ) {
201+ MethodAndRequestId [] gotSliced =
202+ Arrays .copyOfRange (gotUnaryValues , 0 , wantUnaryValues .length );
203+ assertEquals (wantUnaryValues , gotSliced );
204+ } else {
205+ assertEquals (wantUnaryValues , gotUnaryValues );
206+ }
207+ }
208+
209+ public void checkExpectedUnaryXGoogRequestIdsAsSuffixes (MethodAndRequestId ... wantUnaryValues ) {
210+ MethodAndRequestId [] gotUnaryValues = this .accumulatedUnaryValues ();
211+ sortValues (gotUnaryValues );
212+ for (int i = 0 ; i < gotUnaryValues .length && false ; i ++) {
213+ System .out .println ("\033 [33misUnary: #" + i + ":: " + gotUnaryValues [i ] + "\033 [00m" );
214+ }
215+ if (wantUnaryValues .length < gotUnaryValues .length ) {
216+ MethodAndRequestId [] gotSliced =
217+ Arrays .copyOfRange (
218+ gotUnaryValues ,
219+ gotUnaryValues .length - wantUnaryValues .length ,
220+ gotUnaryValues .length );
221+ assertEquals (wantUnaryValues , gotSliced );
222+ } else {
223+ assertEquals (wantUnaryValues , gotUnaryValues );
224+ }
225+ }
226+
227+ private void sortValues (MethodAndRequestId [] values ) {
228+ massageValues (values );
229+ Arrays .sort (values , new MethodAndRequestIdComparator ());
230+ }
231+
232+ public void checkExpectedStreamingXGoogRequestIds (MethodAndRequestId ... wantStreamingValues ) {
233+ MethodAndRequestId [] gotStreamingValues = this .accumulatedStreamingValues ();
234+ for (int i = 0 ; i < gotStreamingValues .length && false ; i ++) {
235+ System .out .println (
236+ "\033 [32misStreaming: #" + i + ":: " + gotStreamingValues [i ] + "\033 [00m" );
237+ }
238+ sortValues (gotStreamingValues );
239+ assertEquals (wantStreamingValues , gotStreamingValues );
194240 }
195241
196242 public void reset () {
@@ -199,4 +245,80 @@ public void reset() {
199245 this .streamingResults .clear ();
200246 }
201247 }
248+
249+ public static class MethodAndRequestId {
250+ String method ;
251+ XGoogSpannerRequestId requestId ;
252+
253+ public MethodAndRequestId (String method , XGoogSpannerRequestId requestId ) {
254+ this .method = method ;
255+ this .requestId = requestId ;
256+ }
257+
258+ public String toString () {
259+ return "{" + this .method + ":" + this .requestId .debugToString () + "}" ;
260+ }
261+
262+ @ Override
263+ public boolean equals (Object o ) {
264+ if (!(o instanceof MethodAndRequestId )) {
265+ return false ;
266+ }
267+ MethodAndRequestId other = (MethodAndRequestId ) o ;
268+ return Objects .equals (this .method , other .method )
269+ && Objects .equals (this .requestId , other .requestId );
270+ }
271+ }
272+
273+ static class MethodAndRequestIdComparator implements Comparator <MethodAndRequestId > {
274+ @ Override
275+ public int compare (MethodAndRequestId mr1 , MethodAndRequestId mr2 ) {
276+ int cmpMethod = mr1 .method .compareTo (mr2 .method );
277+ if (cmpMethod != 0 ) {
278+ return cmpMethod ;
279+ }
280+
281+ if (Objects .equals (mr1 .requestId , mr2 .requestId )) {
282+ return 0 ;
283+ }
284+ if (mr1 .requestId .isGreaterThan (mr2 .requestId )) {
285+ return +1 ;
286+ }
287+ return -1 ;
288+ }
289+ }
290+
291+ static void massageValues (MethodAndRequestId [] mreqs ) {
292+ for (int i = 0 ; i < mreqs .length ; i ++) {
293+ MethodAndRequestId mreq = mreqs [i ];
294+ // BatchCreateSessions is so hard to control as the round-robin doling out
295+ // hence we might need to be able to scrub the nth_request that won't match
296+ // nth_req in consecutive order of nth_client.
297+ if (mreq .method .compareTo ("google.spanner.v1.Spanner/BatchCreateSessions" ) == 0 ) {
298+ mreqs [i ] =
299+ new MethodAndRequestId (
300+ mreq .method ,
301+ mreq .requestId
302+ .withNthRequest (NON_DETERMINISTIC )
303+ .withChannelId (NON_DETERMINISTIC )
304+ .withNthClientId (NON_DETERMINISTIC ));
305+ } else if (mreq .method .compareTo ("google.spanner.v1.Spanner/BeginTransaction" ) == 0
306+ || mreq .method .compareTo ("google.spanner.v1.Spanner/ExecuteStreamingSql" ) == 0
307+ || mreq .method .compareTo ("google.spanner.v1.Spanner/ExecuteSql" ) == 0
308+ || mreq .method .compareTo ("google.spanner.v1.Spanner/CreateSession" ) == 0
309+ || mreq .method .compareTo ("google.spanner.v1.Spanner/Commit" ) == 0 ) {
310+ mreqs [i ] =
311+ new MethodAndRequestId (mreq .method , mreq .requestId .withNthClientId (NON_DETERMINISTIC ));
312+ }
313+ }
314+ }
315+
316+ public static MethodAndRequestId ofMethodAndRequestId (String method , String reqId ) {
317+ return new MethodAndRequestId (method , XGoogSpannerRequestId .of (reqId ));
318+ }
319+
320+ public static MethodAndRequestId ofMethodAndRequestId (
321+ String method , XGoogSpannerRequestId reqId ) {
322+ return new MethodAndRequestId (method , reqId );
323+ }
202324}
0 commit comments