github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/worker/gclient/retryable_garden_connection_test.go (about) 1 package gclient_test 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 8 "github.com/pf-qiu/concourse/v6/atc/worker/gclient" 9 gconn "github.com/pf-qiu/concourse/v6/atc/worker/gclient/connection" 10 11 "code.cloudfoundry.org/garden" 12 "code.cloudfoundry.org/garden/gardenfakes" 13 "github.com/pf-qiu/concourse/v6/atc/worker/gclient/connection/connectionfakes" 14 . "github.com/onsi/ginkgo" 15 . "github.com/onsi/gomega" 16 "github.com/onsi/gomega/gbytes" 17 ) 18 19 var _ = Describe("Retryable Garden Connection", func() { 20 var innerConnection *connectionfakes.FakeConnection 21 var conn gconn.Connection 22 23 BeforeEach(func() { 24 innerConnection = new(connectionfakes.FakeConnection) 25 conn = gclient.NewRetryableConnection(innerConnection) 26 }) 27 28 Describe("StreamIn", func() { 29 var spec garden.StreamInSpec 30 31 BeforeEach(func() { 32 spec = garden.StreamInSpec{ 33 Path: "some-path", 34 User: "some-user", 35 } 36 innerConnection.StreamInReturns(nil) 37 err := conn.StreamIn("some-handle", spec) 38 Expect(err).NotTo(HaveOccurred()) 39 }) 40 41 It("calls through to garden", func() { 42 Expect(innerConnection.StreamInCallCount()).To(Equal(1)) 43 calledHandle, calledSpec := innerConnection.StreamInArgsForCall(0) 44 Expect(calledHandle).To(Equal("some-handle")) 45 Expect(calledSpec).To(Equal(spec)) 46 }) 47 }) 48 49 Describe("Capacity", func() { 50 var capacity garden.Capacity 51 var gotCapacity garden.Capacity 52 var err error 53 54 BeforeEach(func() { 55 capacity = garden.Capacity{MemoryInBytes: 1024} 56 innerConnection.CapacityReturns(capacity, nil) 57 gotCapacity, err = conn.Capacity() 58 Expect(err).NotTo(HaveOccurred()) 59 }) 60 61 It("calls through to garden", func() { 62 Expect(innerConnection.CapacityCallCount()).To(Equal(1)) 63 Expect(gotCapacity).To(Equal(capacity)) 64 Expect(err).NotTo(HaveOccurred()) 65 }) 66 }) 67 68 Describe("Create", func() { 69 spec := garden.ContainerSpec{ 70 RootFSPath: "/dev/mouse", 71 } 72 73 var gotHandle string 74 var err error 75 76 BeforeEach(func() { 77 innerConnection.CreateReturns("some-handle", nil) 78 gotHandle, err = conn.Create(spec) 79 Expect(err).NotTo(HaveOccurred()) 80 }) 81 82 It("calls through to garden", func() { 83 Expect(innerConnection.CreateCallCount()).To(Equal(1)) 84 calledSpec := innerConnection.CreateArgsForCall(0) 85 Expect(calledSpec).To(Equal(spec)) 86 Expect(gotHandle).To(Equal("some-handle")) 87 Expect(err).NotTo(HaveOccurred()) 88 }) 89 }) 90 91 Describe("Destroy", func() { 92 BeforeEach(func() { 93 innerConnection.DestroyReturns(nil) 94 err := conn.Destroy("some-handle") 95 Expect(err).NotTo(HaveOccurred()) 96 }) 97 98 It("calls through to garden", func() { 99 Expect(innerConnection.DestroyCallCount()).To(Equal(1)) 100 calledHandle := innerConnection.DestroyArgsForCall(0) 101 Expect(calledHandle).To(Equal("some-handle")) 102 }) 103 }) 104 105 Describe("Stop", func() { 106 BeforeEach(func() { 107 innerConnection.StopReturns(nil) 108 err := conn.Stop("some-handle", true) 109 Expect(err).NotTo(HaveOccurred()) 110 }) 111 112 It("calls through to garden", func() { 113 Expect(innerConnection.StopCallCount()).To(Equal(1)) 114 calledHandle, kill := innerConnection.StopArgsForCall(0) 115 Expect(calledHandle).To(Equal("some-handle")) 116 Expect(kill).To(BeTrue()) 117 }) 118 }) 119 120 Describe("CurrentBandwidthLimits", func() { 121 122 handle := "suitcase" 123 124 limits := garden.BandwidthLimits{ 125 RateInBytesPerSecond: 234, 126 } 127 128 var gotLimits garden.BandwidthLimits 129 var err error 130 131 Context("CurrentBandwidthLimits succeeds", func() { 132 BeforeEach(func() { 133 innerConnection.CurrentBandwidthLimitsReturns(limits, err) 134 gotLimits, err = conn.CurrentBandwidthLimits(handle) 135 Expect(err).NotTo(HaveOccurred()) 136 }) 137 138 It("calls through to garden", func() { 139 Expect(innerConnection.CurrentBandwidthLimitsCallCount()).To(Equal(1)) 140 141 calledHandle := innerConnection.CurrentBandwidthLimitsArgsForCall(0) 142 Expect(calledHandle).To(Equal(handle)) 143 }) 144 145 It("returns the limits", func() { 146 Expect(gotLimits).To(Equal(limits)) 147 }) 148 }) 149 }) 150 151 Describe("CurrentCPULimits", func() { 152 handle := "suitcase" 153 154 limits := garden.CPULimits{ 155 LimitInShares: 7, 156 } 157 158 var gotLimits garden.CPULimits 159 var err error 160 161 Context("CurrentCPULimits succeeds", func() { 162 BeforeEach(func() { 163 innerConnection.CurrentCPULimitsReturns(limits, err) 164 gotLimits, err = conn.CurrentCPULimits(handle) 165 Expect(err).NotTo(HaveOccurred()) 166 }) 167 168 It("calls through to garden", func() { 169 Expect(innerConnection.CurrentCPULimitsCallCount()).To(Equal(1)) 170 171 calledHandle := innerConnection.CurrentCPULimitsArgsForCall(0) 172 Expect(calledHandle).To(Equal(handle)) 173 }) 174 175 It("returns the limits", func() { 176 Expect(gotLimits).To(Equal(limits)) 177 }) 178 }) 179 }) 180 181 Context("CurrentDiskLimits succeeds", func() { 182 handle := "suitcase" 183 184 limits := garden.DiskLimits{ 185 ByteHard: 234, 186 } 187 188 var gotLimits garden.DiskLimits 189 var err error 190 191 BeforeEach(func() { 192 innerConnection.CurrentDiskLimitsReturns(limits, err) 193 gotLimits, err = conn.CurrentDiskLimits(handle) 194 Expect(err).NotTo(HaveOccurred()) 195 }) 196 197 It("calls through to garden", func() { 198 Expect(innerConnection.CurrentDiskLimitsCallCount()).To(Equal(1)) 199 200 calledHandle := innerConnection.CurrentDiskLimitsArgsForCall(0) 201 Expect(calledHandle).To(Equal(handle)) 202 }) 203 204 It("returns the limits", func() { 205 Expect(gotLimits).To(Equal(limits)) 206 }) 207 }) 208 209 Describe("CurrentMemoryLimits", func() { 210 handle := "suitcase" 211 212 limits := garden.MemoryLimits{ 213 LimitInBytes: 234, 214 } 215 216 var gotLimits garden.MemoryLimits 217 var err error 218 219 Context("CurrentMemoryLimits succeeds", func() { 220 BeforeEach(func() { 221 innerConnection.CurrentMemoryLimitsReturns(limits, err) 222 gotLimits, err = conn.CurrentMemoryLimits(handle) 223 Expect(err).NotTo(HaveOccurred()) 224 }) 225 226 It("calls through to garden", func() { 227 Expect(innerConnection.CurrentMemoryLimitsCallCount()).To(Equal(1)) 228 229 calledHandle := innerConnection.CurrentMemoryLimitsArgsForCall(0) 230 Expect(calledHandle).To(Equal(handle)) 231 }) 232 233 It("returns the limits", func() { 234 Expect(gotLimits).To(Equal(limits)) 235 }) 236 }) 237 }) 238 239 Describe("Property", func() { 240 handle := "suitcase" 241 property := "dfghjkl" 242 243 var gotValue string 244 var err error 245 246 BeforeEach(func() { 247 innerConnection.PropertyReturns("some-value", err) 248 gotValue, err = conn.Property(handle, property) 249 Expect(err).NotTo(HaveOccurred()) 250 }) 251 252 It("calls through to garden", func() { 253 Expect(innerConnection.PropertyCallCount()).To(Equal(1)) 254 255 calledHandle, calledProperty := innerConnection.PropertyArgsForCall(0) 256 Expect(calledHandle).To(Equal(handle)) 257 Expect(calledProperty).To(Equal(property)) 258 }) 259 260 It("returns the value", func() { 261 Expect(gotValue).To(Equal("some-value")) 262 }) 263 }) 264 265 Describe("StreamOut", func() { 266 var spec garden.StreamOutSpec 267 268 BeforeEach(func() { 269 spec = garden.StreamOutSpec{ 270 Path: "/etc/passwd", 271 User: "admin", 272 } 273 274 innerConnection.StreamOutReturns(gbytes.NewBuffer(), nil) 275 276 _, err := conn.StreamOut("some-handle", spec) 277 Expect(err).NotTo(HaveOccurred()) 278 }) 279 280 It("calls through to garden", func() { 281 Expect(innerConnection.StreamOutCallCount()).To(Equal(1)) 282 calledHandle, calledSpec := innerConnection.StreamOutArgsForCall(0) 283 Expect(calledHandle).To(Equal("some-handle")) 284 Expect(calledSpec).To(Equal(spec)) 285 }) 286 }) 287 288 Describe("Attach", func() { 289 var ( 290 fakeProcess *gardenfakes.FakeProcess 291 process garden.Process 292 ) 293 294 processIO := garden.ProcessIO{ 295 Stdout: gbytes.NewBuffer(), 296 } 297 298 BeforeEach(func() { 299 fakeProcess = new(gardenfakes.FakeProcess) 300 fakeProcess.IDReturns("process-id") 301 innerConnection.AttachReturns(fakeProcess, nil) 302 var err error 303 process, err = conn.Attach(context.TODO(), "la-contineur", "process-id", processIO) 304 Expect(err).NotTo(HaveOccurred()) 305 }) 306 307 It("calls through to garden", func() { 308 Expect(innerConnection.AttachCallCount()).To(Equal(1)) 309 310 _, handle, processID, calledProcessIO := innerConnection.AttachArgsForCall(0) 311 Expect(handle).To(Equal("la-contineur")) 312 Expect(processID).To(Equal("process-id")) 313 Expect(calledProcessIO).To(Equal(processIO)) 314 }) 315 316 Describe("the process", func() { 317 Describe("Wait", func() { 318 BeforeEach(func() { 319 errs := make(chan error, 1) 320 errs <- fmt.Errorf("connection: decode failed: %s", io.EOF) 321 close(errs) 322 323 fakeProcess.WaitStub = func() (int, error) { 324 err := <-errs 325 if err == nil { 326 return 42, nil 327 } 328 329 return 0, err 330 } 331 }) 332 333 It("reattaches on EOF", func() { 334 result, err := process.Wait() 335 Expect(err).NotTo(HaveOccurred()) 336 Expect(result).To(Equal(42)) 337 338 Expect(innerConnection.AttachCallCount()).To(Equal(2)) 339 _, handle, processID, calledProcessIO := innerConnection.AttachArgsForCall(1) 340 Expect(handle).To(Equal("la-contineur")) 341 Expect(processID).To(Equal("process-id")) 342 Expect(calledProcessIO).To(Equal(processIO)) 343 }) 344 }) 345 346 Describe("Signal", func() { 347 BeforeEach(func() { 348 errs := make(chan error, 1) 349 errs <- io.EOF 350 close(errs) 351 352 fakeProcess.SignalStub = func(garden.Signal) error { 353 return <-errs 354 } 355 }) 356 357 It("reattaches on use of closed connection", func() { 358 Expect(process.Signal(garden.SignalTerminate)).To(Succeed()) 359 Expect(fakeProcess.SignalArgsForCall(0)).To(Equal(garden.SignalTerminate)) 360 361 Expect(innerConnection.AttachCallCount()).To(Equal(2)) 362 _, handle, processID, calledProcessIO := innerConnection.AttachArgsForCall(1) 363 Expect(handle).To(Equal("la-contineur")) 364 Expect(processID).To(Equal("process-id")) 365 Expect(calledProcessIO).To(Equal(processIO)) 366 }) 367 }) 368 369 Describe("SetTTY", func() { 370 BeforeEach(func() { 371 errs := make(chan error, 1) 372 errs <- io.EOF 373 close(errs) 374 375 fakeProcess.SetTTYStub = func(garden.TTYSpec) error { 376 return <-errs 377 } 378 }) 379 380 It("reattaches on use of closed connection", func() { 381 ttySpec := garden.TTYSpec{ 382 WindowSize: &garden.WindowSize{Columns: 345678, Rows: 45689}, 383 } 384 385 Expect(process.SetTTY(ttySpec)).To(Succeed()) 386 Expect(fakeProcess.SetTTYArgsForCall(0)).To(Equal(ttySpec)) 387 388 Expect(innerConnection.AttachCallCount()).To(Equal(2)) 389 _, handle, processID, calledProcessIO := innerConnection.AttachArgsForCall(1) 390 Expect(handle).To(Equal("la-contineur")) 391 Expect(processID).To(Equal("process-id")) 392 Expect(calledProcessIO).To(Equal(processIO)) 393 }) 394 }) 395 }) 396 }) 397 398 Describe("Run", func() { 399 var ( 400 fakeProcess *gardenfakes.FakeProcess 401 process garden.Process 402 ) 403 404 processSpec := garden.ProcessSpec{ 405 Path: "reboot", 406 } 407 408 processIO := garden.ProcessIO{ 409 Stdout: gbytes.NewBuffer(), 410 } 411 412 BeforeEach(func() { 413 fakeProcess = new(gardenfakes.FakeProcess) 414 fakeProcess.IDReturns("process-id") 415 innerConnection.RunReturns(fakeProcess, nil) 416 var err error 417 process, err = conn.Run(context.TODO(), "la-contineur", processSpec, processIO) 418 Expect(err).NotTo(HaveOccurred()) 419 }) 420 421 It("calls through to garden", func() { 422 Expect(innerConnection.RunCallCount()).To(Equal(1)) 423 424 _, handle, calledProcessSpec, calledProcessIO := innerConnection.RunArgsForCall(0) 425 Expect(handle).To(Equal("la-contineur")) 426 Expect(calledProcessSpec).To(Equal(processSpec)) 427 Expect(calledProcessIO).To(Equal(processIO)) 428 }) 429 430 Describe("the process", func() { 431 BeforeEach(func() { 432 innerConnection.AttachReturns(fakeProcess, nil) 433 }) 434 435 Describe("Wait", func() { 436 BeforeEach(func() { 437 errs := make(chan error, 1) 438 errs <- io.EOF 439 close(errs) 440 441 fakeProcess.WaitStub = func() (int, error) { 442 err := <-errs 443 if err == nil { 444 return 42, nil 445 } 446 447 return 0, err 448 } 449 }) 450 451 It("reattaches on EOF", func() { 452 Expect(process.Wait()).To(Equal(42)) 453 454 Expect(innerConnection.AttachCallCount()).To(Equal(1)) 455 _, handle, processID, calledProcessIO := innerConnection.AttachArgsForCall(0) 456 Expect(handle).To(Equal("la-contineur")) 457 Expect(processID).To(Equal("process-id")) 458 Expect(calledProcessIO).To(Equal(processIO)) 459 }) 460 }) 461 462 Describe("Signal", func() { 463 BeforeEach(func() { 464 errs := make(chan error, 1) 465 errs <- io.EOF 466 close(errs) 467 468 fakeProcess.SignalStub = func(garden.Signal) error { 469 return <-errs 470 } 471 }) 472 473 It("reattaches on use of closed connection", func() { 474 Expect(process.Signal(garden.SignalTerminate)).To(Succeed()) 475 Expect(fakeProcess.SignalArgsForCall(0)).To(Equal(garden.SignalTerminate)) 476 477 Expect(innerConnection.AttachCallCount()).To(Equal(1)) 478 _, handle, processID, calledProcessIO := innerConnection.AttachArgsForCall(0) 479 Expect(handle).To(Equal("la-contineur")) 480 Expect(processID).To(Equal("process-id")) 481 Expect(calledProcessIO).To(Equal(processIO)) 482 }) 483 }) 484 485 Describe("SetTTY", func() { 486 BeforeEach(func() { 487 errs := make(chan error, 1) 488 errs <- io.EOF 489 close(errs) 490 491 fakeProcess.SetTTYStub = func(garden.TTYSpec) error { 492 return <-errs 493 } 494 }) 495 496 It("reattaches on use of closed connection", func() { 497 ttySpec := garden.TTYSpec{ 498 WindowSize: &garden.WindowSize{Columns: 345678, Rows: 45689}, 499 } 500 501 Expect(process.SetTTY(ttySpec)).To(Succeed()) 502 Expect(fakeProcess.SetTTYArgsForCall(0)).To(Equal(ttySpec)) 503 504 Expect(innerConnection.AttachCallCount()).To(Equal(1)) 505 _, handle, processID, calledProcessIO := innerConnection.AttachArgsForCall(0) 506 Expect(handle).To(Equal("la-contineur")) 507 Expect(processID).To(Equal("process-id")) 508 Expect(calledProcessIO).To(Equal(processIO)) 509 }) 510 }) 511 }) 512 }) 513 })