<commit_before>package route_fetcher_test

import (
	"errors"
	"time"

	"github.com/cloudfoundry-incubator/routing-api"
	"github.com/cloudfoundry-incubator/routing-api/db"
	fake_routing_api "github.com/cloudfoundry-incubator/routing-api/fake_routing_api"
	token_fetcher "github.com/cloudfoundry-incubator/uaa-token-fetcher"
	testTokenFetcher "github.com/cloudfoundry-incubator/uaa-token-fetcher/fakes"
	"github.com/cloudfoundry/gorouter/config"
	testRegistry "github.com/cloudfoundry/gorouter/registry/fakes"
	"github.com/cloudfoundry/gorouter/route"
	"github.com/cloudfoundry/gosteno"

	. "github.com/cloudfoundry/gorouter/route_fetcher"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("RouteFetcher", func() {
	var (
		cfg           *config.Config
		tokenFetcher  *testTokenFetcher.FakeTokenFetcher
		registry      *testRegistry.FakeRegistryInterface
		fetcher       *RouteFetcher
		logger        *gosteno.Logger
		sink          *gosteno.TestingSink
		client        *fake_routing_api.FakeClient
		retryInterval int

		token *token_fetcher.Token

		response []db.Route
	)

	BeforeEach(func() {
		cfg = config.DefaultConfig()

		retryInterval := 0
		tokenFetcher = &testTokenFetcher.FakeTokenFetcher{}
		registry = &testRegistry.FakeRegistryInterface{}
		sink = gosteno.NewTestingSink()

		loggerConfig := &gosteno.Config{
			Sinks: []gosteno.Sink{
				sink,
			},
		}
		gosteno.Init(loggerConfig)
		logger = gosteno.NewLogger("route_fetcher_test")

		token = &token_fetcher.Token{
			AccessToken: "access_token",
			ExpireTime:  5,
		}

		client = &fake_routing_api.FakeClient{}
		fetcher = NewRouteFetcher(logger, tokenFetcher, registry, cfg, client, retryInterval)
	})

	Describe(".FetchRoutes", func() {
		BeforeEach(func() {
			tokenFetcher.FetchTokenReturns(token, nil)

			response = []db.Route{
				{
					Route:   "foo",
					Port:    1,
					IP:      "1.1.1.1",
					TTL:     1,
					LogGuid: "guid",
				},
				{
					Route:   "foo",
					Port:    2,
					IP:      "2.2.2.2",
					TTL:     1,
					LogGuid: "guid",
				},
				{
					Route:   "bar",
					Port:    3,
					IP:      "3.3.3.3",
					TTL:     1,
					LogGuid: "guid",
				},
			}

		})

		It("updates the route registry", func() {
			client.RoutesReturns(response, nil)

			err := fetcher.FetchRoutes()
			Expect(err).ToNot(HaveOccurred())

			Expect(registry.RegisterCallCount()).To(Equal(3))

			for i := 0; i < 3; i++ {
				response := response[i]
				uri, endpoint := registry.RegisterArgsForCall(i)
				Expect(uri).To(Equal(route.Uri(response.Route)))
				Expect(endpoint).To(Equal(route.NewEndpoint(response.LogGuid, response.IP, uint16(response.Port), response.LogGuid, nil, response.TTL)))
			}
		})

		It("removes unregistered routes", func() {
			secondResponse := []db.Route{
				response[0],
			}

			client.RoutesReturns(response, nil)

			err := fetcher.FetchRoutes()
			Expect(err).ToNot(HaveOccurred())
			Expect(registry.RegisterCallCount()).To(Equal(3))

			client.RoutesReturns(secondResponse, nil)

			err = fetcher.FetchRoutes()
			Expect(err).ToNot(HaveOccurred())
			Expect(registry.RegisterCallCount()).To(Equal(4))
			Expect(registry.UnregisterCallCount()).To(Equal(2))

			for i := 0; i < 2; i++ {
				response := response[i+1]
				uri, endpoint := registry.UnregisterArgsForCall(i)
				Expect(uri).To(Equal(route.Uri(response.Route)))
				Expect(endpoint).To(Equal(route.NewEndpoint(response.LogGuid, response.IP, uint16(response.Port), response.LogGuid, nil, response.TTL)))
			}
		})

		Context("when the routing api returns an error", func() {
			It("returns an error", func() {
				client.RoutesReturns(nil, errors.New("Oops!"))

				err := fetcher.FetchRoutes()
				Expect(err).To(HaveOccurred())
			})
		})

		Context("When the token fetcher returns an error", func() {
			BeforeEach(func() {
				tokenFetcher.FetchTokenReturns(nil, errors.New("token fetcher error"))
			})

			It("returns an error", func() {
				err := fetcher.FetchRoutes()
				Expect(err).To(HaveOccurred())
				Expect(registry.RegisterCallCount()).To(Equal(0))
			})
		})
	})

	Describe(".StartFetchCycle", func() {
		BeforeEach(func() {
			cfg.PruneStaleDropletsInterval = 10 * time.Millisecond
			fetcher = NewRouteFetcher(logger, tokenFetcher, registry, cfg, client, retryInterval)

			tokenFetcher.FetchTokenReturns(token, nil)

			client.RoutesReturns(response, nil)
		})

		It("periodically fetches routes", func() {
			received := make(chan struct{})

			client.RoutesStub = func() ([]db.Route, error) {
				received <- struct{}{}
				return []db.Route{}, nil
			}

			fetcher.StartFetchCycle()

			Eventually(received).Should(Receive())
			Eventually(received).Should(Receive())
		})

		It("logs the error", func() {
			tokenFetcher.FetchTokenReturns(nil, errors.New("Unauthorized"))
			fetcher.StartFetchCycle()

			time.Sleep(cfg.PruneStaleDropletsInterval + 10*time.Millisecond)
			Expect(sink.Records()).ToNot(BeNil())
			Expect(sink.Records()[0].Message).To(Equal("Unauthorized"))
		})

		It("logs the error", func() {
			tokenFetcher.FetchTokenReturns(nil, errors.New("Unauthorized"))
			fetcher.StartFetchCycle()

			time.Sleep(cfg.PruneStaleDropletsInterval + 10*time.Millisecond)
			Expect(sink.Records()).ToNot(BeNil())
			Expect(sink.Records()[0].Message).To(Equal("Unauthorized"))
		})
	})

	Describe(".StartEventCycle", func() {
		Context("when fetching the auth token fails", func() {
			It("logs the failure and tries again", func() {
				tokenFetcher.FetchTokenReturns(nil, errors.New("failed to get the token"))
				fetcher.StartEventCycle()

				time.Sleep(1 * time.Millisecond)
				Expect(sink.Records()).ToNot(BeNil())
				Expect(sink.Records()[0].Message).To(Equal("failed to get the token"))
				Eventually(func() int {
					return tokenFetcher.FetchTokenCallCount()
				}, 1).Should(BeNumerically(">=", 2))
			})
		})<commit_msg>Remove additional time.Sleep calls from route_fetcher tests<commit_after>package route_fetcher_test

import (
	"errors"
	"time"

	"github.com/cloudfoundry-incubator/routing-api"
	"github.com/cloudfoundry-incubator/routing-api/db"
	fake_routing_api "github.com/cloudfoundry-incubator/routing-api/fake_routing_api"
	token_fetcher "github.com/cloudfoundry-incubator/uaa-token-fetcher"
	testTokenFetcher "github.com/cloudfoundry-incubator/uaa-token-fetcher/fakes"
	"github.com/cloudfoundry/gorouter/config"
	testRegistry "github.com/cloudfoundry/gorouter/registry/fakes"
	"github.com/cloudfoundry/gorouter/route"
	"github.com/cloudfoundry/gosteno"

	. "github.com/cloudfoundry/gorouter/route_fetcher"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("RouteFetcher", func() {
	var (
		cfg           *config.Config
		tokenFetcher  *testTokenFetcher.FakeTokenFetcher
		registry      *testRegistry.FakeRegistryInterface
		fetcher       *RouteFetcher
		logger        *gosteno.Logger
		sink          *gosteno.TestingSink
		client        *fake_routing_api.FakeClient
		retryInterval int

		token *token_fetcher.Token

		response []db.Route
	)

	BeforeEach(func() {
		cfg = config.DefaultConfig()

		retryInterval := 0
		tokenFetcher = &testTokenFetcher.FakeTokenFetcher{}
		registry = &testRegistry.FakeRegistryInterface{}
		sink = gosteno.NewTestingSink()

		loggerConfig := &gosteno.Config{
			Sinks: []gosteno.Sink{
				sink,
			},
		}
		gosteno.Init(loggerConfig)
		logger = gosteno.NewLogger("route_fetcher_test")

		token = &token_fetcher.Token{
			AccessToken: "access_token",
			ExpireTime:  5,
		}

		client = &fake_routing_api.FakeClient{}
		fetcher = NewRouteFetcher(logger, tokenFetcher, registry, cfg, client, retryInterval)
	})

	Describe(".FetchRoutes", func() {
		BeforeEach(func() {
			tokenFetcher.FetchTokenReturns(token, nil)

			response = []db.Route{
				{
					Route:   "foo",
					Port:    1,
					IP:      "1.1.1.1",
					TTL:     1,
					LogGuid: "guid",
				},
				{
					Route:   "foo",
					Port:    2,
					IP:      "2.2.2.2",
					TTL:     1,
					LogGuid: "guid",
				},
				{
					Route:   "bar",
					Port:    3,
					IP:      "3.3.3.3",
					TTL:     1,
					LogGuid: "guid",
				},
			}

		})

		It("updates the route registry", func() {
			client.RoutesReturns(response, nil)

			err := fetcher.FetchRoutes()
			Expect(err).ToNot(HaveOccurred())

			Expect(registry.RegisterCallCount()).To(Equal(3))

			for i := 0; i < 3; i++ {
				response := response[i]
				uri, endpoint := registry.RegisterArgsForCall(i)
				Expect(uri).To(Equal(route.Uri(response.Route)))
				Expect(endpoint).To(Equal(route.NewEndpoint(response.LogGuid, response.IP, uint16(response.Port), response.LogGuid, nil, response.TTL)))
			}
		})

		It("removes unregistered routes", func() {
			secondResponse := []db.Route{
				response[0],
			}

			client.RoutesReturns(response, nil)

			err := fetcher.FetchRoutes()
			Expect(err).ToNot(HaveOccurred())
			Expect(registry.RegisterCallCount()).To(Equal(3))

			client.RoutesReturns(secondResponse, nil)

			err = fetcher.FetchRoutes()
			Expect(err).ToNot(HaveOccurred())
			Expect(registry.RegisterCallCount()).To(Equal(4))
			Expect(registry.UnregisterCallCount()).To(Equal(2))

			for i := 0; i < 2; i++ {
				response := response[i+1]
				uri, endpoint := registry.UnregisterArgsForCall(i)
				Expect(uri).To(Equal(route.Uri(response.Route)))
				Expect(endpoint).To(Equal(route.NewEndpoint(response.LogGuid, response.IP, uint16(response.Port), response.LogGuid, nil, response.TTL)))
			}
		})

		Context("when the routing api returns an error", func() {
			It("returns an error", func() {
				client.RoutesReturns(nil, errors.New("Oops!"))

				err := fetcher.FetchRoutes()
				Expect(err).To(HaveOccurred())
			})
		})

		Context("When the token fetcher returns an error", func() {
			BeforeEach(func() {
				tokenFetcher.FetchTokenReturns(nil, errors.New("token fetcher error"))
			})

			It("returns an error", func() {
				err := fetcher.FetchRoutes()
				Expect(err).To(HaveOccurred())
				Expect(registry.RegisterCallCount()).To(Equal(0))
			})
		})
	})

	Describe(".StartFetchCycle", func() {
		BeforeEach(func() {
			cfg.PruneStaleDropletsInterval = 10 * time.Millisecond
			fetcher = NewRouteFetcher(logger, tokenFetcher, registry, cfg, client, retryInterval)

			tokenFetcher.FetchTokenReturns(token, nil)

			client.RoutesReturns(response, nil)
		})

		It("periodically fetches routes", func() {
			received := make(chan struct{})

			client.RoutesStub = func() ([]db.Route, error) {
				received <- struct{}{}
				return []db.Route{}, nil
			}

			fetcher.StartFetchCycle()

			Eventually(received).Should(Receive())
			Eventually(received).Should(Receive())
		})

		It("logs the error", func() {
			tokenFetcher.FetchTokenReturns(nil, errors.New("Unauthorized"))
			fetcher.StartFetchCycle()

			Eventually(func() int {
				return len(sink.Records())
			}).Should(BeNumerically(">=", 1))

			Expect(sink.Records()).ToNot(BeNil())
			Expect(sink.Records()[0].Message).To(Equal("Unauthorized"))
		})
	})

	Describe(".StartEventCycle", func() {
		Context("when fetching the auth token fails", func() {
			It("logs the failure and tries again", func() {
				received := make(chan struct{})

				tokenFetcher.FetchTokenStub = func() (*token_fetcher.Token, error) {
					received <- struct{}{}
					return nil, errors.New("failed to get the token")
				}
				fetcher.StartEventCycle()

				Eventually(received).Should(Receive())
				Eventually(received).Should(Receive())

				Expect(sink.Records()).ToNot(BeNil())
				Expect(sink.Records()[0].Message).To(Equal("failed to get the token"))
				Expect(tokenFetcher.FetchTokenCallCount()).To(Equal(2))
			})
		})
{'fraction_non_alphanumeric': 0.1509515198484457, 'fraction_numerical': 0.00757771463015586, 'mean_word_length': 3.813095731454621, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 6, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4805459', 'n_tokens_mistral': 4669, 'n_tokens_neox': 3960, 'n_words': 636}