veyron/runtimes/google/ipc: Improve the test coverage for contexts.
Especially cancellation.
Change-Id: I88806a4972c937e6679ef8d940213002abf88ba9
diff --git a/runtimes/google/ipc/context.go b/runtimes/google/ipc/context.go
index c8d23a3..28dff36 100644
--- a/runtimes/google/ipc/context.go
+++ b/runtimes/google/ipc/context.go
@@ -8,11 +8,13 @@
"veyron.io/veyron/veyron2/context"
)
+const nilRuntimeMessage = "attempting to create a context with a nil runtime"
+
// InternalNewContext creates a new context.T. This function should only
// be called from within the runtime implementation.
func InternalNewContext(runtime veyron2.Runtime) context.T {
if runtime == nil {
- panic("attempting to create a context with a nil runtime")
+ panic(nilRuntimeMessage)
}
return rootContext{runtime}
}
@@ -133,9 +135,6 @@
return
}
-func (c *cancelContext) parent() context.T {
- return c.T
-}
// addChild sets child as a descendant cancellable context. This
// allows us to propagate cancellations through the context tree.
@@ -211,7 +210,7 @@
}
parent = c.parent()
}
- return nil, false
+ return nil, false // Unreachable.
}
func (c *cancelContext) Done() <-chan struct{} { return c.done }
diff --git a/runtimes/google/ipc/context_test.go b/runtimes/google/ipc/context_test.go
index 7b9137c..515ee26 100644
--- a/runtimes/google/ipc/context_test.go
+++ b/runtimes/google/ipc/context_test.go
@@ -49,9 +49,44 @@
}
}
+func TestRootContext(t *testing.T) {
+ r := &runtime.PanicRuntime{}
+ ctx := InternalNewContext(r)
+
+ if got := ctx.Runtime(); got != r {
+ t.Errorf("Expected runtime %v, but found %v", r, got)
+ }
+
+ if got := ctx.Err(); got != nil {
+ t.Errorf("Expected nil error, got: %v", got)
+ }
+
+ defer func() {
+ r := recover()
+ if r != nilRuntimeMessage {
+ t.Errorf("Unexpected recover value: %s", r)
+ }
+ }()
+ InternalNewContext(nil)
+}
+
func TestCancelContext(t *testing.T) {
ctx, cancel := testContext().WithCancel()
testCancel(t, ctx, cancel)
+
+ // Test cancelling a cancel context which is the child
+ // of a cancellable context.
+ parent, _ := testContext().WithCancel()
+ child, cancel := parent.WithCancel()
+ cancel()
+ <-child.Done()
+
+ // Test adding a cancellable child context after the parent is
+ // already cancelled.
+ parent, cancel = testContext().WithCancel()
+ cancel()
+ child, _ = parent.WithCancel()
+ <-child.Done() // The child should have been cancelled right away.
}
func TestMultiLevelCancelContext(t *testing.T) {
@@ -80,11 +115,14 @@
}
func TestCancelContextWithNonStandard(t *testing.T) {
- c0, c0Cancel := testContext().WithCancel()
- c1 := &nonStandardContext{c0}
+ // Test that cancellation flows properly through non-standard intermediates.
+ ctx := testContext()
+ c0 := &nonStandardContext{ctx}
+ c1, c1Cancel := c0.WithCancel()
c2 := &nonStandardContext{c1}
- c3, _ := c2.WithCancel()
- testCancel(t, c3, c0Cancel)
+ c3 := &nonStandardContext{c2}
+ c4, _ := c3.WithCancel()
+ testCancel(t, c4, c1Cancel)
}
func testDeadline(t *testing.T, ctx context.T, start time.Time, desiredTimeout time.Duration) {
@@ -99,12 +137,37 @@
func TestDeadlineContext(t *testing.T) {
cases := []time.Duration{
- 10 * time.Millisecond,
+ 3 * time.Millisecond,
0,
}
+ rootCtx := InternalNewContext(&runtime.PanicRuntime{})
+ cancelCtx, _ := rootCtx.WithCancel()
+ deadlineCtx, _ := rootCtx.WithDeadline(time.Now().Add(time.Hour))
+
for _, desiredTimeout := range cases {
+ // Test all the various ways of getting deadline contexts.
start := time.Now()
- ctx, _ := testContext().WithDeadline(start.Add(desiredTimeout))
+ ctx, _ := rootCtx.WithDeadline(start.Add(desiredTimeout))
+ testDeadline(t, ctx, start, desiredTimeout)
+
+ start = time.Now()
+ ctx, _ = cancelCtx.WithDeadline(start.Add(desiredTimeout))
+ testDeadline(t, ctx, start, desiredTimeout)
+
+ start = time.Now()
+ ctx, _ = deadlineCtx.WithDeadline(start.Add(desiredTimeout))
+ testDeadline(t, ctx, start, desiredTimeout)
+
+ start = time.Now()
+ ctx, _ = rootCtx.WithTimeout(desiredTimeout)
+ testDeadline(t, ctx, start, desiredTimeout)
+
+ start = time.Now()
+ ctx, _ = cancelCtx.WithTimeout(desiredTimeout)
+ testDeadline(t, ctx, start, desiredTimeout)
+
+ start = time.Now()
+ ctx, _ = deadlineCtx.WithTimeout(desiredTimeout)
testDeadline(t, ctx, start, desiredTimeout)
}