291 lines
6.4 KiB
Go
291 lines
6.4 KiB
Go
package engine
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/nalgeon/codapi/internal/config"
|
|
"github.com/nalgeon/codapi/internal/execy"
|
|
"github.com/nalgeon/codapi/internal/logx"
|
|
)
|
|
|
|
var dockerCfg = &config.Config{
|
|
Boxes: map[string]*config.Box{
|
|
"alpine": {
|
|
Image: "codapi/alpine",
|
|
Runtime: "runc",
|
|
Host: config.Host{
|
|
CPU: 1, Memory: 64, Network: "none",
|
|
Volume: "%s:/sandbox:ro",
|
|
NProc: 64,
|
|
},
|
|
},
|
|
"go": {
|
|
Image: "codapi/go",
|
|
Runtime: "runc",
|
|
Host: config.Host{
|
|
CPU: 1, Memory: 64, Network: "none",
|
|
Volume: "%s:/sandbox:ro",
|
|
NProc: 64,
|
|
},
|
|
},
|
|
"go:dev": {
|
|
Image: "codapi/go:dev",
|
|
Runtime: "runc",
|
|
Host: config.Host{
|
|
CPU: 1, Memory: 64, Network: "none",
|
|
Volume: "%s:/sandbox:ro",
|
|
NProc: 64,
|
|
},
|
|
},
|
|
"python": {
|
|
Image: "codapi/python",
|
|
Runtime: "runc",
|
|
Host: config.Host{
|
|
CPU: 1, Memory: 64, Network: "none",
|
|
Volume: "%s:/sandbox:ro",
|
|
NProc: 64,
|
|
},
|
|
},
|
|
"python:dev": {
|
|
Image: "codapi/python:dev",
|
|
Runtime: "runc",
|
|
Host: config.Host{
|
|
CPU: 1, Memory: 64, Network: "none",
|
|
Volume: "%s:/sandbox:ro",
|
|
NProc: 64,
|
|
},
|
|
},
|
|
},
|
|
Commands: map[string]config.SandboxCommands{
|
|
"go": map[string]*config.Command{
|
|
"run": {
|
|
Engine: "docker",
|
|
Steps: []*config.Step{
|
|
{
|
|
Box: "go", User: "sandbox", Action: "run",
|
|
Command: []string{"go", "build"},
|
|
NOutput: 4096,
|
|
},
|
|
{
|
|
Box: "alpine", Version: "latest",
|
|
User: "sandbox", Action: "run",
|
|
Command: []string{"./main"},
|
|
NOutput: 4096,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"postgresql": map[string]*config.Command{
|
|
"run": {
|
|
Engine: "docker",
|
|
Before: &config.Step{
|
|
Box: "postgres", User: "sandbox", Action: "exec",
|
|
Command: []string{"psql", "-f", "create.sql"},
|
|
NOutput: 4096,
|
|
},
|
|
Steps: []*config.Step{
|
|
{
|
|
Box: "postgres", User: "sandbox", Action: "exec", Stdin: true,
|
|
Command: []string{"psql", "--user=:name"},
|
|
NOutput: 4096,
|
|
},
|
|
},
|
|
After: &config.Step{
|
|
Box: "postgres", User: "sandbox", Action: "exec",
|
|
Command: []string{"psql", "-f", "drop.sql"},
|
|
NOutput: 4096,
|
|
},
|
|
},
|
|
},
|
|
"python": map[string]*config.Command{
|
|
"run": {
|
|
Engine: "docker",
|
|
Entry: "main.py",
|
|
Steps: []*config.Step{
|
|
{
|
|
Box: "python", User: "sandbox", Action: "run",
|
|
Command: []string{"python", "main.py"},
|
|
NOutput: 4096,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
func TestDockerRun(t *testing.T) {
|
|
logx.Mock()
|
|
commands := map[string]execy.CmdOut{
|
|
"docker run": {Stdout: "hello world", Stderr: "", Err: nil},
|
|
}
|
|
mem := execy.Mock(commands)
|
|
|
|
t.Run("success", func(t *testing.T) {
|
|
mem.Clear()
|
|
engine := NewDocker(dockerCfg, "python", "run")
|
|
req := Request{
|
|
ID: "http_42",
|
|
Sandbox: "python",
|
|
Command: "run",
|
|
Files: map[string]string{
|
|
"": "print('hello world')",
|
|
},
|
|
}
|
|
out := engine.Exec(req)
|
|
if out.ID != req.ID {
|
|
t.Errorf("ID: expected %s, got %s", req.ID, out.ID)
|
|
}
|
|
if !out.OK {
|
|
t.Error("OK: expected true")
|
|
}
|
|
want := "hello world"
|
|
if out.Stdout != want {
|
|
t.Errorf("Stdout: expected %q, got %q", want, out.Stdout)
|
|
}
|
|
if out.Stderr != "" {
|
|
t.Errorf("Stderr: expected %q, got %q", "", out.Stdout)
|
|
}
|
|
if out.Err != nil {
|
|
t.Errorf("Err: expected nil, got %v", out.Err)
|
|
}
|
|
mem.MustHave(t, "codapi/python")
|
|
mem.MustHave(t, "python main.py")
|
|
})
|
|
|
|
t.Run("latest version", func(t *testing.T) {
|
|
mem.Clear()
|
|
engine := NewDocker(dockerCfg, "python", "run")
|
|
req := Request{
|
|
ID: "http_42",
|
|
Sandbox: "python",
|
|
Command: "run",
|
|
Files: map[string]string{
|
|
"": "print('hello world')",
|
|
},
|
|
}
|
|
out := engine.Exec(req)
|
|
if !out.OK {
|
|
t.Error("OK: expected true")
|
|
}
|
|
mem.MustHave(t, "codapi/python")
|
|
})
|
|
|
|
t.Run("custom version", func(t *testing.T) {
|
|
mem.Clear()
|
|
engine := NewDocker(dockerCfg, "python", "run")
|
|
req := Request{
|
|
ID: "http_42",
|
|
Sandbox: "python",
|
|
Version: "dev",
|
|
Command: "run",
|
|
Files: map[string]string{
|
|
"": "print('hello world')",
|
|
},
|
|
}
|
|
out := engine.Exec(req)
|
|
if !out.OK {
|
|
t.Error("OK: expected true")
|
|
}
|
|
mem.MustHave(t, "codapi/python:dev")
|
|
})
|
|
|
|
t.Run("step version", func(t *testing.T) {
|
|
mem.Clear()
|
|
engine := NewDocker(dockerCfg, "go", "run")
|
|
req := Request{
|
|
ID: "http_42",
|
|
Sandbox: "go",
|
|
Version: "dev",
|
|
Command: "run",
|
|
Files: map[string]string{
|
|
"": "var n = 42",
|
|
},
|
|
}
|
|
out := engine.Exec(req)
|
|
if !out.OK {
|
|
t.Error("OK: expected true")
|
|
}
|
|
mem.MustHave(t, "codapi/go:dev")
|
|
mem.MustHave(t, "codapi/alpine")
|
|
})
|
|
|
|
t.Run("unsupported version", func(t *testing.T) {
|
|
mem.Clear()
|
|
engine := NewDocker(dockerCfg, "python", "run")
|
|
req := Request{
|
|
ID: "http_42",
|
|
Sandbox: "python",
|
|
Version: "42",
|
|
Command: "run",
|
|
Files: map[string]string{
|
|
"": "print('hello world')",
|
|
},
|
|
}
|
|
out := engine.Exec(req)
|
|
if out.OK {
|
|
t.Error("OK: expected false")
|
|
}
|
|
want := "unknown box python:42"
|
|
if out.Stderr != want {
|
|
t.Errorf("Stderr: unexpected value: %s", out.Stderr)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDockerExec(t *testing.T) {
|
|
logx.Mock()
|
|
commands := map[string]execy.CmdOut{
|
|
"docker exec": {Stdout: "hello world", Stderr: "", Err: nil},
|
|
}
|
|
mem := execy.Mock(commands)
|
|
engine := NewDocker(dockerCfg, "postgresql", "run")
|
|
|
|
t.Run("success", func(t *testing.T) {
|
|
req := Request{
|
|
ID: "http_42",
|
|
Sandbox: "postgresql",
|
|
Command: "run",
|
|
Files: map[string]string{
|
|
"": "select 'hello world'",
|
|
},
|
|
}
|
|
out := engine.Exec(req)
|
|
if out.ID != req.ID {
|
|
t.Errorf("ID: expected %s, got %s", req.ID, out.ID)
|
|
}
|
|
if !out.OK {
|
|
t.Error("OK: expected true")
|
|
}
|
|
want := "hello world"
|
|
if out.Stdout != want {
|
|
t.Errorf("Stdout: expected %q, got %q", want, out.Stdout)
|
|
}
|
|
if out.Stderr != "" {
|
|
t.Errorf("Stderr: expected %q, got %q", "", out.Stdout)
|
|
}
|
|
if out.Err != nil {
|
|
t.Errorf("Err: expected nil, got %v", out.Err)
|
|
}
|
|
mem.MustHave(t, "psql -f create.sql")
|
|
mem.MustHave(t, "psql --user=http_42")
|
|
mem.MustHave(t, "psql -f drop.sql")
|
|
})
|
|
}
|
|
|
|
func Test_expandVars(t *testing.T) {
|
|
const name = "codapi_01"
|
|
commands := map[string]string{
|
|
"python main.py": "python main.py",
|
|
"sh create.sh :name": "sh create.sh " + name,
|
|
}
|
|
for cmd, want := range commands {
|
|
src := strings.Fields(cmd)
|
|
exp := expandVars(src, name)
|
|
got := strings.Join(exp, " ")
|
|
if got != want {
|
|
t.Errorf("%q: expected %q, got %q", cmd, got, want)
|
|
}
|
|
}
|
|
}
|