blob: 5e887d01070fc6477543539fb450ec899dfcb335 [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"
"log"
"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.Device {
config := devicePkg.DeviceConfig{
Network: &devicePkg.NetworkProperties{
Nodename: name,
IPv4Addr: "000.000.00.0",
Mac: mac,
},
Power: &devicePkg.PowerClient{
Host: "000.000.00.0",
Username: "user",
Password: "Pwd",
},
}
target, err := devicePkg.NewNuc(config, cmd)
if err != nil {
log.Fatalf("creating mock device failed: %v", err)
}
return target
}
// Test that NUC server does not start up when port environment variable isn't set.
func TestNUCServerNonexistence(t *testing.T) {
var devices []devicePkg.Device
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.Device
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.Device
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.Device{
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())
}