github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/worker/transport/garden_round_tripper_test.go (about)

     1  package transport_test
     2  
     3  import (
     4  	"errors"
     5  	"net/http"
     6  	"net/url"
     7  	"time"
     8  
     9  	"github.com/pf-qiu/concourse/v6/atc/db/dbfakes"
    10  	"github.com/pf-qiu/concourse/v6/atc/worker/transport"
    11  	"github.com/pf-qiu/concourse/v6/atc/worker/transport/transportfakes"
    12  	"github.com/concourse/retryhttp/retryhttpfakes"
    13  
    14  	"github.com/pf-qiu/concourse/v6/atc/db"
    15  	. "github.com/onsi/ginkgo"
    16  	. "github.com/onsi/gomega"
    17  )
    18  
    19  var _ = Describe("GardenRoundTripper #RoundTrip", func() {
    20  	var (
    21  		request          http.Request
    22  		fakeDB           *transportfakes.FakeTransportDB
    23  		fakeRoundTripper *retryhttpfakes.FakeRoundTripper
    24  		roundTripper     http.RoundTripper
    25  		response         *http.Response
    26  		err              error
    27  	)
    28  
    29  	BeforeEach(func() {
    30  		fakeDB = new(transportfakes.FakeTransportDB)
    31  		fakeRoundTripper = new(retryhttpfakes.FakeRoundTripper)
    32  		workerAddr := "some-worker-address"
    33  		roundTripper = transport.NewGardenRoundTripper("some-worker", &workerAddr, fakeDB, fakeRoundTripper)
    34  		requestUrl, err := url.Parse("http://1.2.3.4/something")
    35  		Expect(err).NotTo(HaveOccurred())
    36  
    37  		request = http.Request{
    38  			URL: requestUrl,
    39  		}
    40  
    41  		fakeRoundTripper.RoundTripReturns(&http.Response{StatusCode: http.StatusTeapot}, nil)
    42  	})
    43  
    44  	JustBeforeEach(func() {
    45  		response, err = roundTripper.RoundTrip(&request)
    46  	})
    47  
    48  	It("returns the response", func() {
    49  		Expect(err).NotTo(HaveOccurred())
    50  		Expect(response).To(Equal(&http.Response{StatusCode: http.StatusTeapot}))
    51  	})
    52  
    53  	It("sends the request with worker's garden address", func() {
    54  		Expect(fakeRoundTripper.RoundTripCallCount()).To(Equal(1))
    55  		actualRequest := fakeRoundTripper.RoundTripArgsForCall(0)
    56  		Expect(actualRequest.URL.Host).To(Equal("some-worker-address"))
    57  		Expect(actualRequest.URL.Path).To(Equal("/something"))
    58  	})
    59  
    60  	It("reuses the request cached host on subsequent calls", func() {
    61  		Expect(fakeDB.GetWorkerCallCount()).To(Equal(0))
    62  		_, err := roundTripper.RoundTrip(&request)
    63  		Expect(err).NotTo(HaveOccurred())
    64  		Expect(fakeDB.GetWorkerCallCount()).To(Equal(0))
    65  	})
    66  
    67  	Context("when inner roundtrip fails", func() {
    68  		BeforeEach(func() {
    69  			fakeRoundTripper.RoundTripReturns(nil, errors.New("some-error"))
    70  
    71  			address := "some-new-worker-address"
    72  			savedWorker := new(dbfakes.FakeWorker)
    73  			savedWorker.GardenAddrReturns(&address)
    74  			savedWorker.ExpiresAtReturns(time.Now().Add(123 * time.Minute))
    75  			savedWorker.StateReturns(db.WorkerStateRunning)
    76  
    77  			fakeDB.GetWorkerReturns(savedWorker, true, nil)
    78  		})
    79  
    80  		It("updates cached request host on subsequent call", func() {
    81  			Expect(err).To(HaveOccurred())
    82  			Expect(err.Error()).To(ContainSubstring("some-error"))
    83  
    84  			Expect(fakeRoundTripper.RoundTripCallCount()).To(Equal(1))
    85  			actualRequest := fakeRoundTripper.RoundTripArgsForCall(0)
    86  			Expect(actualRequest.URL.Host).To(Equal("some-worker-address"))
    87  			Expect(fakeDB.GetWorkerCallCount()).To(Equal(0))
    88  
    89  			_, err := roundTripper.RoundTrip(&request)
    90  			Expect(err).To(HaveOccurred())
    91  
    92  			Expect(fakeDB.GetWorkerCallCount()).To(Equal(1))
    93  			Expect(fakeRoundTripper.RoundTripCallCount()).To(Equal(2))
    94  			actualRequest = fakeRoundTripper.RoundTripArgsForCall(1)
    95  			Expect(actualRequest.URL.Host).To(Equal("some-new-worker-address"))
    96  		})
    97  
    98  		Context("when the lookup of the worker in the db errors", func() {
    99  			var expectedErr error
   100  			BeforeEach(func() {
   101  				expectedErr = errors.New("some-db-error")
   102  				fakeDB.GetWorkerReturns(nil, true, expectedErr)
   103  			})
   104  
   105  			It("throws an error", func() {
   106  				_, err := roundTripper.RoundTrip(&request)
   107  				Expect(err).To(HaveOccurred())
   108  				Expect(err.Error()).To(ContainSubstring(expectedErr.Error()))
   109  			})
   110  		})
   111  
   112  		Context("when the worker is in the DB and the garden addr is empty", func() {
   113  			BeforeEach(func() {
   114  				runningWorker := new(dbfakes.FakeWorker)
   115  				runningWorker.StateReturns(db.WorkerStateStalled)
   116  				runningWorker.GardenAddrReturns(nil)
   117  
   118  				fakeDB.GetWorkerReturns(runningWorker, true, nil)
   119  			})
   120  
   121  			It("throws a descriptive error", func() {
   122  				_, err := roundTripper.RoundTrip(&request)
   123  				Expect(err).To(MatchError("worker 'some-worker' is unreachable (state is 'stalled')"))
   124  			})
   125  		})
   126  
   127  		Context("when the worker is not found in the db", func() {
   128  			BeforeEach(func() {
   129  				fakeDB.GetWorkerReturns(nil, false, nil)
   130  			})
   131  
   132  			It("throws an error", func() {
   133  				_, err := roundTripper.RoundTrip(&request)
   134  				Expect(err).To(HaveOccurred())
   135  				Expect(err).To(Equal(transport.WorkerMissingError{WorkerName: "some-worker"}))
   136  			})
   137  		})
   138  	})
   139  })