blob: 2f5f115bf03cf9a9b52777d594275ffe610dffc2 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can
// found in the LICENSE file.
package main
import (
"context"
"fmt"
"math/rand"
"net"
"net/http"
"os"
"strconv"
"testing"
"time"
devicePkg "go.fuchsia.dev/infra/devices"
)
const (
successExitCode = 0
)
var (
sigTermExitCode = rand.Int()%50 + 1
failCode = rand.Int()%50 + 51
)
func constructDummyCmd(fail bool) []string {
failureExitCode := -1
if fail {
failureExitCode = failCode
}
return []string{
"./dummy.sh",
strconv.Itoa(failureExitCode),
strconv.Itoa(sigTermExitCode),
}
}
func checkExitCode(t *testing.T, actual int, expected int) {
if actual != expected {
t.Errorf("Expected exit code: %d Actual %d", expected, actual)
}
}
// Test that runSubprocess propagates success code.
func TestSuccessfulSubprocess(t *testing.T) {
cmd := constructDummyCmd(false)
exitCode := runSubprocess(context.Background(), cmd)
checkExitCode(t, exitCode, successExitCode)
}
// Test that runSubprocess propagates failure code.
func TestFailingSubprocess(t *testing.T) {
cmd := constructDummyCmd(true)
exitCode := runSubprocess(context.Background(), cmd)
checkExitCode(t, exitCode, failCode)
}
// Test that sigterms are propagated to running subprocesses on context cancel.
func TestSigtermRunningSubprocess(t *testing.T) {
cmd := constructDummyCmd(false)
subprocessCtx, cancel := context.WithCancel(context.Background())
go func() {
time.Sleep(2 * time.Second)
cancel()
}()
exitCode := runSubprocess(subprocessCtx, cmd)
checkExitCode(t, exitCode, sigTermExitCode)
}
// Test that sigterms sent after the subprocess is done running do not get propagated.
func TestSigtermDoneSubprocess(t *testing.T) {
cmd := constructDummyCmd(false)
subprocessCtx, cancel := context.WithCancel(context.Background())
go func() {
time.Sleep(7 * time.Second)
cancel()
}()
exitCode := runSubprocess(subprocessCtx, cmd)
checkExitCode(t, exitCode, successExitCode)
}
func createMockDevice(name string, mac string, cmd []string) *devicePkg.DeviceTarget {
target := &devicePkg.DeviceTarget{BootserverCmd: cmd}
config := devicePkg.DeviceConfig{
Network: devicePkg.NetworkProperties{
Nodename: name,
IPv4Addr: "000.000.00.0",
Mac: mac,
},
}
target.SetConfig(config)
return target
}
// Test running runBootservers with successful results using mock devices.
func TestBootserverSuccess(t *testing.T) {
cmd := constructDummyCmd(false)
devices := []*devicePkg.DeviceTarget{
createMockDevice("dummy1", "00:00:00:00:00", cmd),
createMockDevice("dummy2", "00:00:00:00:01", cmd),
}
exitCode := runBootservers(context.Background(), devices)
checkExitCode(t, exitCode, successExitCode)
}
// Test running runBootservers with failed results using mock devices.
func TestBootserverFailure(t *testing.T) {
devices := []*devicePkg.DeviceTarget{
createMockDevice("dummy1", "00:00:00:00:00", constructDummyCmd(false)),
createMockDevice("dummy2", "00:00:00:00:01", constructDummyCmd(true)),
}
exitCode := runBootservers(context.Background(), devices)
checkExitCode(t, exitCode, failureExitCode)
}
// Test that NUC server does not start up when port environment variable isn't set.
func TestNUCServerNonexistence(t *testing.T) {
var devices []*devicePkg.DeviceTarget
srv, err := runNUCServer(context.Background(), devices, false)
if srv != nil {
t.Errorf("NUC server was created without port set.")
} else if err != nil {
t.Errorf("%v\n", err)
}
}
// Test that NUC server is disabled when flag is set and port environment variable is set.
func TestNUCServerDisabled(t *testing.T) {
var devices []*devicePkg.DeviceTarget
os.Setenv(portEnvVar, "8000")
srv, err := runNUCServer(context.Background(), devices, true)
if srv != nil {
t.Errorf("NUC server was created without port set.")
} else if err != nil {
t.Errorf("%v\n", err)
}
os.Setenv(portEnvVar, "")
}
// Test that NUC server is started up when port environment variable is set.
func TestNUCServerExistence(t *testing.T) {
var devices []*devicePkg.DeviceTarget
os.Setenv(portEnvVar, "8000")
srv, err := runNUCServer(context.Background(), devices, false)
os.Setenv(portEnvVar, "")
if srv == nil {
t.Errorf("NUC server was not created even with port var set.")
}
if err != nil {
t.Errorf("%v\n", err)
}
srv.Shutdown(context.Background())
}
// Test that each device has an endpoint in the NUC server.
func TestNUCServerEndpoints(t *testing.T) {
// Create mock devices
cmd := constructDummyCmd(false)
devices := []*devicePkg.DeviceTarget{
createMockDevice("dummy1", "00:00:00:00:00", cmd),
createMockDevice("dummy2", "00:00:00:00:01", cmd),
}
os.Setenv(portEnvVar, "8000")
srv, err := runNUCServer(context.Background(), devices, false)
os.Setenv(portEnvVar, "")
if srv == nil {
t.Errorf("NUC server was not created even with port var set.")
}
if err != nil {
t.Errorf("%v\n", err)
}
// Wait until the webserver has come online.
for {
_, err := net.DialTimeout("tcp", "127.0.0.1:8000", 1*time.Second)
if err == nil {
break
}
}
// Retrieve the chainloader from each endpoint.
for _, device := range devices {
resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:8000/%s.ipxe", device.Mac()))
if err != nil {
t.Errorf("%v\n", err)
} else if resp.StatusCode != 200 {
t.Errorf("Was unable to get chainloader for mac: %s", device.Mac())
}
}
srv.Shutdown(context.Background())
}