github.com/googleapis/api-linter@v1.65.2/rules/aip0121/resource_must_support_list_test.go (about)

     1  // Copyright 2023 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 aip0121
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/googleapis/api-linter/lint"
    21  	"github.com/googleapis/api-linter/rules/internal/testutils"
    22  )
    23  
    24  // TestResourceMustSupportList tests the resourceMustSupportList
    25  // lint rule by declaring a service proto, then declaring a
    26  // google.api.resource message, then declaring non-List
    27  // methods.
    28  func TestResourceMustSupportList(t *testing.T) {
    29  	for _, test := range []struct {
    30  		name     string
    31  		RPCs     string
    32  		problems testutils.Problems
    33  	}{
    34  		{"ValidCreateList", `
    35  			rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {};
    36  			rpc CreateBook(CreateBookRequest) returns (Book) {};
    37  		`, nil},
    38  		{"ValidCreateListLRO", `
    39  			rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {};
    40  			rpc CreateBook(CreateBookRequest) returns (google.longrunning.Operation) {
    41  				option (google.longrunning.operation_info) = {
    42  					response_type: "Book"
    43  				};
    44  			};
    45  		`, nil},
    46  		{"ValidListGet", `
    47  			rpc GetBook(GetBookRequest) returns (Book) {};
    48  			rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {};
    49  		`, nil},
    50  		{"ValidUpdateList", `
    51  			rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {};
    52  			rpc UpdateBook(UpdateBookRequest) returns (Book) {};
    53  		`, nil},
    54  		{"InvalidCreateOnly", `
    55  			rpc CreateBook(CreateBookRequest) returns (Book) {};
    56  		`, []lint.Problem{
    57  			{Message: `resource "library.googleapis.com/Book"`},
    58  		}},
    59  		{"InvalidCreateOnlyLRO", `
    60  			rpc CreateBook(CreateBookRequest) returns (google.longrunning.Operation) {
    61  				option (google.longrunning.operation_info) = {
    62  					response_type: "Book"
    63  				};
    64  			};
    65  		`, []lint.Problem{
    66  			{Message: `resource "library.googleapis.com/Book"`},
    67  		}},
    68  		{"InvalidUpdateOnly", `
    69  			rpc UpdateBook(UpdateBookRequest) returns (Book) {};
    70  		`, []lint.Problem{
    71  			{Message: `resource "library.googleapis.com/Book"`},
    72  		}},
    73  		{"InvalidGetOnly", `
    74  			rpc GetBook(GetBookRequest) returns (Book) {};
    75  		`, []lint.Problem{
    76  			{Message: `resource "library.googleapis.com/Book"`},
    77  		}},
    78  		{"ValidIgnoreSingleton", `
    79  			rpc GetBookCover(GetBookCoverRequest) returns (BookCover) {};
    80  		`, nil},
    81  		{"ValidIgnoreNonResource", `
    82  			rpc GetBookCover(GetBookCoverRequest) returns (Other) {};
    83  		`, nil},
    84  		{"ValidIgnoreStreamingLookalike", `
    85  			rpc GetBook(GetBookRequest) returns (stream Book) {};
    86  		`, nil},
    87  	} {
    88  		t.Run(test.name, func(t *testing.T) {
    89  			file := testutils.ParseProto3Tmpl(t, `
    90  				import "google/api/resource.proto";
    91  				import "google/longrunning/operations.proto";
    92  				import "google/protobuf/field_mask.proto";
    93  				service Foo {
    94  					{{.RPCs}}
    95  				}
    96  
    97  				// This is at the top to make it retrievable
    98  				// by the test code.
    99  				message Book {
   100  					option (google.api.resource) = {
   101  						type: "library.googleapis.com/Book"
   102  						pattern: "books/{book}"
   103  						singular: "book"
   104  						plural: "books"
   105  					};
   106  				}
   107  
   108  				message BookCover {
   109  					option (google.api.resource) = {
   110  						type: "library.googleapis.com/BookCover"
   111  						pattern: "books/{book}/bookCover"
   112  						singular: "bookCover"
   113  					};
   114  				}
   115  
   116  				message GetBookCoverRequest {
   117  					string name = 1;
   118  				}
   119  
   120  				message CreateBookRequest {
   121  					// The parent resource where this book will be created.
   122  					// Format: publishers/{publisher}
   123  					string parent = 1;
   124  
   125  					// The book to create.
   126  					Book book = 2;
   127  				}
   128  
   129  				message GetBookRequest {
   130  					string name = 1;
   131  				}
   132  
   133  				message UpdateBookRequest {
   134  					Book book = 1;
   135  					google.protobuf.FieldMask update_mask = 2;
   136  				}
   137  
   138  				 message ListBooksRequest {
   139  					string parent = 1;
   140  					int32 page_size = 2;
   141  					string page_token = 3;
   142  				 }
   143  
   144  				 message ListBooksResponse {
   145  					repeated Book books = 1;
   146  					string next_page_token = 2;
   147  				 }
   148  
   149  				 message Other {
   150  					string other = 1;
   151  				 }
   152  			`, test)
   153  			s := file.GetServices()[0]
   154  			got := resourceMustSupportList.Lint(file)
   155  			if diff := test.problems.SetDescriptor(s).Diff(got); diff != "" {
   156  				t.Error(diff)
   157  			}
   158  		})
   159  	}
   160  }