blob: 315636757c892b95762834cb9e0cb845b8995245 [file] [log] [blame]
package processor
import (
"context"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.skia.org/infra/go/metrics2"
"go.skia.org/infra/go/testutils/unittest"
"go.skia.org/infra/machine/go/machine"
)
func TestParseAndroidProperties_HappyPath(t *testing.T) {
unittest.SmallTest(t)
const adbResponseHappyPath = `
[ro.product.manufacturer]: [asus]
[ro.product.model]: [Nexus 7]
[ro.product.name]: [razor]
`
want := map[string]string{
"ro.product.manufacturer": "asus",
"ro.product.model": "Nexus 7",
"ro.product.name": "razor",
}
got := parseAndroidProperties(adbResponseHappyPath)
assert.Equal(t, want, got)
}
func TestParseAndroidProperties_EmptyStringGivesEmptyMap(t *testing.T) {
unittest.SmallTest(t)
assert.Empty(t, parseAndroidProperties(""))
}
func TestDimensionsFromAndroidProperties_Success(t *testing.T) {
unittest.SmallTest(t)
adbResponse := strings.Join([]string{
"[ro.product.manufacturer]: [Google]", // Ignored
"[ro.product.model]: [Pixel 3a]", // Ignored
"[ro.build.id]: [QQ2A.200305.002]", // device_os
"[ro.product.brand]: [google]", // device_os_flavor
"[ro.build.type]: [user]", // device_os_type
"[ro.product.board]: []", // Ignore empty values.
"[ro.product.device]: [4560MMX_sprout]", // device_type
"[ro.build.product]: [sargo]", // device_type
"[ro.product.system.brand]: [google]", // device_os_flavor (dup should be ignored)
"[ro.product.system.brand]: [aosp]", // device_os_flavor (should be converted to "android")
}, "\n")
dimensions := parseAndroidProperties(adbResponse)
got := dimensionsFromAndroidProperties(dimensions)
expected := map[string][]string{
"android_devices": {"1"},
"device_os": {"Q", "QQ2A.200305.002"},
"device_os_flavor": {"google", "android"},
"device_os_type": {"user"},
machine.DimDeviceType: {"4560MMX_sprout", "sargo"},
machine.DimOS: {"Android"},
}
assert.Equal(t, expected, got)
}
func TestDimensionsFromAndroidProperties_AppendIncrementalBuildToDeviceOS(t *testing.T) {
unittest.SmallTest(t)
adbResponse := strings.Join([]string{
"[ro.build.id]: [QQ2A.200305.002]", // device_os
"[ro.build.version.incremental]: [6254899]", // device_os additional data.
}, "\n")
dimensions := parseAndroidProperties(adbResponse)
got := dimensionsFromAndroidProperties(dimensions)
expected := map[string][]string{
"android_devices": {"1"},
"device_os": {"Q", "QQ2A.200305.002", "QQ2A.200305.002_6254899"},
machine.DimOS: {"Android"},
}
assert.Equal(t, expected, got)
}
func TestDimensionsFromAndroidProperties_EmptyFromEmpty(t *testing.T) {
unittest.SmallTest(t)
dimensions := parseAndroidProperties("")
assert.Empty(t, dimensionsFromAndroidProperties(dimensions))
}
func newProcessorForTest(t *testing.T) *ProcessorImpl {
p := New(context.Background())
p.eventsProcessedCount.Reset()
p.unknownEventTypeCount.Reset()
return p
}
func TestProcess_DetectBadEventType(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
event := machine.Event{
EventType: machine.EventType(-1),
}
previous := machine.Description{}
p := newProcessorForTest(t)
_ = p.Process(ctx, previous, event)
require.Equal(t, int64(1), p.eventsProcessedCount.Get())
require.Equal(t, int64(1), p.unknownEventTypeCount.Get())
}
func TestProcess_SwarmingTaskIsRunning(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
event := machine.Event{
EventType: machine.EventTypeRawState,
RunningSwarmingTask: true,
}
previous := machine.Description{}
p := newProcessorForTest(t)
next := p.Process(ctx, previous, event)
assert.True(t, next.RunningSwarmingTask)
require.Equal(t, int64(1), p.eventsProcessedCount.Get())
require.Equal(t, int64(0), p.unknownEventTypeCount.Get())
}
func TestProcess_NewDeviceAttached(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
// The current machine has nothing attached.
previous := machine.NewDescription()
require.Empty(t, previous.Dimensions)
// An event arrives with the attachment of an Android device.
props := strings.Join([]string{
"[ro.build.id]: [QQ2A.200305.002]", // device_os
"[ro.product.brand]: [google]", // device_os_flavor
"[ro.build.type]: [user]", // device_os_type
"[ro.build.product]: [sargo]", // device_type
"[ro.product.system.brand]: [aosp]", // device_os_flavor
}, "\n")
event := machine.Event{
EventType: machine.EventTypeRawState,
Android: machine.Android{
GetProp: props,
},
Host: machine.Host{
Name: "skia-rpi2-0001",
PodName: "rpi-swarming-12345-987",
KubernetesImage: "gcr.io/skia-public/rpi-swarming-client:2020-05-09T19_28_20Z-jcgregorio-4fef3ca-clean",
},
}
p := newProcessorForTest(t)
next := p.Process(ctx, previous, event)
require.Equal(t, int64(1), p.eventsProcessedCount.Get())
require.Equal(t, int64(0), p.unknownEventTypeCount.Get())
// The Android device should be reflected in the returned Dimensions.
expected := machine.SwarmingDimensions{
"android_devices": []string{"1"},
"device_os": []string{"Q", "QQ2A.200305.002"},
"device_os_flavor": []string{"google", "android"},
"device_os_type": []string{"user"},
machine.DimDeviceType: []string{"sargo"},
machine.DimOS: []string{"Android"},
machine.DimID: []string{"skia-rpi2-0001"},
"inside_docker": []string{"1", "containerd"},
}
assert.Equal(t, expected, next.Dimensions)
assert.Equal(t, machine.ModeAvailable, next.Mode)
assert.Equal(t, event.Host.PodName, next.PodName)
assert.Equal(t, event.Host.KubernetesImage, next.KubernetesImage)
}
func TestProcess_DetectInsideDocker(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
// The current machine has nothing attached.
previous := machine.NewDescription()
require.Empty(t, previous.Dimensions)
// An event arrives with the attachment of an Android device.
event := machine.Event{
EventType: machine.EventTypeRawState,
Android: machine.Android{},
Host: machine.Host{
Name: "skia-rpi2-0001",
},
}
p := newProcessorForTest(t)
next := p.Process(ctx, previous, event)
require.Equal(t, int64(1), p.eventsProcessedCount.Get())
require.Equal(t, int64(0), p.unknownEventTypeCount.Get())
// The Android device should be reflected in the returned Dimensions.
expected := machine.SwarmingDimensions{
machine.DimID: []string{"skia-rpi2-0001"},
"inside_docker": []string{"1", "containerd"},
}
assert.Equal(t, expected, next.Dimensions)
assert.Equal(t, machine.ModeAvailable, next.Mode)
}
func TestProcess_DetectNotInsideDocker(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
// The current machine has nothing attached.
previous := machine.NewDescription()
require.Empty(t, previous.Dimensions)
// An event arrives with the attachment of an Android device.
event := machine.Event{
EventType: machine.EventTypeRawState,
Android: machine.Android{},
Host: machine.Host{
Name: "skia-rpi-0001",
},
}
p := newProcessorForTest(t)
next := p.Process(ctx, previous, event)
require.Equal(t, int64(1), p.eventsProcessedCount.Get())
require.Equal(t, int64(0), p.unknownEventTypeCount.Get())
// The Android device should be reflected in the returned Dimensions.
expected := machine.SwarmingDimensions{
machine.DimID: []string{"skia-rpi-0001"},
}
assert.Equal(t, expected, next.Dimensions)
assert.Equal(t, machine.ModeAvailable, next.Mode)
}
func TestProcess_ClearScheduledForDelectionOnPodNameChange(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
// The current machine has nothing attached.
previous := machine.NewDescription()
require.Empty(t, previous.Dimensions)
previous.ScheduledForDeletion = "foo"
previous.PodName = "foo"
// An event arrives with the attachment of an Android device.
event := machine.Event{
EventType: machine.EventTypeRawState,
Android: machine.Android{},
Host: machine.Host{
Name: "skia-rpi-0001",
PodName: "bar",
},
}
p := newProcessorForTest(t)
next := p.Process(ctx, previous, event)
require.Equal(t, int64(1), p.eventsProcessedCount.Get())
require.Equal(t, int64(0), p.unknownEventTypeCount.Get())
// The Android should no longer be scheduled for deletion.
assert.Equal(t, "", next.ScheduledForDeletion)
}
func TestProcess_DeviceGoingMissingMeansQuarantine(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
// The current machine has a device attached.
previous := machine.NewDescription()
previous.Dimensions = machine.SwarmingDimensions{
"android_devices": []string{"1"},
"device_os": []string{"Q", "QQ2A.200305.002"},
"device_os_flavor": []string{"google", "android"},
"device_os_type": []string{"user"},
machine.DimDeviceType: []string{"sargo"},
machine.DimOS: []string{"Android"},
machine.DimID: []string{"skia-rpi2-0001"},
"inside_docker": []string{"1", "containerd"},
}
// An event arrives without any device info.
event := machine.Event{
EventType: machine.EventTypeRawState,
Android: machine.Android{
GetProp: "",
},
Host: machine.Host{
Name: "skia-rpi2-0001",
},
}
p := newProcessorForTest(t)
next := p.Process(ctx, previous, event)
require.Equal(t, int64(1), p.eventsProcessedCount.Get())
require.Equal(t, int64(0), p.unknownEventTypeCount.Get())
// The dimensions should not change, except for the addition of the
// quarantine message, which tells swarming to quarantine this machine.
expected := previous.Dimensions
expected[machine.DimQuarantined] = []string{"Device [\"sargo\"] has gone missing"}
assert.Equal(t, expected, next.Dimensions)
assert.Equal(t, machine.ModeAvailable, next.Mode)
}
func TestProcess_QuarantineDevicesInMaintenanceMode(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
// The current machine has a device attached.
previous := machine.NewDescription()
previous.Dimensions = machine.SwarmingDimensions{
"android_devices": []string{"1"},
"device_os": []string{"Q", "QQ2A.200305.002"},
"device_os_flavor": []string{"google", "android"},
"device_os_type": []string{"user"},
machine.DimDeviceType: []string{"sargo"},
machine.DimOS: []string{"Android"},
machine.DimID: []string{"skia-rpi2-0001"},
"inside_docker": []string{"1", "containerd"},
}
previous.Mode = machine.ModeMaintenance
// An event arrives without any device info.
event := machine.Event{
EventType: machine.EventTypeRawState,
Host: machine.Host{
Name: "skia-rpi2-0001",
},
}
p := newProcessorForTest(t)
next := p.Process(ctx, previous, event)
require.Equal(t, int64(1), p.eventsProcessedCount.Get())
require.Equal(t, int64(0), p.unknownEventTypeCount.Get())
// The dimensions should not change, except for the addition of the
// quarantine message.
expected := previous.Dimensions
expected[machine.DimQuarantined] = []string{"Device is quarantined for maintenance"}
assert.Equal(t, expected, next.Dimensions)
assert.Equal(t, machine.ModeMaintenance, next.Mode)
assert.Equal(t, int64(1), metrics2.GetInt64Metric("machine_processor_device_quarantined", map[string]string{"machine": "skia-rpi2-0001"}).Get())
}
func TestProcess_RemoveMachineFromQuarantineIfDeviceReturns(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
// The current machine has been quarantined because the device went missing.
previous := machine.NewDescription()
previous.Dimensions = machine.SwarmingDimensions{
"android_devices": []string{"1"},
"device_os": []string{"Q", "QQ2A.200305.002"},
"device_os_flavor": []string{"google", "android"},
"device_os_type": []string{"user"},
machine.DimDeviceType: []string{"sargo"},
machine.DimOS: []string{"Android"},
machine.DimQuarantined: []string{"Device [\"sargo\"] has gone missing"},
machine.DimID: []string{"skia-rpi2-0001"},
"inside_docker": []string{"1", "containerd"},
}
// An event arrives tith the device restored.
props := strings.Join([]string{
"[ro.build.id]: [QQ2A.200305.002]", // device_os
"[ro.product.brand]: [google]", // device_os_flavor
"[ro.build.type]: [user]", // device_os_type
"[ro.build.product]: [sargo]", // device_type
"[ro.product.system.brand]: [aosp]", // device_os_flavor
}, "\n")
event := machine.Event{
EventType: machine.EventTypeRawState,
Android: machine.Android{
GetProp: props,
},
Host: machine.Host{
Name: "skia-rpi2-0001",
},
}
p := newProcessorForTest(t)
next := p.Process(ctx, previous, event)
require.Equal(t, int64(1), p.eventsProcessedCount.Get())
require.Equal(t, int64(0), p.unknownEventTypeCount.Get())
// The machine should no longer be quarantined.
expected := machine.SwarmingDimensions{
"android_devices": []string{"1"},
"device_os": []string{"Q", "QQ2A.200305.002"},
"device_os_flavor": []string{"google", "android"},
"device_os_type": []string{"user"},
machine.DimDeviceType: []string{"sargo"},
machine.DimOS: []string{"Android"},
machine.DimID: []string{"skia-rpi2-0001"},
"inside_docker": []string{"1", "containerd"},
}
assert.Equal(t, expected, next.Dimensions)
assert.Equal(t, int64(0), metrics2.GetInt64Metric("machine_processor_device_quarantined", map[string]string{"machine": "skia-rpi2-0001"}).Get())
}
func TestProcess_QuarantineIfDeviceBatteryTooLow(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
previous := machine.NewDescription()
event := machine.Event{
EventType: machine.EventTypeRawState,
Host: machine.Host{
Name: "skia-rpi2-0001",
},
Android: machine.Android{
DumpsysBattery: `Current Battery Service state:
AC powered: true
USB powered: false
Wireless powered: false
Max charging current: 1500000
Max charging voltage: 5000000
Charge counter: 2448973
status: 2
health: 2
present: true
level: 9
scale: 100
voltage: 4248`,
},
}
p := newProcessorForTest(t)
next := p.Process(ctx, previous, event)
assert.Equal(t, "Battery is too low: 9 < 30 (%)", next.Dimensions[machine.DimQuarantined][0])
assert.Equal(t, 9, next.Battery)
assert.Equal(t, int64(9), metrics2.GetInt64Metric("machine_processor_device_battery_level", map[string]string{"machine": "skia-rpi2-0001"}).Get())
}
func TestProcess_QuarantineIfDeviceTooHot(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
previous := machine.NewDescription()
event := machine.Event{
EventType: machine.EventTypeRawState,
Host: machine.Host{
Name: "skia-rpi2-0001",
},
Android: machine.Android{
DumpsysThermalService: `IsStatusOverride: false
ThermalEventListeners:
callbacks: 3
killed: false
broadcasts count: -1
ThermalStatusListeners:
callbacks: 1
killed: false
broadcasts count: -1
Thermal Status: 0
Cached temperatures:
Temperature{mValue=32.401, mType=3, mName=mb-therm-monitor, mStatus=0}
Temperature{mValue=46.100002, mType=0, mName=cpu0-silver-usr, mStatus=0}
Temperature{mValue=44.800003, mType=0, mName=cpu1-silver-usr, mStatus=0}
Temperature{mValue=45.100002, mType=0, mName=cpu2-silver-usr, mStatus=0}
Temperature{mValue=40.600002, mType=1, mName=gpu0-usr, mStatus=0}
Temperature{mValue=40.300003, mType=1, mName=gpu1-usr, mStatus=0}
Temperature{mValue=44.100002, mType=0, mName=cpu3-silver-usr, mStatus=0}
Temperature{mValue=45.4, mType=0, mName=cpu4-silver-usr, mStatus=0}
Temperature{mValue=45.4, mType=0, mName=cpu5-silver-usr, mStatus=0}
Temperature{mValue=30.000002, mType=2, mName=battery, mStatus=0}
Temperature{mValue=48.300003, mType=0, mName=cpu1-gold-usr, mStatus=0}
Temperature{mValue=46.7, mType=0, mName=cpu0-gold-usr, mStatus=0}
Temperature{mValue=27.522001, mType=4, mName=usbc-therm-monitor, mStatus=0}
HAL Ready: true
HAL connection:
ThermalHAL 2.0 connected: yes
Current temperatures from HAL:
Temperature{mValue=28.000002, mType=2, mName=battery, mStatus=0}
Temperature{mValue=33.800003, mType=0, mName=cpu0-gold-usr, mStatus=0}
Temperature{mValue=33.800003, mType=0, mName=cpu0-silver-usr, mStatus=0}
Temperature{mValue=33.5, mType=0, mName=cpu1-gold-usr, mStatus=0}
Temperature{mValue=44.1, mType=0, mName=cpu1-silver-usr, mStatus=0}
Temperature{mValue=43.8, mType=0, mName=cpu2-silver-usr, mStatus=0}
Temperature{mValue=33.5, mType=0, mName=cpu3-silver-usr, mStatus=0}
Temperature{mValue=33.5, mType=0, mName=cpu4-silver-usr, mStatus=0}
Temperature{mValue=33.5, mType=0, mName=cpu5-silver-usr, mStatus=0}
Temperature{mValue=32.9, mType=1, mName=gpu0-usr, mStatus=0}
Temperature{mValue=32.9, mType=1, mName=gpu1-usr, mStatus=0}
Temperature{mValue=30.147001, mType=3, mName=mb-therm-monitor, mStatus=0}
Temperature{mValue=26.926, mType=4, mName=usbc-therm-monitor, mStatus=0}
Current cooling devices from HAL:
CoolingDevice{mValue=0, mType=1, mName=battery}
CoolingDevice{mValue=0, mType=2, mName=thermal-cpufreq-0}
CoolingDevice{mValue=0, mType=2, mName=thermal-cpufreq-6}
CoolingDevice{mValue=0, mType=3, mName=thermal-devfreq-0}`,
},
}
p := newProcessorForTest(t)
next := p.Process(ctx, previous, event)
assert.Equal(t, "Temperature is too hot: 44.1 > 35 (C)", next.Dimensions[machine.DimQuarantined][0])
assert.Equal(t, float64(44.1), metrics2.GetFloat64Metric("machine_processor_device_temperature_c", map[string]string{"machine": "skia-rpi2-0001", "sensor": "cpu1-silver-usr"}).Get())
}
func TestProcess_DoNotQuarantineIfDeviceBatteryIsChargedEnough(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
previous := machine.NewDescription()
event := machine.Event{
EventType: machine.EventTypeRawState,
Host: machine.Host{
Name: "skia-rpi2-0001",
},
Android: machine.Android{
DumpsysBattery: `Current Battery Service state:
AC powered: true
USB powered: false
Wireless powered: false
Max charging current: 1500000
Max charging voltage: 5000000
Charge counter: 2448973
status: 2
health: 2
present: true
level: 95
scale: 100
voltage: 4248`,
},
}
p := newProcessorForTest(t)
next := p.Process(ctx, previous, event)
assert.Empty(t, next.Dimensions[machine.DimQuarantined])
assert.Equal(t, 95, next.Battery)
}
func TestProcess_ReportBadBatteryIfDumpsysBatteryIsMissing(t *testing.T) {
unittest.SmallTest(t)
ctx := context.Background()
previous := machine.NewDescription()
event := machine.Event{
EventType: machine.EventTypeRawState,
Host: machine.Host{
Name: "skia-rpi2-0001",
},
Android: machine.Android{
DumpsysBattery: "",
},
}
p := newProcessorForTest(t)
next := p.Process(ctx, previous, event)
assert.Empty(t, next.Dimensions[machine.DimQuarantined])
assert.Equal(t, badBatteryLevel, next.Battery)
}
func TestBatteryFromAndroidDumpSys_Success(t *testing.T) {
unittest.SmallTest(t)
battery, ok := batteryFromAndroidDumpSys(`Current Battery Service state:
level: 94
scale: 100
`)
assert.True(t, ok)
assert.Equal(t, 94, battery)
}
func TestBatteryFromAndroidDumpSys_FalseOnEmptyString(t *testing.T) {
unittest.SmallTest(t)
_, ok := batteryFromAndroidDumpSys("")
assert.False(t, ok)
}
func TestBatteryFromAndroidDumpSys_FalseIfNoLevel(t *testing.T) {
unittest.SmallTest(t)
_, ok := batteryFromAndroidDumpSys(`Current Battery Service state:
scale: 100
`)
assert.False(t, ok)
}
func TestBatteryFromAndroidDumpSys_FalseIfNoScale(t *testing.T) {
unittest.SmallTest(t)
_, ok := batteryFromAndroidDumpSys(`Current Battery Service state:
level: 94
`)
assert.False(t, ok)
}
func TestBatteryFromAndroidDumpSys_FailOnBadScale(t *testing.T) {
unittest.SmallTest(t)
_, ok := batteryFromAndroidDumpSys(`Current Battery Service state:
level: 94
scale: 0
`)
assert.False(t, ok)
}
func TestTemperatureFromAndroid_FindTempInThermalServiceOutput(t *testing.T) {
unittest.SmallTest(t)
thermalServiceOutput := `IsStatusOverride: false
ThermalEventListeners:
callbacks: 1
killed: false
broadcasts count: -1
ThermalStatusListeners:
callbacks: 1
killed: false
broadcasts count: -1
Thermal Status: 0
Cached temperatures:
Temperature{mValue=-99.9, mType=6, mName=TYPE_POWER_AMPLIFIER, mStatus=0}
Temperature{mValue=25.3, mType=4, mName=TYPE_SKIN, mStatus=0}
Temperature{mValue=24.0, mType=1, mName=TYPE_CPU, mStatus=0}
Temperature{mValue=24.4, mType=3, mName=TYPE_BATTERY, mStatus=0}
Temperature{mValue=24.2, mType=5, mName=TYPE_USB_PORT, mStatus=0}
HAL Ready: true
HAL connection:
Sdhms connected: yes
Current temperatures from HAL:
Temperature{mValue=24.0, mType=1, mName=TYPE_CPU, mStatus=0}
Temperature{mValue=24.4, mType=3, mName=TYPE_BATTERY, mStatus=0}
Temperature{mValue=25.3, mType=4, mName=TYPE_SKIN, mStatus=0}
Temperature{mValue=24.2, mType=5, mName=TYPE_USB_PORT, mStatus=0}
Temperature{mValue=-99.9, mType=6, mName=TYPE_POWER_AMPLIFIER, mStatus=0}
Current cooling devices from HAL:
CoolingDevice{mValue=0, mType=2, mName=TYPE_CPU}
CoolingDevice{mValue=0, mType=3, mName=TYPE_GPU}
CoolingDevice{mValue=0, mType=1, mName=TYPE_BATTERY}
CoolingDevice{mValue=1, mType=4, mName=TYPE_MODEM}`
a := machine.Android{
DumpsysThermalService: thermalServiceOutput,
}
temp, ok := temperatureFromAndroid(a)
assert.True(t, ok)
assert.Equal(t, map[string]float64{
"TYPE_CPU": 24.0,
"TYPE_BATTERY": 24.4,
"TYPE_SKIN": 25.3,
"TYPE_USB_PORT": 24.2,
}, temp)
}
func TestTemperatureFromAndroid_ReturnFalseIfNoOutputFromThermalOrBatteryService(t *testing.T) {
unittest.SmallTest(t)
a := machine.Android{}
_, ok := temperatureFromAndroid(a)
assert.False(t, ok)
}
func TestTemperatureFromAndroid_FindTempInBatteryServiceOutput(t *testing.T) {
unittest.SmallTest(t)
batteryOutput := `Current Battery Service state:
AC powered: true
USB powered: false
Wireless powered: false
Max charging current: 1500000
Max charging voltage: 5000000
Charge counter: 2448973
status: 2
health: 2
present: true
level: 94
scale: 100
voltage: 4248
temperature: 281
technology: Li-ion
`
a := machine.Android{
DumpsysBattery: batteryOutput,
}
temp, ok := temperatureFromAndroid(a)
assert.True(t, ok)
assert.Equal(t, map[string]float64{batteryTemperatureKey: 28.1}, temp)
}
func TestSanitizeKubernetesImageName_SuccessForExpectedValue(t *testing.T) {
unittest.SmallTest(t)
assert.Equal(t,
"gcr.io/skia-public/rpi-swarming-client:2020-05-09T19_28_20Z-jcgregorio-4fef3ca-clean",
sanitizeKubernetesImageName("image: gcr.io/skia-public/rpi-swarming-client:2020-05-09T19_28_20Z-jcgregorio-4fef3ca-clean\n"),
)
}
func TestSanitizeKubernetesImageName_PassesEmptyStringThrough(t *testing.T) {
unittest.SmallTest(t)
assert.Equal(t, "", sanitizeKubernetesImageName(""))
}
func TestSanitizeKubernetesImageName_PassesStringWithoutImagePrefix(t *testing.T) {
unittest.SmallTest(t)
const imageName = "gcr.io/skia-public/rpi-swarming-client:2020-05-09T19_28_20Z-jcgregorio-4fef3ca-clean"
assert.Equal(t, imageName, sanitizeKubernetesImageName(imageName))
}