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  })