From 18d5ef10b034a8ab8d3a11fac130ac6f00a3c56a Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Fri, 20 Sep 2024 16:40:31 -0600 Subject: [PATCH] Updated tests fixing some issues --- tests/api_test.go | 204 +++++++++++++++++++++--------------- tests/compatibility_test.go | 66 +++++++++--- 2 files changed, 169 insertions(+), 101 deletions(-) diff --git a/tests/api_test.go b/tests/api_test.go index b3a8ebf..bc4bf1c 100644 --- a/tests/api_test.go +++ b/tests/api_test.go @@ -8,9 +8,12 @@ package tests import ( + "bytes" + "crypto/tls" "fmt" "net" "net/http" + "os" "os/exec" "testing" "time" @@ -20,70 +23,72 @@ import ( magellan "github.com/OpenCHAMI/magellan/internal" "github.com/OpenCHAMI/magellan/internal/util" "github.com/OpenCHAMI/magellan/pkg/client" + "github.com/rs/zerolog/log" ) var ( - scanParams = &magellan.ScanParams{ - TargetHosts: [][]string{ - []string{ - "http://127.0.0.1:443", - "http://127.0.0.1:5000", - }, - }, - Scheme: "https", - Protocol: "tcp", - Concurrency: 1, - Timeout: 30, - DisableProbing: false, - Verbose: false, - } - exePath = flag.String("exe", "./magellan", "path to 'magellan' binary executable") + exePath = flag.String("exe", "../magellan", "path to 'magellan' binary executable") emuPath = flag.String("emu", "./emulator/setup.sh", "path to emulator 'setup.sh' script") ) -func runEmulator() {} - func TestScanAndCollect(t *testing.T) { var ( err error - emuErr error - output []byte tempDir = t.TempDir() command string + cwd string + cmd *exec.Cmd + buf bytes.Buffer ) - // try and start the emulator in the background if arg passed - if *emuPath != "" { - t.Parallel() - t.Run("emulator", func(t *testing.T) { - _, emuErr = exec.Command("bash", "-c", *emuPath).CombinedOutput() - if emuErr != nil { - t.Fatalf("failed to start emulator: %v", emuErr) - } - }) + // set up the emulator to run before test + err = waitUntilEmulatorIsReady() + if err != nil { + t.Fatalf("failed while waiting for emulator: %v", err) } + // get the current working directory and print + cwd, err = os.Getwd() + if err != nil { + t.Fatalf("failed to get working directory: %v", err) + } + fmt.Printf("cwd: %s\n", cwd) + + // path, err := exec.LookPath("dexdump") + // if err != nil { + // log.Fatal(err) + // } + // try and run a "scan" with the emulator - command = fmt.Sprintf("%s scan --subnet 127.0.0.1 --subnet-mask 255.255.255.0 --cache %s", exePath, tempDir) - output, err = exec.Command("bash", "-c", command).CombinedOutput() + command = fmt.Sprintf("%s scan https://172.23.0.2 --port 5000 --cache %s", *exePath, tempDir) + cmd = exec.Command("bash", "-c", command) + cmd.Stdout = &buf + err = cmd.Run() if err != nil { t.Fatalf("failed to run 'scan' command: %v", err) } // make sure that the expected output is not empty - if len(output) <= 0 { + if len(buf.Bytes()) <= 0 { t.Fatalf("expected the 'scan' output to not be empty") } // try and run a "collect" with the emulator - command = fmt.Sprintf("%s collect --username root --password root_password --cache %s", exePath, tempDir) - output, err = exec.Command("bash", "-c", command).CombinedOutput() + command = fmt.Sprintf("%s collect --username root --password root_password --cache %s", *exePath, tempDir) + cmd = exec.Command("bash", "-c", command) + cmd.Stdout = &buf + err = cmd.Start() if err != nil { t.Fatalf("failed to run 'collect' command: %v", err) } + err = cmd.Wait() + if err != nil { + t.Fatalf("failed to call 'wait' for scan: %v", err) + } + // make sure that the output is not empty - if len(output) <= 0 { + if len(buf.Bytes()) <= 0 { t.Fatalf("expected the 'collect' output to not be empty") } @@ -93,67 +98,57 @@ func TestScanAndCollect(t *testing.T) { func TestCrawlCommand(t *testing.T) { var ( err error - emuErr error - output []byte command string + cmd *exec.Cmd + buf bytes.Buffer ) // set up the emulator to run before test err = waitUntilEmulatorIsReady() if err != nil { - t.Fatalf("failed to start emulator: %v", err) - } - - // try and start the emulator in the background if arg passed - if *emuPath != "" { - t.Parallel() - t.Run("emulator", func(t *testing.T) { - _, emuErr = exec.Command("bash", "-c", *emuPath).CombinedOutput() - if emuErr != nil { - t.Fatalf("failed to start emulator: %v", emuErr) - } - }) + t.Fatalf("failed while waiting for emulator: %v", err) } // try and run a "collect" with the emulator - command = fmt.Sprintf("%s crawl --username root --password root_password -i", exePath) - output, err = exec.Command("bash", "-c", command).CombinedOutput() + command = fmt.Sprintf("%s crawl --username root --password root_password -i", *exePath) + cmd = exec.Command("bash", "-c", command) + cmd.Stdout = &buf + err = cmd.Start() if err != nil { t.Fatalf("failed to run 'crawl' command: %v", err) } + err = cmd.Wait() + if err != nil { + t.Fatalf("failed to call 'wait' for crawl: %v", err) + } + // make sure that the output is not empty - if len(output) <= 0 { + if len(buf.Bytes()) <= 0 { t.Fatalf("expected the 'crawl' output to not be empty") } } func TestListCommand(t *testing.T) { - // TODO: need magellan binary to test command var ( - cmd *exec.Cmd - err error - output []byte + err error + cmd *exec.Cmd ) // set up the emulator to run before test err = waitUntilEmulatorIsReady() if err != nil { - t.Fatalf("failed to start emulator: %v", err) + t.Fatalf("failed while waiting for emulator: %v", err) } // set up temporary directory cmd = exec.Command("bash", "-c", fmt.Sprintf("%s list", *exePath)) - output, err = cmd.CombinedOutput() + err = cmd.Start() if err != nil { t.Fatalf("failed to run 'list' command: %v", err) } - - // make sure that the output is not empty - if len(output) <= 0 { - t.Fatalf("expected the 'list' output to not be empty") - } + // NOTE: the output of `list` can be empty if no scan has been performed } @@ -161,28 +156,23 @@ func TestUpdateCommand(t *testing.T) { // TODO: add test that does a Redfish simple update checking it success and // failure points var ( - cmd *exec.Cmd - err error - output []byte + cmd *exec.Cmd + err error ) // set up the emulator to run before test err = waitUntilEmulatorIsReady() if err != nil { - t.Fatalf("failed to start emulator: %v", err) + t.Fatalf("failed while waiting for emulator: %v", err) } // set up temporary directory - cmd = exec.Command("bash", "-c", fmt.Sprintf("%s list", *exePath)) - output, err = cmd.CombinedOutput() + cmd = exec.Command("bash", "-c", fmt.Sprintf("%s update", *exePath)) + err = cmd.Start() if err != nil { - t.Fatalf("failed to run 'list' command: %v", err) + t.Fatalf("failed to run 'update' command: %v", err) } - // make sure that the output is not empty - if len(output) <= 0 { - t.Fatalf("expected the 'list' output to not be empty") - } } func TestGofishFunctions(t *testing.T) { @@ -193,9 +183,8 @@ func TestGofishFunctions(t *testing.T) { // TestGenerateHosts() tests creating a collection of hosts by changing arguments // and calling GenerateHostsWithSubnet(). func TestGenerateHosts(t *testing.T) { - // TODO: add test to generate hosts using a collection of subnets/masks var ( - subnet = "127.0.0.1" + subnet = "172.23.0.0" subnetMask = &net.IPMask{255, 255, 255, 0} ports = []int{443} scheme = "https" @@ -221,7 +210,7 @@ func TestGenerateHosts(t *testing.T) { }) t.Run("generate-hosts-with-subnet-mask", func(t *testing.T) { - subnetMask = &net.IPMask{255, 255, 125, 0} + subnetMask = &net.IPMask{255, 255, 0, 0} hosts = magellan.GenerateHostsWithSubnet(subnet, subnetMask, ports, scheme) // check for at least one host to be generated @@ -232,29 +221,74 @@ func TestGenerateHosts(t *testing.T) { } +func startEmulatorInBackground(path string) (int, error) { + // try and start the emulator in the background if arg passed + var ( + cmd *exec.Cmd + err error + ) + if path != "" { + cmd = exec.Command("bash", "-c", path) + err = cmd.Start() + if err != nil { + return -1, fmt.Errorf("failed while executing emulator startup script: %v", err) + } + } else { + return -1, fmt.Errorf("path to emulator start up script is required") + } + return cmd.Process.Pid, nil +} + // waitUntilEmulatorIsReady() polls with func waitUntilEmulatorIsReady() error { var ( interval = time.Second * 5 - timeout = time.Second * 60 - testClient = &http.Client{} - body client.HTTPBody - header client.HTTPHeader - err error + timeout = time.Second * 15 + testClient = &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + } + body client.HTTPBody + header client.HTTPHeader + err error ) err = util.CheckUntil(interval, timeout, func() (bool, error) { // send request to host until we get expected response - res, _, err := client.MakeRequest(testClient, "http://127.0.0.1", http.MethodPost, body, header) + res, _, err := client.MakeRequest(testClient, "https://172.23.0.2:5000/redfish/v1/", http.MethodGet, body, header) if err != nil { - return false, fmt.Errorf("failed to start emulator: %w", err) + return false, fmt.Errorf("failed to make request to emulator: %w", err) } if res == nil { - return false, fmt.Errorf("response returned nil") + return false, fmt.Errorf("invalid response from emulator (response is nil)") } if res.StatusCode == http.StatusOK { return true, nil + } else { + return false, fmt.Errorf("unexpected status code %d", res.StatusCode) } - return false, nil + }) return err } + +func init() { + var ( + cwd string + err error + ) + // get the current working directory + cwd, err = os.Getwd() + if err != nil { + log.Error().Err(err).Msg("failed to get working directory") + } + fmt.Printf("cwd: %s\n", cwd) + + // start emulator in the background before running tests + pid, err := startEmulatorInBackground(*emuPath) + if err != nil { + log.Error().Err(err).Msg("failed to start emulator in background") + os.Exit(1) + } + _ = pid +} diff --git a/tests/compatibility_test.go b/tests/compatibility_test.go index 7825a66..0e220f2 100644 --- a/tests/compatibility_test.go +++ b/tests/compatibility_test.go @@ -7,6 +7,7 @@ package tests import ( + "crypto/tls" "encoding/json" "flag" "fmt" @@ -18,9 +19,9 @@ import ( ) var ( - host = flag.String("host", "localhost", "set the BMC host") - username = flag.String("username", "", "set the BMC username used for the tests") - password = flag.String("password", "", "set the BMC password used for the tests") + host = flag.String("host", "https://172.23.0.2:5000", "set the BMC host") + username = flag.String("username", "root", "set the BMC username used for the tests") + password = flag.String("password", "root_password", "set the BMC password used for the tests") ) func checkResponse(res *http.Response, b []byte) error { @@ -35,7 +36,7 @@ func checkResponse(res *http.Response, b []byte) error { } // make sure the response body is in a valid JSON format - if json.Valid(b) { + if !json.Valid(b) { return fmt.Errorf("expected response body to be valid JSON") } return nil @@ -44,11 +45,24 @@ func checkResponse(res *http.Response, b []byte) error { // Simple test to fetch the base Redfish URL and assert a 200 OK response. func TestRedfishV1ServiceRootAvailability(t *testing.T) { var ( - url = fmt.Sprintf("%s/redfish/v1", *host) - body = []byte{} - headers = map[string]string{} + url = fmt.Sprintf("%s/redfish/v1/", *host) + body = []byte{} + headers = map[string]string{} + testClient = &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + } + err error ) - res, b, err := client.MakeRequest(nil, url, http.MethodGet, body, headers) + + // set up the emulator to run before test + err = waitUntilEmulatorIsReady() + if err != nil { + t.Fatalf("failed while waiting for emulator: %v", err) + } + + res, b, err := client.MakeRequest(testClient, url, http.MethodGet, body, headers) if err != nil { t.Fatalf("failed to make request to BMC node: %v", err) } @@ -63,13 +77,19 @@ func TestRedfishV1ServiceRootAvailability(t *testing.T) { // Simple test to ensure an expected Redfish version minimum requirement. func TestRedfishV1Version(t *testing.T) { var ( - url string = fmt.Sprintf("%s/redfish/v1", *host) - body client.HTTPBody = []byte{} - headers client.HTTPHeader = map[string]string{} - err error + url string = fmt.Sprintf("%s/redfish/v1/", *host) + body client.HTTPBody = []byte{} + headers client.HTTPHeader = map[string]string{} + testClient = &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + } + root map[string]any + err error ) - res, b, err := client.MakeRequest(nil, url, http.MethodGet, body, headers) + res, b, err := client.MakeRequest(testClient, url, http.MethodGet, body, headers) if err != nil { t.Fatalf("failed to make request to BMC node: %v", err) } @@ -77,6 +97,17 @@ func TestRedfishV1Version(t *testing.T) { if err != nil { t.Fatalf("failed to check response for redfish version: %v", err) } + + // check the "RedfishVersion" from service root + err = json.Unmarshal(b, &root) + if err != nil { + t.Fatalf("failed to unmarshal redfish response: %v", err) + } + + _, ok := root["RedfishVersion"] + if !ok { + t.Fatalf("failed to get 'RedfishVersion' from service root") + } } // Crawls a BMC node and checks that we're able to query certain properties @@ -89,6 +120,12 @@ func TestExpectedOutput(t *testing.T) { t.Fatal("invalid host (host is nil)") } + // set up the emulator to run before test + err := waitUntilEmulatorIsReady() + if err != nil { + t.Fatalf("failed while waiting for emulator: %v", err) + } + systems, err := crawler.CrawlBMC( crawler.CrawlerConfig{ URI: *host, @@ -117,8 +154,5 @@ func TestExpectedOutput(t *testing.T) { if len(system.EthernetInterfaces) <= 0 { t.Errorf("no ethernet interfaces found for system '%s'", system.Name) } - if len(system.NetworkInterfaces) <= 0 { - t.Errorf("no network interfaces found for system '%s'", system.Name) - } } }