github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/environs/manual/fakessh_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package manual_test 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "path/filepath" 10 "strings" 11 12 "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/environs/manual" 17 ) 18 19 // sshscript should only print the result on the first execution, 20 // to handle the case where it's called multiple times. On 21 // subsequent executions, it should find the next 'ssh' in $PATH 22 // and exec that. 23 var sshscript = `#!/bin/bash --norc 24 if [ ! -e "$0.run" ]; then 25 touch "$0.run" 26 if [ -e "$0.expected-input" ]; then 27 diff "$0.expected-input" - 28 exitcode=$? 29 if [ $exitcode -ne 0 ]; then 30 echo "ERROR: did not match expected input" >&2 31 exit $exitcode 32 fi 33 else 34 head >/dev/null 35 fi 36 # stdout 37 %s 38 # stderr 39 %s 40 exit %d 41 else 42 export PATH=${PATH#*:} 43 exec ssh $* 44 fi` 45 46 // installFakeSSH creates a fake "ssh" command in a new $PATH, 47 // updates $PATH, and returns a function to reset $PATH to its 48 // original value when called. 49 // 50 // input may be: 51 // - nil (ignore input) 52 // - a string (match input exactly) 53 // output may be: 54 // - nil (no output) 55 // - a string (stdout) 56 // - a slice of strings, of length two (stdout, stderr) 57 func installFakeSSH(c *gc.C, input, output interface{}, rc int) testing.Restorer { 58 fakebin := c.MkDir() 59 ssh := filepath.Join(fakebin, "ssh") 60 switch input := input.(type) { 61 case nil: 62 case string: 63 sshexpectedinput := ssh + ".expected-input" 64 err := ioutil.WriteFile(sshexpectedinput, []byte(input), 0644) 65 c.Assert(err, jc.ErrorIsNil) 66 default: 67 c.Errorf("input has invalid type: %T", input) 68 } 69 var stdout, stderr string 70 switch output := output.(type) { 71 case nil: 72 case string: 73 stdout = fmt.Sprintf("cat<<EOF\n%s\nEOF", output) 74 case []string: 75 c.Assert(output, gc.HasLen, 2) 76 stdout = fmt.Sprintf("cat<<EOF\n%s\nEOF", output[0]) 77 stderr = fmt.Sprintf("cat>&2<<EOF\n%s\nEOF", output[1]) 78 } 79 script := fmt.Sprintf(sshscript, stdout, stderr, rc) 80 err := ioutil.WriteFile(ssh, []byte(script), 0777) 81 c.Assert(err, jc.ErrorIsNil) 82 return testing.PatchEnvPathPrepend(fakebin) 83 } 84 85 // installDetectionFakeSSH installs a fake SSH command, which will respond 86 // to the series/hardware detection script with the specified 87 // series/arch. 88 func installDetectionFakeSSH(c *gc.C, series, arch string) testing.Restorer { 89 if series == "" { 90 series = "precise" 91 } 92 if arch == "" { 93 arch = "amd64" 94 } 95 detectionoutput := strings.Join([]string{ 96 series, 97 arch, 98 "MemTotal: 4096 kB", 99 "processor: 0", 100 }, "\n") 101 return installFakeSSH(c, manual.DetectionScript, detectionoutput, 0) 102 } 103 104 // fakeSSH wraps the invocation of InstallFakeSSH based on the parameters. 105 type fakeSSH struct { 106 Series string 107 Arch string 108 109 // Provisioned should be set to true if the fakeSSH script 110 // should respond to checkProvisioned with a non-empty result. 111 Provisioned bool 112 113 // exit code for the checkProvisioned script. 114 CheckProvisionedExitCode int 115 116 // exit code for the machine agent provisioning script. 117 ProvisionAgentExitCode int 118 119 // InitUbuntuUser should be set to true if the fakeSSH script 120 // should respond to an attempt to initialise the ubuntu user. 121 InitUbuntuUser bool 122 123 // there are conditions other than error in the above 124 // that might cause provisioning to not go ahead, such 125 // as tools being missing. 126 SkipProvisionAgent bool 127 128 // detection will be skipped if the series/hardware were 129 // detected ahead of time. This should always be set to 130 // true when testing Bootstrap. 131 SkipDetection bool 132 } 133 134 // install installs fake SSH commands, which will respond to 135 // manual provisioning/bootstrapping commands with the specified 136 // output and exit codes. 137 func (r fakeSSH) install(c *gc.C) testing.Restorer { 138 var restore testing.Restorer 139 add := func(input, output interface{}, rc int) { 140 restore = restore.Add(installFakeSSH(c, input, output, rc)) 141 } 142 if !r.SkipProvisionAgent { 143 add(nil, nil, r.ProvisionAgentExitCode) 144 } 145 if !r.SkipDetection { 146 restore.Add(installDetectionFakeSSH(c, r.Series, r.Arch)) 147 } 148 var checkProvisionedOutput interface{} 149 if r.Provisioned { 150 checkProvisionedOutput = "/etc/init/jujud-machine-0.conf" 151 } 152 add(manual.CheckProvisionedScript, checkProvisionedOutput, r.CheckProvisionedExitCode) 153 if r.InitUbuntuUser { 154 add("", nil, 0) 155 } 156 return restore 157 }