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  }