func Test_rebuildHashes_whenDataIsHashedForAProxy_andStillAProxy_keysAreNotChanged(t *testing.T) { RegisterTestingT(t) webserver := false db := cache.NewInMemoryCache() pair := models.RequestResponsePair{ Request: models.RequestDetails{ Path: "/hello", Destination: "a-host.com", }, Response: models.ResponseDetails{ Body: "a body", }, } pairBytes, _ := pair.Encode() db.Set([]byte(pair.Id()), pairBytes) rebuildHashes(db, webserver) result, err := db.Get([]byte(pair.Id())) Expect(err).To(BeNil()) Expect(result).To(Equal(pairBytes)) }
func TestImportImportRequestResponsePairs_CanImportAMultiplePairs(t *testing.T) { RegisterTestingT(t) cache := cache.NewInMemoryCache() cfg := Configuration{Webserver: false} requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver} hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher} RegisterTestingT(t) originalPair1 := v1.RequestResponsePairView{ Response: v1.ResponseDetailsView{ Status: 200, Body: "hello_world", EncodedBody: false, Headers: map[string][]string{"Hoverfly": []string{"testing"}}, }, Request: v1.RequestDetailsView{ Path: StringToPointer("/"), Method: StringToPointer("GET"), Destination: StringToPointer("/"), Scheme: StringToPointer("scheme"), Query: StringToPointer(""), Body: StringToPointer(""), Headers: map[string][]string{"Hoverfly": []string{"testing"}}}} originalPair2 := originalPair1 originalPair2.Request.Path = StringToPointer("/new/path") originalPair3 := originalPair1 originalPair3.Request.Path = StringToPointer("/newer/path") hv.ImportRequestResponsePairViews([]interfaces.RequestResponsePair{originalPair1, originalPair2, originalPair3}) pairBytes, err := cache.Get([]byte("9b114df98da7f7e2afdc975883dab4f2")) Expect(err).To(BeNil()) decodedPair1, err := models.NewRequestResponsePairFromBytes(pairBytes) Expect(err).To(BeNil()) Expect(*decodedPair1).To(Equal(models.NewRequestResponsePairFromRequestResponsePairView(originalPair1))) pairBytes, err = cache.Get([]byte("9c03e4af1f30542ff079a712bddad602")) Expect(err).To(BeNil()) decodedPair2, err := models.NewRequestResponsePairFromBytes(pairBytes) Expect(err).To(BeNil()) Expect(*decodedPair2).To(Equal(models.NewRequestResponsePairFromRequestResponsePairView(originalPair2))) pairBytes, err = cache.Get([]byte("fd099332afee48101edb7441b098cd4a")) Expect(err).To(BeNil()) decodedPair3, err := models.NewRequestResponsePairFromBytes(pairBytes) Expect(err).To(BeNil()) Expect(*decodedPair3).To(Equal(models.NewRequestResponsePairFromRequestResponsePairView(originalPair3))) }
func TestImportRequestResponsePairs_CanImportASinglePair(t *testing.T) { RegisterTestingT(t) cache := cache.NewInMemoryCache() cfg := Configuration{Webserver: false} requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver} hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher} RegisterTestingT(t) originalPair := v1.RequestResponsePairView{ Response: v1.ResponseDetailsView{ Status: 200, Body: "hello_world", EncodedBody: false, Headers: map[string][]string{"Content-Type": []string{"text/plain"}}}, Request: v1.RequestDetailsView{ Path: StringToPointer("/"), Method: StringToPointer("GET"), Destination: StringToPointer("/"), Scheme: StringToPointer("scheme"), Query: StringToPointer(""), Body: StringToPointer(""), Headers: map[string][]string{"Hoverfly": []string{"testing"}}}} hv.ImportRequestResponsePairViews([]interfaces.RequestResponsePair{originalPair}) value, _ := cache.Get([]byte("9b114df98da7f7e2afdc975883dab4f2")) decodedPair, _ := models.NewRequestResponsePairFromBytes(value) Expect(*decodedPair).To(Equal(models.RequestResponsePair{ Response: models.ResponseDetails{ Status: 200, Body: "hello_world", Headers: map[string][]string{"Content-Type": []string{"text/plain"}}, }, Request: models.RequestDetails{ Path: "/", Method: "GET", Destination: "/", Scheme: "scheme", Query: "", Body: "", Headers: map[string][]string{ "Content-Type": []string{"text/plain; charset=utf-8"}, "Hoverfly": []string{"testing"}, }, }, })) }
func TestImportImportRequestResponsePairs_CanImportASingleBase64EncodedPair(t *testing.T) { cache := cache.NewInMemoryCache() cfg := Configuration{Webserver: false} requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver} hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher} RegisterTestingT(t) encodedPair := views.RequestResponsePairView{ Response: views.ResponseDetailsView{ Status: 200, Body: base64String("hello_world"), EncodedBody: true, Headers: map[string][]string{"Content-Encoding": []string{"gzip"}}}, Request: views.RequestDetailsView{ Path: "/", Method: "GET", Destination: "/", Scheme: "scheme", Query: "", Body: "", Headers: map[string][]string{"Hoverfly": []string{"testing"}}}} hv.ImportRequestResponsePairViews([]views.RequestResponsePairView{encodedPair}) value, err := cache.Get([]byte("9b114df98da7f7e2afdc975883dab4f2")) Expect(err).To(BeNil()) decodedPair, err := models.NewRequestResponsePairFromBytes(value) Expect(err).To(BeNil()) Expect(decodedPair).ToNot(Equal(models.RequestResponsePair{ Response: models.ResponseDetails{ Status: 200, Body: "hello_world", Headers: map[string][]string{"Content-Encoding": []string{"gzip"}}}, Request: models.RequestDetails{ Path: "/", Method: "GET", Destination: "/", Scheme: "scheme", Query: "", Body: "", Headers: map[string][]string{"Hoverfly": []string{"testing"}}}})) }
func TestImportImportRequestResponsePairs_CanImportARequestTemplateResponsePair(t *testing.T) { RegisterTestingT(t) cache := cache.NewInMemoryCache() cfg := Configuration{Webserver: false} requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver} hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher} RegisterTestingT(t) requestTemplate := v1.RequestDetailsView{ RequestType: StringToPointer("template"), Method: StringToPointer("GET"), } responseView := v1.ResponseDetailsView{ Status: 200, Body: "hello_world", EncodedBody: false, Headers: map[string][]string{"Hoverfly": []string{"testing"}}, } templatePair := v1.RequestResponsePairView{ Response: responseView, Request: requestTemplate, } hv.ImportRequestResponsePairViews([]interfaces.RequestResponsePair{templatePair}) Expect(len(hv.RequestMatcher.TemplateStore)).To(Equal(1)) request := models.NewRequestDetailsFromRequest(requestTemplate) responseFromCache, err := hv.RequestMatcher.TemplateStore.GetResponse(request, false) Expect(err).To(BeNil()) response := models.NewResponseDetailsFromResponse(responseView) Expect(*responseFromCache).To(Equal(response)) }
func main() { log.SetFormatter(&log.JSONFormatter{}) flag.Var(&importFlags, "import", "import from file or from URL (i.e. '-import my_service.json' or '-import http://mypage.com/service_x.json'") flag.Var(&destinationFlags, "dest", "specify which hosts to process (i.e. '-dest fooservice.org -dest barservice.org -dest catservice.org') - other hosts will be ignored will passthrough'") flag.Parse() if *version { fmt.Println(hoverflyVersion) os.Exit(0) } // getting settings cfg := hv.InitSettings() if *verbose { // Only log the warning severity or above. log.SetLevel(log.DebugLevel) } cfg.Verbose = *verbose if *dev { // making text pretty log.SetFormatter(&log.TextFormatter{}) } if *generateCA { tlsc, err := hvc.GenerateAndSave(*certName, *certOrg, 365*24*time.Hour) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), }).Fatal("failed to generate certificate.") } goproxy.GoproxyCa = *tlsc } else if *cert != "" && *key != "" { tlsc, err := tls.LoadX509KeyPair(*cert, *key) if err != nil { log.Fatalf("Failed to load certifiate and key pair, got error: %s", err.Error()) } goproxy.GoproxyCa = tlsc } // overriding environment variables (proxy and admin ports) if *proxyPort != "" { cfg.ProxyPort = *proxyPort } if *adminPort != "" { cfg.AdminPort = *adminPort } // development settings cfg.Development = *dev // overriding default middleware setting cfg.Middleware = *middleware mode := getInitialMode(cfg) // setting mode cfg.SetMode(mode) // disabling authentication if no-auth for auth disabled env variable if *authEnabled { cfg.AuthEnabled = true } // disabling tls verification if flag or env variable is set to 'false' (defaults to true) if !cfg.TLSVerification || !*tlsVerification { cfg.TLSVerification = false log.Info("tls certificate verification is now turned off!") } if len(destinationFlags) > 0 { cfg.Destination = strings.Join(destinationFlags[:], "|") } else { // setting destination regexp cfg.Destination = *destination } var requestCache cache.Cache var metadataCache cache.Cache var tokenCache cache.Cache var userCache cache.Cache if *databasePath != "" { cfg.DatabasePath = *databasePath } if *database == boltBackend { log.Info("Creating bolt db backend...") db := cache.GetDB(cfg.DatabasePath) defer db.Close() requestCache = cache.NewBoltDBCache(db, []byte("requestsBucket")) metadataCache = cache.NewBoltDBCache(db, []byte("metadataBucket")) tokenCache = cache.NewBoltDBCache(db, []byte(backends.TokenBucketName)) userCache = cache.NewBoltDBCache(db, []byte(backends.UserBucketName)) } else if *database == inmemoryBackend { log.Info("Creating in memory map backend...") log.Warn("Turning off authentication...") cfg.AuthEnabled = false requestCache = cache.NewInMemoryCache() metadataCache = cache.NewInMemoryCache() tokenCache = cache.NewInMemoryCache() userCache = cache.NewInMemoryCache() } else { log.Fatalf("unknown database type chosen: %s", *database) } authBackend := backends.NewCacheBasedAuthBackend(tokenCache, userCache) hoverfly := hv.GetNewHoverfly(cfg, requestCache, metadataCache, authBackend) // if add new user supplied - adding it to database if *addNew { err := hoverfly.Authentication.AddUser(*addUser, *addPassword, *isAdmin) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), "username": *addUser, }).Fatal("failed to add new user") } else { log.WithFields(log.Fields{ "username": *addUser, }).Info("user added successfuly") } return } if cfg.AuthEnabled { if os.Getenv(hv.HoverflyAdminUsernameEV) != "" && os.Getenv(hv.HoverflyAdminPasswordEV) != "" { hoverfly.Authentication.AddUser( os.Getenv(hv.HoverflyAdminUsernameEV), os.Getenv(hv.HoverflyAdminPasswordEV), true) } // checking if there are any users users, err := hoverfly.Authentication.GetAllUsers() if err != nil { log.WithFields(log.Fields{ "error": err, }).Fatal("got error while trying to get all users") } if len(users) < 1 { createSuperUser(hoverfly) } } // importing records if environment variable is set ev := os.Getenv(hv.HoverflyImportRecordsEV) if ev != "" { err := hoverfly.Import(ev) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), "import": ev, }).Fatal("Environment variable for importing was set but failed to import this resource") } else { err = hoverfly.MetadataCache.Set([]byte("import_from_env_variable"), []byte(ev)) } } // importing stuff if len(importFlags) > 0 { for i, v := range importFlags { if v != "" { log.WithFields(log.Fields{ "import": v, }).Debug("Importing given resource") err := hoverfly.Import(v) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), "import": v, }).Fatal("Failed to import given resource") } else { err = hoverfly.MetadataCache.Set([]byte(fmt.Sprintf("import_%d", i+1)), []byte(v)) } } } } // start metrics registry flush if *metrics { hoverfly.Counter.Init() } cfg.Webserver = *webserver err := hoverfly.StartProxy() if err != nil { log.WithFields(log.Fields{ "error": err.Error(), }).Fatal("failed to start proxy...") } // starting admin interface, this is blocking hoverfly.StartAdminInterface() }
func TestImportImportRequestResponsePairs_CanImportARequestResponsePair_AndRequestTemplateResponsePair(t *testing.T) { RegisterTestingT(t) cache := cache.NewInMemoryCache() cfg := Configuration{Webserver: false} requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver} hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher} RegisterTestingT(t) requestTemplate := v1.RequestDetailsView{ RequestType: StringToPointer("template"), Method: StringToPointer("GET"), } requestView := v1.RequestDetailsView{ Method: StringToPointer("GET"), Path: StringToPointer("/"), Destination: StringToPointer("test.com"), Scheme: StringToPointer("http"), } responseView := v1.ResponseDetailsView{ Status: 200, Body: "hello_world", EncodedBody: false, Headers: map[string][]string{"Hoverfly": []string{"testing"}}, } templatePair := v1.RequestResponsePairView{ Request: requestTemplate, Response: responseView, } ordinaryPair := v1.RequestResponsePairView{ Request: requestView, Response: responseView, } hv.ImportRequestResponsePairViews([]interfaces.RequestResponsePair{templatePair, ordinaryPair}) cacheCount, err := hv.RequestCache.RecordsCount() Expect(cacheCount).To(Equal(1)) Expect(err).To(BeNil()) Expect(len(hv.RequestMatcher.TemplateStore)).To(Equal(1)) request := models.NewRequestDetailsFromRequest(requestTemplate) response := models.NewResponseDetailsFromResponse(responseView) pairBytes, err := hv.RequestCache.Get([]byte("76cf08e38439f083de2658b0971df9bf")) Expect(err).To(BeNil()) savedPair, err := models.NewRequestResponsePairFromBytes(pairBytes) Expect(err).To(BeNil()) Expect(savedPair.Response).To(Equal(response)) responseFromCache, err := hv.RequestMatcher.TemplateStore.GetResponse(request, false) Expect(err).To(BeNil()) Expect(*responseFromCache).To(Equal(response)) }