| /* | 
 | 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" | 
 |  | 
 | 	mpb "github.com/maps-booking-v3/v3" | 
 | ) | 
 |  | 
 | 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'.") | 
 | 	testSlots        = flag.Int("num_test_slots", 10, "Maximum number of slots to test from availability_feed. Slots will be selected randomly") | 
 | 	allFlows         = flag.Bool("all_tests", false, "Whether to test all endpoints syncronously, including ListOrders flow.") | 
 | 	healthFlow       = flag.Bool("health_check_test", false, "Whether to test the Health endpoint.") | 
 | 	checkFlow        = flag.Bool("check_order_test", false, "Whether to test the CheckOrderFulfillability endpoint.") | 
 | 	orderFlow        = flag.Bool("create_order_test", false, "Whether to test the CreateOrder endpoint.") | 
 | 	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") | 
 | 	availabilityFeed = flag.String("availability_feed", "", "Absolute path to availability 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.") | 
 | ) | 
 |  | 
 | type counters struct { | 
 | 	TotalSlotsProcessed             int | 
 | 	HealthCheckSuccess              bool | 
 | 	CheckOrderFulfillabilitySuccess int | 
 | 	CheckOrderFulfillabilityErrors  int | 
 | 	CreateOrderSuccess              int | 
 | 	CreateOrderErrors               int | 
 | 	ListOrdersSuccess               bool | 
 | } | 
 |  | 
 | 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 *checkFlow || *allFlows { | 
 | 		totalErrors += stats.CheckOrderFulfillabilityErrors | 
 | 		log.Printf("CheckOrderFulfillability Errors: %d/%d", stats.CheckOrderFulfillabilityErrors, stats.CheckOrderFulfillabilityErrors+stats.CheckOrderFulfillabilitySuccess) | 
 | 	} | 
 | 	if *orderFlow || *allFlows { | 
 | 		totalErrors += stats.CreateOrderErrors | 
 | 		log.Printf("CreateOrder Errors: %d/%d", stats.CreateOrderErrors, stats.CreateOrderErrors+stats.CreateOrderSuccess) | 
 | 	} | 
 | 	if *allFlows { | 
 | 		if stats.ListOrdersSuccess { | 
 | 			log.Println("ListOrders Succeeded") | 
 | 		} else { | 
 | 			totalErrors++ | 
 | 			log.Println("ListOrders Failed") | 
 | 		} | 
 | 	} | 
 | 	if *checkFlow || *orderFlow || *allFlows { | 
 | 		log.Printf("Total Slots Processed: %d", stats.TotalSlotsProcessed) | 
 | 	} | 
 |  | 
 | 	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(0) | 
 | } | 
 |  | 
 | func main() { | 
 | 	flag.Parse() | 
 | 	var stats counters | 
 |  | 
 | 	// 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 && !*checkFlow && !*orderFlow { | 
 | 			logStats(stats) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if *availabilityFeed == "" || *serviceFeed == "" { | 
 | 		log.Fatal("please set both availability_feed and service_feed flags") | 
 | 	} | 
 |  | 
 | 	testInventory, err := utils.MerchantLineItemMapFrom(*serviceFeed, *availabilityFeed, *testSlots) | 
 | 	if err != nil { | 
 | 		log.Fatal(err.Error()) | 
 | 	} | 
 |  | 
 | 	// CheckOrderFulfillability Flow | 
 | 	if *checkFlow || *allFlows { | 
 | 		utils.LogFlow("CheckOrderFulfillability", "Start") | 
 | 		for _, value := range testInventory { | 
 | 			stats.TotalSlotsProcessed += len(value) | 
 | 		} | 
 |  | 
 | 		i := 0 | 
 | 		for merchantID, lineItems := range testInventory { | 
 | 			if err = api.CheckOrderFulfillability(merchantID, lineItems, conn); err != nil { | 
 | 				log.Printf("%s. skipping slots %d-%d/%d", err.Error(), i, i+len(lineItems)-1, stats.TotalSlotsProcessed) | 
 | 				stats.CheckOrderFulfillabilityErrors += len(lineItems) | 
 | 				delete(testInventory, merchantID) | 
 | 				i += len(lineItems) | 
 | 				continue | 
 | 			} | 
 | 			stats.CheckOrderFulfillabilitySuccess += len(lineItems) | 
 | 			i += len(lineItems) | 
 | 		} | 
 | 		utils.LogFlow("CheckOrderFulfillability", "End") | 
 | 	} | 
 | 	// CreateOrder Flow. | 
 | 	var orders []*mpb.Order | 
 | 	if *orderFlow || *allFlows { | 
 | 		utils.LogFlow("CreateOrder", "Start") | 
 | 		if stats.TotalSlotsProcessed == 0 { | 
 | 			for _, value := range testInventory { | 
 | 				stats.TotalSlotsProcessed += len(value) | 
 | 			} | 
 | 		} | 
 |  | 
 | 		i := 0 | 
 | 		for merchantID, lineItems := range testInventory { | 
 | 			order, err := api.CreateOrder(merchantID, lineItems, conn) | 
 | 			if err != nil { | 
 | 				log.Printf("%s. skipping slot %d-%d/%d", err.Error(), i, i+len(lineItems)-1, stats.TotalSlotsProcessed) | 
 | 				stats.CreateOrderErrors += len(lineItems) | 
 | 				delete(testInventory, merchantID) | 
 | 				i += len(lineItems) | 
 | 				continue | 
 | 			} | 
 | 			orders = append(orders, order) | 
 | 			stats.CreateOrderSuccess += len(lineItems) | 
 | 			i += len(lineItems) | 
 | 		} | 
 | 		utils.LogFlow("CreateOrder", "End") | 
 | 	} | 
 | 	// ListOrders Flow | 
 | 	if *allFlows { | 
 | 		utils.LogFlow("ListOrders", "Start") | 
 | 		stats.ListOrdersSuccess = true | 
 | 		if err = api.ListOrders(orders, conn); err != nil { | 
 | 			stats.ListOrdersSuccess = false | 
 | 			log.Println(err.Error()) | 
 | 		} | 
 | 		utils.LogFlow("ListOrders", "End") | 
 | 	} | 
 |  | 
 | 	logStats(stats) | 
 | } |