| // 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))) |
| } |