blob: 4f673e773229038b47a81462961bfc2330f1531d [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
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
See the License for the specific language governing permissions and
limitations under the License.
package main
import (
fpb ""
const logFile = "http_test_client_log_"
var (
serverAddr = flag.String("server_addr", "", "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 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())
out = append(out, id)
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 {
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)
if totalErrors == 0 {
log.Println("All Tests Pass!")
} else {
log.Printf("Found %d Errors", totalErrors)
log.Println("\n************* End Stats *************\n")
func main() {
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()
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
if !*allFlows && !*batchGetWaitEstimatesFlow && !*createWaitlistEntryFlow &&
!*getWaitlistEntryFlow && !*deleteWaitlistEntryFlow {
// 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(waitlistServices) == 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())
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)
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)
utils.LogFlow("DeleteWaitlistEntry", "End")