blob: 7c8c2dbfd5d7767058e69dc85ce9548a63a2ced8 [file] [log] [blame]
// Copyright 2020 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 firmware
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"
"chromiumos/tast/errors"
"chromiumos/tast/testutil"
)
// These are the names of the mock platforms whose configs we will define.
const (
myBoardName = "myboard"
myParentName = "myparent"
myGrandparentName = "mygrandparent"
myModelName = "mymodel"
myOtherModelName = "myothermodel"
withECBatteryName = "withECBattery"
)
// In order to tell more easily where each value is obtained from, each mock config sets all numeric fields to the same value.
// Exercise both integers and floats.
const (
defaultValue = 1
myGrandparentValue = 2.2
myParentValue = 3.3
myBoardValue = 4.4
myModelValue = 5.5
// Duration equivalents of the above
defaultDuration = 1 * time.Second
myGrandparentDuration = 2200 * time.Millisecond
myParentDuration = 3300 * time.Millisecond
myBoardDuration = 4400 * time.Millisecond
myModelDuration = 5500 * time.Millisecond
)
var mockData = map[string]json.RawMessage{
defaultName: json.RawMessage(fmt.Sprintf(`{
"platform": null,
"parent": null,
"firmware_screen": %d,
"delay_reboot_to_ping": %d,
"keypress_delay": %d,
"usb_plug": %d
}`, defaultValue, defaultValue, defaultValue, defaultValue)),
myBoardName: json.RawMessage(fmt.Sprintf(`{
"platform": %q,
"parent": %q,
"firmware_screen": %f,
"models": {
%q: {
"firmware_screen": %f
}
}
}`, myBoardName, myParentName, myBoardValue, myModelName, myModelValue)),
myParentName: json.RawMessage(fmt.Sprintf(`{
"platform": %q,
"parent": %q,
"keypress_delay": %f,
"firmware_screen": %f
}`, myParentName, myGrandparentName, myParentValue, myParentValue)),
myGrandparentName: json.RawMessage(fmt.Sprintf(`{
"platform": %q,
"usb_plug": %f,
"keypress_delay": %f
}`, myGrandparentName, myGrandparentValue, myGrandparentValue)),
withECBatteryName: json.RawMessage(fmt.Sprintf(`{
"platform": %q,
"ec_capability": [
%q
]
}`, withECBatteryName, ECBattery)),
}
// setupMockData creates a temporary directory with a consolidated JSON file containing all the data from mockData.
func setupMockData(t *testing.T) (cfgDir, cfgFilepath string, retErr error) {
// Create JSON bytes out of mock data
mockJSON, err := json.Marshal(mockData)
if err != nil {
return "", "", errors.Wrap(err, "marshaling mock data into JSON")
}
// Create temp dir to contain mock consolidated JSON file
cfgDir = testutil.TempDir(t)
defer func() {
if retErr != nil {
os.RemoveAll(cfgDir)
}
}()
// Create mock consolidated JSON file
cfgFilepath = filepath.Join(cfgDir, consolidatedBasename)
if err = ioutil.WriteFile(cfgFilepath, mockJSON, 0644); err != nil {
return "", "", errors.Wrapf(err, "writing mock json to file %s", cfgFilepath)
}
return cfgDir, cfgFilepath, nil
}
// TestNewConfig verifies that we can create a new Config object with proper inheritance.
func TestNewConfig(t *testing.T) {
cfgDir, cfgFilepath, err := setupMockData(t)
defer os.RemoveAll(cfgDir)
if err != nil {
t.Fatal(err)
}
cfg, err := NewConfig(cfgFilepath, myBoardName, "")
if err != nil {
t.Fatalf("creating config for %s: %+v", myBoardName, err)
}
if cfg.Platform != myBoardName {
t.Errorf("unexpected Platform value; got %q, want %q", cfg.Platform, myBoardName)
}
// Platform and parents do not set values; inherit defaults.
if cfg.DelayRebootToPing != defaultDuration {
t.Errorf("unexpected DelayRebootToPing value; got %s, want %s", cfg.DelayRebootToPing, defaultDuration)
}
// Platform overwrites defaults (even though parent also sets the value)
if cfg.FirmwareScreen != myBoardDuration {
t.Errorf("unexpected FirmwareScreen value; got %s, want %s", cfg.FirmwareScreen, myBoardDuration)
}
// Platform inherits from parent (even though grandparent also sets the value)
if cfg.KeypressDelay != myParentDuration {
t.Errorf("unexpected KeypressDelay value; got %s, want %s", cfg.KeypressDelay, myParentDuration)
}
// Platform inherits from grandparent
if cfg.USBPlug != myGrandparentDuration {
t.Errorf("unexpected USBPlug value; got %s, want %s", cfg.USBPlug, myGrandparentDuration)
}
}
// TestNewConfigNoParent verifies that a new config with no parent value has proper inheritance.
func TestNewConfigNoParent(t *testing.T) {
cfgDir, cfgFilepath, err := setupMockData(t)
defer os.RemoveAll(cfgDir)
if err != nil {
t.Fatal(err)
}
cfg, err := NewConfig(cfgFilepath, myGrandparentName, "")
if err != nil {
t.Fatalf("creating config for %s: %+v", myGrandparentName, err)
}
if cfg.Platform != myGrandparentName {
t.Errorf("unexpected Platform value; got %q, want %q", cfg.Platform, myGrandparentName)
}
// mygrandparent has a custom value for USBPlug, overwriting defaults.
if cfg.USBPlug != myGrandparentDuration {
t.Errorf("unexpected USBPlug value; got %s, want %s", cfg.USBPlug, myGrandparentDuration)
}
// mygrandparent does not set a value for FirmwareScreen, so should inherit defaults.
if cfg.FirmwareScreen != defaultDuration {
t.Errorf("unexpected FirmwareScreen value; got %s, want %s", cfg.FirmwareScreen, defaultDuration)
}
}
// TestNewConfigNoParent verifies that a model-specific config overrides the platform config.
func TestNewConfigModelOverride(t *testing.T) {
cfgDir, cfgFilepath, err := setupMockData(t)
defer os.RemoveAll(cfgDir)
if err != nil {
t.Fatal(err)
}
// Test with model-specific override
cfg, err := NewConfig(cfgFilepath, myBoardName, myModelName)
if cfg.FirmwareScreen != myModelDuration {
t.Errorf("unexpected FirmwareScreen value; got %s, want %s // %+v", cfg.FirmwareScreen, myModelDuration, cfg)
}
// Test with no model-specific override
cfg, err = NewConfig(cfgFilepath, myBoardName, myOtherModelName)
if cfg.FirmwareScreen != myBoardDuration {
t.Errorf("unexpected FirmwareScreen value; got %s, want %s", cfg.FirmwareScreen, myModelDuration)
}
}
// TestHasECCapability exercises HasECCapability to verify that we can check whether a Config contains a certain EC capability.
func TestHasECCapability(t *testing.T) {
cfgDir, cfgFilepath, err := setupMockData(t)
defer os.RemoveAll(cfgDir)
if err != nil {
t.Fatal(err)
}
// Test a platform that does not define any ec_capability
cfg, err := NewConfig(cfgFilepath, myBoardName, "")
if err != nil {
t.Fatalf("Creating config for platform %s: %+v", myBoardName, err)
}
if cfg.HasECCapability(ECBattery) {
t.Fatalf("Platform %q: HasECCapability(ECBattery) returned True; want False", myBoardName)
}
// Test a platform that defines some ec_capabilities
cfg, err = NewConfig(cfgFilepath, withECBatteryName, "")
if err != nil {
t.Fatalf("Creating config for platform %s: %+v", withECBatteryName, err)
}
if !cfg.HasECCapability(ECBattery) {
t.Fatalf("Platform %q: HasECCapability(ECBattery) returned False; want True", withECBatteryName)
}
if cfg.HasECCapability(ECPECI) {
t.Fatalf("Platform %q: HasECCapability(ECPECI) returned True; want False", withECBatteryName)
}
}