blob: 3e68abff35ddb03a3efabdb08eb8fc7908937c56 [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 utils
import (
"errors"
"fmt"
"strings"
"testing"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
const (
testInstanceURL = "cos-review.googlesource.com"
)
func testCLLink(clID, instanceURL string) string {
return fmt.Sprintf("<a href=\"%s/c/%s\" target=\"_blank\">CL %s</a>", instanceURL, clID, clID)
}
func TestGerritErrCode(t *testing.T) {
tests := map[string]struct {
inputErr error
expectedCode string
}{
"Empty Error": {
inputErr: errors.New(""),
expectedCode: "500",
},
"Mapped Error Code": {
inputErr: errors.New("failed to fetch \"https://cos-internal-review.googlesource.com/a/changes/?n=1&o=CURRENT_REVISION&q=1\", status code 403"),
expectedCode: "403",
},
"Irregular Code": {
inputErr: errors.New("failed to fetch \"https://cos-internal-review.googlesource.com/a/changes/?n=1&o=CURRENT_REVISION&q=1\", status code 689"),
expectedCode: "689",
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
code := GerritErrCode(test.inputErr)
if code != test.expectedCode {
t.Errorf("expected HTTP code %s, got %s", test.expectedCode, code)
}
})
}
}
func TestGitilesErrCode(t *testing.T) {
tests := map[string]struct {
inputErr error
expectedCode string
}{
"Default Error Code": {
inputErr: errors.New("code = e desc = not a desc"),
expectedCode: "500",
},
"Mapped Error Code": {
inputErr: status.New(codes.NotFound, "not found").Err(),
expectedCode: "404",
},
"403 Code Edge Case": {
inputErr: status.New(codes.Internal, "unexpected HTTP 403 from Gitiles").Err(),
expectedCode: "403",
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
code := GitilesErrCode(test.inputErr)
if code != test.expectedCode {
t.Errorf("expected HTTP code %s, got %s", test.expectedCode, code)
}
})
}
}
func TestBothBuildsNotFound(t *testing.T) {
source := "cos-stable-81-12871-103-0"
target := "cos-stable-81-12871-117-0"
croslandURL := "https://www.google.com"
expectedCode := "404"
expectedErrHeader := "Build Not Found"
expectedErrStr := strings.Join([]string{
"The builds associated with input",
source,
"and",
target,
"cannot be found. It may be possible that the inputs are either invalid or both belong",
"to pre-Cusky builds. If both of the inputs belong to pre-Cusky builds, note that this tool only supports changelogs",
"between Cusky builds. Otherwise, please input valid build numbers (example: 13310.1035.0) or valid image names",
"(example: cos-rc-85-13310-1034-0).",
}, " ")
expectedHTMLErrStr := fmt.Sprintf("%s %s and %s %s<br><br>%s %s <a href=%s target=\"_blank\">%s</a>. %s %s",
"The builds associated with input",
source,
target,
"could not be found.",
"It may be possible that the inputs are either invalid or both belong to pre-Cusky builds.",
"If both of the inputs belong to pre-Cusky builds, please check",
croslandLink(croslandURL, source, target),
croslandLink(croslandURL, source, target),
"Otherwise, please input valid build numbers",
"(example: 13310.1035.0) or valid image names (example: cos-rc-85-13310-1034-0).",
)
err := BothBuildsNotFound(croslandURL, source, target, source, target)
if err.HTTPCode() != expectedCode {
t.Errorf("expected HTTP code %s, got %s", expectedCode, err.HTTPCode())
} else if err.Header() != expectedErrHeader {
t.Errorf("expected error header \"%s\", got %s", expectedErrHeader, err.Header())
} else if err.Error() != expectedErrStr {
t.Errorf("expected error string %s, got %s", expectedErrStr, err.Error())
} else if err.HTMLError() != expectedHTMLErrStr {
t.Errorf("expected html error string %s, got %s", expectedErrStr, err.HTMLError())
} else if err.Retryable() {
t.Errorf("expected retryable = false, got true")
}
}
func TestBuildNotFound(t *testing.T) {
buildNumber := "cos-stable-81-12871-117-0"
expectedCode := "404"
expectedErrHeader := "Build Not Found"
expectedErrStr := strings.Join([]string{
"The build associated with input",
buildNumber,
"cannot be found. It may be possible that the input is either invalid or belongs to a",
"pre-Cusky build. If you entered a pre-Cusky build number or image name, note that changelog between",
"pre-Cusky and Cusky builds are not supported. Otherwise, please input a valid build number",
"(example: 13310.1035.0) or a valid image name (example: cos-rc-85-13310-1034-0).",
}, " ")
expectedHTMLErrStr := fmt.Sprintf("%s %s %s<br><br>%s %s %s %s",
"The build associated with input",
buildNumber,
"cannot be found.",
"It may be possible that either the input is either invalid or belongs to a",
"pre-Cusky build. If you entered a pre-Cusky build number or image name, note that changelog between",
"pre-Cusky and Cusky builds are not supported. Otherwise, please input a valid build number",
"(example: 13310.1035.0) or a valid image name (example: cos-rc-85-13310-1034-0).",
)
err := BuildNotFound(buildNumber)
if err.HTTPCode() != expectedCode {
t.Errorf("expected HTTP code %s, got %s", expectedCode, err.HTTPCode())
} else if err.Header() != expectedErrHeader {
t.Errorf("expected error header \"%s\", got %s", expectedErrHeader, err.Header())
} else if err.Error() != expectedErrStr {
t.Errorf("expected error string %s, got %s", expectedErrStr, err.Error())
} else if err.HTMLError() != expectedHTMLErrStr {
t.Errorf("expected html error string %s, got %s", expectedErrStr, err.HTMLError())
} else if err.Retryable() {
t.Errorf("expected retryable = false, got true")
}
}
func TestCLNotFound(t *testing.T) {
clID := "1540"
expectedCode := "404"
expectedErrHeader := "CL Not Found"
expectedErrStr := fmt.Sprintf("No CL was found matching the identifier: %s. Please enter either the CL-number (example: 3206) or a Commit-SHA (example: I7e549d7753cc7acec2b44bb5a305347a97719ab9) of a submitted CL.", clID)
err := CLNotFound(clID)
if err.HTTPCode() != expectedCode {
t.Errorf("expected HTTP code %s, got %s", expectedCode, err.HTTPCode())
} else if err.Header() != expectedErrHeader {
t.Errorf("expected error header \"%s\", got %s", expectedErrHeader, err.Header())
} else if err.Error() != expectedErrStr {
t.Errorf("expected error string %s, got %s", expectedErrStr, err.Error())
} else if err.HTMLError() != expectedErrStr {
t.Errorf("expected html error string %s, got %s", expectedErrStr, err.HTMLError())
} else if err.Retryable() {
t.Errorf("expected retryable = false, got true")
}
}
func TestCLLandingNotFound(t *testing.T) {
clID := "1540"
expectedCode := "406"
expectedErrHeader := "No Build Found"
expectedErrStr := fmt.Sprintf("No build was found containing CL %s.", clID)
link := testCLLink(clID, testInstanceURL)
expectedHTMLErrStr := fmt.Sprintf("No build was found containing %s.", link)
err := CLLandingNotFound(clID, testInstanceURL)
if err.HTTPCode() != expectedCode {
t.Errorf("expected HTTP code %s, got %s", expectedCode, err.HTTPCode())
} else if err.Header() != expectedErrHeader {
t.Errorf("expected error header \"%s\", got %s", expectedErrHeader, err.Header())
} else if err.Error() != expectedErrStr {
t.Errorf("expected error string %s, got %s", expectedErrStr, err.Error())
} else if err.HTMLError() != expectedHTMLErrStr {
t.Errorf("expected html error string %s, got %s", expectedHTMLErrStr, err.HTMLError())
} else if !err.Retryable() {
t.Errorf("expected retryable = true, got false")
}
}
func TestCLNotUsed(t *testing.T) {
clID := "1540"
repo := "cos/tools"
branch := "master"
expectedCode := "406"
expectedErrHeader := "CL Not Used"
expectedErrStr := fmt.Sprintf("CL %s modifies the %s repository on the %s branch, which has not been used in COS builds since the CL's submission.", clID, repo, branch)
link := testCLLink(clID, testInstanceURL)
expectedHTMLErrStr := fmt.Sprintf("%s modifies the %s repository on the %s branch, which has not been used in COS builds since the CL's submission.", link, repo, branch)
err := CLNotUsed(clID, repo, branch, testInstanceURL)
if err.HTTPCode() != expectedCode {
t.Errorf("expected HTTP code %s, got %s", expectedCode, err.HTTPCode())
} else if err.Header() != expectedErrHeader {
t.Errorf("expected error header \"%s\", got %s", expectedErrHeader, err.Header())
} else if err.Error() != expectedErrStr {
t.Errorf("expected error string %s, got %s", expectedErrStr, err.Error())
} else if err.HTMLError() != expectedHTMLErrStr {
t.Errorf("expected html error string %s, got %s", expectedHTMLErrStr, err.HTMLError())
} else if err.Retryable() {
t.Errorf("expected retryable = false, got true")
}
}
func TestCLTooRecent(t *testing.T) {
clID := "1540"
expectedCode := "406"
expectedErrHeader := "CL Too Recent"
expectedErrStr := fmt.Sprintf("CL %s was submitted too recently to be included in any builds. Please wait a couple hours and try again.", clID)
link := testCLLink(clID, testInstanceURL)
expectedHTMLErrStr := fmt.Sprintf("%s was submitted too recently to be included in any builds. Please wait a couple hours and try again.", link)
err := CLTooRecent(clID, testInstanceURL)
if err.HTTPCode() != expectedCode {
t.Errorf("expected HTTP code %s, got %s", expectedCode, err.HTTPCode())
} else if err.Header() != expectedErrHeader {
t.Errorf("expected error header \"%s\", got %s", expectedErrHeader, err.Header())
} else if err.Error() != expectedErrStr {
t.Errorf("expected error string %s, got %s", expectedErrStr, err.Error())
} else if err.HTMLError() != expectedHTMLErrStr {
t.Errorf("expected html error string %s, got %s", expectedHTMLErrStr, err.HTMLError())
} else if err.Retryable() {
t.Errorf("expected retryable = false, got true")
}
}
func TestCLNotSubmitted(t *testing.T) {
clID := "1540"
expectedCode := "406"
expectedErrHeader := "CL Not Submitted"
expectedErrStr := fmt.Sprintf("CL %s has not been submitted yet. A CL will not enter any build until it is successfully submitted.", clID)
link := testCLLink(clID, testInstanceURL)
expectedHTMLErrStr := fmt.Sprintf("%s has not been submitted yet. A CL will not enter any build until it is successfully submitted.", link)
err := CLNotSubmitted(clID, testInstanceURL)
if err.HTTPCode() != expectedCode {
t.Errorf("expected HTTP code %s, got %s", expectedCode, err.HTTPCode())
} else if err.Header() != expectedErrHeader {
t.Errorf("expected error header \"%s\", got %s", expectedErrHeader, err.Header())
} else if err.Error() != expectedErrStr {
t.Errorf("expected error string %s, got %s", expectedErrStr, err.Error())
} else if err.HTMLError() != expectedHTMLErrStr {
t.Errorf("expected html error string %s, got %s", expectedHTMLErrStr, err.HTMLError())
}
}
func TestCLInvalidRelease(t *testing.T) {
clID := "1540"
release := "master"
expectedCode := "406"
expectedErrHeader := "Invalid Release Branch"
expectedErrStr := fmt.Sprintf("CL %s maps to release %s, which is not a valid release", clID, release)
link := testCLLink(clID, testInstanceURL)
expectedHTMLErrStr := fmt.Sprintf("%s maps to release %s, which is not a valid release", link, release)
err := CLInvalidRelease(clID, release, testInstanceURL)
if err.HTTPCode() != expectedCode {
t.Errorf("expected HTTP code %s, got %s", expectedCode, err.HTTPCode())
} else if err.Header() != expectedErrHeader {
t.Errorf("expected error header \"%s\", got %s", expectedErrHeader, err.Header())
} else if err.Error() != expectedErrStr {
t.Errorf("expected error string %s, got %s", expectedErrStr, err.Error())
} else if err.HTMLError() != expectedHTMLErrStr {
t.Errorf("expected html error string %s, got %s", expectedHTMLErrStr, err.HTMLError())
} else if err.Retryable() {
t.Errorf("expected retryable = false, got true")
}
}