package vm import ( "errors" "os" "path/filepath" "reflect" "testing" "time" "github.com/gofrs/uuid" ) const ( maxTestVirtualMachines uint8 = 30 testVirtualMachineTimeout = time.Minute scriptName = "1D01TH0RS3.gct" ) var ( testScript = filepath.Join("..", "..", "testdata", "gctscript", "once.gct") testInvalidScript = filepath.Join("..", "..", "testdata", "gctscript", "invalid.gct") testBrokenScript = filepath.Join("..", "..", "testdata", "gctscript", "broken.gct") testScriptRunner = filepath.Join("..", "..", "testdata", "gctscript", "timer.gct") testScriptRunner1s = filepath.Join("..", "..", "testdata", "gctscript", "1s_timer.gct") testScriptRunnerNegative = filepath.Join("..", "..", "testdata", "gctscript", "negative_timer.gct") testScriptRunnerInvalid = filepath.Join("..", "..", "testdata", "gctscript", "invalid_timer.gct") ) func TestNewVM(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), } x := manager.New() if x != nil { t.Error("Should not create a VM when manager not started") } manager.started = 1 x = manager.New() xType := reflect.TypeOf(x).String() if xType != "*vm.VM" { t.Fatalf("vm.New should return pointer to VM instead received: %v", x) } } func TestVMLoad(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } testVM := manager.New() err := testVM.Load(testScript) if err != nil { t.Fatal(err) } testScript = testScript[0 : len(testScript)-4] testVM = manager.New() err = testVM.Load(testScript) if err != nil { t.Fatal(err) } manager.config = configHelper(false, false, maxTestVirtualMachines) err = testVM.Load(testScript) if err != nil { if !errors.Is(err, ErrScriptingDisabled) { t.Fatal(err) } } } func TestVMLoad1s(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } testVM := manager.New() err := testVM.Load(testScriptRunner1s) if err != nil { t.Fatal(err) } testVM.CompileAndRun() err = testVM.Shutdown() if err != nil { if !errors.Is(err, ErrNoVMLoaded) { t.Fatal(err) } } } func TestVMLoadNegativeTimer(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } testVM := manager.New() err := testVM.Load(testScriptRunnerNegative) if err != nil { if !errors.Is(err, ErrNoVMLoaded) { t.Fatal(err) } } testVM.CompileAndRun() err = testVM.Shutdown() if err == nil { t.Fatal("expect error on shutdown due to invalid VM") } } func TestVMLoadNilVM(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } testVM := manager.New() err := testVM.Load(testScript) if err != nil { if !errors.Is(err, ErrNoVMLoaded) { t.Fatal(err) } } testVM = nil err = testVM.Load(testScript) if err != nil { if !errors.Is(err, ErrNoVMLoaded) { t.Fatal(err) } } } func TestCompileAndRunNilVM(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } vmcount := VMSCount.Len() testVM := manager.New() err := testVM.Load(testScript) if err != nil { if !errors.Is(err, ErrNoVMLoaded) { t.Fatal(err) } } err = testVM.Load(testScript) if err != nil { if !errors.Is(err, ErrNoVMLoaded) { t.Fatal(err) } } testVM = nil testVM.CompileAndRun() err = testVM.Shutdown() if err == nil { t.Fatal("VM should not be running with invalid timer") } if VMSCount.Len() == vmcount-1 { t.Fatal("expected VM count to decrease") } } func TestVMLoadNoFile(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } testVM := manager.New() err := testVM.Load("missing file") if err != nil { if !errors.Is(err, os.ErrNotExist) { t.Fatal(err) } } } func TestVMCompile(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } testVM := manager.New() err := testVM.Load(testScript) if err != nil { t.Fatal(err) } err = testVM.Compile() if err != nil { t.Fatal(err) } } func TestVMRun(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } testVM := manager.NewVM() err := testVM.Load(testScript) if err != nil { t.Fatal(err) } err = testVM.Compile() if err != nil { t.Fatal(err) } err = testVM.RunCtx() if err != nil { t.Fatal(err) } } func TestVMRunTX(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } testVM := manager.NewVM() err := testVM.Load(testScript) if err != nil { t.Fatal(err) } err = testVM.Compile() if err != nil { t.Fatal(err) } err = testVM.RunCtx() if err != nil { t.Fatal(err) } } func TestVMWithRunner(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } vmCount := VMSCount.Len() VM := manager.New() if VM == nil { t.Fatal("Failed to allocate new VM exiting") } err := VM.Load(testScriptRunner) if err != nil { t.Fatal(err) } if VMSCount.Len() == vmCount { t.Fatal("expected VM count to increase") } VM.CompileAndRun() err = VM.Shutdown() if err != nil { t.Fatal(err) } if VMSCount.Len() == vmCount-1 { t.Fatal("expected VM count to decrease") } } func TestVMWithRunnerOnce(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } vmCount := VMSCount.Len() // nolint:ifshort,nolintlint // false positive and triggers only on Windows VM := manager.New() if VM == nil { t.Fatal("Failed to allocate new VM exiting") } err := VM.Load(testScript) if err != nil { t.Fatal(err) } if VMSCount.Len() == vmCount { t.Fatal("expected VM count to increase") } VM.CompileAndRun() err = VM.Shutdown() if err == nil { t.Fatal("VM should not be running with invalid timer") } } func TestVMWithRunnerNegativeTimer(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } vmCount := VMSCount.Len() VM := manager.New() if VM == nil { t.Fatal("Failed to allocate new VM exiting") } err := VM.Load(testScriptRunnerNegative) if err != nil { t.Fatal(err) } if VMSCount.Len() == vmCount { t.Fatal("expected VM count to increase") } VM.CompileAndRun() err = VM.Shutdown() if err == nil { t.Fatal("VM should not be running with invalid timer") } if VMSCount.Len() == vmCount-1 { t.Fatal("expected VM count to decrease") } } func TestVMWithRunnerInvalidTimer(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } vmCount := VMSCount.Len() VM := manager.New() if VM == nil { t.Fatal("Failed to allocate new VM exiting") } err := VM.Load(testScriptRunnerInvalid) if err != nil { t.Fatal(err) } if VMSCount.Len() == vmCount { t.Fatal("expected VM count to increase") } VM.CompileAndRun() err = VM.Shutdown() if err == nil { t.Fatal("VM should not be running with invalid timer") } if VMSCount.Len() == vmCount-1 { t.Fatal("expected VM count to decrease") } } func TestShutdownAll(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } vmCount := VMSCount.Len() VM := manager.New() err := VM.Load(testScriptRunner) if err != nil { t.Fatal(err) } VM.CompileAndRun() if VMSCount.Len() == vmCount { t.Fatal("expected VM count to increase") } err = manager.ShutdownAll() if err != nil { t.Fatal(err) } if VMSCount.Len() == vmCount-1 { t.Fatal("expected VM count to decrease") } } func TestRead(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } VM := manager.NewVM() err := VM.Load(testScriptRunner) if err != nil { t.Fatal(err) } ScriptPath = filepath.Join("..", "..", "testdata", "gctscript") data, err := VM.Read() if err != nil { t.Fatal(err) } if len(data) < 1 { t.Fatal("expected data to be returned") } _ = VM.Shutdown() } func TestRemoveVM(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } id, _ := uuid.FromString("6f20c907-64a0-48f2-848a-7837dee61672") err := manager.RemoveVM(id) if err != nil { if err.Error() != "VM 6f20c907-64a0-48f2-848a-7837dee61672 not found" { t.Fatal(err) } } } func TestError_Error(t *testing.T) { x := Error{ Script: "noscript.gct", Action: "test", Cause: errors.New("HELLO ERROR"), } if x.Error() != "GCT Script: (ACTION) test (SCRIPT) noscript.gct HELLO ERROR" { t.Fatal(x.Error()) } } func TestVM_CompileInvalid(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } testVM := manager.New() err := testVM.Load(testInvalidScript) if err != nil { t.Fatal(err) } err = testVM.Compile() if err != nil { t.Fatal(err) } err = testVM.RunCtx() if err == nil { t.Fatal("unexpected result broken script compiled successfully ") } testVM = manager.New() err = testVM.Load(testInvalidScript) if err != nil { t.Fatal(err) } err = testVM.Compile() if err != nil { t.Fatal(err) } err = testVM.RunCtx() if err == nil { t.Fatal("unexpected result broken script compiled successfully ") } testVM = manager.New() err = testVM.Load(testInvalidScript) if err != nil { t.Fatal(err) } testVM.CompileAndRun() err = testVM.Shutdown() if err == nil { t.Fatal("Shutdown() passed successfully but expected to fail with invalid script") } } func TestVM_CompileBroken(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } testVM := manager.New() err := testVM.Load(testBrokenScript) if err != nil { t.Fatal(err) } err = testVM.Compile() if err == nil { t.Fatal("unexpected result broken script compiled successfully ") } } func TestVM_CompileAndRunBroken(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } testVM := manager.New() err := testVM.Load(testBrokenScript) if err != nil { t.Fatal(err) } testVM.CompileAndRun() err = testVM.Shutdown() if err == nil { t.Fatal("expect error on shutdown due to invalid VM") } } func TestValidate(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, true, maxTestVirtualMachines), started: 1, } err := manager.Validate(testBrokenScript) if err == nil { t.Fatal(err) } err = manager.Validate(testScript) if err != nil { t.Fatal(err) } } func TestVMLimit(t *testing.T) { manager := GctScriptManager{ config: configHelper(true, false, 0), started: 1, } if testVM := manager.New(); testVM != nil { t.Fatal("expected nil but received pointer to VM") } } func TestAutoload(t *testing.T) { manager := GctScriptManager{ config: &Config{ Enabled: true, AutoLoad: []string{ scriptName, }, Verbose: true, }, } ScriptPath = filepath.Join("..", "..", "testdata", "gctscript") err := manager.Autoload(scriptName, true) if err != nil { t.Fatal(err) } err = manager.Autoload(scriptName, true) if err == nil { t.Fatal("expected err to be script not found received nil") } err = manager.Autoload("once", false) if err != nil { t.Fatal(err) } err = manager.Autoload(scriptName, false) if err == nil { t.Fatal("expected err to be script not found received nil") } } func TestVMCount(t *testing.T) { var c vmscount c.add() if c.Len() != 1 { t.Fatalf("expect c len to be 1 instead received %v", c.Len()) } c.remove() if c.Len() != 0 { t.Fatalf("expect c len to be 0 instead received %v", c.Len()) } } func configHelper(enabled, imports bool, max uint8) *Config { return &Config{ Enabled: enabled, AllowImports: imports, ScriptTimeout: testVirtualMachineTimeout, MaxVirtualMachines: max, Verbose: true, } }