gopkg.in/hashicorp/packer.v1@v1.3.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/hashicorp/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 restart timeout: %s", p.config.RestartTimeout) 36 } 37 38 if p.config.RestartCommand != "shutdown /r /f /t 0 /c \"packer restart\"" { 39 t.Errorf("unexpected restart command: %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 restart timeout: %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.StartStdout = "WIN-V4CEJ7MC5SN restarted." 246 comm.StartExitStatus = 1 247 p.Prepare(config) 248 err := waitForCommunicator(p) 249 250 if err != nil { 251 t.Fatalf("should not have error, got: %s", err.Error()) 252 } 253 254 expectedCommand := DefaultRestartCheckCommand 255 256 // Should run the command without alteration 257 if comm.StartCmd.Command != expectedCommand { 258 t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command) 259 } 260 } 261 262 func TestProvision_waitForCommunicatorWithCancel(t *testing.T) { 263 config := testConfig() 264 265 // Defaults provided by Packer 266 ui := testUi() 267 p := new(Provisioner) 268 269 // Defaults provided by Packer 270 comm := new(packer.MockCommunicator) 271 p.comm = comm 272 p.ui = ui 273 retryableSleep = 5 * time.Second 274 p.cancel = make(chan struct{}) 275 var err error 276 277 comm.StartStderr = "WinRM terminated" 278 comm.StartExitStatus = 1 // Always fail 279 p.Prepare(config) 280 281 // Run 2 goroutines; 282 // 1st to call waitForCommunicator (that will always fail) 283 // 2nd to cancel the operation 284 waitStart := make(chan bool) 285 waitDone := make(chan bool) 286 go func() { 287 waitStart <- true 288 err = waitForCommunicator(p) 289 waitDone <- true 290 }() 291 292 go func() { 293 time.Sleep(10 * time.Millisecond) 294 <-waitStart 295 p.Cancel() 296 }() 297 <-waitDone 298 299 // Expect a Cancel error 300 if err == nil { 301 t.Fatalf("Should have err") 302 } 303 } 304 305 func TestRetryable(t *testing.T) { 306 config := testConfig() 307 308 count := 0 309 retryMe := func() error { 310 t.Logf("RetryMe, attempt number %d", count) 311 if count == 2 { 312 return nil 313 } 314 count++ 315 return errors.New(fmt.Sprintf("Still waiting %d more times...", 2-count)) 316 } 317 retryableSleep = 50 * time.Millisecond 318 p := new(Provisioner) 319 p.config.RestartTimeout = 155 * time.Millisecond 320 err := p.Prepare(config) 321 err = p.retryable(retryMe) 322 if err != nil { 323 t.Fatalf("should not have error retrying function") 324 } 325 326 count = 0 327 p.config.RestartTimeout = 10 * time.Millisecond 328 err = p.Prepare(config) 329 err = p.retryable(retryMe) 330 if err == nil { 331 t.Fatalf("should have error retrying function") 332 } 333 } 334 335 func TestProvision_Cancel(t *testing.T) { 336 config := testConfig() 337 338 // Defaults provided by Packer 339 ui := testUi() 340 p := new(Provisioner) 341 342 var err error 343 344 comm := new(packer.MockCommunicator) 345 p.Prepare(config) 346 waitStart := make(chan bool) 347 waitDone := make(chan bool) 348 349 // Block until cancel comes through 350 waitForCommunicator = func(p *Provisioner) error { 351 waitStart <- true 352 for { 353 select { 354 case <-p.cancel: 355 } 356 } 357 } 358 359 // Create two go routines to provision and cancel in parallel 360 // Provision will block until cancel happens 361 go func() { 362 err = p.Provision(ui, comm) 363 waitDone <- true 364 }() 365 366 go func() { 367 <-waitStart 368 p.Cancel() 369 }() 370 <-waitDone 371 372 // Expect interrupt error 373 if err == nil { 374 t.Fatal("should have error") 375 } 376 }