blob: b8e3845d47d0c53baba1b8746b8b89a7870b1afb [file] [log] [blame]
// Copyright 2017 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package frontend
import (
"fmt"
"testing"
"time"
"go.chromium.org/luci/appengine/gaetesting"
"go.chromium.org/luci/common/clock/testclock"
"go.chromium.org/luci/gae/service/datastore"
"go.chromium.org/luci/server/caching"
"go.chromium.org/luci/milo/common"
"go.chromium.org/luci/milo/common/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestGetBuilderHistories(t *testing.T) {
t.Parallel()
Convey(`TestGetBuilderHistories`, t, func() {
c := gaetesting.TestingContextWithAppID("luci-milo-dev")
c = caching.WithRequestCache(c)
datastore.GetTestable(c).AddIndexes(&datastore.IndexDefinition{
Kind: "BuildSummary",
SortBy: []datastore.IndexColumn{
{Property: "BuilderID"},
{Property: "Created", Descending: true},
},
})
datastore.GetTestable(c).AddIndexes(&datastore.IndexDefinition{
Kind: "BuildSummary",
SortBy: []datastore.IndexColumn{
{Property: "BuilderID"},
{Property: "Summary.Status"},
},
})
datastore.GetTestable(c).CatchupIndexes()
datastore.GetTestable(c).Consistent(true)
p := "proj"
proj := datastore.MakeKey(c, "Project", p)
// Populate consoles.
err := datastore.Put(c, &common.Console{
Parent: proj,
ID: "console",
Builders: []string{
"buildbucket/bucket/b1",
"buildbucket/bucket/b2",
"buildbucket/bucket/b4",
"buildbucket/bucket/b5",
},
})
So(err, ShouldBeNil)
err = datastore.Put(c, &common.Console{
Parent: proj,
ID: "console2",
Builders: []string{"buildbucket/bucket/b4"},
})
So(err, ShouldBeNil)
err = datastore.Put(c, &model.BuilderSummary{
BuilderID: "buildbucket/bucket/b5",
ProjectID: "private",
})
So(err, ShouldBeNil)
// Populate builds.
var builds []*model.BuildSummary
addBuilds := func(builder, project string, statuses ...model.Status) {
buildPrefix := "buildbucket/bucket/"
for i, status := range statuses {
buildID := fmt.Sprintf("%s%s/%d", buildPrefix, builder, i)
builds = append(builds, &model.BuildSummary{
BuildKey: datastore.MakeKey(c, "build", buildID),
ProjectID: project,
BuilderID: buildPrefix + builder,
BuildID: buildID,
Created: testclock.TestRecentTimeUTC.Add(time.Duration(len(builds)) * time.Hour),
Summary: model.Summary{Status: status},
})
}
}
// One builder has lots of builds.
addBuilds("b2", p,
model.Running,
model.Success,
model.Running,
model.Exception,
model.Running,
model.InfraFailure)
// One builder is not on any project's consoles.
addBuilds("b3", p, model.Success)
// One builder is on two consoles.
addBuilds("b4", p, model.Success)
// One builder is on the console of a different project.
addBuilds("b5", "private", model.Success)
err = datastore.Put(c, builds)
So(err, ShouldBeNil)
Convey("Getting recent history for existing project", func() {
Convey("across all consoles", func() {
Convey("with limit less than number of finished builds works", func() {
builders, err := getBuildersForProject(c, p, "")
So(err, ShouldBeNil)
hists, err := getBuilderHistories(c, builders, p, 2)
So(err, ShouldBeNil)
So(hists, ShouldHaveLength, 4)
So(hists[0], ShouldResemble, &builderHistory{
BuilderID: "buildbucket/bucket/b1",
BuilderLink: "/p/proj/builders/bucket/b1",
RecentBuilds: []*model.BuildSummary{},
})
b2Hist := hists[1]
So(b2Hist.BuilderID, ShouldEqual, "buildbucket/bucket/b2")
So(b2Hist.BuilderLink, ShouldEqual, "/p/proj/builders/bucket/b2")
So(b2Hist.NumRunning, ShouldEqual, 3)
So(b2Hist.RecentBuilds, ShouldHaveLength, 2)
So(b2Hist.RecentBuilds[0].BuildID, ShouldEqual, "buildbucket/bucket/b2/5")
So(b2Hist.RecentBuilds[1].BuildID, ShouldEqual, "buildbucket/bucket/b2/3")
b4Hist := hists[2]
So(b4Hist.BuilderID, ShouldEqual, "buildbucket/bucket/b4")
So(b4Hist.BuilderLink, ShouldEqual, "/p/proj/builders/bucket/b4")
So(b4Hist.NumRunning, ShouldEqual, 0)
So(b4Hist.RecentBuilds, ShouldHaveLength, 1)
So(b4Hist.RecentBuilds[0].BuildID, ShouldEqual, "buildbucket/bucket/b4/0")
b5Hist := hists[3]
So(b5Hist.BuilderID, ShouldEqual, "buildbucket/bucket/b5")
So(b5Hist.BuilderLink, ShouldEqual, "/p/private/builders/bucket/b5")
So(b5Hist.NumRunning, ShouldEqual, 0)
So(b5Hist.RecentBuilds, ShouldHaveLength, 1)
So(b5Hist.RecentBuilds[0].BuildID, ShouldEqual, "buildbucket/bucket/b5/0")
})
Convey("with limit greater than number of finished builds works", func() {
builders, err := getBuildersForProject(c, p, "")
So(err, ShouldBeNil)
hists, err := getBuilderHistories(c, builders, p, 5)
So(err, ShouldBeNil)
So(hists, ShouldHaveLength, 4)
So(hists[0], ShouldResemble, &builderHistory{
BuilderID: "buildbucket/bucket/b1",
BuilderLink: "/p/proj/builders/bucket/b1",
RecentBuilds: []*model.BuildSummary{},
})
b2Hist := hists[1]
So(b2Hist.BuilderID, ShouldEqual, "buildbucket/bucket/b2")
So(b2Hist.BuilderLink, ShouldEqual, "/p/proj/builders/bucket/b2")
So(b2Hist.NumRunning, ShouldEqual, 3)
So(b2Hist.RecentBuilds, ShouldHaveLength, 3)
So(b2Hist.RecentBuilds[0].BuildID, ShouldEqual, "buildbucket/bucket/b2/5")
So(b2Hist.RecentBuilds[1].BuildID, ShouldEqual, "buildbucket/bucket/b2/3")
So(b2Hist.RecentBuilds[2].BuildID, ShouldEqual, "buildbucket/bucket/b2/1")
b4Hist := hists[2]
So(b4Hist.BuilderID, ShouldEqual, "buildbucket/bucket/b4")
So(b4Hist.BuilderLink, ShouldEqual, "/p/proj/builders/bucket/b4")
So(b4Hist.NumRunning, ShouldEqual, 0)
So(b4Hist.RecentBuilds, ShouldHaveLength, 1)
So(b4Hist.RecentBuilds[0].BuildID, ShouldEqual, "buildbucket/bucket/b4/0")
})
})
Convey("across a specific console", func() {
Convey("for a valid console works", func() {
builders, err := getBuildersForProject(c, p, "console2")
So(err, ShouldBeNil)
hists, err := getBuilderHistories(c, builders, p, 2)
So(err, ShouldBeNil)
So(hists, ShouldHaveLength, 1)
So(hists[0].BuilderID, ShouldEqual, "buildbucket/bucket/b4")
So(hists[0].BuilderLink, ShouldEqual, "/p/proj/builders/bucket/b4")
So(hists[0].RecentBuilds, ShouldHaveLength, 1)
So(hists[0].RecentBuilds[0].BuildID, ShouldResemble, "buildbucket/bucket/b4/0")
})
Convey("for an invalid console works", func() {
_, err := getBuildersForProject(c, p, "bad_console")
So(err, ShouldNotBeNil)
})
})
})
Convey("Getting recent history for nonexisting project", func() {
builders, err := getBuildersForProject(c, "no_proj", "")
So(err, ShouldBeNil)
So(builders, ShouldHaveLength, 0)
hists, err := getBuilderHistories(c, builders, "no_proj", 3)
So(err, ShouldBeNil)
So(hists, ShouldHaveLength, 0)
})
})
}