go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/buildbucket/appengine/model/tagindex_test.go (about)

     1  // Copyright 2020 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 model
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	"go.chromium.org/luci/gae/impl/memory"
    22  	"go.chromium.org/luci/gae/service/datastore"
    23  
    24  	. "github.com/smartystreets/goconvey/convey"
    25  	. "go.chromium.org/luci/common/testing/assertions"
    26  )
    27  
    28  func TestTagIndex(t *testing.T) {
    29  	t.Parallel()
    30  
    31  	Convey("TagIndex", t, func() {
    32  		ctx := memory.Use(context.Background())
    33  		datastore.GetTestable(ctx).AutoIndex(true)
    34  		datastore.GetTestable(ctx).Consistent(true)
    35  
    36  		Convey("updateTagIndex", func() {
    37  			Convey("create", func() {
    38  				Convey("nil", func() {
    39  					So(updateTagIndex(ctx, "key:val", 0, nil), ShouldBeNil)
    40  
    41  					shd := &TagIndex{
    42  						ID: "key:val",
    43  					}
    44  					So(datastore.Get(ctx, shd), ShouldErrLike, "no such entity")
    45  				})
    46  
    47  				Convey("empty", func() {
    48  					ents := []TagIndexEntry{}
    49  					So(updateTagIndex(ctx, "key:val", 0, ents), ShouldBeNil)
    50  
    51  					shd := &TagIndex{
    52  						ID: "key:val",
    53  					}
    54  					So(datastore.Get(ctx, shd), ShouldErrLike, "no such entity")
    55  				})
    56  
    57  				Convey("one", func() {
    58  					ents := []TagIndexEntry{
    59  						{
    60  							BuildID:  1,
    61  							BucketID: "bucket",
    62  						},
    63  					}
    64  					So(updateTagIndex(ctx, "key:val", 0, ents), ShouldBeNil)
    65  
    66  					shd := &TagIndex{
    67  						ID: "key:val",
    68  					}
    69  					So(datastore.Get(ctx, shd), ShouldBeNil)
    70  					So(shd, ShouldResemble, &TagIndex{
    71  						ID: "key:val",
    72  						Entries: []TagIndexEntry{
    73  							{
    74  								BuildID:  1,
    75  								BucketID: "bucket",
    76  							},
    77  						},
    78  					})
    79  				})
    80  
    81  				Convey("many", func() {
    82  					ents := []TagIndexEntry{
    83  						{
    84  							BuildID:  1,
    85  							BucketID: "bucket",
    86  						},
    87  						{
    88  							BuildID:  2,
    89  							BucketID: "bucket",
    90  						},
    91  					}
    92  					So(updateTagIndex(ctx, "key:val", 0, ents), ShouldBeNil)
    93  
    94  					shd := &TagIndex{
    95  						ID: "key:val",
    96  					}
    97  					So(datastore.Get(ctx, shd), ShouldBeNil)
    98  					So(shd, ShouldResemble, &TagIndex{
    99  						ID: "key:val",
   100  						Entries: []TagIndexEntry{
   101  							{
   102  								BuildID:  1,
   103  								BucketID: "bucket",
   104  							},
   105  							{
   106  								BuildID:  2,
   107  								BucketID: "bucket",
   108  							},
   109  						},
   110  					})
   111  				})
   112  
   113  				Convey("excessive", func() {
   114  					ents := make([]TagIndexEntry, MaxTagIndexEntries+1)
   115  					for i := range ents {
   116  						ents[i] = TagIndexEntry{
   117  							BuildID:  int64(i),
   118  							BucketID: "bucket",
   119  						}
   120  					}
   121  					So(updateTagIndex(ctx, "key:val", 0, ents), ShouldBeNil)
   122  
   123  					shd := &TagIndex{
   124  						ID: "key:val",
   125  					}
   126  					So(datastore.Get(ctx, shd), ShouldBeNil)
   127  					So(shd, ShouldResemble, &TagIndex{
   128  						ID:         "key:val",
   129  						Incomplete: true,
   130  					})
   131  				})
   132  			})
   133  
   134  			Convey("update", func() {
   135  				So(datastore.Put(ctx, &TagIndex{
   136  					ID: ":1:key:val",
   137  					Entries: []TagIndexEntry{
   138  						{
   139  							BuildID:  1,
   140  							BucketID: "bucket",
   141  						},
   142  					},
   143  				}), ShouldBeNil)
   144  
   145  				Convey("nil", func() {
   146  					So(updateTagIndex(ctx, "key:val", 1, nil), ShouldBeNil)
   147  
   148  					shd := &TagIndex{
   149  						ID: ":1:key:val",
   150  					}
   151  					So(datastore.Get(ctx, shd), ShouldBeNil)
   152  					So(shd, ShouldResemble, &TagIndex{
   153  						ID: ":1:key:val",
   154  						Entries: []TagIndexEntry{
   155  							{
   156  								BuildID:  1,
   157  								BucketID: "bucket",
   158  							},
   159  						},
   160  					})
   161  				})
   162  
   163  				Convey("empty", func() {
   164  					ents := []TagIndexEntry{}
   165  					So(updateTagIndex(ctx, "key:val", 1, ents), ShouldBeNil)
   166  
   167  					shd := &TagIndex{
   168  						ID: ":1:key:val",
   169  					}
   170  					So(datastore.Get(ctx, shd), ShouldBeNil)
   171  					So(shd, ShouldResemble, &TagIndex{
   172  						ID: ":1:key:val",
   173  						Entries: []TagIndexEntry{
   174  							{
   175  								BuildID:  1,
   176  								BucketID: "bucket",
   177  							},
   178  						},
   179  					})
   180  				})
   181  
   182  				Convey("one", func() {
   183  					ents := []TagIndexEntry{
   184  						{
   185  							BuildID:  2,
   186  							BucketID: "bucket",
   187  						},
   188  					}
   189  					So(updateTagIndex(ctx, "key:val", 1, ents), ShouldBeNil)
   190  
   191  					shd := &TagIndex{
   192  						ID: ":1:key:val",
   193  					}
   194  					So(datastore.Get(ctx, shd), ShouldBeNil)
   195  					So(shd, ShouldResemble, &TagIndex{
   196  						ID: ":1:key:val",
   197  						Entries: []TagIndexEntry{
   198  							{
   199  								BuildID:  1,
   200  								BucketID: "bucket",
   201  							},
   202  							{
   203  								BuildID:  2,
   204  								BucketID: "bucket",
   205  							},
   206  						},
   207  					})
   208  				})
   209  
   210  				Convey("many", func() {
   211  					ents := []TagIndexEntry{
   212  						{
   213  							BuildID:  2,
   214  							BucketID: "bucket",
   215  						},
   216  						{
   217  							BuildID:  3,
   218  							BucketID: "bucket",
   219  						},
   220  					}
   221  					So(updateTagIndex(ctx, "key:val", 1, ents), ShouldBeNil)
   222  
   223  					shd := &TagIndex{
   224  						ID: ":1:key:val",
   225  					}
   226  					So(datastore.Get(ctx, shd), ShouldBeNil)
   227  					So(shd, ShouldResemble, &TagIndex{
   228  						ID: ":1:key:val",
   229  						Entries: []TagIndexEntry{
   230  							{
   231  								BuildID:  1,
   232  								BucketID: "bucket",
   233  							},
   234  							{
   235  								BuildID:  2,
   236  								BucketID: "bucket",
   237  							},
   238  							{
   239  								BuildID:  3,
   240  								BucketID: "bucket",
   241  							},
   242  						},
   243  					})
   244  				})
   245  
   246  				Convey("excessive", func() {
   247  					ents := make([]TagIndexEntry, MaxTagIndexEntries)
   248  					for i := range ents {
   249  						ents[i] = TagIndexEntry{
   250  							BuildID:  int64(i + 10),
   251  							BucketID: "bucket",
   252  						}
   253  					}
   254  					So(updateTagIndex(ctx, "key:val", 1, ents), ShouldBeNil)
   255  
   256  					shd := &TagIndex{
   257  						ID: ":1:key:val",
   258  					}
   259  					So(datastore.Get(ctx, shd), ShouldBeNil)
   260  					So(shd, ShouldResemble, &TagIndex{
   261  						ID:         ":1:key:val",
   262  						Incomplete: true,
   263  					})
   264  				})
   265  			})
   266  
   267  			Convey("incomplete", func() {
   268  				So(datastore.Put(ctx, &TagIndex{
   269  					ID:         ":2:key:val",
   270  					Incomplete: true,
   271  				}), ShouldBeNil)
   272  
   273  				Convey("nil", func() {
   274  					So(updateTagIndex(ctx, "key:val", 2, nil), ShouldBeNil)
   275  
   276  					shd := &TagIndex{
   277  						ID: ":2:key:val",
   278  					}
   279  					So(datastore.Get(ctx, shd), ShouldBeNil)
   280  					So(shd, ShouldResemble, &TagIndex{
   281  						ID:         ":2:key:val",
   282  						Incomplete: true,
   283  					})
   284  				})
   285  
   286  				Convey("empty", func() {
   287  					ents := []TagIndexEntry{}
   288  					So(updateTagIndex(ctx, "key:val", 2, ents), ShouldBeNil)
   289  
   290  					shd := &TagIndex{
   291  						ID: ":2:key:val",
   292  					}
   293  					So(datastore.Get(ctx, shd), ShouldBeNil)
   294  					So(shd, ShouldResemble, &TagIndex{
   295  						ID:         ":2:key:val",
   296  						Incomplete: true,
   297  					})
   298  				})
   299  
   300  				Convey("one", func() {
   301  					ents := []TagIndexEntry{
   302  						{
   303  							BuildID:  1,
   304  							BucketID: "bucket",
   305  						},
   306  					}
   307  					So(updateTagIndex(ctx, "key:val", 2, ents), ShouldBeNil)
   308  
   309  					shd := &TagIndex{
   310  						ID: ":2:key:val",
   311  					}
   312  					So(datastore.Get(ctx, shd), ShouldBeNil)
   313  					So(shd, ShouldResemble, &TagIndex{
   314  						ID:         ":2:key:val",
   315  						Incomplete: true,
   316  					})
   317  				})
   318  			})
   319  		})
   320  
   321  		Convey("searchTagIndex", func() {
   322  			So(datastore.Put(ctx, &TagIndex{
   323  				ID:      ":1:buildset:patch/gerrit/chromium-review.googlesource.com/123/1",
   324  				Entries: []TagIndexEntry{{BuildID: 123, BucketID: "proj/bkt"}},
   325  			}), ShouldBeNil)
   326  			Convey("found", func() {
   327  				entries, err := SearchTagIndex(ctx, "buildset", "patch/gerrit/chromium-review.googlesource.com/123/1")
   328  				So(err, ShouldBeNil)
   329  				So(entries, ShouldResembleProto, []*TagIndexEntry{
   330  					{BuildID: 123, BucketID: "proj/bkt"},
   331  				})
   332  			})
   333  
   334  			Convey("not found", func() {
   335  				entries, err := SearchTagIndex(ctx, "buildset", "not exist")
   336  				So(err, ShouldBeNil)
   337  				So(entries, ShouldBeNil)
   338  			})
   339  
   340  			Convey("bad TagIndexEntry", func() {
   341  				So(datastore.Put(ctx, &TagIndex{
   342  					ID:      "key:val",
   343  					Entries: []TagIndexEntry{{BuildID: 123, BucketID: "/"}},
   344  				}), ShouldBeNil)
   345  				entries, err := SearchTagIndex(ctx, "key", "val")
   346  				So(err, ShouldBeNil)
   347  				So(entries, ShouldBeNil)
   348  			})
   349  		})
   350  	})
   351  }