blob: 7c623ac19dc8c6dc4640cead67e58b1ed5eab9fd [file] [log] [blame]
// Copyright 2020 Google Inc. All Rights Reserved.
//
// 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 changelog
import (
"reflect"
"testing"
"time"
"go.chromium.org/luci/common/proto/git"
"google.golang.org/protobuf/types/known/timestamppb"
)
const (
id string = "4f07bfb8463cb54227cc4cdbffc5d295edc05631"
tree string = "c005de2ade3f30506e7899b5c95d17f2904a598f"
parent string = "7645df3136c5b5e43eb1af182b0c67d78ca2d517"
authorName string = "Austin Yuan"
committerName string = "Boston Yuan"
timeVal string = "Sat, 1 Feb 2020"
)
var authorTime time.Time
var committerTime time.Time
func init() {
authorTime = time.Date(2019, 6, 6, 10, 50, 0, 0, time.UTC)
committerTime = time.Date(2020, 2, 1, 8, 15, 0, 0, time.UTC)
}
func createCommitWithMessage(message string) *git.Commit {
return &git.Commit{
Id: id,
Tree: tree,
Parents: []string{parent},
Author: &git.Commit_User{Name: authorName, Email: "austinyuan@google.com", Time: timestamppb.New(authorTime)},
Committer: &git.Commit_User{Name: committerName, Email: "bostonyuan@google.com", Time: timestamppb.New(committerTime)},
Message: message,
}
}
func TestParseGitCommitLog(t *testing.T) {
tests := map[string]struct {
Input []*git.Commit
SHAs []string
AuthorNames []string
CommitterNames []string
Subjects []string
Bugs [][]string
ReleaseNote []string
CommitTime []string
ShouldError bool
}{
"basic": {
Input: []*git.Commit{createCommitWithMessage(`provision_AutoUpdate: Do not stage AU payloads unless necessary
Currently provisionning always stages the AU full payloads at the
beginning. But majority of provision runs succeed by quick-provisioning
and they never get to AU provisioning. So this is a waste of time and
space trying to stage large files that are not going to be used. This CL
fixes that problem.
BUG=chromium:1097995
TEST=test_that --args="value='reef-release/R85-13280.0.0'" chromeos6-row4-rack10-host19.cros.corp.google.com provision_AutoUpdate
TEST=same as above, but changed the code to skip the quick-provisioning
RELEASE_NOTE=Upgraded the Linux kernel to v4.14.174
Change-Id: I0b6895f7860921f6bed25090d64f8489dbeeb19e
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/2268290
Tested-by: Amin Hassani <ahassani@chromium.org>
Commit-Queue: Amin Hassani <ahassani@chromium.org>
Reviewed-by: Allen Li <ayatane@chromium.org>
Auto-Submit: Amin Hassani <ahassani@chromium.org>`)},
SHAs: []string{id},
AuthorNames: []string{authorName},
CommitterNames: []string{committerName},
Subjects: []string{"provision_AutoUpdate: Do not stage AU payloads unless necessary"},
Bugs: [][]string{{"crbug/1097995"}},
ReleaseNote: []string{"Upgraded the Linux kernel to v4.14.174"},
CommitTime: []string{timeVal},
ShouldError: false,
},
"multiple bugs": {
Input: []*git.Commit{createCommitWithMessage(`autotest: Move host dependency check inside verifier.
Moved it to minimize fail case if host is not available.
BUG=chromium:1069101, chromium:1059439, b:533302,b/21114011,chromium-os:993221,chrome-os-partner:3341233
TEST=unittests, presubmit, run local
RELEASE_NOTE=Upgraded autotest`)},
SHAs: []string{id},
AuthorNames: []string{authorName},
CommitterNames: []string{committerName},
Subjects: []string{"autotest: Move host dependency check inside verifier."},
Bugs: [][]string{{"crbug/1069101", "crbug/1059439", "b/533302", "b/21114011", "crbug/993221", "crbug/3341233"}},
ReleaseNote: []string{"Upgraded autotest"},
CommitTime: []string{timeVal},
ShouldError: false,
},
"improperly formatted bugs": {
Input: []*git.Commit{createCommitWithMessage(`chrome-os-partner:1224444
b/3225555
BUG=54985123, z, c/54811233, notabug, 0, b%21333443, -3, hello b/12321155,
TEST=b/2222222
RELEASE_NOTE=chromium:5556555`)},
SHAs: []string{id},
AuthorNames: []string{authorName},
CommitterNames: []string{committerName},
Subjects: []string{"chrome-os-partner:1224444"},
Bugs: [][]string{{}},
ReleaseNote: []string{"chromium:5556555"},
CommitTime: []string{timeVal},
ShouldError: false,
},
"proper and improper bugs": {
Input: []*git.Commit{createCommitWithMessage(`autotest: Move host dependency check inside verifier.
Some extra details here
BUG=3, -1, b:2212344, c/54811233, chrome-os-partner:1111111, notabug, b%21333443, test b:6644322
TEST=unittests, presubmit, run local
RELEASE_NOTE=b/1224222`)},
SHAs: []string{id},
AuthorNames: []string{authorName},
CommitterNames: []string{committerName},
Subjects: []string{"autotest: Move host dependency check inside verifier."},
Bugs: [][]string{{"b/2212344", "crbug/1111111"}},
ReleaseNote: []string{"b/1224222"},
CommitTime: []string{timeVal},
ShouldError: false,
},
"empty commit message": {
Input: []*git.Commit{createCommitWithMessage("")},
SHAs: []string{id},
AuthorNames: []string{authorName},
CommitterNames: []string{committerName},
Subjects: []string{""},
Bugs: [][]string{{}},
ReleaseNote: []string{""},
CommitTime: []string{timeVal},
ShouldError: false,
},
"only subject line": {
Input: []*git.Commit{createCommitWithMessage("$()!-1")},
SHAs: []string{id},
AuthorNames: []string{authorName},
CommitterNames: []string{committerName},
Subjects: []string{"$()!-1"},
Bugs: [][]string{{}},
ReleaseNote: []string{""},
CommitTime: []string{timeVal},
ShouldError: false,
},
"no bug line and empty release line": {
Input: []*git.Commit{createCommitWithMessage(`autotest: Move host dependency check inside verifier.
Moved it to minimize fail case if host is not available.
AdminAudit is starting with the set of actions and all of them has to
run if possible. By this move we allowed each verifier to check what
required to run.
If dependency not provided we can skip of the action.
TEST=unittests, presubmit, run local
RELEASE=`)},
SHAs: []string{id},
AuthorNames: []string{authorName},
CommitterNames: []string{committerName},
Subjects: []string{"autotest: Move host dependency check inside verifier."},
Bugs: [][]string{{}},
ReleaseNote: []string{""},
CommitTime: []string{timeVal},
ShouldError: false,
},
"leading spaces for bug and release line": {
Input: []*git.Commit{createCommitWithMessage(`autotest: Move host dependency check inside verifier.
Moved it to minimize fail case if host is not available.
BUG=chromium:1069101, chromium:1059439, b:533302,b/21114011,chromium-os:993221,chrome-os-partner:3341233
TEST=unittests, presubmit, run local
RELEASE_NOTE=Upgraded autotest `)},
SHAs: []string{id},
AuthorNames: []string{authorName},
CommitterNames: []string{committerName},
Subjects: []string{"autotest: Move host dependency check inside verifier."},
Bugs: [][]string{{"crbug/1069101", "crbug/1059439", "b/533302", "b/21114011", "crbug/993221", "crbug/3341233"}},
ReleaseNote: []string{"Upgraded autotest"},
CommitTime: []string{timeVal},
ShouldError: false,
},
"empty bug line": {
Input: []*git.Commit{createCommitWithMessage(`autotest: Move host dependency check inside verifier.
Moved it to minimize fail case if host is not available.
AdminAudit is starting with the set of actions and all of them has to
run if possible. By this move we allowed each verifier to check what
required to run.
If dependency not provided we can skip of the action.
BUG=
TEST=unittests, presubmit, run local
RELEASE=`)},
SHAs: []string{id},
AuthorNames: []string{authorName},
CommitterNames: []string{committerName},
Subjects: []string{"autotest: Move host dependency check inside verifier."},
Bugs: [][]string{{}},
ReleaseNote: []string{""},
CommitTime: []string{timeVal},
ShouldError: false,
},
"missing fields": {
Input: []*git.Commit{{
Id: id,
Tree: "",
Parents: nil,
Author: nil,
Committer: nil,
Message: "",
}},
SHAs: []string{id},
AuthorNames: []string{"None"},
CommitterNames: []string{"None"},
Subjects: []string{""},
Bugs: [][]string{{}},
ReleaseNote: []string{""},
CommitTime: []string{"None"},
ShouldError: false,
},
"multiple commits": {
Input: []*git.Commit{
createCommitWithMessage(`This is a subject
This commit has no bugs
TEST=unittests, presubmit, run local
RELEASE=`),
createCommitWithMessage(`autotest: Some subject
This commit some bugs
BUG=b/4332134, chrome-os-partner:0999212, b:11111
TEST=unittests, presubmit, run local
Change-Id: I0b6895f7860921f6bed25090d64f8489dbeeb19e
RELEASE_NOTE=test release`),
createCommitWithMessage(`Third
This commits has some multiple bugs, some not valid b/1221212
BUG=56456651, chromium:777882, -1, b:9999999`),
},
SHAs: []string{id, id, id},
AuthorNames: []string{authorName, authorName, authorName},
CommitterNames: []string{committerName, committerName, committerName},
Subjects: []string{"This is a subject", "autotest: Some subject", "Third"},
Bugs: [][]string{{}, {"b/4332134", "crbug/0999212", "b/11111"}, {"crbug/777882", "b/9999999"}},
ReleaseNote: []string{"", "test release", ""},
CommitTime: []string{timeVal, timeVal, timeVal},
ShouldError: false,
},
"empty list": {
Input: []*git.Commit{},
SHAs: []string{},
AuthorNames: []string{},
CommitterNames: []string{},
Subjects: []string{},
Bugs: [][]string{},
ShouldError: false,
},
"nil input": {
Input: nil,
ShouldError: true,
},
"normal and nil input": {
Input: []*git.Commit{
createCommitWithMessage(`This is a subject
This commit has no bugs
TEST=unittests, presubmit, run local
RELEASE_NOTE=`),
createCommitWithMessage(`autotest: Some subject
This commit some bugs
BUG=b/4332134, chrome-os-partner:0999212, b:11111
TEST=unittests, presubmit, run local
Change-Id: I0b6895f7860921f6bed25090d64f8489dbeeb19e
RELEASE NOTE=test release`),
nil,
createCommitWithMessage(`Third
This commits has some multiple bugs, some not valid b/1221212
BUG=56456651, chromium:777882, -1, b:9999999`),
},
ShouldError: true,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
res, err := ParseGitCommitLog(test.Input)
switch {
case (err != nil) != test.ShouldError:
ShouldError := "no error"
if test.ShouldError {
ShouldError = "some error"
}
t.Fatalf("expected %v, got: %v\n", ShouldError, err)
case test.ShouldError && (err != nil) == test.ShouldError && res == nil:
}
for i, commit := range res {
switch {
case commit.SHA != test.SHAs[i]:
t.Errorf("expected commitSHA %s, got %s", test.SHAs[i], commit.SHA)
case commit.AuthorName != test.AuthorNames[i]:
t.Errorf("expected authorName: %s, got: %s", test.AuthorNames[i], commit.AuthorName)
case commit.CommitterName != test.CommitterNames[i]:
t.Errorf("expected committerName %s, got %s", test.CommitterNames[i], commit.CommitterName)
case commit.Subject != test.Subjects[i]:
t.Errorf("expected subject %s, got %s", test.Subjects[i], commit.Subject)
case !reflect.DeepEqual(commit.Bugs, test.Bugs[i]):
t.Errorf("exptected bugs %#v, got %#v", test.Bugs[i], commit.Bugs)
case commit.ReleaseNote != test.ReleaseNote[i]:
t.Errorf("expected release note %s, got %s", test.ReleaseNote[i], commit.ReleaseNote)
case commit.CommitTime != test.CommitTime[i]:
t.Errorf("expected commit time %s, got %s", test.CommitTime[i], commit.CommitTime)
}
}
})
}
}