services/mgmt/device/impl/...:
Make testDeviceManager notice an exiting test device manager quickly, rather
than by waiting for timeouts to expire. This allows us to re-enable the
version update test in TestDeviceManagerUpdateAndRevert as the version
mismatch failure is now noticed quickly
Change-Id: I31375ea120a0c2007f90409fae7f6f71616b7227
diff --git a/services/mgmt/device/impl/config_service.go b/services/mgmt/device/impl/config_service.go
index cce62bd..819cf28 100644
--- a/services/mgmt/device/impl/config_service.go
+++ b/services/mgmt/device/impl/config_service.go
@@ -41,8 +41,10 @@
// callback mechanism for a given key.
type callbackListener interface {
// waitForValue blocks until the value that this listener is expecting
- // arrives; or until the timeout expires.
+ // arrives, until the timeout expires, or until stop() is called
waitForValue(timeout time.Duration) (string, error)
+ // stop makes waitForValue return early
+ stop()
// cleanup cleans up any state used by the listener. Should be called
// when the listener is no longer needed.
cleanup()
@@ -53,10 +55,11 @@
// listener implements callbackListener
type listener struct {
- id string
- cs *callbackState
- ch <-chan string
- n string
+ id string
+ cs *callbackState
+ ch <-chan string
+ n string
+ stopper chan struct{}
}
func (l *listener) waitForValue(timeout time.Duration) (string, error) {
@@ -65,9 +68,15 @@
return value, nil
case <-time.After(timeout):
return "", verror.New(ErrOperationFailed, nil, fmt.Sprintf("Waiting for callback timed out after %v", timeout))
+ case <-l.stopper:
+ return "", verror.New(ErrOperationFailed, nil, fmt.Sprintf("Stopped while waiting for callack"))
}
}
+func (l *listener) stop() {
+ close(l.stopper)
+}
+
func (l *listener) cleanup() {
l.cs.unregister(l.id)
}
@@ -84,11 +93,13 @@
// unregisterCallbacks executes before Set is called.
callbackChan := make(chan string, 1)
c.register(id, key, callbackChan)
+ stopchan := make(chan struct{}, 1)
return &listener{
- id: id,
- cs: c,
- ch: callbackChan,
- n: callbackName,
+ id: id,
+ cs: c,
+ ch: callbackChan,
+ n: callbackName,
+ stopper: stopchan,
}
}
diff --git a/services/mgmt/device/impl/device_service.go b/services/mgmt/device/impl/device_service.go
index 0059ee0..0871a95 100644
--- a/services/mgmt/device/impl/device_service.go
+++ b/services/mgmt/device/impl/device_service.go
@@ -396,10 +396,24 @@
vlog.Errorf("Clean() failed: %v", err)
}
}()
+
// Wait for the child process to start.
if err := handle.WaitForReady(childReadyTimeout); err != nil {
return verror.New(ErrOperationFailed, ctx, fmt.Sprintf("WaitForReady(%v) failed: %v", childReadyTimeout, err))
}
+
+ // Watch for the exit of the child. Failures could cause it to happen at any time
+ waitchan := make(chan error, 1)
+ go func() {
+ // Wait timeout needs to be long enough to give the rest of the operations time to run
+ err := handle.Wait(2*childReadyTimeout + childWaitTimeout)
+ if err != nil {
+ waitchan <- verror.New(ErrOperationFailed, ctx, fmt.Sprintf("new device manager failed to exit cleanly: %v", err))
+ }
+ close(waitchan)
+ listener.stop()
+ }()
+
childName, err := listener.waitForValue(childReadyTimeout)
if err != nil {
return verror.New(ErrOperationFailed, ctx, fmt.Sprintf("waitForValue(%v) failed: %v", childReadyTimeout, err))
@@ -410,8 +424,8 @@
if err := dmClient.Stop(ctx, 0); err != nil {
return verror.New(ErrOperationFailed, ctx, fmt.Sprintf("Stop() failed: %v", err))
}
- if err := handle.Wait(childWaitTimeout); err != nil {
- return verror.New(ErrOperationFailed, ctx, fmt.Sprintf("New device manager failed to exit cleanly: %v", err))
+ if err := <-waitchan; err != nil {
+ return err
}
return nil
}
diff --git a/services/mgmt/device/impl/impl_test.go b/services/mgmt/device/impl/impl_test.go
index e897549..fb6ac4e 100644
--- a/services/mgmt/device/impl/impl_test.go
+++ b/services/mgmt/device/impl/impl_test.go
@@ -454,15 +454,13 @@
t.Fatalf("script changed")
}
- if false { // Disabled until we figure out how to make it not take 40 seconds to time out
- // Try issuing an update with a binary that has a different major version number. It should fail
- resolveExpectNotFound(t, ctx, "v2.5DM") // Ensure a clean slate.
- *envelope = envelopeFromShell(sh, dmEnv, deviceManagerV10Cmd, application.DeviceManagerTitle, "v2.5DM")
- updateDeviceExpectError(t, ctx, "v2DM", impl.ErrOperationFailed.ID)
+ // Try issuing an update with a binary that has a different major version number. It should fail
+ resolveExpectNotFound(t, ctx, "v2.5DM") // Ensure a clean slate.
+ *envelope = envelopeFromShell(sh, dmEnv, deviceManagerV10Cmd, application.DeviceManagerTitle, "v2.5DM")
+ updateDeviceExpectError(t, ctx, "v2DM", impl.ErrOperationFailed.ID)
- if evalLink() != scriptPathV2 {
- t.Fatalf("script changed")
- }
+ if evalLink() != scriptPathV2 {
+ t.Fatalf("script changed")
}
// Create a third version of the device manager and issue an update.