| // 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()) |
| } |