go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/cv/internal/cvtesting/e2e/large_cl_stack_test.go (about)

     1  // Copyright 2021 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 e2e
    16  
    17  import (
    18  	"testing"
    19  
    20  	gerritpb "go.chromium.org/luci/common/proto/gerrit"
    21  
    22  	"go.chromium.org/luci/cv/internal/configs/prjcfg/prjcfgtest"
    23  	gf "go.chromium.org/luci/cv/internal/gerrit/gerritfake"
    24  	"go.chromium.org/luci/cv/internal/run"
    25  
    26  	. "github.com/smartystreets/goconvey/convey"
    27  )
    28  
    29  func TestHandleLargeCLStack(t *testing.T) {
    30  	t.Parallel()
    31  
    32  	Convey("CV full runs and submits a large CL stack.", t, func() {
    33  		ct := Test{}
    34  		ctx, cancel := ct.SetUp(t)
    35  		defer cancel()
    36  
    37  		const lProject = "infra"
    38  		const gHost = "g-review"
    39  		const gRepo = "re/po"
    40  		const gRef = "refs/heads/main"
    41  		const gChangeFirst = 1001
    42  		// TODO(tandrii): bump max entities limit in datastore in-memory emulation
    43  		// to from 25 to ~500 and then bump this limit to 200.
    44  		// NOTE: current datastore in-memory emulates classic Datastore, not the
    45  		// Firestore used by CV, and as such its limit of 25 counts entity *groups*,
    46  		// thus Run and all its CLs count as 1 such group.
    47  		const N = 15
    48  
    49  		cfg := MakeCfgCombinable("cg0", gHost, gRepo, gRef)
    50  		prjcfgtest.Create(ctx, lProject, cfg)
    51  		So(ct.PMNotifier.UpdateConfig(ctx, lProject), ShouldBeNil)
    52  
    53  		cis := make([]*gerritpb.ChangeInfo, N)
    54  		for i := range cis {
    55  			cis[i] = gf.CI(
    56  				gChangeFirst+i,
    57  				gf.Project(gRepo), gf.Ref(gRef),
    58  				gf.Owner("user-1"), gf.PS(1),
    59  				gf.CQ(+2, ct.Clock.Now(), gf.U("user-1")),
    60  				gf.Approve(),
    61  				gf.Updated(ct.Clock.Now()))
    62  		}
    63  		// A DryRunner can trigger a FullRun w/ an approval.
    64  		ct.AddDryRunner("user-1")
    65  		ct.GFake.AddFrom(gf.WithCIs(gHost, gf.ACLRestricted(lProject), cis...))
    66  		for i, child := range cis {
    67  			for _, parent := range cis[:i] {
    68  				ct.GFake.SetDependsOn(gHost, child, parent)
    69  			}
    70  		}
    71  
    72  		ct.LogPhase(ctx, "CV creates a Run")
    73  		ct.RunUntil(ctx, func() bool {
    74  			return len(ct.LoadRunsOf(ctx, lProject)) > 0
    75  		})
    76  		r := ct.EarliestCreatedRunOf(ctx, lProject)
    77  		So(r.CLs, ShouldHaveLength, N)
    78  
    79  		ct.LogPhase(ctx, "CV submits all CLs and finishes the Run")
    80  		ct.RunUntil(ctx, func() bool {
    81  			r = ct.LoadRun(ctx, r.ID)
    82  			return run.IsEnded(r.Status)
    83  		})
    84  
    85  		So(r.Status, ShouldEqual, run.Status_SUCCEEDED)
    86  		So(r.Submission.GetCls(), ShouldHaveLength, N)
    87  		So(r.Submission.GetSubmittedCls(), ShouldHaveLength, N)
    88  		var actual, expected []int
    89  		for i := range cis {
    90  			gChange := gChangeFirst + i
    91  			expected = append(expected, gChange)
    92  			if ct.GFake.GetChange(gHost, gChangeFirst+i).Info.GetStatus() == gerritpb.ChangeStatus_MERGED {
    93  				actual = append(actual, gChange)
    94  			}
    95  		}
    96  		So(actual, ShouldResemble, expected)
    97  	})
    98  }