LEFT | RIGHT |
(no file at all) | |
1 // Copyright 2012, 2013 Canonical Ltd. | 1 // Copyright 2012, 2013 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 package main | 4 package main |
5 | 5 |
6 import ( | 6 import ( |
7 "bytes" | 7 "bytes" |
8 "fmt" | 8 "fmt" |
9 "io/ioutil" | 9 "io/ioutil" |
10 "os" | 10 "os" |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 func (suite *PluginSuite) TestRunPluginWithFailing(c *C) { | 85 func (suite *PluginSuite) TestRunPluginWithFailing(c *C) { |
86 suite.makeFailingPlugin("foo", 2) | 86 suite.makeFailingPlugin("foo", 2) |
87 ctx := testing.Context(c) | 87 ctx := testing.Context(c) |
88 err := RunPlugin(ctx, "foo", []string{"some params"}) | 88 err := RunPlugin(ctx, "foo", []string{"some params"}) |
89 c.Assert(err, ErrorMatches, "exit status 2") | 89 c.Assert(err, ErrorMatches, "exit status 2") |
90 c.Assert(testing.Stdout(ctx), Equals, "failing\n") | 90 c.Assert(testing.Stdout(ctx), Equals, "failing\n") |
91 c.Assert(testing.Stderr(ctx), Equals, "") | 91 c.Assert(testing.Stderr(ctx), Equals, "") |
92 } | 92 } |
93 | 93 |
94 func (suite *PluginSuite) TestGatherDescriptionsInParallel(c *C) { | 94 func (suite *PluginSuite) TestGatherDescriptionsInParallel(c *C) { |
95 » suite.makeFullPlugin(PluginParams{Name: "foo", Sleep: 100 * time.Millise
cond}) | 95 » // Make plugins that will deadlock if we don't start them in parallel. |
96 » suite.makeFullPlugin(PluginParams{Name: "bar", Sleep: 150 * time.Millise
cond}) | 96 » // Each plugin depends on another one being started before they will |
97 » suite.makeFullPlugin(PluginParams{Name: "baz", Sleep: 300 * time.Millise
cond}) | 97 » // complete. They make a full loop, so no sequential ordering will ever |
98 » suite.makeFullPlugin(PluginParams{Name: "error", ExitStatus: 1, Sleep: 1
00 * time.Millisecond}) | 98 » // succeed. |
99 » suite.makeFullPlugin(PluginParams{Name: "slow", Sleep: 200 * time.Millis
econd}) | 99 » suite.makeFullPlugin(PluginParams{Name: "foo", Creates: "foo", DependsOn
: "bar"}) |
100 | 100 » suite.makeFullPlugin(PluginParams{Name: "bar", Creates: "bar", DependsOn
: "baz"}) |
101 » start := time.Now() | 101 » suite.makeFullPlugin(PluginParams{Name: "baz", Creates: "baz", DependsOn
: "error"}) |
102 » results := GetPluginDescriptions() | 102 » suite.makeFullPlugin(PluginParams{Name: "error", ExitStatus: 1, Creates:
"error", DependsOn: "foo"}) |
103 » elapsed := time.Since(start) | 103 |
104 | 104 » // If the code was wrong, GetPluginDescriptions would deadlock, |
105 » // 300 for baz above + 50ms wiggle room | 105 » // so timeout after a short while |
106 » expectedDuration := 350 * time.Millisecond | 106 » resultChan := make(chan []PluginDescription) |
107 | 107 » go func() { |
108 » c.Assert(results, HasLen, 5) | 108 » » resultChan <- GetPluginDescriptions() |
109 » c.Check(elapsed, DurationLessThan, expectedDuration) | 109 » }() |
| 110 » // 10 seconds is arbitrary but should always be generously long. Test |
| 111 » // actually only takes about 15ms in practice. But 10s allows for system
hiccups, etc. |
| 112 » waitTime := 10 * time.Second |
| 113 » var results []PluginDescription |
| 114 » select { |
| 115 » case results = <-resultChan: |
| 116 » » break |
| 117 » case <-time.After(waitTime): |
| 118 » » c.Fatalf("Took too more than %fs to complete.", waitTime.Seconds
()) |
| 119 » } |
| 120 |
| 121 » c.Assert(results, HasLen, 4) |
110 c.Assert(results[0].name, Equals, "bar") | 122 c.Assert(results[0].name, Equals, "bar") |
111 c.Assert(results[0].description, Equals, "bar description") | 123 c.Assert(results[0].description, Equals, "bar description") |
112 c.Assert(results[1].name, Equals, "baz") | 124 c.Assert(results[1].name, Equals, "baz") |
113 c.Assert(results[1].description, Equals, "baz description") | 125 c.Assert(results[1].description, Equals, "baz description") |
114 c.Assert(results[2].name, Equals, "error") | 126 c.Assert(results[2].name, Equals, "error") |
115 c.Assert(results[2].description, Equals, "error occurred running 'juju-e
rror --description'") | 127 c.Assert(results[2].description, Equals, "error occurred running 'juju-e
rror --description'") |
116 c.Assert(results[3].name, Equals, "foo") | 128 c.Assert(results[3].name, Equals, "foo") |
117 c.Assert(results[3].description, Equals, "foo description") | 129 c.Assert(results[3].description, Equals, "foo description") |
118 c.Assert(results[4].name, Equals, "slow") | |
119 c.Assert(results[4].description, Equals, "slow description") | |
120 } | 130 } |
121 | 131 |
122 func (suite *PluginSuite) TestHelpPluginsWithNoPlugins(c *C) { | 132 func (suite *PluginSuite) TestHelpPluginsWithNoPlugins(c *C) { |
123 output := badrun(c, 0, "help", "plugins") | 133 output := badrun(c, 0, "help", "plugins") |
124 c.Assert(output, HasPrefix, PluginTopicText) | 134 c.Assert(output, HasPrefix, PluginTopicText) |
125 c.Assert(output, HasSuffix, "\n\nNo plugins found.\n") | 135 c.Assert(output, HasSuffix, "\n\nNo plugins found.\n") |
126 } | 136 } |
127 | 137 |
128 func (suite *PluginSuite) TestHelpPluginsWithPlugins(c *C) { | 138 func (suite *PluginSuite) TestHelpPluginsWithPlugins(c *C) { |
129 suite.makeFullPlugin(PluginParams{Name: "foo"}) | 139 suite.makeFullPlugin(PluginParams{Name: "foo"}) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 | 172 |
163 func (suite *PluginSuite) makeFailingPlugin(name string, exitStatus int) { | 173 func (suite *PluginSuite) makeFailingPlugin(name string, exitStatus int) { |
164 content := fmt.Sprintf("#!/bin/bash\necho failing\nexit %d", exitStatus) | 174 content := fmt.Sprintf("#!/bin/bash\necho failing\nexit %d", exitStatus) |
165 filename := testing.HomePath(JujuPluginPrefix + name) | 175 filename := testing.HomePath(JujuPluginPrefix + name) |
166 ioutil.WriteFile(filename, []byte(content), 0755) | 176 ioutil.WriteFile(filename, []byte(content), 0755) |
167 } | 177 } |
168 | 178 |
169 type PluginParams struct { | 179 type PluginParams struct { |
170 Name string | 180 Name string |
171 ExitStatus int | 181 ExitStatus int |
172 » Sleep time.Duration | 182 » Creates string |
| 183 » DependsOn string |
173 } | 184 } |
174 | 185 |
175 const pluginTemplate = `#!/bin/bash | 186 const pluginTemplate = `#!/bin/bash |
176 | 187 |
177 if [ "$1" = "--description" ]; then | 188 if [ "$1" = "--description" ]; then |
178 sleep {{.Sleep.Seconds}} | 189 if [ -n "{{.Creates}}" ]; then |
| 190 touch "{{.Creates}}" |
| 191 fi |
| 192 if [ -n "{{.DependsOn}}" ]; then |
| 193 # Sleep 10ms while waiting to allow other stuff to do work |
| 194 while [ ! -e "{{.DependsOn}}" ]; do sleep 0.010; done |
| 195 fi |
179 echo "{{.Name}} description" | 196 echo "{{.Name}} description" |
180 exit {{.ExitStatus}} | 197 exit {{.ExitStatus}} |
| 198 else |
| 199 echo "No --description" >2 |
181 fi | 200 fi |
182 | 201 |
183 if [ "$1" = "--help" ]; then | 202 if [ "$1" = "--help" ]; then |
184 echo "{{.Name}} longer help" | 203 echo "{{.Name}} longer help" |
185 echo "" | 204 echo "" |
186 echo "something useful" | 205 echo "something useful" |
187 exit {{.ExitStatus}} | 206 exit {{.ExitStatus}} |
188 fi | 207 fi |
189 | 208 |
190 echo {{.Name}} $* | 209 echo {{.Name}} $* |
191 exit {{.ExitStatus}} | 210 exit {{.ExitStatus}} |
192 ` | 211 ` |
193 | 212 |
194 func (suite *PluginSuite) makeFullPlugin(params PluginParams) { | 213 func (suite *PluginSuite) makeFullPlugin(params PluginParams) { |
195 // Create a new template and parse the plugin into it. | 214 // Create a new template and parse the plugin into it. |
196 t := template.Must(template.New("plugin").Parse(pluginTemplate)) | 215 t := template.Must(template.New("plugin").Parse(pluginTemplate)) |
197 content := &bytes.Buffer{} | 216 content := &bytes.Buffer{} |
| 217 filename := testing.HomePath("juju-" + params.Name) |
| 218 // Create the files in the temp dirs, so we don't pollute the working sp
ace |
| 219 if params.Creates != "" { |
| 220 params.Creates = testing.HomePath(params.Creates) |
| 221 } |
| 222 if params.DependsOn != "" { |
| 223 params.DependsOn = testing.HomePath(params.DependsOn) |
| 224 } |
198 t.Execute(content, params) | 225 t.Execute(content, params) |
199 filename := testing.HomePath("juju-" + params.Name) | |
200 ioutil.WriteFile(filename, content.Bytes(), 0755) | 226 ioutil.WriteFile(filename, content.Bytes(), 0755) |
201 } | 227 } |
LEFT | RIGHT |