blob: 718ff23d0dafb2841e6b697f56fb97a63bb2a7d3 [file] [log] [blame]
/*
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.")
outputToTerminal = flag.Bool("output_to_terminal", false, "Output to terminal rather than a file.")
)
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(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 && !*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)
}