~juju-qa/ubuntu/yakkety/juju/juju-1.25.8

« back to all changes in this revision

Viewing changes to src/gopkg.in/juju/charm.v5/testing/testcharm.go

  • Committer: Nicholas Skaggs
  • Date: 2016-12-02 17:28:37 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161202172837-jkrbdlyjcxtrii2n
Initial commit of 1.25.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2012, 2013 Canonical Ltd.
 
2
// Licensed under the LGPLv3, see LICENCE file for details.
 
3
 
 
4
package testing
 
5
 
 
6
import (
 
7
        "archive/zip"
 
8
        "bytes"
 
9
        "fmt"
 
10
        "os"
 
11
        "path"
 
12
        "strings"
 
13
        "sync"
 
14
 
 
15
        "github.com/juju/testing/filetesting"
 
16
        gc "gopkg.in/check.v1"
 
17
 
 
18
        "gopkg.in/juju/charm.v5"
 
19
)
 
20
 
 
21
// Charm holds a charm for testing. It does not
 
22
// have a representation on disk by default, but
 
23
// can be written to disk using Archive and its ExpandTo
 
24
// method. It implements the charm.Charm interface.
 
25
//
 
26
// All methods on Charm may be called concurrently.
 
27
type Charm struct {
 
28
        meta     *charm.Meta
 
29
        config   *charm.Config
 
30
        actions  *charm.Actions
 
31
        metrics  *charm.Metrics
 
32
        revision int
 
33
 
 
34
        files filetesting.Entries
 
35
 
 
36
        makeArchiveOnce sync.Once
 
37
        archiveBytes    []byte
 
38
        archive         *charm.CharmArchive
 
39
}
 
40
 
 
41
// CharmSpec holds the specification for a charm. The fields
 
42
// hold data in YAML format.
 
43
type CharmSpec struct {
 
44
        // Meta holds the contents of metadata.yaml.
 
45
        Meta string
 
46
 
 
47
        // Config holds the contents of config.yaml.
 
48
        Config string
 
49
 
 
50
        // Actions holds the contents of actions.yaml.
 
51
        Actions string
 
52
 
 
53
        // Metrics holds the contents of metrics.yaml.
 
54
        Metrics string
 
55
 
 
56
        // Files holds any additional files that should be
 
57
        // added to the charm. If this is nil, a minimal set
 
58
        // of files will be added to ensure the charm is readable.
 
59
        Files []filetesting.Entry
 
60
 
 
61
        // Revision specifies the revision of the charm.
 
62
        Revision int
 
63
}
 
64
 
 
65
// NewCharm returns a new charm
 
66
func NewCharm(c *gc.C, spec CharmSpec) *Charm {
 
67
        ch := &Charm{
 
68
                revision: spec.Revision,
 
69
        }
 
70
        var err error
 
71
        ch.meta, err = charm.ReadMeta(strings.NewReader(spec.Meta))
 
72
        c.Assert(err, gc.IsNil)
 
73
        ch.files = append(ch.files, filetesting.File{
 
74
                Path: "metadata.yaml",
 
75
                Data: spec.Meta,
 
76
                Perm: 0644,
 
77
        })
 
78
 
 
79
        if spec.Config != "" {
 
80
                ch.config, err = charm.ReadConfig(strings.NewReader(spec.Config))
 
81
                c.Assert(err, gc.IsNil)
 
82
                ch.files = append(ch.files, filetesting.File{
 
83
                        Path: "config.yaml",
 
84
                        Data: spec.Config,
 
85
                        Perm: 0644,
 
86
                })
 
87
        }
 
88
        if spec.Actions != "" {
 
89
                ch.actions, err = charm.ReadActionsYaml(strings.NewReader(spec.Actions))
 
90
                c.Assert(err, gc.IsNil)
 
91
                ch.files = append(ch.files, filetesting.File{
 
92
                        Path: "actions.yaml",
 
93
                        Data: spec.Actions,
 
94
                        Perm: 0644,
 
95
                })
 
96
        }
 
97
        if spec.Metrics != "" {
 
98
                ch.metrics, err = charm.ReadMetrics(strings.NewReader(spec.Metrics))
 
99
                c.Assert(err, gc.IsNil)
 
100
                ch.files = append(ch.files, filetesting.File{
 
101
                        Path: "metrics.yaml",
 
102
                        Data: spec.Metrics,
 
103
                        Perm: 0644,
 
104
                })
 
105
        }
 
106
        if spec.Files == nil {
 
107
                ch.files = append(ch.files, filetesting.File{
 
108
                        Path: "hooks/install",
 
109
                        Data: "#!/bin/sh\n",
 
110
                        Perm: 0755,
 
111
                }, filetesting.File{
 
112
                        Path: "hooks/start",
 
113
                        Data: "#!/bin/sh\n",
 
114
                        Perm: 0755,
 
115
                })
 
116
        } else {
 
117
                ch.files = append(ch.files, spec.Files...)
 
118
                // Check for duplicates.
 
119
                names := make(map[string]bool)
 
120
                for _, f := range ch.files {
 
121
                        name := path.Clean(f.GetPath())
 
122
                        if names[name] {
 
123
                                panic(fmt.Errorf("duplicate file entry %q", f.GetPath()))
 
124
                        }
 
125
                        names[name] = true
 
126
                }
 
127
        }
 
128
        return ch
 
129
}
 
