github.com/dacamp/packer@v0.10.2/provisioner/windows-restart/provisioner_test.go (about) 1 package restart 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "testing" 8 "time" 9 10 "github.com/mitchellh/packer/packer" 11 ) 12 13 func testConfig() map[string]interface{} { 14 return map[string]interface{}{} 15 } 16 17 func TestProvisioner_Impl(t *testing.T) { 18 var raw interface{} 19 raw = &Provisioner{} 20 if _, ok := raw.(packer.Provisioner); !ok { 21 t.Fatalf("must be a Provisioner") 22 } 23 } 24 25 func TestProvisionerPrepare_Defaults(t *testing.T) { 26 var p Provisioner 27 config := testConfig() 28 29 err := p.Prepare(config) 30 if err != nil { 31 t.Fatalf("err: %s", err) 32 } 33 34 if p.config.RestartTimeout != 5*time.Minute { 35 t.Errorf("unexpected remote path: %s", p.config.RestartTimeout) 36 } 37 38 if p.config.RestartCommand != "shutdown /r /f /t 0 /c \"packer restart\"" { 39 t.Errorf("unexpected remote path: %s", p.config.RestartCommand) 40 } 41 } 42 43 func TestProvisionerPrepare_ConfigRetryTimeout(t *testing.T) { 44 var p Provisioner 45 config := testConfig() 46 config["restart_timeout"] = "1m" 47 48 err := p.Prepare(config) 49 if err != nil { 50 t.Fatalf("err: %s", err) 51 } 52 53 if p.config.RestartTimeout != 1*time.Minute { 54 t.Errorf("unexpected remote path: %s", p.config.RestartTimeout) 55 } 56 } 57 58 func TestProvisionerPrepare_ConfigErrors(t *testing.T) { 59 var p Provisioner 60 config := testConfig() 61 config["restart_timeout"] = "m" 62 63 err := p.Prepare(config) 64 if err == nil { 65 t.Fatal("Expected error parsing restart_timeout but did not receive one.") 66 } 67 } 68 69 func TestProvisionerPrepare_InvalidKey(t *testing.T) { 70 var p Provisioner 71 config := testConfig() 72 73 // Add a random key 74 config["i_should_not_be_valid"] = true 75 err := p.Prepare(config) 76 if err == nil { 77 t.Fatal("should have error") 78 } 79 } 80 81 func testUi() *packer.BasicUi { 82 return &packer.BasicUi{ 83 Reader: new(bytes.Buffer), 84 Writer: new(bytes.Buffer), 85 ErrorWriter: new(bytes.Buffer), 86 } 87 } 88 89 func TestProvisionerProvision_Success(t *testing.T) { 90 config := testConfig() 91 92 // Defaults provided by Packer 93 ui := testUi() 94 p := new(Provisioner) 95 96 // Defaults provided by Packer 97 comm := new(packer.MockCommunicator) 98 p.Prepare(config) 99 waitForCommunicatorOld := waitForCommunicator 100 waitForCommunicator = func(p *Provisioner) error { 101 return nil 102 } 103 waitForRestartOld := waitForRestart 104 waitForRestart = func(p *Provisioner, comm packer.Communicator) error { 105 return nil 106 } 107 err := p.Provision(ui, comm) 108 if err != nil { 109 t.Fatal("should not have error") 110 } 111 112 expectedCommand := DefaultRestartCommand 113 114 // Should run the command without alteration 115 if comm.StartCmd.Command != expectedCommand { 116 t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command) 117 } 118 // Set this back! 119 waitForCommunicator = waitForCommunicatorOld 120 waitForRestart = waitForRestartOld 121 } 122 123 func TestProvisionerProvision_CustomCommand(t *testing.T) { 124 config := testConfig() 125 126 // Defaults provided by Packer 127 ui := testUi() 128 p := new(Provisioner) 129 expectedCommand := "specialrestart.exe -NOW" 130 config["restart_command"] = expectedCommand 131 132 // Defaults provided by Packer 133 comm := new(packer.MockCommunicator) 134 p.Prepare(config) 135 waitForCommunicatorOld := waitForCommunicator 136 waitForCommunicator = func(p *Provisioner) error { 137 return nil 138 } 139 waitForRestartOld := waitForRestart 140 waitForRestart = func(p *Provisioner, comm packer.Communicator) error { 141 return nil 142 } 143 err := p.Provision(ui, comm) 144 if err != nil { 145 t.Fatal("should not have error") 146 } 147 148 // Should run the command without alteration 149 if comm.StartCmd.Command != expectedCommand { 150 t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command) 151 } 152 // Set this back! 153 waitForCommunicator = waitForCommunicatorOld 154 waitForRestart = waitForRestartOld 155 } 156 157 func TestProvisionerProvision_RestartCommandFail(t *testing.T) { 158 config := testConfig() 159 ui := testUi() 160 p := new(Provisioner) 161 comm := new(packer.MockCommunicator) 162 comm.StartStderr = "WinRM terminated" 163 comm.StartExitStatus = 1 164 165 p.Prepare(config) 166 err := p.Provision(ui, comm) 167 if err == nil { 168 t.Fatal("should have error") 169 } 170 } 171 func TestProvisionerProvision_WaitForRestartFail(t *testing.T) { 172 config := testConfig() 173 174 // Defaults provided by Packer 175 ui := testUi() 176 p := new(Provisioner) 177 178 // Defaults provided by Packer 179 comm := new(packer.MockCommunicator) 180 p.Prepare(config) 181 waitForCommunicatorOld := waitForCommunicator 182 waitForCommunicator = func(p *Provisioner) error { 183 return fmt.Errorf("Machine did not restart properly") 184 } 185 err := p.Provision(ui, comm) 186 if err == nil { 187 t.Fatal("should have error") 188 } 189 190 // Set this back! 191 waitForCommunicator = waitForCommunicatorOld 192 } 193 194 func TestProvision_waitForRestartTimeout(t *testing.T) { 195 retryableSleep = 10 * time.Millisecond 196 config := testConfig() 197 config["restart_timeout"] = "1ms" 198 ui := testUi() 199 p := new(Provisioner) 200 comm := new(packer.MockCommunicator) 201 var err error 202 203 p.Prepare(config) 204 waitForCommunicatorOld := waitForCommunicator 205 waitDone := make(chan bool) 206 waitContinue := make(chan bool) 207 208 // Block until cancel comes through 209 waitForCommunicator = func(p *Provisioner) error { 210 for { 211 select { 212 case <-waitDone: 213 waitContinue <- true 214 } 215 } 216 } 217 218 go func() { 219 err = p.Provision(ui, comm) 220 waitDone <- true 221 }() 222 <-waitContinue 223 224 if err == nil { 225 t.Fatal("should not have error") 226 } 227 228 // Set this back! 229 waitForCommunicator = waitForCommunicatorOld 230 231 } 232 233 func TestProvision_waitForCommunicator(t *testing.T) { 234 config := testConfig() 235 236 // Defaults provided by Packer 237 ui := testUi() 238 p := new(Provisioner) 239 240 // Defaults provided by Packer 241 comm := new(packer.MockCommunicator) 242 p.comm = comm 243 p.ui = ui 244 comm.StartStderr = "WinRM terminated" 245 comm.StartExitStatus = 1 246 p.Prepare(config) 247 err := waitForCommunicator(p) 248 249 if err != nil { 250 t.Fatalf("should not have error, got: %s", err.Error()) 251 } 252 253 expectedCommand := DefaultRestartCheckCommand 254 255 // Should run the command without alteration 256 if comm.StartCmd.Command != expectedCommand { 257 t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command) 258 } 259 } 260 261 func TestProvision_waitForCommunicatorWithCancel(t *testing.T) { 262 config := testConfig() 263 264 // Defaults provided by Packer 265 ui := testUi() 266 p := new(Provisioner) 267 268 // Defaults provided by Packer 269 comm := new(packer.MockCommunicator) 270 p.comm = comm 271 p.ui = ui 272 retryableSleep = 5 * time.Second 273 p.cancel = make(chan struct{}) 274 var err error 275 276 comm.StartStderr = "WinRM terminated" 277 comm.StartExitStatus = 1 // Always fail 278 p.Prepare(config) 279 280 // Run 2 goroutines; 281 // 1st to call waitForCommunicator (that will always fail) 282 // 2nd to cancel the operation 283 waitStart := make(chan bool) 284 waitDone := make(chan bool) 285 go func() { 286 waitStart <- true 287 err = waitForCommunicator(p) 288 waitDone <- true 289 }() 290 291 go func() { 292 time.Sleep(10 * time.Millisecond) 293 <-waitStart 294 p.Cancel() 295 }() 296 <-waitDone 297 298 // Expect a Cancel error 299 if err == nil { 300 t.Fatalf("Should have err") 301 } 302 } 303 304 func TestRetryable(t *testing.T) { 305 config := testConfig() 306 307 count := 0 308 retryMe := func() error { 309 t.Logf("RetryMe, attempt number %d", count) 310 if count == 2 { 311 return nil 312 } 313 count++ 314 return errors.New(fmt.Sprintf("Still waiting %d more times...", 2-count)) 315 } 316 retryableSleep = 50 * time.Millisecond 317 p := new(Provisioner) 318 p.config.RestartTimeout = 155 * time.Millisecond 319 err := p.Prepare(config) 320 err = p.retryable(retryMe) 321 if err != nil { 322 t.Fatalf("should not have error retrying funuction") 323 } 324 325 count = 0 326 p.config.RestartTimeout = 10 * time.Millisecond 327 err = p.Prepare(config) 328 err = p.retryable(retryMe) 329 if err == nil { 330 t.Fatalf("should have error retrying funuction") 331 } 332 } 333 334 func TestProvision_Cancel(t *testing.T) { 335 config := testConfig() 336 337 // Defaults provided by Packer 338 ui := testUi() 339 p := new(Provisioner) 340 341 var err error 342 343 comm := new(packer.MockCommunicator) 344 p.Prepare(config) 345 waitStart := make(chan bool) 346 waitDone := make(chan bool) 347 348 // Block until cancel comes through 349 waitForCommunicator = func(p *Provisioner) error { 350 waitStart <- true 351 for { 352 select { 353 case <-p.cancel: 354 } 355 } 356 } 357 358 // Create two go routines to provision and cancel in parallel 359 // Provision will block until cancel happens 360 go func() { 361 err = p.Provision(ui, comm) 362 waitDone <- true 363 }() 364 365 go func() { 366 <-waitStart 367 p.Cancel() 368 }() 369 <-waitDone 370 371 // Expect interupt error 372 if err == nil { 373 t.Fatal("should have error") 374 } 375 }