| // Copyright (C) 2019 Google LLC | 
 | // | 
 | // 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 | 
 | // | 
 | // http://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. | 
 |  | 
 | // Program to benchmark Gerrit.  Creates pending changes in a loop, | 
 | // which tests performance of BatchRefUpdate and Lucene indexing | 
 | package main | 
 |  | 
 | import ( | 
 | 	"bytes" | 
 | 	"encoding/base64" | 
 | 	"flag" | 
 | 	"fmt" | 
 | 	"io" | 
 | 	"log" | 
 | 	"net/http" | 
 | 	"net/url" | 
 | 	"os" | 
 | 	"sort" | 
 | 	"time" | 
 | ) | 
 |  | 
 | func main() { | 
 | 	user := flag.String("user", "admin", "username for basic auth") | 
 | 	pw := flag.String("password", "secret", "HTTP password for basic auth") | 
 | 	project := flag.String("project", "", "project to create changes in") | 
 | 	gerritURL := flag.String("url", "http://localhost:8080/", "URL to gerrit instance") | 
 | 	numChanges := flag.Int("n", 100, "number of changes to create") | 
 | 	flag.Parse() | 
 | 	if *gerritURL == "" { | 
 | 		log.Fatal("provide --url") | 
 | 	} | 
 | 	if *project == "" { | 
 | 		log.Fatal("provide --project") | 
 | 	} | 
 |  | 
 | 	u, err := url.Parse(*gerritURL) | 
 | 	if err != nil { | 
 | 		log.Fatal(err) | 
 | 	} | 
 |  | 
 | 	basicAuth := fmt.Sprintf("%s:%s", *user, *pw) | 
 | 	authHeader := base64.StdEncoding.EncodeToString([]byte(basicAuth)) | 
 |  | 
 | 	client := &http.Client{} | 
 |  | 
 | 	var dts []time.Duration | 
 | 	startAll := time.Now() | 
 | 	var lastSec int | 
 | 	for i := 0; i < *numChanges; i++ { | 
 | 		body := fmt.Sprintf(`{ | 
 |     "project" : "%s", | 
 |     "subject" : "change %d", | 
 |     "branch" : "master", | 
 |     "status" : "NEW" | 
 |   }`, *project, i) | 
 | 		start := time.Now() | 
 |  | 
 | 		thisSec := int(start.Sub(startAll) / time.Second) | 
 | 		if thisSec != lastSec { | 
 | 			log.Printf("change %d", i) | 
 | 		} | 
 | 		lastSec = thisSec | 
 |  | 
 | 		u.Path = "/a/changes/" | 
 | 		req, err := http.NewRequest("POST", u.String(), bytes.NewBufferString(body)) | 
 | 		if err != nil { | 
 | 			log.Fatal(err) | 
 | 		} | 
 | 		req.Header.Add("Authorization", "Basic "+authHeader) | 
 | 		req.Header.Add("Content-Type", "application/json; charset=UTF-8") | 
 | 		resp, err := client.Do(req) | 
 | 		if err != nil { | 
 | 			log.Fatal(err) | 
 | 		} | 
 | 		dt := time.Now().Sub(start) | 
 | 		dts = append(dts, dt) | 
 |  | 
 | 		if resp.StatusCode/100 == 2 { | 
 | 			continue | 
 | 		} | 
 | 		log.Println("code", resp.StatusCode) | 
 | 		io.Copy(os.Stdout, resp.Body) | 
 | 	} | 
 |  | 
 | 	sort.Slice(dts, func(i, j int) bool { return dts[i] < dts[j] }) | 
 |  | 
 | 	var total time.Duration | 
 | 	for _, dt := range dts { | 
 | 		total += dt | 
 | 	} | 
 | 	log.Printf("min %v max %v median %v avg %v", dts[0], dts[len(dts)-1], dts[len(dts)/2], total/time.Duration(len(dts))) | 
 | } |