blob: f8db9a49f01f68b8753f87d59f8c561181a8ec54 [file]
// Copyright 2025 The Fuchsia 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 tefmocheck
import (
"testing"
"go.fuchsia.dev/fuchsia/tools/testing/runtests"
"github.com/google/go-cmp/cmp"
)
func TestNearbyStringCheck(t *testing.T) {
tests := []struct {
name string
log string
check *NearbyStringCheck
expectedCheck bool
expectedName string
expectedFailure string
expectedLine1 string
expectedLine2 string
}{
{
name: "strings within distance",
log: `line 1
string1
line 3
string2
line 5`,
check: &NearbyStringCheck{
String1: "string1",
String2: "string2",
MaxDistanceLines: 2,
Type: serialLogType,
},
expectedCheck: true,
expectedName: "nearby_string/serial_log.txt/string1/string2",
expectedFailure: "Found lines nearby:\nstring1\nstring2",
expectedLine1: "string1",
expectedLine2: "string2",
},
{
name: "strings outside distance",
log: `string1
line 2
line 3
line 4
string2`,
check: &NearbyStringCheck{
String1: "string1",
String2: "string2",
MaxDistanceLines: 2,
Type: serialLogType,
},
expectedCheck: false,
},
{
name: "strings in reverse order within distance",
log: `string2
line 2
string1`,
check: &NearbyStringCheck{
String1: "string1",
String2: "string2",
MaxDistanceLines: 2,
Type: serialLogType,
},
expectedCheck: true,
expectedName: "nearby_string/serial_log.txt/string1/string2",
expectedFailure: "Found lines nearby:\nstring1\nstring2",
expectedLine1: "string1",
expectedLine2: "string2",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
outputs := &TestingOutputs{
SerialLogs: [][]byte{[]byte(test.log)},
SwarmingSummary: &SwarmingTaskSummary{Results: &SwarmingRpcsTaskResult{}},
}
if got := test.check.Check(outputs); got != test.expectedCheck {
t.Errorf("Check() = %v, want %v", got, test.expectedCheck)
}
if test.expectedCheck {
if name := test.check.Name(); name != test.expectedName {
t.Errorf("Name() = %q, want %q", name, test.expectedName)
}
if reason := test.check.FailureReason(); reason != test.expectedFailure {
t.Errorf("FailureReason() = %q, want %q", reason, test.expectedFailure)
}
if test.check.line1 != test.expectedLine1 {
t.Errorf("line1 = %q, want %q", test.check.line1, test.expectedLine1)
}
if test.check.line2 != test.expectedLine2 {
t.Errorf("line2 = %q, want %q", test.check.line2, test.expectedLine2)
}
}
})
}
}
func TestNearbyStringCheckWithSwarming(t *testing.T) {
const (
passedTest1 = "passedTest1"
passedTest2 = "passedTest2"
failedTest1 = "failedTest1"
failedTest2 = "failedTest2"
)
failedTestLog := "string1\nstring2"
passedTestLog := "nothing interesting"
testCases := []struct {
name string
check *NearbyStringCheck
swarmingResult *SwarmingRpcsTaskResult
testSummary *runtests.TestSummary
swarmingOutputPerTest []TestLog
expectedCheck bool
expectedIsFlake bool
}{
{
name: "SkipPassedTask returns false for passed task",
check: &NearbyStringCheck{
String1: "string1",
String2: "string2",
MaxDistanceLines: 20,
SkipPassedTask: true,
Type: swarmingOutputType,
},
swarmingResult: &SwarmingRpcsTaskResult{State: "COMPLETED"},
expectedCheck: false,
},
{
name: "SkipPassedTask returns true for failed task",
check: &NearbyStringCheck{
String1: "string1",
String2: "string2",
MaxDistanceLines: 20,
SkipPassedTask: true,
Type: swarmingOutputType,
},
swarmingResult: &SwarmingRpcsTaskResult{State: "COMPLETED", Failure: true},
expectedCheck: true, // because the log contains the strings
},
{
name: "SkipAllPassedTests returns false for all passed tests",
check: &NearbyStringCheck{
String1: "string1",
String2: "string2",
MaxDistanceLines: 20,
SkipAllPassedTests: true,
Type: swarmingOutputType,
},
swarmingResult: &SwarmingRpcsTaskResult{State: "COMPLETED"},
testSummary: &runtests.TestSummary{
Tests: []runtests.TestDetails{
{Name: passedTest1, Status: runtests.TestSuccess},
{Name: passedTest2, Status: runtests.TestSuccess},
},
},
expectedCheck: false,
},
{
name: "SkipAllPassedTests returns true for some failed tests",
check: &NearbyStringCheck{
String1: "string1",
String2: "string2",
MaxDistanceLines: 20,
SkipAllPassedTests: true,
Type: swarmingOutputType,
},
swarmingResult: &SwarmingRpcsTaskResult{State: "COMPLETED"},
testSummary: &runtests.TestSummary{
Tests: []runtests.TestDetails{
{Name: passedTest1, Status: runtests.TestSuccess},
{Name: failedTest1, Status: runtests.TestFailure},
},
},
expectedCheck: true,
},
{
name: "SkipAllPassedTests with IgnoreFlakes returns false",
check: &NearbyStringCheck{
String1: "string1",
String2: "string2",
MaxDistanceLines: 20,
SkipAllPassedTests: true,
IgnoreFlakes: true,
Type: swarmingOutputType,
},
swarmingResult: &SwarmingRpcsTaskResult{State: "COMPLETED"},
testSummary: &runtests.TestSummary{
Tests: []runtests.TestDetails{
{Name: failedTest1, Status: runtests.TestFailure},
{Name: failedTest1, Status: runtests.TestSuccess},
},
},
expectedCheck: false,
},
{
name: "AlwaysFlake returns true and isFlake",
check: &NearbyStringCheck{
String1: "string1",
String2: "string2",
MaxDistanceLines: 20,
AlwaysFlake: true,
Type: swarmingOutputType,
},
swarmingResult: &SwarmingRpcsTaskResult{State: "COMPLETED", Failure: true},
expectedCheck: true,
expectedIsFlake: true,
},
{
name: "SkipPassedTest finds in failed test",
check: &NearbyStringCheck{
String1: "string1",
String2: "string2",
MaxDistanceLines: 20,
SkipPassedTest: true,
Type: swarmingOutputType,
},
swarmingResult: &SwarmingRpcsTaskResult{State: "COMPLETED", Failure: true},
testSummary: &runtests.TestSummary{
Tests: []runtests.TestDetails{
{Name: failedTest1, Status: runtests.TestFailure},
{Name: passedTest1, Status: runtests.TestSuccess},
},
},
swarmingOutputPerTest: []TestLog{
{TestName: failedTest1, Bytes: []byte(failedTestLog)},
{TestName: passedTest1, Bytes: []byte(passedTestLog)},
},
expectedCheck: true,
},
{
name: "SkipPassedTest does not find in passed test",
check: &NearbyStringCheck{
String1: "string1",
String2: "string2",
MaxDistanceLines: 20,
SkipPassedTest: true,
Type: swarmingOutputType,
},
swarmingResult: &SwarmingRpcsTaskResult{State: "COMPLETED", Failure: true},
testSummary: &runtests.TestSummary{
Tests: []runtests.TestDetails{
{Name: failedTest1, Status: runtests.TestFailure},
{Name: passedTest1, Status: runtests.TestSuccess},
},
},
swarmingOutputPerTest: []TestLog{
{TestName: failedTest1, Bytes: []byte(passedTestLog)},
{TestName: passedTest1, Bytes: []byte(failedTestLog)},
},
expectedCheck: false,
},
{
name: "SkipPassedTest with IgnoreFlakes",
check: &NearbyStringCheck{
String1: "string1",
String2: "string2",
MaxDistanceLines: 20,
SkipPassedTest: true,
IgnoreFlakes: true,
Type: swarmingOutputType,
},
swarmingResult: &SwarmingRpcsTaskResult{State: "COMPLETED", Failure: true},
testSummary: &runtests.TestSummary{
Tests: []runtests.TestDetails{
{Name: failedTest1, Status: runtests.TestFailure},
{Name: failedTest2, Status: runtests.TestFailure},
{Name: failedTest2, Status: runtests.TestSuccess},
},
},
swarmingOutputPerTest: []TestLog{
{TestName: failedTest1, Bytes: []byte(passedTestLog)},
{TestName: failedTest2, Bytes: []byte(failedTestLog)},
{TestName: failedTest2, Bytes: []byte(passedTestLog)},
},
expectedCheck: true,
expectedIsFlake: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
outputs := &TestingOutputs{
SwarmingOutput: []byte(failedTestLog),
SwarmingSummary: &SwarmingTaskSummary{Results: tc.swarmingResult},
TestSummary: tc.testSummary,
SwarmingOutputPerTest: tc.swarmingOutputPerTest,
}
if got := tc.check.Check(outputs); got != tc.expectedCheck {
t.Errorf("Check() got %v, want %v", got, tc.expectedCheck)
}
if tc.expectedCheck {
if diff := cmp.Diff(tc.expectedIsFlake, tc.check.IsFlake()); diff != "" {
t.Errorf("IsFlake() mismatch (-want +got):\n%s", diff)
}
}
})
}
}