Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 Canonical Ltd. | |
2 // Licensed under the AGPLv3, see LICENCE file for details. | |
3 | |
4 package manual | |
5 | |
6 import ( | |
7 "fmt" | |
8 "io/ioutil" | |
9 "os" | |
10 "path/filepath" | |
11 "strings" | |
12 | |
13 gc "launchpad.net/gocheck" | |
14 | |
15 "launchpad.net/juju-core/testing" | |
16 ) | |
17 | |
18 // sshscript should only print the result on the first execution, | |
19 // to handle the case where it's called multiple times. On | |
20 // subsequent executions, it should find the next 'ssh' in $PATH | |
21 // and exec that. | |
22 var sshscript = `#!/bin/bash | |
23 if [ ! -e "$0.run" ]; then | |
24 touch "$0.run" | |
25 diff "$0.expected-input" - | |
26 exitcode=$? | |
27 if [ $exitcode -ne 0 ]; then | |
28 echo "ERROR: did not match expected input" >&2 | |
29 exit $exitcode | |
30 fi | |
31 %s | |
32 exit %d | |
33 else | |
34 export PATH=${PATH#*:} | |
35 exec ssh $* | |
36 fi` | |
37 | |
38 // sshresponse creates a fake "ssh" command in a new $PATH, | |
39 // updates $PATH, and returns a function to reset $PATH to | |
40 // its original value when called. | |
41 func sshresponse(c *gc.C, input, output string, rc int) func() { | |
rog
2013/09/14 07:28:03
I found these names quite confusing; the respond m
axw1
2013/09/16 04:56:48
Done.
| |
42 fakebin := c.MkDir() | |
43 ssh := filepath.Join(fakebin, "ssh") | |
44 sshexpectedinput := ssh + ".expected-input" | |
45 if output != "" { | |
46 output = fmt.Sprintf("cat<<EOF\n%s\nEOF", output) | |
47 } | |
48 script := fmt.Sprintf(sshscript, output, rc) | |
49 err := ioutil.WriteFile(ssh, []byte(script), 0777) | |
50 c.Assert(err, gc.IsNil) | |
51 err = ioutil.WriteFile(sshexpectedinput, []byte(input), 0644) | |
52 c.Assert(err, gc.IsNil) | |
53 return testing.PatchEnvironment("PATH", fakebin+":"+os.Getenv("PATH")) | |
thumper
2013/09/16 03:02:08
I've been thinking of better ways to get test code
axw1
2013/09/16 04:56:48
That sounds fine. Since there's no way in hell our
| |
54 } | |
55 | |
56 // sshsesponder wraps the invocation of sshresponse based on the parameters. | |
57 type sshresponder struct { | |
58 series string | |
59 arch string | |
60 | |
61 // exit code for the machine agent provisioning script. | |
62 provisionAgentExitCode int | |
63 | |
64 // there are conditions other than error in the above | |
65 // that might cause provisioning to not go ahead, such | |
66 // as tools being missing. | |
67 skipProvisionAgent bool | |
68 } | |
69 | |
70 func (r sshresponder) respond(c *gc.C) func() { | |
rog
2013/09/14 07:28:03
I'd like to see a doc comment on this please.
axw1
2013/09/16 04:56:48
Done.
| |
71 series := r.series | |
72 if series == "" { | |
73 series = "precise" | |
74 } | |
75 arch := r.arch | |
76 if arch == "" { | |
77 arch = "amd64" | |
78 } | |
79 detectionoutput := strings.Join([]string{ | |
80 series, | |
81 arch, | |
82 "MemTotal: 4096 kB", | |
83 "processor: 0", | |
84 }, "\n") | |
85 // Responses are elicited conditionally, hence this mess of dynamicity. | |
86 add := func(oldf func(), input, output string, rc int) func() { | |
87 f := sshresponse(c, input, output, rc) | |
rog
2013/09/14 07:28:03
I think things can be simpler here. How about some
axw1
2013/09/16 04:56:48
Much nicer, thank you.
| |
88 if oldf != nil { | |
89 newf := f | |
90 f = func() { | |
91 newf() | |
92 oldf() | |
93 } | |
94 } | |
95 return f | |
96 } | |
97 var f func() | |
98 if !r.skipProvisionAgent { | |
99 f = add(f, "", "", r.provisionAgentExitCode) | |
100 } | |
101 f = add(f, detectionScript, detectionoutput, 0) | |
102 return add(f, checkProvisionedScript, "", 0) | |
103 } | |
OLD | NEW |