blob: dce5a21398ac03eb4fceba226eea934b4eba78bb [file] [log] [blame]
// Copyright 2019 The Chromium OS 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 deviceconfig
import (
"context"
"io/ioutil"
"testing"
"github.com/golang/mock/gomock"
. "github.com/smartystreets/goconvey/convey"
"go.chromium.org/chromiumos/infra/proto/go/device"
"go.chromium.org/luci/appengine/gaetesting"
"go.chromium.org/luci/common/errors"
"go.chromium.org/luci/common/proto/gitiles"
"go.chromium.org/luci/common/proto/gitiles/mock_gitiles"
"go.chromium.org/luci/gae/service/datastore"
)
var deviceConfigJSON = `
{
"configs": [
{
"unkonwnField": "hahaha",
"id": {
"platformId": {
"value": "Arcada"
},
"modelId": {
"value": "arcada"
},
"variantId": {}
},
"hardwareFeatures": [
"HARDWARE_FEATURE_BLUETOOTH",
"HARDWARE_FEATURE_TOUCHSCREEN"
],
"power": "POWER_SUPPLY_BATTERY",
"storage": "STORAGE_NVME",
"videoAccelerationSupports": [
"VIDEO_ACCELERATION_H264",
"VIDEO_ACCELERATION_ENC_MJPG"
],
"soc": "SOC_WHISKEY_LAKE_U"
},
{
"id": {
"platformId": {
"value": "Arcada"
},
"modelId": {
"value": "arcada"
},
"variantId": {
"value": "2"
}
},
"hardwareFeatures": [
"HARDWARE_FEATURE_TOUCHPAD",
"HARDWARE_FEATURE_TOUCHSCREEN"
],
"power": "POWER_SUPPLY_BATTERY",
"storage": "STORAGE_NVME",
"videoAccelerationSupports": [
"VIDEO_ACCELERATION_MJPG",
"VIDEO_ACCELERATION_ENC_MJPG"
],
"soc": "SOC_WHISKEY_LAKE_U"
}
]
}
`
func TestUpdateDatastore(t *testing.T) {
Convey("Test update device config cache", t, func() {
ctx := gaetesting.TestingContextWithAppID("go-test")
ctl := gomock.NewController(t)
defer ctl.Finish()
gitilesMock := mock_gitiles.NewMockGitilesClient(ctl)
gitilesMock.EXPECT().DownloadFile(gomock.Any(), gomock.Any()).Return(
&gitiles.DownloadFileResponse{
Contents: deviceConfigJSON,
},
nil,
)
Convey("Happy path", func() {
err := UpdateDatastore(ctx, gitilesMock, "", "", "")
So(err, ShouldBeNil)
// There should be 2 entities created in datastore.
var cfgs []*devcfgEntity
datastore.GetTestable(ctx).Consistent(true)
err = datastore.GetAll(ctx, datastore.NewQuery(entityKind), &cfgs)
So(err, ShouldBeNil)
So(cfgs, ShouldHaveLength, 2)
})
})
}
func TestGetCachedDeviceConfig(t *testing.T) {
ctx := gaetesting.TestingContextWithAppID("go-test")
Convey("Test get device config from datastore", t, func() {
err := datastore.Put(ctx, []devcfgEntity{
{ID: "platform.model.variant1"},
{ID: "platform.model.variant2"},
{
ID: "platform.model.variant3",
DevConfig: []byte("bad data"),
},
})
So(err, ShouldBeNil)
Convey("Happy path", func() {
devcfg, err := GetCachedConfig(ctx, []*device.ConfigId{
{
PlatformId: &device.PlatformId{Value: "platform"},
ModelId: &device.ModelId{Value: "model"},
VariantId: &device.VariantId{Value: "variant1"},
BrandId: &device.BrandId{Value: "brand1"},
},
{
PlatformId: &device.PlatformId{Value: "platform"},
ModelId: &device.ModelId{Value: "model"},
VariantId: &device.VariantId{Value: "variant2"},
BrandId: &device.BrandId{Value: "brand2"},
},
})
So(err, ShouldBeNil)
So(devcfg, ShouldHaveLength, 2)
})
Convey("Device id is case insensitive", func() {
devcfg, err := GetCachedConfig(ctx, []*device.ConfigId{
{
PlatformId: &device.PlatformId{Value: "PLATFORM"},
ModelId: &device.ModelId{Value: "model"},
VariantId: &device.VariantId{Value: "variant1"},
BrandId: &device.BrandId{Value: "brand1"},
},
})
So(err, ShouldBeNil)
So(devcfg, ShouldHaveLength, 1)
})
Convey("Data unmarshal error", func() {
_, err := GetCachedConfig(ctx, []*device.ConfigId{
{
PlatformId: &device.PlatformId{Value: "platform"},
ModelId: &device.ModelId{Value: "model"},
VariantId: &device.VariantId{Value: "variant3"},
BrandId: &device.BrandId{Value: "brand3"},
},
})
So(err, ShouldNotBeNil)
So(err.Error(), ShouldContainSubstring, "unmarshal config data")
})
Convey("Get nonexisting data", func() {
resp, err := GetCachedConfig(ctx, []*device.ConfigId{
{
PlatformId: &device.PlatformId{Value: "platform"},
ModelId: &device.ModelId{Value: "model"},
VariantId: &device.VariantId{Value: "variant-nonexisting"},
BrandId: &device.BrandId{Value: "nonexisting"},
},
{
PlatformId: &device.PlatformId{Value: "platform"},
ModelId: &device.ModelId{Value: "model"},
VariantId: &device.VariantId{Value: "variant1"},
BrandId: &device.BrandId{Value: "brand1"},
},
{
PlatformId: &device.PlatformId{Value: "platform"},
ModelId: &device.ModelId{Value: "model"},
VariantId: &device.VariantId{Value: "variant-nonexisting2"},
BrandId: &device.BrandId{Value: "nonexisting"},
},
})
So(err, ShouldNotBeNil)
errs := err.(errors.MultiError)
So(errs, ShouldHaveLength, 3)
So(resp, ShouldHaveLength, 3)
So(errs[0].Error(), ShouldContainSubstring, "no such entity")
So(resp[0], ShouldBeNil)
So(errs[1], ShouldBeNil)
So(resp[1].(*device.Config), ShouldNotBeNil)
So(errs[2].Error(), ShouldContainSubstring, "no such entity")
So(resp[2], ShouldBeNil)
})
})
}
func TestGetAllCachedConfig(t *testing.T) {
Convey("Test get all device config cache", t, func() {
ctx := gaetesting.TestingContextWithAppID("go-test")
datastore.GetTestable(ctx).Consistent(true)
err := datastore.Put(ctx, []devcfgEntity{
{ID: "platform.model.variant1"},
{ID: "platform.model.variant2"},
{
ID: "platform.model.variant3",
DevConfig: []byte("bad data"),
},
})
So(err, ShouldBeNil)
devConfigs, err := GetAllCachedConfig(ctx)
So(err, ShouldBeNil)
So(devConfigs, ShouldHaveLength, 2)
for dc := range devConfigs {
So(dc.GetId(), ShouldBeNil)
}
})
}
func TestDeviceConfigsExists(t *testing.T) {
ctx := gaetesting.TestingContextWithAppID("go-test")
Convey("Test exists device config in datastore", t, func() {
err := datastore.Put(ctx, []devcfgEntity{
{ID: "kunimitsu.lars.variant1"},
{ID: "arcada.arcada.variant2"},
{
ID: "platform.model.variant3",
DevConfig: []byte("bad data"),
},
})
So(err, ShouldBeNil)
Convey("Happy path", func() {
exists, err := DeviceConfigsExists(ctx, []*device.ConfigId{
{
PlatformId: &device.PlatformId{Value: "kunimitsu"},
ModelId: &device.ModelId{Value: "lars"},
VariantId: &device.VariantId{Value: "variant1"},
},
{
PlatformId: &device.PlatformId{Value: "arcada"},
ModelId: &device.ModelId{Value: "arcada"},
VariantId: &device.VariantId{Value: "variant2"},
},
})
So(err, ShouldBeNil)
So(exists[0], ShouldBeTrue)
So(exists[1], ShouldBeTrue)
})
Convey("check for nonexisting data", func() {
exists, err := DeviceConfigsExists(ctx, []*device.ConfigId{
{
PlatformId: &device.PlatformId{Value: "platform"},
ModelId: &device.ModelId{Value: "model"},
VariantId: &device.VariantId{Value: "variant-nonexisting"},
BrandId: &device.BrandId{Value: "nonexisting"},
},
})
So(err, ShouldBeNil)
So(exists[0], ShouldBeFalse)
})
Convey("check for existing and nonexisting data", func() {
exists, err := DeviceConfigsExists(ctx, []*device.ConfigId{
{
PlatformId: &device.PlatformId{Value: "platform"},
ModelId: &device.ModelId{Value: "model"},
VariantId: &device.VariantId{Value: "variant-nonexisting"},
},
{
PlatformId: &device.PlatformId{Value: "arcada"},
ModelId: &device.ModelId{Value: "arcada"},
VariantId: &device.VariantId{Value: "variant2"},
},
})
So(err, ShouldBeNil)
So(exists[0], ShouldBeFalse)
So(exists[1], ShouldBeTrue)
})
})
}
type fakeGitClient struct {
project string
}
type fakeGSClient struct{}
func (gc *fakeGitClient) GetFile(ctx context.Context, path string) (string, error) {
if path != "generated/configs.jsonproto" {
return "", nil
}
b, err := ioutil.ReadFile("test_device_config_v2.jsonproto")
if err != nil {
return "", err
}
return string(b), nil
}
func (gc *fakeGitClient) SwitchProject(ctx context.Context, project string) error {
gc.project = project
return nil
}
func (gsClient *fakeGSClient) GetFile(ctx context.Context, path string) ([]byte, error) {
b, err := ioutil.ReadFile("test_program_configs.json")
if err != nil {
return []byte{}, err
}
return b, nil
}
func TestUpdateDatastoreFromBoxter(t *testing.T) {
Convey("Test update device config from boxster", t, func() {
ctx := gaetesting.TestingContextWithAppID("go-test")
gitilesMock := &fakeGitClient{}
Convey("Happy path", func() {
err := UpdateDatastoreFromBoxster(ctx, gitilesMock, "generated/configs.jsonproto", nil, "", "", "")
So(err, ShouldBeNil)
// There should be 6 entities created in datastore as
// test_device_config_v2.jsonproto contains 11 device configs:
// 5 sku-less device configs & 6 real device configs.
var cfgs []*devcfgEntity
datastore.GetTestable(ctx).Consistent(true)
err = datastore.GetAll(ctx, datastore.NewQuery(entityKind), &cfgs)
So(err, ShouldBeNil)
So(cfgs, ShouldHaveLength, 11)
})
})
}