1
// Copyright 2012, 2013 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
16
"github.com/juju/loggo"
17
"github.com/juju/utils"
18
gc "gopkg.in/check.v1"
20
"gopkg.in/juju/charm.v4"
23
var logger = loggo.GetLogger("juju.charm.testing.mockstore")
25
// MockStore provides a mock charm store implementation useful when testing.
26
type MockStore struct {
31
Downloads []*charm.URL
32
DownloadsNoStats []*charm.URL
33
Authorizations []string
36
InfoRequestCountNoStats int
42
// NewMockStore creates a mock charm store containing the specified charms.
43
func NewMockStore(c *gc.C, repo *Repo, charms map[string]int) *MockStore {
44
s := &MockStore{charms: charms, DefaultSeries: "precise"}
45
f, err := os.Open(repo.CharmArchivePath(c.MkDir(), "dummy"))
46
c.Assert(err, gc.IsNil)
48
buf := &bytes.Buffer{}
49
s.archiveSha256, _, err = utils.ReadSHA256(io.TeeReader(f, buf))
50
c.Assert(err, gc.IsNil)
51
s.archiveBytes = buf.Bytes()
52
c.Assert(err, gc.IsNil)
53
s.mux = http.NewServeMux()
54
s.mux.HandleFunc("/charm-info", s.serveInfo)
55
s.mux.HandleFunc("/charm-event", s.serveEvent)
56
s.mux.HandleFunc("/charm/", s.serveCharm)
57
lis, err := net.Listen("tcp", "127.0.0.1:0")
58
c.Assert(err, gc.IsNil)
60
go http.Serve(s.listener, s)
64
// Close closes the mock store's socket.
65
func (s *MockStore) Close() {
69
// Address returns the URL used to make requests to the mock store.
70
func (s *MockStore) Address() string {
71
return "http://" + s.listener.Addr().String()
74
// UpdateStoreRevision sets the revision of the specified charm to rev.
75
func (s *MockStore) UpdateStoreRevision(ch string, rev int) {
79
// ServeHTTP implements http.ServeHTTP
80
func (s *MockStore) ServeHTTP(w http.ResponseWriter, r *http.Request) {
84
func (s *MockStore) serveInfo(w http.ResponseWriter, r *http.Request) {
85
if metadata := r.Header.Get("Juju-Metadata"); metadata != "" {
86
s.Metadata = append(s.Metadata, metadata)
87
logger.Infof("Juju metadata: " + metadata)
91
if r.Form.Get("stats") == "0" {
92
s.InfoRequestCountNoStats += 1
94
s.InfoRequestCount += 1
97
response := map[string]*charm.InfoResponse{}
98
for _, url := range r.Form["charms"] {
99
cr := &charm.InfoResponse{}
101
charmURL, err := charm.ParseURL(url)
102
if err == charm.ErrUnresolvedUrl {
103
ref, err := charm.ParseReference(url)
107
charmURL, err = ref.URL(s.DefaultSeries)
112
switch charmURL.Name {
114
cr.Errors = append(cr.Errors, "badness")
116
cr.Errors = append(cr.Errors, "cannot get revision")
118
cr.Warnings = append(cr.Warnings, "foolishness")
121
if rev, ok := s.charms[charmURL.WithRevision(-1).String()]; ok {
122
if charmURL.Revision == -1 {
125
cr.Revision = charmURL.Revision
127
cr.Sha256 = s.archiveSha256
128
cr.CanonicalURL = charmURL.String()
130
cr.Errors = append(cr.Errors, "entry not found")
134
data, err := json.Marshal(response)
138
w.Header().Set("Content-Type", "application/json")
139
_, err = w.Write(data)
145
func (s *MockStore) serveEvent(w http.ResponseWriter, r *http.Request) {
147
response := map[string]*charm.EventResponse{}
148
for _, url := range r.Form["charms"] {
150
if i := strings.Index(url, "@"); i >= 0 {
154
er := &charm.EventResponse{}
156
if digest != "" && digest != "the-digest" {
157
er.Kind = "not-found"
158
er.Errors = []string{"entry not found"}
161
charmURL := charm.MustParseURL(url)
162
switch charmURL.Name {
164
er.Kind = "publish-error"
165
er.Errors = append(er.Errors, "badness")
167
er.Warnings = append(er.Warnings, "foolishness")
170
if rev, ok := s.charms[charmURL.WithRevision(-1).String()]; ok {
171
er.Kind = "published"
173
er.Digest = "the-digest"
175
er.Kind = "not-found"
176
er.Errors = []string{"entry not found"}
180
data, err := json.Marshal(response)
184
w.Header().Set("Content-Type", "application/json")
185
_, err = w.Write(data)
191
func (s *MockStore) serveCharm(w http.ResponseWriter, r *http.Request) {
192
charmURL := charm.MustParseURL("cs:" + r.URL.Path[len("/charm/"):])
195
if r.Form.Get("stats") == "0" {
196
s.DownloadsNoStats = append(s.DownloadsNoStats, charmURL)
198
s.Downloads = append(s.Downloads, charmURL)
201
if auth := r.Header.Get("Authorization"); auth != "" {
202
s.Authorizations = append(s.Authorizations, auth)
205
w.Header().Set("Connection", "close")
206
w.Header().Set("Content-Type", "application/octet-stream")
207
w.Header().Set("Content-Length", strconv.Itoa(len(s.archiveBytes)))
208
_, err := w.Write(s.archiveBytes)