func (s *CredentialsCommandSuite) TestInit(c *gc.C) { for i, test := range []struct { args []string outPath string errorString string }{ { // no args is fine }, { args: []string{"--output=foo.bar"}, outPath: "foo.bar", }, { args: []string{"-o", "foo.bar"}, outPath: "foo.bar", }, { args: []string{"foobar"}, errorString: `unrecognized args: \["foobar"\]`, }, } { c.Logf("test %d", i) command := &user.CredentialsCommand{} err := testing.InitCommand(command, test.args) if test.errorString == "" { c.Check(command.OutPath, gc.Equals, test.outPath) } else { c.Check(err, gc.ErrorMatches, test.errorString) } } }
func (s *modelManagerSuite) TestCreateModelBadAgentVersion(c *gc.C) { s.PatchValue(&version.Current, coretesting.FakeVersionNumber) admin := s.AdminUserTag(c) s.setAPIUser(c, admin) bigger := version.Current bigger.Minor += 1 smaller := version.Current smaller.Minor -= 1 for i, test := range []struct { value interface{} errMatch string }{ { value: 42, errMatch: `failed to create config: agent-version must be a string but has type 'int'`, }, { value: "not a number", errMatch: `failed to create config: invalid version \"not a number\"`, }, { value: bigger.String(), errMatch: "failed to create config: agent-version cannot be greater than the server: .*", }, { value: smaller.String(), errMatch: "failed to create config: no tools found for version .*", }, } { c.Logf("test %d", i) args := s.createArgsForVersion(c, admin, test.value) _, err := s.modelmanager.CreateModel(args) c.Check(err, gc.ErrorMatches, test.errMatch) } }
func (s *ActionSuite) TestFindActionTagsByPrefix(c *gc.C) { prefix := "feedbeef" uuidMock := uuidMockHelper{} uuidMock.SetPrefixMask(prefix) s.PatchValue(&state.NewUUID, uuidMock.NewUUID) actions := []struct { Name string Parameters map[string]interface{} }{ {Name: "action-1", Parameters: map[string]interface{}{}}, {Name: "fake", Parameters: map[string]interface{}{"yeah": true, "take": nil}}, {Name: "action-9", Parameters: map[string]interface{}{"district": 9}}, {Name: "blarney", Parameters: map[string]interface{}{"conversation": []string{"what", "now"}}}, } for _, action := range actions { _, err := s.State.EnqueueAction(s.unit.Tag(), action.Name, action.Parameters) c.Assert(err, gc.Equals, nil) } tags := s.State.FindActionTagsByPrefix(prefix) c.Assert(len(tags), gc.Equals, len(actions)) for i, tag := range tags { c.Logf("check %q against %d:%q", prefix, i, tag) c.Check(tag.Id()[:len(prefix)], gc.Equals, prefix) } }
func (s *ValidateImageMetadataSuite) TestInitErrors(c *gc.C) { for i, t := range validateInitImageErrorTests { c.Logf("test %d", i) err := coretesting.InitCommand(newValidateImageMetadataCommand(), t.args) c.Check(err, gc.ErrorMatches, t.err) } }
func (s *guiArchiveSuite) TestGUIArchivePostErrors(c *gc.C) { type exoticReader struct { io.Reader } for i, test := range guiArchivePostErrorsTests { c.Logf("\n%d: %s", i, test.about) // Prepare the request. var r io.Reader = strings.NewReader("archive contents") if test.noContentLength { // net/http will automatically add a Content-Length header if it // sees *strings.Reader, but not if it's a type it doesn't know. r = exoticReader{r} } // Send the request and retrieve the error response. resp := s.authRequest(c, httpRequestParams{ method: "POST", url: s.guiURL(c) + test.query, contentType: test.contentType, body: r, }) body := assertResponse(c, resp, test.expectedStatus, params.ContentTypeJSON) var jsonResp params.ErrorResult err := json.Unmarshal(body, &jsonResp) c.Assert(err, jc.ErrorIsNil, gc.Commentf("body: %s", body)) c.Assert(jsonResp.Error.Message, gc.Matches, test.expectedError) } }
func (s *MachineClassifySuite) TestMachineClassification(c *gc.C) { test := func(t machineClassificationTest, id string) { // Run a sub-test from the test table s2e := func(s string) error { // Little helper to turn a non-empty string into a useful error for "ErrorMaches" if s != "" { return ¶ms.Error{Code: s} } return nil } c.Logf("%s: %s", id, t.description) machine := MockMachine{t.life, t.status, id, s2e(t.idErr), s2e(t.ensureDeadErr), s2e(t.statusErr)} classification, err := provisioner.ClassifyMachine(&machine) if err != nil { c.Assert(err, gc.ErrorMatches, fmt.Sprintf(t.expectErrFmt, machine.Id())) } else { c.Assert(err, gc.Equals, s2e(t.expectErrCode)) } c.Assert(classification, gc.Equals, t.classification) } machineIds := []string{"0/lxc/0", "0/kvm/0", "0"} for _, id := range machineIds { tests := machineClassificationTests if id == "0" { tests = append(tests, machineClassificationTestsNoMaintenance) } else { tests = append(tests, machineClassificationTestsRequireMaintenance) } for _, t := range tests { test(t, id) } } }
func (s *httpSuite) TestHTTPClient(c *gc.C) { var handler http.HandlerFunc srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { handler(w, req) })) defer srv.Close() s.client.BaseURL = srv.URL for i, test := range httpClientTests { c.Logf("test %d: %s", i, test.about) handler = test.handler var resp interface{} if test.expectResponse != nil { resp = reflect.New(reflect.TypeOf(test.expectResponse).Elem()).Interface() } err := s.client.Get("/", resp) if test.expectError != "" { c.Check(err, gc.ErrorMatches, test.expectError) c.Check(params.ErrCode(err), gc.Equals, test.expectErrorCode) if err, ok := errors.Cause(err).(*params.Error); ok { c.Check(err.Info, jc.DeepEquals, test.expectErrorInfo) } else if test.expectErrorInfo != nil { c.Fatalf("no error info found in error") } continue } c.Check(err, gc.IsNil) c.Check(resp, jc.DeepEquals, test.expectResponse) } }
func (s *deployRepoCharmStoreSuite) TestDeployBundleErrors(c *gc.C) { for i, test := range deployBundleErrorsTests { c.Logf("test %d: %s", i, test.about) _, err := s.deployBundleYAML(c, test.content) c.Assert(err, gc.ErrorMatches, test.err) } }
func (s addRelation) step(c *gc.C, ctx *context) { if ctx.relation != nil { panic("don't add two relations!") } if ctx.relatedSvc == nil { ctx.relatedSvc = ctx.s.AddTestingService(c, "mysql", ctx.s.AddTestingCharm(c, "mysql")) } eps, err := ctx.st.InferEndpoints("u", "mysql") c.Assert(err, jc.ErrorIsNil) ctx.relation, err = ctx.st.AddRelation(eps...) c.Assert(err, jc.ErrorIsNil) ctx.relationUnits = map[string]*state.RelationUnit{} if !s.waitJoin { return } // It's hard to do this properly (watching scope) without perturbing other tests. ru, err := ctx.relation.Unit(ctx.unit) c.Assert(err, jc.ErrorIsNil) timeout := time.After(worstCase) for { c.Logf("waiting to join relation") select { case <-timeout: c.Fatalf("failed to join relation") case <-time.After(coretesting.ShortWait): inScope, err := ru.InScope() c.Assert(err, jc.ErrorIsNil) if inScope { return } } } }
func (certSuite) TestNewServerHostnames(c *gc.C) { type test struct { hostnames []string expectedDNSNames []string expectedIPAddresses []net.IP } tests := []test{{ []string{}, nil, nil, }, { []string{"example.com"}, []string{"example.com"}, nil, }, { []string{"example.com", "127.0.0.1"}, []string{"example.com"}, []net.IP{net.IPv4(127, 0, 0, 1).To4()}, }, { []string{"::1"}, nil, []net.IP{net.IPv6loopback}, }} for i, t := range tests { c.Logf("test %d: %v", i, t.hostnames) expiry := roundTime(time.Now().AddDate(1, 0, 0)) srvCertPEM, srvKeyPEM, err := cert.NewServer(caCertPEM, caKeyPEM, expiry, t.hostnames) c.Assert(err, jc.ErrorIsNil) srvCert, _, err := cert.ParseCertAndKey(srvCertPEM, srvKeyPEM) c.Assert(err, jc.ErrorIsNil) c.Assert(srvCert.DNSNames, gc.DeepEquals, t.expectedDNSNames) c.Assert(srvCert.IPAddresses, gc.DeepEquals, t.expectedIPAddresses) } }
func (s *ConstraintsSuite) TestHasContainer(c *gc.C) { for i, t := range hasContainerTests { c.Logf("test %d", i) cons := constraints.MustParse(t.constraints) c.Check(cons.HasContainer(), gc.Equals, t.hasContainer) } }
func (*HostPortSuite) TestParseHostPortsSuccess(c *gc.C) { for i, test := range []struct { args []string expect []network.HostPort }{{ args: nil, expect: []network.HostPort{}, }, { args: []string{"1.2.3.4:42"}, expect: network.NewHostPorts(42, "1.2.3.4"), }, { args: []string{"[fc00::1]:1234"}, expect: network.NewHostPorts(1234, "fc00::1"), }, { args: []string{"[fc00::1]:1234", "127.0.0.1:4321", "example.com:42"}, expect: []network.HostPort{ {network.NewAddress("fc00::1"), 1234}, {network.NewAddress("127.0.0.1"), 4321}, {network.NewAddress("example.com"), 42}, }, }} { c.Logf("test %d: args %v", i, test.args) hps, err := network.ParseHostPorts(test.args...) c.Check(err, jc.ErrorIsNil) c.Check(hps, jc.DeepEquals, test.expect) } }
func (s *SimpleStreamsToolsSuite) TestFindTools(c *gc.C) { for i, test := range findToolsTests { c.Logf("\ntest %d: %s", i, test.info) s.reset(c, nil) custom := s.uploadCustom(c, test.custom...) public := s.uploadPublic(c, test.public...) stream := envtools.PreferredStream(&version.Current, s.env.Config().Development(), s.env.Config().AgentStream()) actual, err := envtools.FindTools(s.env, test.major, test.minor, stream, coretools.Filter{}) if test.err != nil { if len(actual) > 0 { c.Logf(actual.String()) } c.Check(err, jc.Satisfies, errors.IsNotFound) continue } expect := map[version.Binary]string{} for _, expected := range test.expect { // If the tools exist in custom, that's preferred. var ok bool if expect[expected], ok = custom[expected]; !ok { expect[expected] = public[expected] } } c.Check(actual.URLs(), gc.DeepEquals, expect) } }
func (s *AddressSuite) TestString(c *gc.C) { for i, test := range stringTests { c.Logf("test %d: %#v", i, test.addr) c.Check(test.addr.String(), gc.Equals, test.str) c.Check(test.addr.GoString(), gc.Equals, test.str) } }
func (s *SSHSuite) TestSSHCommand(c *gc.C) { m := s.makeMachines(3, c, true) ch := testcharms.Repo.CharmDir("dummy") curl := charm.MustParseURL( fmt.Sprintf("local:quantal/%s-%d", ch.Meta().Name, ch.Revision()), ) info := state.CharmInfo{ Charm: ch, ID: curl, StoragePath: "dummy-path", SHA256: "dummy-1-sha256", } dummy, err := s.State.AddCharm(info) c.Assert(err, jc.ErrorIsNil) srv := s.AddTestingService(c, "mysql", dummy) s.addUnit(srv, m[0], c) srv = s.AddTestingService(c, "mongodb", dummy) s.addUnit(srv, m[1], c) s.addUnit(srv, m[2], c) for i, t := range sshTests { c.Logf("test %d: %s -> %s", i, t.about, t.args) ctx := coretesting.Context(c) jujucmd := cmd.NewSuperCommand(cmd.SuperCommandParams{}) jujucmd.Register(newSSHCommand()) code := cmd.Main(jujucmd, ctx, t.args) c.Check(code, gc.Equals, 0) c.Check(ctx.Stderr.(*bytes.Buffer).String(), gc.Equals, "") c.Check(strings.TrimRight(ctx.Stdout.(*bytes.Buffer).String(), "\r\n"), gc.Equals, t.result) } }
func (s *NewAPIClientSuite) bootstrapEnv(c *gc.C, envName string, store configstore.Storage) { if store == nil { store = configstore.NewMem() } ctx := envtesting.BootstrapContext(c) c.Logf("env name: %s", envName) env, err := environs.PrepareFromName(envName, ctx, store) c.Assert(err, jc.ErrorIsNil) storageDir := c.MkDir() s.PatchValue(&envtools.DefaultBaseURL, storageDir) stor, err := filestorage.NewFileStorageWriter(storageDir) c.Assert(err, jc.ErrorIsNil) envtesting.UploadFakeTools(c, stor, "released", "released") err = bootstrap.Bootstrap(ctx, env, bootstrap.BootstrapParams{}) c.Assert(err, jc.ErrorIsNil) info, err := store.ReadInfo(envName) c.Assert(err, jc.ErrorIsNil) creds := info.APICredentials() creds.User = dummy.AdminUserTag().Name() c.Logf("set creds: %#v", creds) info.SetAPICredentials(creds) err = info.Write() c.Assert(err, jc.ErrorIsNil) c.Logf("creds: %#v", info.APICredentials()) info, err = store.ReadInfo(envName) c.Assert(err, jc.ErrorIsNil) c.Logf("read creds: %#v", info.APICredentials()) c.Logf("store: %#v", store) }
func (s *createBudgetSuite) TestCreateBudgetErrors(c *gc.C) { tests := []struct { about string args []string expectedError string }{ { about: "test value needs to be a number", args: []string{"name", "badvalue"}, expectedError: "budget value needs to be a whole number", }, { about: "value is missing", args: []string{"name"}, expectedError: "name and value required", }, { about: "no args", args: []string{}, expectedError: "name and value required", }, } for i, test := range tests { c.Logf("test %d: %s", i, test.about) if test.expectedError != "" { s.mockAPI.SetErrors(errors.New(test.expectedError)) } createCmd := createbudget.NewCreateBudgetCommand() _, err := cmdtesting.RunCommand(c, createCmd, test.args...) c.Assert(err, gc.ErrorMatches, test.expectedError) s.mockAPI.CheckNoCalls(c) } }
func (s *setBudgetSuite) TestSetBudgetErrors(c *gc.C) { tests := []struct { about string args []string expectedError string }{ { about: "value needs to be a number", args: []string{"name", "badvalue"}, expectedError: "budget value needs to be a whole number", }, { about: "value is missing", args: []string{"name"}, expectedError: "name and value required", }, { about: "no args", args: []string{}, expectedError: "name and value required", }, } for i, test := range tests { c.Logf("test %d: %s", i, test.about) s.stub.SetErrors(errors.New(test.expectedError)) defer s.mockAPI.ResetCalls() set := setbudget.NewSetBudgetCommand() _, err := cmdtesting.RunCommand(c, set, test.args...) c.Assert(err, gc.ErrorMatches, test.expectedError) s.mockAPI.CheckNoCalls(c) } }
func (s *prepareSuite) TestErrorWithEnvironMethodsFailing(c *gc.C) { container := s.newAPI(c, true, true) args := s.makeArgs(container) s.fillSubnet(c, 10) // NOTE: We're testing AllocateAddress and ReleaseAddress separately. for i, test := range []struct { method string err string errCheck func(error) bool }{{ method: "NetworkInterfaces", err: "cannot allocate addresses: dummy.NetworkInterfaces is broken", }, { method: "Subnets", err: "cannot allocate addresses: dummy.Subnets is broken", }, { method: "SupportsAddressAllocation", err: "cannot allocate addresses: address allocation on any available subnets is not supported", errCheck: errors.IsNotSupported, }} { c.Logf("test %d: broken %q", i, test.method) s.breakEnvironMethods(c, test.method) var err error if test.err != "" { err, _ = s.assertCall(c, args, nil, test.err) } if test.errCheck != nil { c.Check(err, jc.Satisfies, test.errCheck) } } }
func (s *DeployCharmStoreSuite) TestDeployAuthorization(c *gc.C) { // Upload the two charms required to upload the bundle. testcharms.UploadCharm(c, s.client, "trusty/mysql-0", "mysql") testcharms.UploadCharm(c, s.client, "trusty/wordpress-1", "wordpress") // Run the tests. for i, test := range deployAuthorizationTests { c.Logf("test %d: %s", i, test.about) // Upload the charm or bundle under test. url := charm.MustParseURL(test.uploadURL) if url.Series == "bundle" { url, _ = testcharms.UploadBundle(c, s.client, test.uploadURL, "wordpress-simple") } else { url, _ = testcharms.UploadCharm(c, s.client, test.uploadURL, "wordpress") } // Change the ACL of the uploaded entity if required in this case. if test.readPermUser != "" { s.changeReadPerm(c, url, test.readPermUser) } ctx, err := coretesting.RunCommand(c, envcmd.Wrap(&deployCommand{}), test.deployURL, fmt.Sprintf("wordpress%d", i)) if test.expectError != "" { c.Assert(err, gc.ErrorMatches, test.expectError) continue } c.Assert(err, jc.ErrorIsNil) output := strings.Trim(coretesting.Stderr(ctx), "\n") c.Assert(output, gc.Equals, strings.TrimSpace(test.expectOutput)) } }
func (s *statusGetSuite) TestOutputFormatJustStatus(c *gc.C) { for i, t := range statusGetTests { c.Logf("test %d: %#v", i, t.args) hctx := s.GetStatusHookContext(c) setFakeStatus(hctx) com, err := jujuc.NewCommand(hctx, cmdString("status-get")) c.Assert(err, jc.ErrorIsNil) ctx := testing.Context(c) code := cmd.Main(com, ctx, t.args) c.Assert(code, gc.Equals, 0) c.Assert(bufferString(ctx.Stderr), gc.Equals, "") var out interface{} var outMap map[string]interface{} switch t.format { case formatYaml: c.Check(goyaml.Unmarshal(bufferBytes(ctx.Stdout), &outMap), gc.IsNil) out = outMap case formatJson: c.Check(json.Unmarshal(bufferBytes(ctx.Stdout), &outMap), gc.IsNil) out = outMap default: out = string(bufferBytes(ctx.Stdout)) } c.Check(out, gc.DeepEquals, t.out) } }
func (s *DeploySuite) TestInitErrors(c *gc.C) { for i, t := range initErrorTests { c.Logf("test %d", i) err := coretesting.InitCommand(envcmd.Wrap(&deployCommand{}), t.args) c.Assert(err, gc.ErrorMatches, t.err) } }
func diffStrings(c *gc.C, value, expected string) { // If only Go had a diff library. vlines := strings.Split(value, "\n") elines := strings.Split(expected, "\n") vsize := len(vlines) esize := len(elines) if vsize < 2 || esize < 2 { return } smaller := elines if vsize < esize { smaller = vlines } for i := range smaller { vline := vlines[i] eline := elines[i] if vline != eline { c.Logf("first mismatched line (%d/%d):", i, len(smaller)) c.Log("expected: " + eline) c.Log("got: " + vline) break } } }
func mockAPICaller(c *gc.C, callNumber *int32, apiCalls ...apiCall) apitesting.APICallerFunc { apiCaller := apitesting.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error { switch objType { case "NotifyWatcher": return nil case "Uniter": index := int(atomic.AddInt32(callNumber, 1)) - 1 c.Check(index < len(apiCalls), jc.IsTrue) call := apiCalls[index] c.Logf("request %d, %s", index, request) c.Check(version, gc.Equals, 4) c.Check(id, gc.Equals, "") c.Check(request, gc.Equals, call.request) c.Check(arg, jc.DeepEquals, call.args) if call.err != nil { return common.ServerError(call.err) } testing.PatchValue(result, call.result) default: c.Fail() } return nil }) return apiCaller }
func (s *migrateAgentEnvUUIDSuite) removeEnvUUIDFromAgentConfig(c *gc.C) { // Read the file in as simple map[string]interface{} and delete // the element, and write it back out again. // First step, read the file contents. filename := agent.ConfigPath(agent.DefaultDataDir, s.machine.Tag()) data, err := ioutil.ReadFile(filename) c.Assert(err, jc.ErrorIsNil) c.Logf("Data in:\n\n%s\n", data) // Parse it into the map. var content map[string]interface{} err = goyaml.Unmarshal(data, &content) c.Assert(err, jc.ErrorIsNil) // Remove the environment value, and marshal back into bytes. delete(content, "environment") data, err = goyaml.Marshal(content) c.Assert(err, jc.ErrorIsNil) // Write the yaml back out remembering to add the format prefix. data = append([]byte("# format 1.18\n"), data...) c.Logf("Data out:\n\n%s\n", data) err = ioutil.WriteFile(filename, data, 0644) c.Assert(err, jc.ErrorIsNil) // Reset test attributes. cfg, err := agent.ReadConfig(filename) c.Assert(err, jc.ErrorIsNil) s.ctx.realAgentConfig = cfg }
func (s *BootstrapSuite) TestRunTests(c *gc.C) { for i, test := range bootstrapTests { c.Logf("\ntest %d: %s", i, test.info) restore := s.run(c, test) restore() } }
func (*ConfigSuite) TestConfigString(c *gc.C) { for i, test := range []struct { config Config expected string }{{ config: nil, expected: "", }, { config: Config{"": INFO}, expected: "<root>=INFO", }, { config: Config{"": UNSPECIFIED}, expected: "<root>=UNSPECIFIED", }, { config: Config{"": DEBUG}, expected: "<root>=DEBUG", }, { config: Config{"test.module": DEBUG}, expected: "test.module=DEBUG", }, { config: Config{ "": WARNING, "module": INFO, "sub.module": DEBUG, "other.module": WARNING, }, expected: "<root>=WARNING;module=INFO;other.module=WARNING;sub.module=DEBUG", }} { c.Logf("%d: %q", i, test.expected) c.Check(test.config.String(), gc.Equals, test.expected) } }
func (s *ResolvedSuite) TestResolved(c *gc.C) { ch := testcharms.Repo.CharmArchivePath(s.CharmsPath, "dummy") err := runDeploy(c, "-n", "5", ch, "dummy", "--series", "quantal") c.Assert(err, jc.ErrorIsNil) for _, name := range []string{"dummy/2", "dummy/3", "dummy/4"} { u, err := s.State.Unit(name) c.Assert(err, jc.ErrorIsNil) err = u.SetAgentStatus(status.StatusError, "lol borken", nil) c.Assert(err, jc.ErrorIsNil) } for i, t := range resolvedTests { c.Logf("test %d: %v", i, t.args) err := runResolved(c, t.args) if t.err != "" { c.Assert(err, gc.ErrorMatches, t.err) } else { c.Assert(err, jc.ErrorIsNil) } if t.unit != "" { unit, err := s.State.Unit(t.unit) c.Assert(err, jc.ErrorIsNil) c.Assert(unit.Resolved(), gc.Equals, t.mode) } } }
func (s *charmsSuite) TestGetReturnsFileContents(c *gc.C) { // Add the dummy charm. ch := testcharms.Repo.CharmArchive(c.MkDir(), "dummy") _, err := s.uploadRequest( c, s.charmsURI(c, "?series=quantal"), true, ch.Path) c.Assert(err, jc.ErrorIsNil) // Ensure the file contents are properly returned. for i, t := range []struct { summary string file string response string }{{ summary: "relative path", file: "revision", response: "1", }, { summary: "exotic path", file: "./hooks/../revision", response: "1", }, { summary: "sub-directory path", file: "hooks/install", response: "#!/bin/bash\necho \"Done!\"\n", }, } { c.Logf("test %d: %s", i, t.summary) uri := s.charmsURI(c, "?url=local:quantal/dummy-1&file="+t.file) resp, err := s.authRequest(c, "GET", uri, "", nil) c.Assert(err, jc.ErrorIsNil) s.assertGetFileResponse(c, resp, t.response, "text/plain; charset=utf-8") } }
func (s *ConfigSuite) TestBootstrapConfig(c *gc.C) { for i, test := range bootstrapConfigTests { c.Logf("test %d: %s", i, test.info) attrs := validAttrs().Merge(test.insert).Delete(test.remove...) credentialAttrs := make(map[string]string, len(attrs)) for k, v := range attrs.Delete("type") { credentialAttrs[k] = fmt.Sprintf("%v", v) } testConfig := newConfig(c, attrs) preparedConfig, err := jp.Provider.BootstrapConfig(environs.BootstrapConfigParams{ Config: testConfig, Credentials: cloud.NewCredential( cloud.UserPassAuthType, credentialAttrs, ), }) if test.err == "" { c.Check(err, jc.ErrorIsNil) attrs := preparedConfig.AllAttrs() for field, value := range test.expect { c.Check(attrs[field], gc.Equals, value) } } else { c.Check(preparedConfig, gc.IsNil) c.Check(err, gc.ErrorMatches, test.err) } } }