launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/charm/repo_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package charm_test
     5  
     6  import (
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  
    12  	"github.com/loggo/loggo"
    13  	gc "launchpad.net/gocheck"
    14  
    15  	"launchpad.net/juju-core/charm"
    16  	charmtesting "launchpad.net/juju-core/charm/testing"
    17  	env_config "launchpad.net/juju-core/environs/config"
    18  	"launchpad.net/juju-core/testing"
    19  	jc "launchpad.net/juju-core/testing/checkers"
    20  	"launchpad.net/juju-core/testing/testbase"
    21  )
    22  
    23  type StoreSuite struct {
    24  	testbase.LoggingSuite
    25  	server *charmtesting.MockStore
    26  	store  *charm.CharmStore
    27  }
    28  
    29  var _ = gc.Suite(&StoreSuite{})
    30  
    31  func (s *StoreSuite) SetUpSuite(c *gc.C) {
    32  	s.LoggingSuite.SetUpSuite(c)
    33  	s.server = charmtesting.NewMockStore(c, map[string]int{
    34  		"cs:series/good":   23,
    35  		"cs:series/unwise": 23,
    36  		"cs:series/better": 24,
    37  		"cs:series/best":   25,
    38  	})
    39  }
    40  
    41  func (s *StoreSuite) SetUpTest(c *gc.C) {
    42  	s.LoggingSuite.SetUpTest(c)
    43  	s.PatchValue(&charm.CacheDir, c.MkDir())
    44  	s.store = charm.NewStore(s.server.Address())
    45  	s.server.Downloads = nil
    46  	s.server.Authorizations = nil
    47  	s.server.Metadata = nil
    48  }
    49  
    50  type cleanupAdder interface {
    51  	AddCleanup(testbase.CleanupFunc)
    52  }
    53  
    54  func StartTestLog(suite cleanupAdder, level loggo.Level) *loggo.TestWriter {
    55  	tw := &loggo.TestWriter{}
    56  	if err := loggo.RegisterWriter("charm-tester", tw, level); err != nil {
    57  		panic(err)
    58  	}
    59  	suite.AddCleanup(func(c *gc.C) {
    60  		loggo.RemoveWriter("charm-tester")
    61  	})
    62  	return tw
    63  }
    64  
    65  // Uses the TearDownTest from testbase.LoggingSuite
    66  
    67  func (s *StoreSuite) TearDownSuite(c *gc.C) {
    68  	s.server.Close()
    69  	s.LoggingSuite.TearDownSuite(c)
    70  }
    71  
    72  func (s *StoreSuite) TestMissing(c *gc.C) {
    73  	charmURL := charm.MustParseURL("cs:series/missing")
    74  	expect := `charm not found: cs:series/missing`
    75  	_, err := charm.Latest(s.store, charmURL)
    76  	c.Assert(err, gc.ErrorMatches, expect)
    77  	_, err = s.store.Get(charmURL)
    78  	c.Assert(err, gc.ErrorMatches, expect)
    79  }
    80  
    81  func (s *StoreSuite) TestError(c *gc.C) {
    82  	charmURL := charm.MustParseURL("cs:series/borken")
    83  	expect := `charm info errors for "cs:series/borken": badness`
    84  	_, err := charm.Latest(s.store, charmURL)
    85  	c.Assert(err, gc.ErrorMatches, expect)
    86  	_, err = s.store.Get(charmURL)
    87  	c.Assert(err, gc.ErrorMatches, expect)
    88  }
    89  
    90  func (s *StoreSuite) TestWarning(c *gc.C) {
    91  	charmURL := charm.MustParseURL("cs:series/unwise")
    92  	tw := StartTestLog(s, loggo.WARNING)
    93  	r, err := charm.Latest(s.store, charmURL)
    94  	c.Assert(r, gc.Equals, 23)
    95  	c.Assert(err, gc.IsNil)
    96  	expect := jc.SimpleMessage{
    97  		loggo.WARNING,
    98  		`charm store reports for "cs:series/unwise": foolishness`,
    99  	}
   100  	c.Assert(tw.Log, jc.LogMatches, []jc.SimpleMessage{expect})
   101  	ch, err := s.store.Get(charmURL)
   102  	c.Assert(ch, gc.NotNil)
   103  	c.Assert(err, gc.IsNil)
   104  	c.Assert(tw.Log, jc.LogMatches, []jc.SimpleMessage{expect, expect})
   105  }
   106  
   107  func (s *StoreSuite) TestLatest(c *gc.C) {
   108  	urls := []*charm.URL{
   109  		charm.MustParseURL("cs:series/good"),
   110  		charm.MustParseURL("cs:series/good-2"),
   111  		charm.MustParseURL("cs:series/good-99"),
   112  	}
   113  	revInfo, err := s.store.Latest(urls...)
   114  	c.Assert(err, gc.IsNil)
   115  	c.Assert(revInfo, gc.DeepEquals, []charm.CharmRevision{
   116  		{23, "2c9f01a53a73c221d5360207e7bb2f887ff83c32b04e58aca76c4d99fd071ec7", nil},
   117  		{23, "2c9f01a53a73c221d5360207e7bb2f887ff83c32b04e58aca76c4d99fd071ec7", nil},
   118  		{23, "2c9f01a53a73c221d5360207e7bb2f887ff83c32b04e58aca76c4d99fd071ec7", nil},
   119  	})
   120  }
   121  
   122  func (s *StoreSuite) assertCached(c *gc.C, charmURL *charm.URL) {
   123  	s.server.Downloads = nil
   124  	ch, err := s.store.Get(charmURL)
   125  	c.Assert(err, gc.IsNil)
   126  	c.Assert(ch, gc.NotNil)
   127  	c.Assert(s.server.Downloads, gc.IsNil)
   128  }
   129  
   130  func (s *StoreSuite) TestGetCacheImplicitRevision(c *gc.C) {
   131  	base := "cs:series/good"
   132  	charmURL := charm.MustParseURL(base)
   133  	revCharmURL := charm.MustParseURL(base + "-23")
   134  	ch, err := s.store.Get(charmURL)
   135  	c.Assert(err, gc.IsNil)
   136  	c.Assert(ch, gc.NotNil)
   137  	c.Assert(s.server.Downloads, gc.DeepEquals, []*charm.URL{revCharmURL})
   138  	s.assertCached(c, charmURL)
   139  	s.assertCached(c, revCharmURL)
   140  }
   141  
   142  func (s *StoreSuite) TestGetCacheExplicitRevision(c *gc.C) {
   143  	base := "cs:series/good-12"
   144  	charmURL := charm.MustParseURL(base)
   145  	ch, err := s.store.Get(charmURL)
   146  	c.Assert(err, gc.IsNil)
   147  	c.Assert(ch, gc.NotNil)
   148  	c.Assert(s.server.Downloads, gc.DeepEquals, []*charm.URL{charmURL})
   149  	s.assertCached(c, charmURL)
   150  }
   151  
   152  func (s *StoreSuite) TestGetBadCache(c *gc.C) {
   153  	c.Assert(os.Mkdir(filepath.Join(charm.CacheDir, "cache"), 0777), gc.IsNil)
   154  	base := "cs:series/good"
   155  	charmURL := charm.MustParseURL(base)
   156  	revCharmURL := charm.MustParseURL(base + "-23")
   157  	name := charm.Quote(revCharmURL.String()) + ".charm"
   158  	err := ioutil.WriteFile(filepath.Join(charm.CacheDir, "cache", name), nil, 0666)
   159  	c.Assert(err, gc.IsNil)
   160  	ch, err := s.store.Get(charmURL)
   161  	c.Assert(err, gc.IsNil)
   162  	c.Assert(ch, gc.NotNil)
   163  	c.Assert(s.server.Downloads, gc.DeepEquals, []*charm.URL{revCharmURL})
   164  	s.assertCached(c, charmURL)
   165  	s.assertCached(c, revCharmURL)
   166  }
   167  
   168  // The following tests cover the low-level CharmStore-specific API.
   169  
   170  func (s *StoreSuite) TestInfo(c *gc.C) {
   171  	charmURLs := []*charm.URL{
   172  		charm.MustParseURL("cs:series/good"),
   173  		charm.MustParseURL("cs:series/better"),
   174  		charm.MustParseURL("cs:series/best"),
   175  	}
   176  	infos, err := s.store.Info(charmURLs...)
   177  	c.Assert(err, gc.IsNil)
   178  	c.Assert(infos, gc.HasLen, 3)
   179  	expected := []int{23, 24, 25}
   180  	for i, info := range infos {
   181  		c.Assert(info.Errors, gc.IsNil)
   182  		c.Assert(info.Revision, gc.Equals, expected[i])
   183  	}
   184  }
   185  
   186  func (s *StoreSuite) TestInfoNotFound(c *gc.C) {
   187  	charmURL := charm.MustParseURL("cs:series/missing")
   188  	info, err := s.store.Info(charmURL)
   189  	c.Assert(err, gc.IsNil)
   190  	c.Assert(info, gc.HasLen, 1)
   191  	c.Assert(info[0].Errors, gc.HasLen, 1)
   192  	c.Assert(info[0].Errors[0], gc.Matches, `charm not found: cs:series/missing`)
   193  }
   194  
   195  func (s *StoreSuite) TestInfoError(c *gc.C) {
   196  	charmURL := charm.MustParseURL("cs:series/borken")
   197  	info, err := s.store.Info(charmURL)
   198  	c.Assert(err, gc.IsNil)
   199  	c.Assert(info, gc.HasLen, 1)
   200  	c.Assert(info[0].Errors, gc.DeepEquals, []string{"badness"})
   201  }
   202  
   203  func (s *StoreSuite) TestInfoWarning(c *gc.C) {
   204  	charmURL := charm.MustParseURL("cs:series/unwise")
   205  	info, err := s.store.Info(charmURL)
   206  	c.Assert(err, gc.IsNil)
   207  	c.Assert(info, gc.HasLen, 1)
   208  	c.Assert(info[0].Warnings, gc.DeepEquals, []string{"foolishness"})
   209  }
   210  
   211  func (s *StoreSuite) TestInfoDNSError(c *gc.C) {
   212  	store := charm.NewStore("http://0.1.2.3")
   213  	charmURL := charm.MustParseURL("cs:series/good")
   214  	resp, err := store.Info(charmURL)
   215  	c.Assert(resp, gc.IsNil)
   216  	expect := `Cannot access the charm store. Are you connected to the internet. Error details:.*`
   217  	c.Assert(err, gc.ErrorMatches, expect)
   218  }
   219  
   220  func (s *StoreSuite) TestEvent(c *gc.C) {
   221  	charmURL := charm.MustParseURL("cs:series/good")
   222  	event, err := s.store.Event(charmURL, "")
   223  	c.Assert(err, gc.IsNil)
   224  	c.Assert(event.Errors, gc.IsNil)
   225  	c.Assert(event.Revision, gc.Equals, 23)
   226  	c.Assert(event.Digest, gc.Equals, "the-digest")
   227  }
   228  
   229  func (s *StoreSuite) TestEventWithDigest(c *gc.C) {
   230  	charmURL := charm.MustParseURL("cs:series/good")
   231  	event, err := s.store.Event(charmURL, "the-digest")
   232  	c.Assert(err, gc.IsNil)
   233  	c.Assert(event.Errors, gc.IsNil)
   234  	c.Assert(event.Revision, gc.Equals, 23)
   235  	c.Assert(event.Digest, gc.Equals, "the-digest")
   236  }
   237  
   238  func (s *StoreSuite) TestEventNotFound(c *gc.C) {
   239  	charmURL := charm.MustParseURL("cs:series/missing")
   240  	event, err := s.store.Event(charmURL, "")
   241  	c.Assert(err, gc.ErrorMatches, `charm event not found for "cs:series/missing"`)
   242  	c.Assert(event, gc.IsNil)
   243  }
   244  
   245  func (s *StoreSuite) TestEventNotFoundDigest(c *gc.C) {
   246  	charmURL := charm.MustParseURL("cs:series/good")
   247  	event, err := s.store.Event(charmURL, "missing-digest")
   248  	c.Assert(err, gc.ErrorMatches, `charm event not found for "cs:series/good" with digest "missing-digest"`)
   249  	c.Assert(event, gc.IsNil)
   250  }
   251  
   252  func (s *StoreSuite) TestEventError(c *gc.C) {
   253  	charmURL := charm.MustParseURL("cs:series/borken")
   254  	event, err := s.store.Event(charmURL, "")
   255  	c.Assert(err, gc.IsNil)
   256  	c.Assert(event.Errors, gc.DeepEquals, []string{"badness"})
   257  }
   258  
   259  func (s *StoreSuite) TestAuthorization(c *gc.C) {
   260  	config := testing.CustomEnvironConfig(c,
   261  		testing.Attrs{"charm-store-auth": "token=value"})
   262  	store := env_config.AuthorizeCharmRepo(s.store, config)
   263  
   264  	base := "cs:series/good"
   265  	charmURL := charm.MustParseURL(base)
   266  	_, err := store.Get(charmURL)
   267  
   268  	c.Assert(err, gc.IsNil)
   269  
   270  	c.Assert(s.server.Authorizations, gc.HasLen, 1)
   271  	c.Assert(s.server.Authorizations[0], gc.Equals, "charmstore token=value")
   272  }
   273  
   274  func (s *StoreSuite) TestNilAuthorization(c *gc.C) {
   275  	config := testing.EnvironConfig(c)
   276  	store := env_config.AuthorizeCharmRepo(s.store, config)
   277  
   278  	base := "cs:series/good"
   279  	charmURL := charm.MustParseURL(base)
   280  	_, err := store.Get(charmURL)
   281  
   282  	c.Assert(err, gc.IsNil)
   283  	c.Assert(s.server.Authorizations, gc.HasLen, 0)
   284  }
   285  
   286  func (s *StoreSuite) TestMetadata(c *gc.C) {
   287  	store := s.store.WithJujuAttrs("juju-metadata")
   288  
   289  	base := "cs:series/good"
   290  	charmURL := charm.MustParseURL(base)
   291  	_, err := store.Get(charmURL)
   292  
   293  	c.Assert(err, gc.IsNil)
   294  	c.Assert(s.server.Metadata, gc.HasLen, 1)
   295  	c.Assert(s.server.Metadata[0], gc.Equals, "juju-metadata")
   296  }
   297  
   298  func (s *StoreSuite) TestNilMetadata(c *gc.C) {
   299  	base := "cs:series/good"
   300  	charmURL := charm.MustParseURL(base)
   301  	_, err := s.store.Get(charmURL)
   302  
   303  	c.Assert(err, gc.IsNil)
   304  	c.Assert(s.server.Metadata, gc.HasLen, 0)
   305  }
   306  
   307  func (s *StoreSuite) TestEventWarning(c *gc.C) {
   308  	charmURL := charm.MustParseURL("cs:series/unwise")
   309  	event, err := s.store.Event(charmURL, "")
   310  	c.Assert(err, gc.IsNil)
   311  	c.Assert(event.Warnings, gc.DeepEquals, []string{"foolishness"})
   312  }
   313  
   314  func (s *StoreSuite) TestBranchLocation(c *gc.C) {
   315  	charmURL := charm.MustParseURL("cs:series/name")
   316  	location := s.store.BranchLocation(charmURL)
   317  	c.Assert(location, gc.Equals, "lp:charms/series/name")
   318  
   319  	charmURL = charm.MustParseURL("cs:~user/series/name")
   320  	location = s.store.BranchLocation(charmURL)
   321  	c.Assert(location, gc.Equals, "lp:~user/charms/series/name/trunk")
   322  }
   323  
   324  func (s *StoreSuite) TestCharmURL(c *gc.C) {
   325  	tests := []struct{ url, loc string }{
   326  		{"cs:precise/wordpress", "lp:charms/precise/wordpress"},
   327  		{"cs:precise/wordpress", "http://launchpad.net/+branch/charms/precise/wordpress"},
   328  		{"cs:precise/wordpress", "https://launchpad.net/+branch/charms/precise/wordpress"},
   329  		{"cs:precise/wordpress", "http://code.launchpad.net/+branch/charms/precise/wordpress"},
   330  		{"cs:precise/wordpress", "https://code.launchpad.net/+branch/charms/precise/wordpress"},
   331  		{"cs:precise/wordpress", "bzr+ssh://bazaar.launchpad.net/+branch/charms/precise/wordpress"},
   332  		{"cs:~charmers/precise/wordpress", "lp:~charmers/charms/precise/wordpress/trunk"},
   333  		{"cs:~charmers/precise/wordpress", "http://launchpad.net/~charmers/charms/precise/wordpress/trunk"},
   334  		{"cs:~charmers/precise/wordpress", "https://launchpad.net/~charmers/charms/precise/wordpress/trunk"},
   335  		{"cs:~charmers/precise/wordpress", "http://code.launchpad.net/~charmers/charms/precise/wordpress/trunk"},
   336  		{"cs:~charmers/precise/wordpress", "https://code.launchpad.net/~charmers/charms/precise/wordpress/trunk"},
   337  		{"cs:~charmers/precise/wordpress", "http://launchpad.net/+branch/~charmers/charms/precise/wordpress/trunk"},
   338  		{"cs:~charmers/precise/wordpress", "https://launchpad.net/+branch/~charmers/charms/precise/wordpress/trunk"},
   339  		{"cs:~charmers/precise/wordpress", "http://code.launchpad.net/+branch/~charmers/charms/precise/wordpress/trunk"},
   340  		{"cs:~charmers/precise/wordpress", "https://code.launchpad.net/+branch/~charmers/charms/precise/wordpress/trunk"},
   341  		{"cs:~charmers/precise/wordpress", "bzr+ssh://bazaar.launchpad.net/~charmers/charms/precise/wordpress/trunk"},
   342  		{"cs:~charmers/precise/wordpress", "bzr+ssh://bazaar.launchpad.net/~charmers/charms/precise/wordpress/trunk/"},
   343  		{"cs:~charmers/precise/wordpress", "~charmers/charms/precise/wordpress/trunk"},
   344  		{"", "lp:~charmers/charms/precise/wordpress/whatever"},
   345  		{"", "lp:~charmers/whatever/precise/wordpress/trunk"},
   346  		{"", "lp:whatever/precise/wordpress"},
   347  	}
   348  	for _, t := range tests {
   349  		charmURL, err := s.store.CharmURL(t.loc)
   350  		if t.url == "" {
   351  			c.Assert(err, gc.ErrorMatches, fmt.Sprintf("unknown branch location: %q", t.loc))
   352  		} else {
   353  			c.Assert(err, gc.IsNil)
   354  			c.Assert(charmURL.String(), gc.Equals, t.url)
   355  		}
   356  	}
   357  }
   358  
   359  type LocalRepoSuite struct {
   360  	testbase.LoggingSuite
   361  	repo       *charm.LocalRepository
   362  	seriesPath string
   363  }
   364  
   365  var _ = gc.Suite(&LocalRepoSuite{})
   366  
   367  func (s *LocalRepoSuite) SetUpTest(c *gc.C) {
   368  	s.LoggingSuite.SetUpTest(c)
   369  	root := c.MkDir()
   370  	s.repo = &charm.LocalRepository{root}
   371  	s.seriesPath = filepath.Join(root, "quantal")
   372  	c.Assert(os.Mkdir(s.seriesPath, 0777), gc.IsNil)
   373  }
   374  
   375  func (s *LocalRepoSuite) addBundle(name string) string {
   376  	return testing.Charms.BundlePath(s.seriesPath, name)
   377  }
   378  
   379  func (s *LocalRepoSuite) addDir(name string) string {
   380  	return testing.Charms.ClonedDirPath(s.seriesPath, name)
   381  }
   382  
   383  func (s *LocalRepoSuite) checkNotFoundErr(c *gc.C, err error, charmURL *charm.URL) {
   384  	expect := `charm not found in "` + s.repo.Path + `": ` + charmURL.String()
   385  	c.Check(err, gc.ErrorMatches, expect)
   386  }
   387  
   388  func (s *LocalRepoSuite) TestMissingCharm(c *gc.C) {
   389  	for i, str := range []string{
   390  		"local:quantal/zebra", "local:badseries/zebra",
   391  	} {
   392  		c.Logf("test %d: %s", i, str)
   393  		charmURL := charm.MustParseURL(str)
   394  		_, err := charm.Latest(s.repo, charmURL)
   395  		s.checkNotFoundErr(c, err, charmURL)
   396  		_, err = s.repo.Get(charmURL)
   397  		s.checkNotFoundErr(c, err, charmURL)
   398  	}
   399  }
   400  
   401  func (s *LocalRepoSuite) TestMissingRepo(c *gc.C) {
   402  	c.Assert(os.RemoveAll(s.repo.Path), gc.IsNil)
   403  	_, err := charm.Latest(s.repo, charm.MustParseURL("local:quantal/zebra"))
   404  	c.Assert(err, gc.ErrorMatches, `no repository found at ".*"`)
   405  	_, err = s.repo.Get(charm.MustParseURL("local:quantal/zebra"))
   406  	c.Assert(err, gc.ErrorMatches, `no repository found at ".*"`)
   407  	c.Assert(ioutil.WriteFile(s.repo.Path, nil, 0666), gc.IsNil)
   408  	_, err = charm.Latest(s.repo, charm.MustParseURL("local:quantal/zebra"))
   409  	c.Assert(err, gc.ErrorMatches, `no repository found at ".*"`)
   410  	_, err = s.repo.Get(charm.MustParseURL("local:quantal/zebra"))
   411  	c.Assert(err, gc.ErrorMatches, `no repository found at ".*"`)
   412  }
   413  
   414  func (s *LocalRepoSuite) TestMultipleVersions(c *gc.C) {
   415  	charmURL := charm.MustParseURL("local:quantal/upgrade")
   416  	s.addDir("upgrade1")
   417  	rev, err := charm.Latest(s.repo, charmURL)
   418  	c.Assert(err, gc.IsNil)
   419  	c.Assert(rev, gc.Equals, 1)
   420  	ch, err := s.repo.Get(charmURL)
   421  	c.Assert(err, gc.IsNil)
   422  	c.Assert(ch.Revision(), gc.Equals, 1)
   423  
   424  	s.addDir("upgrade2")
   425  	rev, err = charm.Latest(s.repo, charmURL)
   426  	c.Assert(err, gc.IsNil)
   427  	c.Assert(rev, gc.Equals, 2)
   428  	ch, err = s.repo.Get(charmURL)
   429  	c.Assert(err, gc.IsNil)
   430  	c.Assert(ch.Revision(), gc.Equals, 2)
   431  
   432  	revCharmURL := charmURL.WithRevision(1)
   433  	rev, err = charm.Latest(s.repo, revCharmURL)
   434  	c.Assert(err, gc.IsNil)
   435  	c.Assert(rev, gc.Equals, 2)
   436  	ch, err = s.repo.Get(revCharmURL)
   437  	c.Assert(err, gc.IsNil)
   438  	c.Assert(ch.Revision(), gc.Equals, 1)
   439  
   440  	badRevCharmURL := charmURL.WithRevision(33)
   441  	rev, err = charm.Latest(s.repo, badRevCharmURL)
   442  	c.Assert(err, gc.IsNil)
   443  	c.Assert(rev, gc.Equals, 2)
   444  	_, err = s.repo.Get(badRevCharmURL)
   445  	s.checkNotFoundErr(c, err, badRevCharmURL)
   446  }
   447  
   448  func (s *LocalRepoSuite) TestBundle(c *gc.C) {
   449  	charmURL := charm.MustParseURL("local:quantal/dummy")
   450  	s.addBundle("dummy")
   451  
   452  	rev, err := charm.Latest(s.repo, charmURL)
   453  	c.Assert(err, gc.IsNil)
   454  	c.Assert(rev, gc.Equals, 1)
   455  	ch, err := s.repo.Get(charmURL)
   456  	c.Assert(err, gc.IsNil)
   457  	c.Assert(ch.Revision(), gc.Equals, 1)
   458  }
   459  
   460  func (s *LocalRepoSuite) TestLogsErrors(c *gc.C) {
   461  	err := ioutil.WriteFile(filepath.Join(s.seriesPath, "blah.charm"), nil, 0666)
   462  	c.Assert(err, gc.IsNil)
   463  	err = os.Mkdir(filepath.Join(s.seriesPath, "blah"), 0666)
   464  	c.Assert(err, gc.IsNil)
   465  	samplePath := s.addDir("upgrade2")
   466  	gibberish := []byte("don't parse me by")
   467  	err = ioutil.WriteFile(filepath.Join(samplePath, "metadata.yaml"), gibberish, 0666)
   468  	c.Assert(err, gc.IsNil)
   469  
   470  	tw := StartTestLog(s, loggo.WARNING)
   471  	charmURL := charm.MustParseURL("local:quantal/dummy")
   472  	s.addDir("dummy")
   473  	ch, err := s.repo.Get(charmURL)
   474  	c.Assert(err, gc.IsNil)
   475  	c.Assert(ch.Revision(), gc.Equals, 1)
   476  	c.Assert(tw.Log, jc.LogMatches, []jc.SimpleMessage{
   477  		{loggo.WARNING, `failed to load charm at ".*/quantal/blah": .*`},
   478  		{loggo.WARNING, `failed to load charm at ".*/quantal/blah.charm": .*`},
   479  		{loggo.WARNING, `failed to load charm at ".*/quantal/upgrade2": .*`},
   480  	})
   481  }
   482  
   483  func renameSibling(c *gc.C, path, name string) {
   484  	c.Assert(os.Rename(path, filepath.Join(filepath.Dir(path), name)), gc.IsNil)
   485  }
   486  
   487  func (s *LocalRepoSuite) TestIgnoresUnpromisingNames(c *gc.C) {
   488  	err := ioutil.WriteFile(filepath.Join(s.seriesPath, "blah.notacharm"), nil, 0666)
   489  	c.Assert(err, gc.IsNil)
   490  	err = os.Mkdir(filepath.Join(s.seriesPath, ".blah"), 0666)
   491  	c.Assert(err, gc.IsNil)
   492  	renameSibling(c, s.addDir("dummy"), ".dummy")
   493  	renameSibling(c, s.addBundle("dummy"), "dummy.notacharm")
   494  	charmURL := charm.MustParseURL("local:quantal/dummy")
   495  
   496  	tw := StartTestLog(s, loggo.WARNING)
   497  	_, err = s.repo.Get(charmURL)
   498  	s.checkNotFoundErr(c, err, charmURL)
   499  	_, err = charm.Latest(s.repo, charmURL)
   500  	s.checkNotFoundErr(c, err, charmURL)
   501  	c.Assert(tw.Log, gc.HasLen, 0)
   502  }
   503  
   504  func (s *LocalRepoSuite) TestFindsSymlinks(c *gc.C) {
   505  	realPath := testing.Charms.ClonedDirPath(c.MkDir(), "dummy")
   506  	linkPath := filepath.Join(s.seriesPath, "dummy")
   507  	err := os.Symlink(realPath, linkPath)
   508  	c.Assert(err, gc.IsNil)
   509  	ch, err := s.repo.Get(charm.MustParseURL("local:quantal/dummy"))
   510  	c.Assert(err, gc.IsNil)
   511  	checkDummy(c, ch, linkPath)
   512  }