github.com/googleapis/api-linter@v1.65.2/rules/internal/utils/http_test.go (about) 1 // Copyright 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package utils 16 17 import ( 18 "strings" 19 "testing" 20 21 "github.com/google/go-cmp/cmp" 22 "github.com/googleapis/api-linter/rules/internal/testutils" 23 apb "google.golang.org/genproto/googleapis/api/annotations" 24 ) 25 26 func TestGetHTTPRules(t *testing.T) { 27 for _, method := range []string{"GET", "POST", "PUT", "PATCH", "DELETE"} { 28 t.Run(method, func(t *testing.T) { 29 file := testutils.ParseProto3Tmpl(t, ` 30 import "google/api/annotations.proto"; 31 service Library { 32 rpc FrobBook(FrobBookRequest) returns (FrobBookResponse) { 33 option (google.api.http) = { 34 {{.M}}: "/v1/publishers/*/books/*" 35 additional_bindings { 36 {{.M}}: "/v1/books/*" 37 } 38 }; 39 } 40 } 41 message FrobBookRequest {} 42 message FrobBookResponse {} 43 `, struct{ M string }{M: strings.ToLower(method)}) 44 45 // Get the rules. 46 resp := GetHTTPRules(file.GetServices()[0].GetMethods()[0]) 47 48 // Establish that we get back both HTTP rules, in order. 49 if got, want := resp[0].URI, "/v1/publishers/*/books/*"; got != want { 50 t.Errorf("Rule 1: Got URI %q, expected %q.", got, want) 51 } 52 if got, want := resp[1].URI, "/v1/books/*"; got != want { 53 t.Errorf("Rule 2: Got URI %q, expected %q.", got, want) 54 } 55 for _, httpRules := range resp { 56 if got, want := httpRules.Method, method; got != want { 57 t.Errorf("Got method %q, expected %q.", got, want) 58 } 59 } 60 }) 61 } 62 } 63 64 func TestGetHTTPRulesEmpty(t *testing.T) { 65 file := testutils.ParseProto3String(t, ` 66 import "google/api/annotations.proto"; 67 service Library { 68 rpc FrobBook(FrobBookRequest) returns (FrobBookResponse); 69 } 70 message FrobBookRequest {} 71 message FrobBookResponse {} 72 `) 73 if resp := GetHTTPRules(file.GetServices()[0].GetMethods()[0]); len(resp) > 0 { 74 t.Errorf("Got %v; expected no rules.", resp) 75 } 76 } 77 78 func TestParseRuleEmpty(t *testing.T) { 79 http := &apb.HttpRule{} 80 if got := parseRule(http); got != nil { 81 t.Errorf("Got %v, expected nil.", got) 82 } 83 } 84 85 func TestGetHTTPRulesCustom(t *testing.T) { 86 file := testutils.ParseProto3String(t, ` 87 import "google/api/annotations.proto"; 88 service Library { 89 rpc FrobBook(FrobBookRequest) returns (FrobBookResponse) { 90 option (google.api.http) = { 91 custom: { 92 kind: "HEAD" 93 path: "/v1/books/*" 94 } 95 }; 96 } 97 } 98 message FrobBookRequest {} 99 message FrobBookResponse {} 100 `) 101 rule := GetHTTPRules(file.GetServices()[0].GetMethods()[0])[0] 102 if got, want := rule.Method, "HEAD"; got != want { 103 t.Errorf("Got %q; expected %q.", got, want) 104 } 105 if got, want := rule.URI, "/v1/books/*"; got != want { 106 t.Errorf("Got %q; expected %q.", got, want) 107 } 108 } 109 110 func TestGetPlainURI(t *testing.T) { 111 tests := []struct { 112 name string 113 uri string 114 plainURI string 115 }{ 116 {"KeyOnly", "/v1/publishers/{pub_id}/books/{book_id}", "/v1/publishers/*/books/*"}, 117 {"KeyValue", "/v1/{name=publishers/*/books/*}", "/v1/publishers/*/books/*"}, 118 {"MultiKeyValue", "/v1/{publisher=publishers/*}/{book=books/*}", "/v1/publishers/*/books/*"}, 119 {"TemplateVariableSegment", "/{$api_version}/publishers/{pub_id}/books/{book_id}", "/v/publishers/*/books/*"}, 120 } 121 for _, test := range tests { 122 t.Run(test.name, func(t *testing.T) { 123 rule := &HTTPRule{URI: test.uri} 124 if diff := cmp.Diff(rule.GetPlainURI(), test.plainURI); diff != "" { 125 t.Errorf(diff) 126 } 127 }) 128 } 129 } 130 131 func TestGetVariables(t *testing.T) { 132 tests := []struct { 133 name string 134 uri string 135 vars map[string]string 136 }{ 137 {"KeyOnly", "/v1/publishers/{pub_id}/books/{book_id}", map[string]string{"pub_id": "*", "book_id": "*"}}, 138 {"KeyValue", "/v1/{name=publishers/*/books/*}", map[string]string{"name": "publishers/*/books/*"}}, 139 {"MultiKeyValue", "/v1/{publisher=publishers/*}/{book=books/*}", map[string]string{"publisher": "publishers/*", "book": "books/*"}}, 140 {"IgnoreVersioningVariable", "/{$api_version}/{name=publishers/*/books/*}", map[string]string{"name": "publishers/*/books/*"}}, 141 } 142 for _, test := range tests { 143 t.Run(test.name, func(t *testing.T) { 144 rule := &HTTPRule{URI: test.uri} 145 if diff := cmp.Diff(rule.GetVariables(), test.vars); diff != "" { 146 t.Errorf(diff) 147 } 148 }) 149 } 150 } 151 152 func TestHasHTTPRules(t *testing.T) { 153 for _, tst := range []struct { 154 name string 155 Annotation string 156 }{ 157 {"has_rule", `option (google.api.http) = {get: "/v1/foos"};`}, 158 {"no_rule", ""}, 159 } { 160 t.Run(tst.name, func(t *testing.T) { 161 file := testutils.ParseProto3Tmpl(t, ` 162 import "google/api/annotations.proto"; 163 164 service Foo { 165 rpc ListFoos (ListFoosRequest) returns (ListFoosResponse) { 166 {{ .Annotation }} 167 } 168 } 169 170 message ListFoosRequest {} 171 message ListFoosResponse {} 172 `, tst) 173 want := tst.Annotation != "" 174 175 got := HasHTTPRules(file.GetServices()[0].GetMethods()[0]) 176 177 if got != want { 178 t.Errorf("Got %v, expected %v", got, want) 179 } 180 }) 181 } 182 }