Storage and test doubles

Jeroen Vermeulen jeroen.vermeulen at canonical.com
Thu Jul 11 04:00:18 UTC 2013


Hi folks,

Hopefully this will make your development lives a bit easier.

Each of the providers in Juju can now work with any of the Storage
implementations.  You could make an EC2 environment using an OpenStack
storage object, or couple an OpenStack storage object to a MAAS
environment, or you could use the "local" storage implementation for any
provider.

Why would you want to?  Testing.  Some provider methods are hard to
write tests for because they access storage, and storage is out on the
cloud.  But now, you can inject a fake "localstorage" implementation,
and it'll work like a coherent real-life storage... without talking to
any remote services on the network.

Here's an example of how to inject the fake.  There are really only 3
simple steps.  This is from the Azure provider, but it should be very
similar for other providers:

«BEGIN EXAMPLE»
import (
        gc "launchpad.net/gocheck"
	"launchpad.net/juju-core/environs/localstorage"
)

// setDummyStorage injects the local provider's fake storage
// implementation into the given environment, so that tests can
// manipulate storage as if it were real.
// Returns a cleanup function that must be called when done with
// the storage.
func setDummyStorage(c *gc.C, env *azureEnviron) func() {
	// The local storage works through http.  Have it listen on
	// any port on the local host.
        listener, err := localstorage.Serve("127.0.0.1:0", c.MkDir())
        c.Assert(err, IsNil)
        env.storage = localstorage.Client(listener.Addr().String())
        return func() { listener.Close() }
}
«END EXAMPLE»

With this, a test can:

    cleanup := setDummyStorage(c, environ)
    defer cleanup()

...and "env" will magically have working storage.

Injecting a fake storage used to be technically possible in some places,
but not everywhere, and it took some hackery.

So, next time you work on provider code, I would like to ask you to give
a few moments' thought to how this affects test coverage.  Are you
perhaps working on a function that should have had unit-tests in the
past but didn't because of how it deals with storage?  Are you writing
code that can be exercised in tests if you can just get rid of the
storage calls?  Can you factor your code in ways that become more
testable with a fake storage?  Better test coverage means you can be
more confident that your code is of good quality and robust to change.

Any questions?  Please ask!


Jeroen



More information about the Juju-dev mailing list