blob: dc320d6ae1c87cce252bf1f275dab4812d866b7c [file] [log] [blame]
Han-Wen Nienhuys3133fea2019-09-05 19:53:32 +02001// Copyright (C) 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Program to benchmark Gerrit. Creates pending changes in a loop,
16// which tests performance of BatchRefUpdate and Lucene indexing
17package main
18
19import (
20 "bytes"
21 "encoding/base64"
22 "flag"
23 "fmt"
24 "io"
25 "log"
26 "net/http"
27 "net/url"
28 "os"
29 "sort"
30 "time"
31)
32
33func main() {
34 user := flag.String("user", "admin", "username for basic auth")
35 pw := flag.String("password", "secret", "HTTP password for basic auth")
36 project := flag.String("project", "", "project to create changes in")
37 gerritURL := flag.String("url", "http://localhost:8080/", "URL to gerrit instance")
38 numChanges := flag.Int("n", 100, "number of changes to create")
39 flag.Parse()
40 if *gerritURL == "" {
41 log.Fatal("provide --url")
42 }
43 if *project == "" {
44 log.Fatal("provide --project")
45 }
46
47 u, err := url.Parse(*gerritURL)
48 if err != nil {
49 log.Fatal(err)
50 }
51
52 basicAuth := fmt.Sprintf("%s:%s", *user, *pw)
53 authHeader := base64.StdEncoding.EncodeToString([]byte(basicAuth))
54
55 client := &http.Client{}
56
57 var dts []time.Duration
58 startAll := time.Now()
59 var lastSec int
60 for i := 0; i < *numChanges; i++ {
61 body := fmt.Sprintf(`{
62 "project" : "%s",
63 "subject" : "change %d",
64 "branch" : "master",
65 "status" : "NEW"
66 }`, *project, i)
67 start := time.Now()
68
69 thisSec := int(start.Sub(startAll) / time.Second)
70 if thisSec != lastSec {
71 log.Printf("change %d", i)
72 }
73 lastSec = thisSec
74
75 u.Path = "/a/changes/"
76 req, err := http.NewRequest("POST", u.String(), bytes.NewBufferString(body))
77 if err != nil {
78 log.Fatal(err)
79 }
80 req.Header.Add("Authorization", "Basic "+authHeader)
81 req.Header.Add("Content-Type", "application/json; charset=UTF-8")
82 resp, err := client.Do(req)
83 if err != nil {
84 log.Fatal(err)
85 }
86 dt := time.Now().Sub(start)
87 dts = append(dts, dt)
88
89 if resp.StatusCode/100 == 2 {
90 continue
91 }
92 log.Println("code", resp.StatusCode)
93 io.Copy(os.Stdout, resp.Body)
94 }
95
96 sort.Slice(dts, func(i, j int) bool { return dts[i] < dts[j] })
97
98 var total time.Duration
99 for _, dt := range dts {
100 total += dt
101 }
102 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)))
103}