go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/scheduler/appengine/engine/pubsub_test.go (about)

     1  // Copyright 2015 The LUCI Authors.
     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  //      http://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 engine
    16  
    17  import (
    18  	"encoding/json"
    19  	"io"
    20  	"net/http"
    21  	"net/http/httptest"
    22  	"testing"
    23  
    24  	. "github.com/smartystreets/goconvey/convey"
    25  )
    26  
    27  func TestConfigureTopic(t *testing.T) {
    28  	t.Parallel()
    29  
    30  	Convey("configureTopic works", t, func(ctx C) {
    31  		c := newTestContext(epoch)
    32  
    33  		calls := []struct {
    34  			Call     string
    35  			Code     int
    36  			Request  string
    37  			Response string
    38  		}{
    39  			// First round.
    40  			{
    41  				Call:     "PUT /v1/projects/abc/topics/def",
    42  				Code:     200,
    43  				Response: `{}`,
    44  			},
    45  			{
    46  				Call:     "PUT /v1/projects/abc/subscription/def",
    47  				Code:     200,
    48  				Response: `{}`,
    49  			},
    50  			{
    51  				Call:     "GET /v1/projects/abc/topics/def:getIamPolicy",
    52  				Code:     200,
    53  				Response: `{"etag": "some_etag"}`,
    54  			},
    55  			{
    56  				Call: "POST /v1/projects/abc/topics/def:setIamPolicy",
    57  				Code: 200,
    58  				Request: `{
    59  					"policy": {
    60  						"bindings": [
    61  							{
    62  								"role": "roles/pubsub.publisher",
    63  								"members": ["user:some@publisher.com"]
    64  							}
    65  						],
    66  						"etag": "some_etag"
    67  					}
    68  				}`,
    69  				Response: `{}`,
    70  			},
    71  
    72  			// Repeat to test idempotency.
    73  			{
    74  				Call:     "PUT /v1/projects/abc/topics/def",
    75  				Code:     409,
    76  				Response: `{}`,
    77  			},
    78  			{
    79  				Call:     "PUT /v1/projects/abc/subscription/def",
    80  				Code:     409,
    81  				Response: `{}`,
    82  			},
    83  			{
    84  				Call: "GET /v1/projects/abc/topics/def:getIamPolicy",
    85  				Code: 200,
    86  				Response: `{
    87  					"bindings": [
    88  						{
    89  							"role": "roles/pubsub.publisher",
    90  							"members": ["user:some@publisher.com"]
    91  						}
    92  					],
    93  					"etag": "some_etag"
    94  				}`,
    95  			},
    96  		}
    97  		idx := 0
    98  
    99  		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   100  			if idx == len(calls) {
   101  				ctx.Printf("Unexpected URL call '%s %s'", r.Method, r.URL.Path)
   102  				ctx.So(idx, ShouldNotEqual, len(calls))
   103  			}
   104  			call := calls[idx]
   105  			idx++
   106  			ctx.So(r.Method+" "+r.URL.Path, ShouldEqual, call.Call)
   107  			if call.Request != "" {
   108  				blob, err := io.ReadAll(r.Body)
   109  				ctx.So(err, ShouldBeNil)
   110  				expected := make(map[string]any)
   111  				received := make(map[string]any)
   112  				ctx.So(json.Unmarshal([]byte(call.Request), &expected), ShouldBeNil)
   113  				ctx.So(json.Unmarshal([]byte(blob), &received), ShouldBeNil)
   114  				ctx.So(received, ShouldResemble, expected)
   115  			}
   116  			w.Header().Set("Content-Type", "application/json")
   117  			w.WriteHeader(call.Code)
   118  			w.Write([]byte(call.Response))
   119  		}))
   120  		defer ts.Close()
   121  
   122  		err := configureTopic(
   123  			c,
   124  			"projects/abc/topics/def",
   125  			"projects/abc/subscription/def",
   126  			"http://push_url",
   127  			"some@publisher.com",
   128  			ts.URL)
   129  		So(err, ShouldBeNil)
   130  
   131  		// Repeat to test idempotency.
   132  		err = configureTopic(
   133  			c,
   134  			"projects/abc/topics/def",
   135  			"projects/abc/subscription/def",
   136  			"http://push_url",
   137  			"some@publisher.com",
   138  			ts.URL)
   139  		So(err, ShouldBeNil)
   140  
   141  		// All expected calls are made.
   142  		So(idx, ShouldEqual, len(calls))
   143  	})
   144  }