blob: e344cf023cbe975e19f3bd35987224f468b9d164 [file]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package tricium
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
"go.chromium.org/luci/auth/identity"
"go.chromium.org/luci/common/logging/memlogger"
"go.chromium.org/luci/gae/impl/memory"
"go.chromium.org/luci/server/auth"
"go.chromium.org/luci/server/auth/authtest"
)
func TestLookupRepoDetails(t *testing.T) {
pc := &ProjectConfig{
Repos: []*RepoDetails{
{
Source: &RepoDetails_GitRepo{
GitRepo: &GitRepo{
Url: "https://github.com/google/gitiles.git",
},
},
},
{
Source: &RepoDetails_GerritProject{
GerritProject: &GerritProject{
Host: "chromium.googlesource.com",
Project: "infra/infra",
GitUrl: "https://chromium.googlesource.com/infra/infra.git",
},
},
},
},
}
Convey("Matches GerritProject when URL matches", t, func() {
request := &AnalyzeRequest{
Source: &AnalyzeRequest_GerritRevision{
GerritRevision: &GerritRevision{
GitUrl: "https://chromium.googlesource.com/infra/infra.git",
GitRef: "refs/changes/97/12397/1",
},
},
}
So(LookupRepoDetails(pc, request), ShouldEqual, pc.Repos[1])
})
Convey("Matches GitRepo when URL matches", t, func() {
request := &AnalyzeRequest{
Source: &AnalyzeRequest_GitCommit{
GitCommit: &GitCommit{
Url: "https://github.com/google/gitiles.git",
Ref: "refs/heads/master",
},
},
}
So(LookupRepoDetails(pc, request), ShouldEqual, pc.Repos[0])
})
Convey("Returns nil when no repo is found", t, func() {
request := &AnalyzeRequest{
Source: &AnalyzeRequest_GerritRevision{
GerritRevision: &GerritRevision{
GitUrl: "https://foo.googlesource.com/bar",
GitRef: "refs/changes/97/197/2",
},
},
}
So(LookupRepoDetails(pc, request), ShouldBeNil)
})
}
func TestCanRequest(t *testing.T) {
ctx := memory.Use(memlogger.Use(context.Background()))
okACLGroup := "tricium-playground-requesters"
okACLUser := "user:ok@example.com"
pc := &ProjectConfig{
Acls: []*Acl{
{
Role: Acl_REQUESTER,
Group: okACLGroup,
},
{
Role: Acl_REQUESTER,
Identity: okACLUser,
},
},
}
Convey("Only users in OK ACL group can request", t, func() {
ctx = auth.WithState(ctx, &authtest.FakeState{
Identity: "user:abc@example.com",
IdentityGroups: []string{okACLGroup},
})
ok, err := CanRequest(ctx, pc)
So(err, ShouldBeNil)
So(ok, ShouldBeTrue)
})
Convey("User with OK ACL can request", t, func() {
ctx = auth.WithState(ctx, &authtest.FakeState{
Identity: identity.Identity(okACLUser),
})
ok, err := CanRequest(ctx, pc)
So(err, ShouldBeNil)
So(ok, ShouldBeTrue)
})
Convey("Anonymous users cannot request", t, func() {
ctx = auth.WithState(ctx, &authtest.FakeState{
Identity: identity.AnonymousIdentity,
})
ok, err := CanRequest(ctx, pc)
So(err, ShouldBeNil)
So(ok, ShouldBeFalse)
})
}
func TestLookupFunction(t *testing.T) {
functions := []*Function{
{
Name: "Pylint",
Type: Function_ANALYZER,
},
}
Convey("Known function is known", t, func() {
So(LookupFunction(functions, "Pylint"), ShouldResemble, functions[0])
})
Convey("Unknown function is unknown", t, func() {
So(LookupFunction(functions, "blabla"), ShouldBeNil)
})
}
func TestSupportsPlatform(t *testing.T) {
analyzer := &Function{
Type: Function_ANALYZER,
Name: "PyLint",
Impls: []*Impl{
{
ProvidesForPlatform: Platform_WINDOWS,
},
{
ProvidesForPlatform: Platform_UBUNTU,
},
},
}
Convey("Supported platform is supported", t, func() {
So(SupportsPlatform(analyzer, Platform_UBUNTU), ShouldBeTrue)
})
Convey("Unsupported platform is not supported", t, func() {
So(SupportsPlatform(analyzer, Platform_MAC), ShouldBeFalse)
})
Convey("ANY platform always supported", t, func() {
So(SupportsPlatform(analyzer, Platform_ANY), ShouldBeTrue)
})
}
func TestLookupImplForPlatform(t *testing.T) {
implForLinux := &Impl{ProvidesForPlatform: Platform_LINUX}
implForMac := &Impl{ProvidesForPlatform: Platform_MAC}
analyzer := &Function{
Impls: []*Impl{
implForLinux,
implForMac,
},
}
Convey("Impl for known platform is returned", t, func() {
i := LookupImplForPlatform(analyzer, Platform_LINUX)
So(i, ShouldEqual, implForLinux)
})
Convey("Impl for any platform returns first", t, func() {
// In this case, there is no implementation in
// the list that is explicitly for any platform;
// we return the first implementation.
i := LookupImplForPlatform(analyzer, Platform_ANY)
So(i, ShouldEqual, implForLinux)
})
Convey("Impl for unknown platform returns nil", t, func() {
i := LookupImplForPlatform(analyzer, Platform_WINDOWS)
So(i, ShouldBeNil)
})
implForAny := &Impl{ProvidesForPlatform: Platform_ANY}
analyzer = &Function{
Impls: []*Impl{
implForLinux,
implForAny,
},
}
Convey("Impl for 'any' platform is used if present", t, func() {
// In this case, there is an implementation in
// the list that is explicitly for any platform;
// we return the 'any' implementation.
i := LookupImplForPlatform(analyzer, Platform_ANY)
So(i, ShouldEqual, implForAny)
})
}
func TestLookupPlatform(t *testing.T) {
platform := Platform_UBUNTU
sc := &ServiceConfig{Platforms: []*Platform_Details{{Name: platform}}}
Convey("Known platform is returned", t, func() {
p := LookupPlatform(sc, platform)
So(p, ShouldNotBeNil)
})
Convey("Unknown platform returns nil", t, func() {
p := LookupPlatform(sc, Platform_WINDOWS)
So(p, ShouldBeNil)
})
}
func TestValidateFunction(t *testing.T) {
sc := &ServiceConfig{
Platforms: []*Platform_Details{
{
Name: Platform_LINUX,
Dimensions: []string{"pool:Default"},
HasRuntime: true,
},
{
Name: Platform_IOS,
Dimensions: []string{"pool:Default"},
HasRuntime: false,
},
},
}
Convey("Function with all required fields is valid", t, func() {
f := &Function{
Type: Function_ANALYZER,
Name: "PyLint",
Needs: Data_FILES,
Provides: Data_RESULTS,
}
So(ValidateFunction(f, sc), ShouldBeNil)
})
Convey("Function names must not be non-empty", t, func() {
f := &Function{
Type: Function_ANALYZER,
Name: "",
Needs: Data_FILES,
Provides: Data_RESULTS,
}
So(ValidateFunction(f, sc), ShouldNotBeNil)
})
Convey("Function names must not contain underscore", t, func() {
f := &Function{
Type: Function_ANALYZER,
Name: "Py_Lint",
Needs: Data_FILES,
Provides: Data_RESULTS,
}
So(ValidateFunction(f, sc), ShouldNotBeNil)
})
Convey("Function without type is invalid", t, func() {
f := &Function{
Name: "PyLint",
Needs: Data_FILES,
Provides: Data_RESULTS,
}
So(ValidateFunction(f, sc), ShouldNotBeNil)
})
Convey("Function without name is invalid", t, func() {
f := &Function{
Type: Function_ANALYZER,
Needs: Data_FILES,
Provides: Data_RESULTS,
}
So(ValidateFunction(f, sc), ShouldNotBeNil)
})
Convey("Analyzer function must return results", t, func() {
f := &Function{
Type: Function_ANALYZER,
Name: "ConfusedAnalyzer",
Needs: Data_FILES,
Provides: Data_GIT_FILE_DETAILS,
}
So(ValidateFunction(f, sc), ShouldNotBeNil)
f.Provides = Data_RESULTS
So(ValidateFunction(f, sc), ShouldBeNil)
})
Convey("Function with impl without platforms is invalid", t, func() {
f := &Function{
Type: Function_ANALYZER,
Name: "PyLint",
Impls: []*Impl{{}},
}
So(ValidateFunction(f, sc), ShouldNotBeNil)
})
}
func TestValidateImpl(t *testing.T) {
sc := &ServiceConfig{
Platforms: []*Platform_Details{
{
Name: Platform_UBUNTU,
Dimensions: []string{"pool:Default"},
HasRuntime: true,
},
{
Name: Platform_ANDROID,
HasRuntime: false,
},
},
}
anyType := &Data_TypeDetails{
IsPlatformSpecific: false,
}
Convey("Impl must have a recipe specified", t, func() {
impl := &Impl{
RuntimePlatform: Platform_UBUNTU,
}
So(validateImpl(impl, sc, anyType, anyType), ShouldNotBeNil)
})
}