Storage Module Basis (#13)

* Added storage module, base structs, getDevices() func, taskGetStorageDevices (ticks every 30)

* GetDevices now returns a complete description w/ disk partitions

* Added InUse flag to Device, fixed logic bugs

* Added disk space usage for partitions in use by the system

* Cleanup

* Added UsageStat and UsageSplit filling for in use devices

* Changed value of lsblk block usage output to bytes

* Cleanup, small fixes

* Added ExecAndGetLines util func

* Added explicit detection of disk or part block type, ignoring non-suppoorted devices

* Added command line tool dependencies for the project in README file

* Added comment to func ExecAndGetLines

* Removed GetMySQLDbConnectionDetails()

* Added tests to utils module

* Fix invalid argument type for Exec family of tests

* Removed too much verbosity from utils.GetPath when no env file is available, added new argument (path) to Exec family of funcs

* Added new path argument to utils.Exec... test

* Fixed TestExec

* Added spaces trim to Exec result

* Trimming spaces and newlines from result of Exec

* Better visibility for test result log of TestExec

* Added ExampleExecAndStream test

* Added Example tests with failure status for ExecAndStream

* Added branch to test for valid key in GetPath

* Added missing t.Fail() statements in utils_test.go

* Added storage_test.go file, smoke test

* TestGetDevices
This commit is contained in:
Paulo Truta
2021-06-13 12:03:36 +02:00
committed by GitHub
parent 92ac9c2b03
commit 9339e6cf09
9 changed files with 483 additions and 46 deletions
+20 -28
View File
@@ -1,31 +1,33 @@
package utils
import (
"bufio"
"bytes"
"fmt"
"io"
"log"
"os"
"os/exec"
"strings"
"time"
"github.com/joho/godotenv"
)
// ExecAndStream : Runs a terminal command, but streams progress instead of outputting. Ideal for long lived process that need to be logged.
func ExecAndStream(command string, args []string) {
func ExecAndStream(path string, command string, args []string) {
cmd := exec.Command(command, args...)
var stdoutBuf, stderrBuf bytes.Buffer
cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
cmd.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
cmd.Dir = GetPath("wsPath")
cmd.Dir = path
err := cmd.Run()
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
fmt.Printf("cmd.Run() failed with %s\n", err)
}
outStr, errStr := string(stdoutBuf.Bytes()), string(stderrBuf.Bytes())
@@ -34,13 +36,13 @@ func ExecAndStream(command string, args []string) {
}
// Exec : Runs a terminal Command, catches and logs errors, returns the result.
func Exec(command string, args []string) string {
func Exec(path string, command string, args []string) string {
cmd := exec.Command(command, args...)
var out bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &stderr
cmd.Dir = GetPath("wsPath")
cmd.Dir = path
err := cmd.Run()
if err != nil {
// TODO: Deal with possibility of error in command, allow explicit error handling and return proper formatted stderr
@@ -49,10 +51,20 @@ func Exec(command string, args []string) string {
// log.Println("Result: " + out.String()) // ... Silence ...
return out.String()
return strings.Trim(out.String(), " \n")
}
// Exec : Runs a terminal Command, returns the result as a *bufio.Scanner type, split in lines and ready to parse.
func ExecAndGetLines(path string, command string, args []string) *bufio.Scanner {
cmdOutput := Exec(path, command, args)
cmdOutputReader := strings.NewReader(cmdOutput)
scanner := bufio.NewScanner(cmdOutputReader)
scanner.Split(bufio.ScanLines)
return scanner
}
// DeleteEmptySlices : Given a string array, delete empty entries.
func DeleteEmptySlices(s []string) []string {
var r []string
@@ -64,25 +76,6 @@ func DeleteEmptySlices(s []string) []string {
return r
}
// GetMySQLDbConnectionDetails : Returns the necessary string as connection info for SQL.db()
func GetMySQLDbConnectionDetails() string {
var apiEnv map[string]string
apiEnv, err := godotenv.Read(GetPath("apiEnvFileLocation"))
if err != nil {
log.Fatal("Error loading .env file")
}
Dbhost := "127.0.0.1:" + apiEnv["HOST_MACHINE_MYSQL_PORT"]
Dbname := apiEnv["MYSQL_DATABASE"]
Dbuser := apiEnv["MYSQL_USER"]
Dbpass := apiEnv["MYSQL_PASSWORD"]
return Dbuser + ":" + Dbpass + "@tcp(" + Dbhost + ")/" + Dbname
}
// GetSQLiteDbConnectionDetails : Returns the necessary string as connection info for SQL.db()
func GetSQLiteDbConnectionDetails() string {
@@ -112,11 +105,10 @@ func GetPath(pathKey string) string {
// Read whole of .env file to map.
var env map[string]string
env, err := godotenv.Read()
targetPath := ""
var targetPath string
if err != nil {
// log.Println("Project .env file not found withing project root. Using only hardcoded path variables.")
// Do Nothing...
targetPath = ""
}
switch pathKey {
+90
View File
@@ -7,6 +7,96 @@ import (
"time"
)
func TestExec(t *testing.T) {
testCommand := "echo"
testArguments := []string{"Hello World"}
result := Exec("/", testCommand, testArguments)
if result != "Hello World" {
t.Log("Expected 'Hello World' but got", "'"+result+"'")
t.Fail()
}
}
func ExampleExecAndStream() {
ExecAndStream("/", "echo", []string{"Hello"})
// Output:
// Hello
//
// out:
// Hello
//
// err:
}
func ExampleExecAndStreamExecutableNotFound() {
ExecAndStream("/", "testcommand", []string{"Hello"})
// Output:
// cmd.Run() failed with exec: "testcommand": executable file not found in $PATH
//
// out:
//
// err:
}
func ExampleExecAndStreamError() {
ExecAndStream("/", "man", []string{"Hello"})
// Output:
// cmd.Run() failed with exit status 16
//
// out:
//
// err:
// No manual entry for Hello
}
func TestExecAndGetLines(t *testing.T) {
testCommand := "echo"
testArguments := []string{"$'Line1\nLine2\nLine3'"}
var result []string
scanner := ExecAndGetLines("/", testCommand, testArguments)
for scanner.Scan() {
result = append(result, scanner.Text())
}
if len(result) != 3 {
t.Log("Expected 3 lines but got ", len(result))
t.Fail()
}
}
func TestDeleteEmptySlices(t *testing.T) {
testSlice := []string{"Line1", "", "Line3"}
resultSlice := DeleteEmptySlices(testSlice)
if (len(resultSlice)) != 2 {
t.Log("Expected 2 slices but got ", len(resultSlice))
t.Fail()
}
}
func TestGetPath(t *testing.T) {
invalidPathKey := "test"
result := GetPath(invalidPathKey)
if result != "" {
t.Log("Expected empty result but got ", result)
t.Fail()
}
validPathKey := "wsPath"
result = GetPath(validPathKey)
if result != "/home/system/components/ws/" {
t.Log("Expected /home/system/components/ws/ but got", result)
t.Fail()
}
}
func TestGetSQLiteFormattedDateTime(t *testing.T) {
datetime := time.Date(2021, time.Month(1), 01, 1, 30, 15, 0, time.UTC)
result := GetSQLiteFormattedDateTime(datetime)