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