spanner/spannertest: skip DDL apply waiting when LROs have been probed

The purpose of the artificial wait is to verify that callers will wait
for the LRO before assuming the DDL has been applied. However, if there
is a waiter, they use the GetOperation RPC, so we can disable the sleep
to speed up tests. For the tests of spannertest itself, this halves the
test's run time.

Change-Id: I7f58c4d75759ddff86f87a02dbd172f84645ccb5
Reviewed-on: https://code-review.googlesource.com/c/gocloud/+/53251
Reviewed-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Knut Olav Løite <koloite@gmail.com>
diff --git a/spanner/spannertest/inmem.go b/spanner/spannertest/inmem.go
index bd9c9f1..0cdea97 100644
--- a/spanner/spannertest/inmem.go
+++ b/spanner/spannertest/inmem.go
@@ -142,8 +142,9 @@
 
 // lro represents a Long-Running Operation, generally a schema change.
 type lro struct {
-	mu    sync.Mutex
-	state *lropb.Operation
+	mu      sync.Mutex
+	state   *lropb.Operation
+	waiters bool // Whether anyone appears to be waiting.
 }
 
 func (l *lro) State() *lropb.Operation {
@@ -222,6 +223,12 @@
 	if !ok {
 		return nil, status.Errorf(codes.NotFound, "unknown LRO %q", req.Name)
 	}
+
+	// Someone is waiting on this LRO. Disable sleeping in its Run method.
+	lro.mu.Lock()
+	lro.waiters = true
+	lro.mu.Unlock()
+
 	return lro.State(), nil
 }
 
@@ -272,7 +279,14 @@
 	ctx := context.Background()
 
 	for _, stmt := range stmts {
-		time.Sleep(100 * time.Millisecond)
+		l.mu.Lock()
+		waiters := l.waiters
+		l.mu.Unlock()
+		if !waiters {
+			// Simulate delayed DDL application, but only if nobody is waiting.
+			time.Sleep(100 * time.Millisecond)
+		}
+
 		if st := s.runOneDDL(ctx, stmt); st.Code() != codes.OK {
 			l.mu.Lock()
 			l.state.Done = true