| /* | 
 | Copyright 2017 Google Inc. | 
 |  | 
 | Licensed under the Apache License, Version 2.0 (the "License"); | 
 | you may not use this file except in compliance with the License. | 
 | You may obtain a copy of the License at | 
 |  | 
 | https://www.apache.org/licenses/LICENSE-2.0 | 
 |  | 
 | Unless required by applicable law or agreed to in writing, software | 
 | distributed under the License is distributed on an "AS IS" BASIS, | 
 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | See the License for the specific language governing permissions and | 
 | limitations under the License. | 
 | */ | 
 | package main | 
 |  | 
 | import ( | 
 | 	"flag" | 
 | 	"fmt" | 
 | 	"log" | 
 | 	"os" | 
 | 	"path/filepath" | 
 | 	"time" | 
 |  | 
 | 	"github.com/maps-booking-v3/api" | 
 | 	"github.com/maps-booking-v3/utils" | 
 |  | 
 | 	fpb "github.com/maps-booking-v3/feeds" | 
 | ) | 
 |  | 
 | const logFile = "http_test_client_log_" | 
 |  | 
 | var ( | 
 | 	serverAddr                = flag.String("server_addr", "example.com:80", "Your http server's address in the format of host:port") | 
 | 	credentialsFile           = flag.String("credentials_file", "", "File containing credentials for your server. Leave blank to bypass authentication. File should have exactly one line of the form 'username:password'.") | 
 | 	numTestServices           = flag.Int("num_test_services", 10, "Maximum number of services to test from service_feed. Services will be selected randomly") | 
 | 	allFlows                  = flag.Bool("all_tests", false, "Whether to test all endpoints.") | 
 | 	healthFlow                = flag.Bool("health_check_test", false, "Whether to test the Health endpoint.") | 
 | 	batchGetWaitEstimatesFlow = flag.Bool("batch_get_wait_estimates_test", false, "Whether to test the BatchGetWaitEstimates endpoint.") | 
 | 	createWaitlistEntryFlow   = flag.Bool("create_waitlist_entry_test", false, "Whether to test the CreateWaitlistEntry endpoint.") | 
 | 	getWaitlistEntryFlow      = flag.Bool("get_waitlist_entry_test", false, "Whether to test the GetWaitlistEntry endpoint. CreateWaitlistEntry will also be called to create the entries.") | 
 | 	deleteWaitlistEntryFlow   = flag.Bool("delete_waitlist_entry_test", false, "Whether to test the DeleteWaitlistEntry endpoint. CreateWaitlistEntry will also be called to create the entries.") | 
 | 	serviceFeed               = flag.String("service_feed", "", "Absolute path to service feed required for all tests except health. Feeds can be in either json or pb3 format.") | 
 | 	outputDir                 = flag.String("output_dir", "", "Absolute path of dir to dump log file.") | 
 | 	caFile                    = flag.String("ca_file", "", "Absolute path to your server's Certificate Authority root cert. Downloading all roots currently recommended by the Google Internet Authority is a suitable alternative https://pki.google.com/roots.pem. Leave blank to connect using http rather than https.") | 
 | 	fullServerName            = flag.String("full_server_name", "", "Fully qualified domain name. Same name used to sign CN. Only necessary if ca_file is specified and the base URL differs from the server address.") | 
 | 	outputToTerminal          = flag.Bool("output_to_terminal", false, "Output to terminal rather than a file.") | 
 | ) | 
 |  | 
 | type counters struct { | 
 | 	TotalServicesProcessed       int | 
 | 	HealthCheckSuccess           bool | 
 | 	BatchGetWaitEstimatesSuccess int | 
 | 	BatchGetWaitEstimatesErrors  int | 
 | 	CreateWaitlistEntrySuccess   int | 
 | 	CreateWaitlistEntryErrors    int | 
 | 	GetWaitlistEntrySuccess      int | 
 | 	GetWaitlistEntryErrors       int | 
 | 	DeleteWaitlistEntrySuccess   int | 
 | 	DeleteWaitlistEntryErrors    int | 
 | } | 
 |  | 
 | // GenerateWaitlistEntries creates a waitlist entry for each provided service. | 
 | func GenerateWaitlistEntries(services []*fpb.Service, stats *counters, conn *api.HTTPConnection) []string { | 
 | 	log.Println("no previous waitlist entries to use, acquiring new inventory") | 
 | 	utils.LogFlow("Generate Fresh Entries", "Start") | 
 | 	defer utils.LogFlow("Generate Fresh Entries", "End") | 
 |  | 
 | 	var out []string | 
 | 	totalServices := len(services) | 
 | 	for i, s := range services { | 
 | 		id, err := api.CreateWaitlistEntry(s, conn) | 
 | 		if err != nil { | 
 | 			log.Printf("%s. skipping waitlistEntry %d/%d, serviceID: %s", | 
 | 				err.Error(), i, totalServices, s.GetServiceId()) | 
 | 			stats.CreateWaitlistEntryErrors++ | 
 | 			continue | 
 | 		} | 
 | 		out = append(out, id) | 
 | 		stats.CreateWaitlistEntrySuccess++ | 
 | 	} | 
 | 	return out | 
 | } | 
 |  | 
 | func createLogFile() (*os.File, error) { | 
 | 	var err error | 
 | 	outPath := *outputDir | 
 | 	if outPath == "" { | 
 | 		outPath, err = os.Getwd() | 
 | 		if err != nil { | 
 | 			return nil, err | 
 | 		} | 
 | 	} | 
 |  | 
 | 	now := time.Now().UTC() | 
 | 	nowString := fmt.Sprintf("%d-%02d-%02d_%02d-%02d-%02d", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second()) | 
 | 	outFile := filepath.Join(outPath, fmt.Sprintf("%s%s", logFile, nowString)) | 
 |  | 
 | 	return os.Create(outFile) | 
 | } | 
 |  | 
 | func logStats(stats counters) { | 
 | 	log.Println("\n************* Begin Stats *************\n") | 
 | 	var totalErrors int | 
 | 	if *healthFlow || *allFlows { | 
 | 		if stats.HealthCheckSuccess { | 
 | 			log.Println("HealthCheck Succeeded") | 
 | 		} else { | 
 | 			totalErrors++ | 
 | 			log.Println("HealthCheck Failed") | 
 | 		} | 
 | 	} | 
 | 	if *batchGetWaitEstimatesFlow || *allFlows { | 
 | 		totalErrors += stats.BatchGetWaitEstimatesErrors | 
 | 		log.Printf("BatchGetWaitEstimates Errors: %d/%d", stats.BatchGetWaitEstimatesErrors, stats.BatchGetWaitEstimatesErrors+stats.BatchGetWaitEstimatesSuccess) | 
 | 	} | 
 | 	if *createWaitlistEntryFlow || *allFlows { | 
 | 		totalErrors += stats.CreateWaitlistEntryErrors | 
 | 		log.Printf("CreateWaitlistEntry Errors: %d/%d", stats.CreateWaitlistEntryErrors, stats.CreateWaitlistEntryErrors+stats.CreateWaitlistEntrySuccess) | 
 | 	} | 
 | 	if *getWaitlistEntryFlow || *allFlows { | 
 | 		totalErrors += stats.GetWaitlistEntryErrors | 
 | 		log.Printf("GetWaitlistEntry Errors: %d/%d", stats.GetWaitlistEntryErrors, stats.GetWaitlistEntryErrors+stats.GetWaitlistEntrySuccess) | 
 | 	} | 
 | 	if *deleteWaitlistEntryFlow || *allFlows { | 
 | 		totalErrors += stats.DeleteWaitlistEntryErrors | 
 | 		log.Printf("DeleteWaitlistEntry Errors: %d/%d", stats.DeleteWaitlistEntryErrors, stats.DeleteWaitlistEntryErrors+stats.DeleteWaitlistEntrySuccess) | 
 | 	} | 
 |  | 
 | 	log.Println("\n\n\n") | 
 | 	if totalErrors == 0 { | 
 | 		log.Println("All Tests Pass!") | 
 | 	} else { | 
 | 		log.Printf("Found %d Errors", totalErrors) | 
 | 	} | 
 |  | 
 | 	log.Println("\n************* End Stats *************\n") | 
 | 	os.Exit(totalErrors) | 
 | } | 
 |  | 
 | func main() { | 
 | 	flag.Parse() | 
 | 	var stats counters | 
 |  | 
 | 	if !*outputToTerminal { | 
 | 		// Set up logging before continuing with flows | 
 | 		f, err := createLogFile() | 
 | 		if err != nil { | 
 | 			log.Fatalf("Failed to create log file %v", err) | 
 | 		} | 
 | 		defer f.Close() | 
 | 		log.SetOutput(f) | 
 | 	} | 
 |  | 
 | 	conn, err := api.InitHTTPConnection(*serverAddr, *credentialsFile, *caFile, *fullServerName) | 
 | 	if err != nil { | 
 | 		log.Fatalf("Failed to init http connection %v", err) | 
 | 	} | 
 |  | 
 | 	// HealthCheck Flow | 
 | 	if *healthFlow || *allFlows { | 
 | 		stats.HealthCheckSuccess = true | 
 | 		if err := api.HealthCheck(conn); err != nil { | 
 | 			stats.HealthCheckSuccess = false | 
 | 			log.Println(err.Error()) | 
 | 		} | 
 | 		if !*allFlows && !*batchGetWaitEstimatesFlow && !*createWaitlistEntryFlow && | 
 | 			!*getWaitlistEntryFlow && !*deleteWaitlistEntryFlow { | 
 | 			logStats(stats) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// Build services. | 
 | 	if *serviceFeed == "" { | 
 | 		log.Fatal("please set service_feed flag if you wish to test additional flows") | 
 | 	} | 
 |  | 
 | 	var services []*fpb.Service | 
 | 	services, err = utils.ParseServiceFeed(*serviceFeed) | 
 | 	if err != nil { | 
 | 		log.Fatalf("Failed to get services: %v", err.Error()) | 
 | 	} | 
 | 	// Remove services without waitlist rules. | 
 | 	waitlistServices := services[:0] | 
 | 	for _, s := range services { | 
 | 		if s.GetWaitlistRules() != nil { | 
 | 			waitlistServices = append(waitlistServices, s) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if len(services) == 0 { | 
 | 		log.Fatal("no services have waitlist rules") | 
 | 	} | 
 | 	reducedServices := utils.ReduceServices(waitlistServices, *numTestServices) | 
 | 	stats.TotalServicesProcessed += len(reducedServices) | 
 |  | 
 | 	// BatchGetWaitEstimates Flow | 
 | 	if *batchGetWaitEstimatesFlow || *allFlows { | 
 | 		utils.LogFlow("BatchGetWaitEstimates", "Start") | 
 |  | 
 | 		for i, s := range reducedServices { | 
 | 			if err = api.BatchGetWaitEstimates(s, conn); err != nil { | 
 | 				log.Printf("%s. BatchGerWaitEstimates failed for service %d/%d. Service_id:", | 
 | 					err.Error(), i, stats.TotalServicesProcessed, s.GetServiceId()) | 
 | 				stats.BatchGetWaitEstimatesErrors++ | 
 | 				continue | 
 | 			} | 
 | 			stats.BatchGetWaitEstimatesSuccess++ | 
 | 		} | 
 | 		utils.LogFlow("BatchGetWaitEstimates", "End") | 
 | 	} | 
 | 	// CreateWaitlistEntry Flow. | 
 | 	var ids []string | 
 | 	if *createWaitlistEntryFlow || *getWaitlistEntryFlow || | 
 | 		*deleteWaitlistEntryFlow || *allFlows { | 
 | 		utils.LogFlow("CreateWaitlistEntry", "Start") | 
 | 		ids = GenerateWaitlistEntries(reducedServices, &stats, conn) | 
 | 		utils.LogFlow("CreateWaitlistEntry", "End") | 
 | 	} | 
 | 	// GetWaitlistEntry Flow | 
 | 	if *getWaitlistEntryFlow || *allFlows { | 
 | 		utils.LogFlow("GetWaitlistEntry", "Start") | 
 | 		for _, id := range ids { | 
 | 			if _, err = api.GetWaitlistEntry(id, conn); err != nil { | 
 | 				log.Printf("%s. get waitlist entry failed for waitlist entry id: %s", | 
 | 					err.Error(), id) | 
 | 				stats.GetWaitlistEntryErrors++ | 
 | 				continue | 
 | 			} | 
 | 			stats.GetWaitlistEntrySuccess++ | 
 | 		} | 
 | 		utils.LogFlow("GetWaitlistEntry", "End") | 
 | 	} | 
 |  | 
 | 	// DeleteWaitlistentry Flow | 
 | 	if *deleteWaitlistEntryFlow || *allFlows { | 
 | 		utils.LogFlow("DeleteWaitlistEntry", "Start") | 
 |  | 
 | 		for _, id := range ids { | 
 | 			if err = api.DeleteWaitlistEntry(id, conn); err != nil { | 
 | 				log.Printf("%s. Delete waitlist entry failed for waitlist entry id: %s", | 
 | 					err.Error(), id) | 
 | 				stats.DeleteWaitlistEntryErrors++ | 
 | 				continue | 
 | 			} | 
 | 			stats.DeleteWaitlistEntrySuccess++ | 
 | 		} | 
 | 		utils.LogFlow("DeleteWaitlistEntry", "End") | 
 | 	} | 
 |  | 
 | 	logStats(stats) | 
 | } |