130
 
 
131
// Meta implements charm.Charm.Meta.
 
132
func (ch *Charm) Meta() *charm.Meta {
 
133
        return ch.meta
 
134
}
 
135
 
 
136
// Config implements charm.Charm.Config.
 
137
func (ch *Charm) Config() *charm.Config {
 
138
        if ch.config == nil {
 
139
                return &charm.Config{
 
140
                        Options: map[string]charm.Option{},
 
141
                }
 
142
        }
 
143
        return ch.config
 
144
}
 
145
 
 
146
// Metrics implements charm.Charm.Metrics.
 
147
func (ch *Charm) Metrics() *charm.Metrics {
 
148
        return ch.metrics
 
149
}
 
150
 
 
151
// Actions implements charm.Charm.Actions.
 
152
func (ch *Charm) Actions() *charm.Actions {
 
153
        if ch.actions == nil {
 
154
                return &charm.Actions{}
 
155
        }
 
156
        return ch.actions
 
157
}
 
158
 
 
159
// Revision implements charm.Charm.Revision.
 
160
func (ch *Charm) Revision() int {
 
161
        return ch.revision
 
162
}
 
163
 
 
164
// Archive returns a charm archive holding the charm.
 
165
func (ch *Charm) Archive() *charm.CharmArchive {
 
166
        ch.makeArchiveOnce.Do(ch.makeArchive)
 
167
        return ch.archive
 
168
}
 
169
 
 
170
// ArchiveBytes returns the contents of the charm archive
 
171
// holding the charm.
 
172
func (ch *Charm) ArchiveBytes() []byte {
 
173
        ch.makeArchiveOnce.Do(ch.makeArchive)
 
174
        return ch.archiveBytes
 
175
}
 
176
 
 
177
func (ch *Charm) makeArchive() {
 
178
        var buf bytes.Buffer
 
179
        zw := zip.NewWriter(&buf)
 
180
 
 
181
        for _, f := range ch.files {
 
182
                addZipEntry(zw, f)
 
183
        }
 
184
        if err := zw.Close(); err != nil {
 
185
                panic(err)
 
186
        }
 
187
        // ReadCharmArchiveFromReader requires a ReaderAt, so make one.
 
188
        r := bytes.NewReader(buf.Bytes())
 
189
 
 
190
        // Actually make the charm archive.
 
191
        archive, err := charm.ReadCharmArchiveFromReader(r, int64(buf.Len()))
 
192
        if err != nil {
 
193
                panic(err)
 
194
        }
 
195
        ch.archiveBytes = buf.Bytes()
 
196
        ch.archive = archive
 
197
        ch.archive.SetRevision(ch.revision)
 
198
}
 
199
 
 
200
func addZipEntry(zw *zip.Writer, f filetesting.Entry) {
 
201
        h := &zip.FileHeader{
 
202
                Name: f.GetPath(),
 
203
                // Don't bother compressing - the contents are so small that
 
204
                // it will just slow things down for no particular benefit.
 
205
                Method: zip.Store,
 
206
        }
 
207
        contents := ""
 
208
        switch f := f.(type) {
 
209
        case filetesting.Dir:
 
210
                h.SetMode(os.ModeDir | 0755)
 
211
        case filetesting.File:
 
212
                h.SetMode(f.Perm)
 
213
                contents = f.Data
 
214
        case filetesting.Symlink:
 
215
                h.SetMode(os.ModeSymlink | 0777)
 
216
                contents = f.Link
 
217
        }
 
218
        w, err := zw.CreateHeader(h)
 
219
        if err != nil {
 
220
                panic(err)
 
221
        }
 
222
        if contents != "" {
 
223
                if _, err := w.Write([]byte(contents)); err != nil {
 
224
                        panic(err)
 
225
                }
 
226
        }
 
227
}