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