blob: 9be3894353a19be4d6c4ebfaa92849d1b90f8c35 [file] [log] [blame]
// Copyright 2020 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.
package proftest
import (
"regexp"
"testing"
"time"
)
func TestParseBenchmarkNumber(t *testing.T) {
benchNumRE, err := regexp.Compile("benchmark (\\d+):")
if err != nil {
t.Fatalf("failed to get benchmark regexp: %v", err)
}
numBenchmarks := 150
for _, tc := range []struct {
desc string
line string
wantBenchNum int
wantErr bool
}{
{
desc: "zero parsed successfully as benchmark number",
line: "benchmark 0: 2020/05/15 23:37:56 start uploading profile",
wantBenchNum: 0,
},
{
desc: "benchmark number for empty line can be parsed",
line: "benchmark 5:",
wantBenchNum: 5,
},
{
desc: "multi-digit benchmark number can be parsed",
line: "benchmark 149: line",
wantBenchNum: 149,
},
{
desc: "benchmark number can be parsed when it is not at the start of the line",
line: "Mon May 18 00:00:00 UTC 2020: benchmark 5: line",
wantBenchNum: 5,
},
{
desc: "an error is returned when benchmark number is outside the expected range of benchmark numbers",
line: "benchmark 150: line",
wantErr: true,
},
{
desc: "an error is returned when benchmark number is not a number",
line: "benchmark abc: 2020/05/15 23:40:46 creating a new profile via profiler service",
wantErr: true,
},
} {
t.Run(tc.desc, func(t *testing.T) {
benchNum, err := parseBenchmarkNumber(tc.line, numBenchmarks, benchNumRE)
if (err != nil) != tc.wantErr {
t.Errorf("got err = %v; want (err != nil) = %v", err, tc.wantErr)
}
if tc.wantErr {
return
}
if benchNum != tc.wantBenchNum {
t.Errorf("got benchmark number = %v, want %v", benchNum, tc.wantBenchNum)
}
})
}
}
func TestParseLogTime(t *testing.T) {
for _, tc := range []struct {
desc string
line string
wantTime time.Time
wantErr bool
}{
{
desc: "a valid timestamp is parsed correctly",
line: "Fri May 15 23:39:53 UTC 2020: benchmark 31: creating a new profile via profiler service",
wantTime: time.Date(2020, 5, 15, 23, 39, 53, 0, time.UTC),
},
{
desc: "an error is returned when the timestamp is invalid",
line: "Fri May 15 26:39:53 UTC 2020: benchmark 31: creating a new profile via profiler service",
wantErr: true,
},
} {
t.Run(tc.desc, func(t *testing.T) {
logTime, err := parseLogTime(tc.line)
if (err != nil) != tc.wantErr {
t.Errorf("got err = %v; want (err != nil) = %v", err, tc.wantErr)
}
if tc.wantErr {
return
}
if !logTime.Equal(tc.wantTime) {
t.Errorf("got log time = %v, want %v", logTime, tc.wantTime)
}
})
}
}
func TestParseBackoffDuration(t *testing.T) {
for _, tc := range []struct {
desc string
line string
wantBackoffDur time.Duration
wantErr bool
}{
{
desc: "a valid backoff duration is parsed correctly",
line: "Fri May 15 22:05:01 UTC 2020: benchmark 0: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 32m0s",
wantBackoffDur: 32 * time.Minute,
},
{
desc: "a floating-point backoff duration is parsed correctly",
line: "Fri May 15 22:05:01 UTC 2020: benchmark 0: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 2000.000s",
wantBackoffDur: 2000 * time.Second,
},
{
desc: "an error is returned when the backoff duration is invalid",
line: "Fri May 15 22:05:01 UTC 2020: benchmark 0: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 32..0.s",
wantErr: true,
},
{
desc: "a backoff duration specifying hours, minutes, seconds, milliseconds and microseconds is parsed correctly.",
line: "Fri May 15 22:05:01 UTC 2020: benchmark 0: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 1h1m1s1ms1us",
wantBackoffDur: time.Hour + time.Minute + time.Second + time.Millisecond + time.Microsecond,
},
} {
t.Run(tc.desc, func(t *testing.T) {
backoffDur, err := parseBackoffDuration(tc.line)
if (err != nil) != tc.wantErr {
t.Errorf("got err = %v; want (err != nil) = %v", err, tc.wantErr)
}
if tc.wantErr {
return
}
if backoffDur != tc.wantBackoffDur {
t.Errorf("backoff duration: got %v, want %v", backoffDur, tc.wantBackoffDur)
}
})
}
}
func TestCheckSerialOutputForBackoffs(t *testing.T) {
for _, tc := range []struct {
desc string
logs string
numBenchmarks int
serverBackoffSubstring string
createProfileSubstring string
benchmarkNumPrefix string
wantErr bool
}{
{
desc: "no error when one benchmark running and the next profile is created after backoff interval",
logs: `
Fri May 15 22:05:00 UTC 2020: benchmark 0: creating a new profile via profiler service
Fri May 15 22:05:01 UTC 2020: benchmark 0: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 32m0s
Fri May 15 22:37:01 UTC 2020: benchmark 0: creating a new profile via profiler service
`,
numBenchmarks: 1,
serverBackoffSubstring: "action throttled, backoff for",
createProfileSubstring: "creating a new profile via profiler service",
benchmarkNumPrefix: "benchmark",
},
{
desc: "no error when one benchmark running and the next profile is created 1 minute after backoff interval has elapsed",
logs: `
Fri May 15 22:05:00 UTC 2020: benchmark 0: creating a new profile via profiler service
Fri May 15 22:05:01 UTC 2020: benchmark 0: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 50m0s
Fri May 15 22:56:01 UTC 2020: benchmark 0: creating a new profile via profiler service
`,
numBenchmarks: 1,
serverBackoffSubstring: "action throttled, backoff for",
createProfileSubstring: "creating a new profile via profiler service",
benchmarkNumPrefix: "benchmark",
},
{
desc: "no error when one benchmark running and the next profile is created 1 minute before backoff interval has elapsed",
logs: `
Fri May 15 22:05:00 UTC 2020: benchmark 0: creating a new profile via profiler service
Fri May 15 22:05:01 UTC 2020: benchmark 0: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 45m0s
Fri May 15 22:49:01 UTC 2020: benchmark 0: creating a new profile via profiler service
`,
numBenchmarks: 1,
serverBackoffSubstring: "action throttled, backoff for",
createProfileSubstring: "creating a new profile via profiler service",
benchmarkNumPrefix: "benchmark",
},
{
desc: "error when one benchmark running and the next profile is created more than 1 minute before backoff interval has elapsed",
logs: `
Fri May 15 22:05:00 UTC 2020: benchmark 0: creating a new profile via profiler service
Fri May 15 22:05:01 UTC 2020: benchmark 0: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 32m0s
Fri May 15 22:36:00 UTC 2020: benchmark 0: creating a new profile via profiler service
`,
numBenchmarks: 1,
serverBackoffSubstring: "action throttled, backoff for",
createProfileSubstring: "creating a new profile via profiler service",
benchmarkNumPrefix: "benchmark",
wantErr: true,
},
{
desc: "error when one benchmark running and the next profile is created more than 1 minute after backoff interval has elapsed",
logs: `
Fri May 15 22:05:00 UTC 2020: benchmark 0: creating a new profile via profiler service
Fri May 15 22:05:01 UTC 2020: benchmark 0: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 32m0s
Fri May 15 22:38:02 UTC 2020: benchmark 0: creating a new profile via profiler service
`,
numBenchmarks: 1,
serverBackoffSubstring: "action throttled, backoff for",
createProfileSubstring: "creating a new profile via profiler service",
benchmarkNumPrefix: "benchmark",
wantErr: true,
},
{
desc: "error when there are no log entries indicating server-specifed backoff",
logs: `
Fri May 15 22:05:00 UTC 2020: benchmark 0: creating a new profile via profiler service
Fri May 15 22:37:01 UTC 2020: benchmark 0: creating a new profile via profiler service
`,
numBenchmarks: 1,
serverBackoffSubstring: "action throttled, backoff for",
createProfileSubstring: "creating a new profile via profiler service",
benchmarkNumPrefix: "benchmark",
wantErr: true,
},
{
desc: "error when missing CreateProfile requests after server specified backoff",
logs: `
Fri May 15 22:05:00 UTC 2020: benchmark 0: creating a new profile via profiler service
Fri May 15 22:05:00 UTC 2020: benchmark 1: creating a new profile via profiler service
Fri May 15 22:05:01 UTC 2020: benchmark 0: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 15m0s
Fri May 15 22:05:01 UTC 2020: benchmark 1: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 32m0s
Fri May 15 22:37:01 UTC 2020: benchmark 1: creating a new profile via profiler service
`,
numBenchmarks: 2,
serverBackoffSubstring: "action throttled, backoff for",
createProfileSubstring: "creating a new profile via profiler service",
benchmarkNumPrefix: "benchmark",
wantErr: true,
},
{
desc: "no error when no missing CreateProfile requests after server specified backoff because benchmarks finished before next request could happen.",
logs: `
Fri May 15 22:05:00 UTC 2020: benchmark 0: creating a new profile via profiler service
Fri May 15 22:05:00 UTC 2020: benchmark 1: creating a new profile via profiler service
Fri May 15 22:05:01 UTC 2020: benchmark 0: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 32m0s
Fri May 15 22:05:01 UTC 2020: benchmark 1: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 32m0s
Fri May 15 22:37:01 UTC 2020: benchmark 0: creating a new profile via profiler service
`,
numBenchmarks: 2,
serverBackoffSubstring: "action throttled, backoff for",
createProfileSubstring: "creating a new profile via profiler service",
benchmarkNumPrefix: "benchmark",
},
{
desc: "no error when there are non-benchmark logs",
logs: `
Fri May 15 22:00:00 UTC 2020: prologue
Fri May 15 22:05:00 UTC 2020: benchmark 0: creating a new profile via profiler service
Fri May 15 22:05:01 UTC 2020: benchmark 0: failed to create profile, will retry: rpc error: code = Aborted desc = generic::aborted: action throttled, backoff for 32m0s
Fri May 15 22:37:01 UTC 2020: benchmark 0: creating a new profile via profiler service
Fri May 15 22:40:00 UTC 2020: epilogue
`,
numBenchmarks: 1,
serverBackoffSubstring: "action throttled, backoff for",
createProfileSubstring: "creating a new profile via profiler service",
benchmarkNumPrefix: "benchmark",
},
} {
t.Run(tc.desc, func(t *testing.T) {
if err := CheckSerialOutputForBackoffs(tc.logs, tc.numBenchmarks, tc.serverBackoffSubstring, tc.createProfileSubstring, tc.benchmarkNumPrefix); (err != nil) != tc.wantErr {
t.Errorf("got err = %v; want (err != nil) = %v", err, tc.wantErr)
}
})
}
}