diff --git a/hook/main.go b/hook/main.go index 8b9b606..a781b11 100644 --- a/hook/main.go +++ b/hook/main.go @@ -30,6 +30,13 @@ const ( kvPairSize = 2 ) +var ( + stdIn = os.Stdin + sysCallExec = syscall.Exec + ascendDockerCliName = ascendDockerCli + defaultAscendDockerCliName = defaultAscendDockerCli +) + type containerConfig struct { Pid int Rootfs string @@ -120,9 +127,9 @@ func parseOciSpecFile(file string) (*specs.Spec, error) { return spec, nil } -func getContainerConfig() (*containerConfig, error) { +var getContainerConfig = func () (*containerConfig, error) { state := new(specs.State) - decoder := json.NewDecoder(os.Stdin) + decoder := json.NewDecoder(stdIn) if err := decoder.Decode(state); err != nil { return nil, fmt.Errorf("failed to parse the container's state") @@ -174,14 +181,14 @@ func doPrestartHook() error { return fmt.Errorf("failed to parse device setting: %w", err) } - cliPath, err := exec.LookPath(ascendDockerCli) + cliPath, err := exec.LookPath(ascendDockerCliName) if err != nil { - _, err = os.Stat(defaultAscendDockerCli) + _, err = os.Stat(defaultAscendDockerCliName) if err != nil { return fmt.Errorf("could not found ascend docker cli") } - cliPath = defaultAscendDockerCli + cliPath = defaultAscendDockerCliName } args := append([]string{cliPath}, @@ -189,7 +196,7 @@ func doPrestartHook() error { "--pid", fmt.Sprintf("%d", containerConfig.Pid), "--rootfs", containerConfig.Rootfs) - if err := syscall.Exec(cliPath, args, os.Environ()); err != nil { + if err := sysCallExec(cliPath, args, os.Environ()); err != nil { return fmt.Errorf("failed to exec ascend-docker-cli %v: %w", args, err) } diff --git a/hook/main_test.go b/hook/main_test.go index a5e982d..7d0aa2a 100644 --- a/hook/main_test.go +++ b/hook/main_test.go @@ -1,20 +1,242 @@ /* * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. * Description: hook main 函数单元测试 -*/ + */ package main import ( + "github.com/prashantv/gostub" + "os" + "os/exec" "reflect" "testing" ) func TestRemoveDuplication(t *testing.T) { - originList := []int {1,2,2,4,5,5,5,6,8,8} - targetList := []int {1,2,4,5,6,8} + originList := []int{1, 2, 2, 4, 5, 5, 5, 6, 8, 8} + targetList := []int{1, 2, 4, 5, 6, 8} resultList := removeDuplication(originList) if !reflect.DeepEqual(resultList, targetList) { t.Fail() } } + +func TestDoPrestartHookCase1(t *testing.T) { + if err := doPrestartHook(); err != nil { + t.Log("failed") + } +} + +func TestDoPrestartHookCase2(t *testing.T) { + conCfg := containerConfig{ + Pid: 123, + Rootfs: ".", + Env: []string{"ASCEND_VISIBLE_DEVICES=0l-3,5,7"}, + } + stub := gostub.StubFunc(&getContainerConfig, &conCfg, nil) + defer stub.Reset() + if err := doPrestartHook(); err != nil { + t.Log("failed") + } +} + +func TestDoPrestartHookCase3(t *testing.T) { + conCfg := containerConfig{ + Pid: 123, + Rootfs: ".", + Env: []string{"ASCEND_VISIBLE_DEVICE=0-3,5,7"}, + } + stub := gostub.StubFunc(&getContainerConfig, &conCfg, nil) + defer stub.Reset() + if err := doPrestartHook(); err != nil { + t.Log("failed") + } +} + +func TestDoPrestartHookCase4(t *testing.T) { + conCfg := containerConfig{ + Pid: 123, + Rootfs: ".", + Env: []string{"ASCEND_VISIBLE_DEVICES=0-3,5,7"}, + } + stub := gostub.StubFunc(&getContainerConfig, &conCfg, nil) + defer stub.Reset() + stub.Stub(&ascendDockerCliName, "") + stub.StubFunc(&sysCallExec, nil) + if err := doPrestartHook(); err != nil { + t.Log("failed") + } +} + +func TestDoPrestartHookCase5(t *testing.T) { + defer func() { + if err := recover(); err != nil { + t.Log("exception", err) + } + }() + conCfg := containerConfig{ + Pid: 123, + Rootfs: ".", + Env: []string{"ASCEND_VISIBLE_DEVICES=0-3,5,7"}, + } + stub := gostub.StubFunc(&getContainerConfig, &conCfg, nil) + defer stub.Reset() + stub.Stub(&ascendDockerCliName, "clii") + stub.Stub(&defaultAscendDockerCliName, "clii") + stub.StubFunc(&sysCallExec, nil) + if err := doPrestartHook(); err != nil { + t.Log("failed") + } +} + +func TestGetValueByKeyCase1(t *testing.T) { + data := []string{"ASCEND_VISIBLE_DEVICES=0-3,5,7"} + key := "ASCEND_VISIBLE_DEVICES" + expectVal := "0-3,5,7" + actualVal := getValueByKey(data, key) + if actualVal != expectVal { + t.Fail() + } +} + +func TestGetValueByKeyCase2(t *testing.T) { + data := []string{"ASCEND_VISIBLE_DEVICES"} + key := "ASCEND_VISIBLE_DEVICES" + expectVal := "" + defer func() { + if err := recover(); err != nil { + t.Log("exception occur") + } + }() + actualVal := getValueByKey(data, key) + if actualVal != expectVal { + t.Fail() + } +} + +func TestGetValueByKeyCase3(t *testing.T) { + data := []string{"ASCEND_VISIBLE_DEVICES=0-3,5,7"} + key := "ASCEND_VISIBLE_DEVICE" + expectVal := "" + actualVal := getValueByKey(data, key) + if actualVal != expectVal { + t.Fail() + } +} + +func TestParseDevicesCase1(t *testing.T) { + visibleDevices := "0-3,5,7" + expectVal := []int{0, 1, 2, 3, 5, 7} + actualVal, err := parseDevices(visibleDevices) + if err != nil || !reflect.DeepEqual(expectVal, actualVal) { + t.Fail() + } +} + +func TestParseDevicesCase2(t *testing.T) { + visibleDevices := "0-3-4,5,7" + _, err := parseDevices(visibleDevices) + if err != nil { + t.Fail() + } +} + +func TestParseDevicesCase3(t *testing.T) { + visibleDevices := "0l-3,5,7" + _, err := parseDevices(visibleDevices) + if err == nil { + t.Fail() + } +} + +func TestParseDevicesCase4(t *testing.T) { + visibleDevices := "0-3o,5,7" + _, err := parseDevices(visibleDevices) + if err == nil { + t.Fail() + } +} + +func TestParseDevicesCase5(t *testing.T) { + visibleDevices := "4-3,5,7" + _, err := parseDevices(visibleDevices) + if err == nil { + t.Fail() + } +} + +func TestParseDevicesCase6(t *testing.T) { + visibleDevices := "3o,5,7" + _, err := parseDevices(visibleDevices) + if err == nil { + t.Fail() + } +} + +func TestParseDevicesCase7(t *testing.T) { + visibleDevices := "0=3,5,7" + _, err := parseDevices(visibleDevices) + if err == nil { + t.Fail() + } +} + +func TestParseOciSpecFileCase1(t *testing.T) { + file := "file" + _, err := parseOciSpecFile(file) + if err == nil { + t.Fail() + } +} + +func TestParseOciSpecFileCase2(t *testing.T) { + file := "file" + f, err := os.Create(file) + defer os.Remove(file) + defer f.Close() + if err != nil { + t.Log("create file failed") + } + _, err = parseOciSpecFile(file) + if err == nil { + t.Fail() + } +} + +func TestParseOciSpecFileCase3(t *testing.T) { + file := "config.json" + cmd := exec.Command("runc", "spec") + if err := cmd.Run(); err != nil { + t.Log("runc spec failed") + } + defer os.Remove(file) + _, err := parseOciSpecFile(file) + if err != nil { + t.Fail() + } +} + +func TestGetContainerConfig(t *testing.T) { + file := "config.json" + cmd := exec.Command("runc", "spec") + if err := cmd.Run(); err != nil { + t.Log("runc spec failed") + } + defer func() { + if err := recover(); err != nil { + t.Log("exception", err) + } + }() + defer os.Remove(file) + stateFile, err := os.Open("config.json") + if err != nil { + t.Log("open file failed") + } + defer stateFile.Close() + + stub := gostub.Stub(&stdIn, stateFile) + defer stub.Reset() + + getContainerConfig() +} diff --git a/runtime/main.go b/runtime/main.go index f257bd8..19aba19 100644 --- a/runtime/main.go +++ b/runtime/main.go @@ -21,6 +21,15 @@ const ( loggingPrefix = "ascend-docker-runtime" hookCli = "ascend-docker-hook" hookDefaultFilePath = "/usr/local/bin/ascend-docker-hook" + dockerRuncFile = "docker-runc" + runcFile = "runc" +) + +var ( + hookCliPath = hookCli + hookDefaultFile = hookDefaultFilePath + dockerRuncName = dockerRuncFile + runcName = runcFile ) type args struct { @@ -46,9 +55,9 @@ func getArgs() (*args, error) { } var execRunc = func() error { - runcPath, err := exec.LookPath("docker-runc") + runcPath, err := exec.LookPath(dockerRuncName) if err != nil { - runcPath, err = exec.LookPath("runc") + runcPath, err = exec.LookPath(runcName) if err != nil { return fmt.Errorf("failed to find the path of runc: %w", err) } @@ -62,9 +71,9 @@ var execRunc = func() error { } func addHook(spec *specs.Spec) error { - path, err := exec.LookPath(hookCli) + path, err := exec.LookPath(hookCliPath) if err != nil { - path = hookDefaultFilePath + path = hookDefaultFile if _, err = os.Stat(path); err != nil { return fmt.Errorf("cannot find the hook") } diff --git a/runtime/main_test.go b/runtime/main_test.go index c585028..2288ac5 100644 --- a/runtime/main_test.go +++ b/runtime/main_test.go @@ -8,6 +8,7 @@ import ( "os" "testing" + "github.com/opencontainers/runtime-spec/specs-go" "github.com/prashantv/gostub" ) @@ -27,3 +28,175 @@ func TestArgsIsCreate(t *testing.T) { t.Fatalf("%v", err) } } + +func TestArgsIsCreateCase1(t *testing.T) { + t.Log("进入测试用例") + + testArgs := []string{"create", "--bundle"} + stub := gostub.Stub(&os.Args, testArgs) + defer stub.Reset() + + stub.Stub(&execRunc, func() error { + t.Log("execute stub") + return nil + }) + + if err := doProcess(); err == nil { + t.Fatalf("%v", err) + } +} + +func TestArgsIsCreateCase2(t *testing.T) { + t.Log("进入测试用例") + + testArgs := []string{"create", "--bundle", ""} + stub := gostub.Stub(&os.Args, testArgs) + defer stub.Reset() + + stub.Stub(&execRunc, func() error { + t.Log("execute stub") + return nil + }) + + if err := doProcess(); err != nil { + t.Fatalf("%v", err) + } +} + +func TestArgsIsCreateCase3(t *testing.T) { + t.Log("进入测试用例") + + if err := os.Mkdir("./test", 0655); err != nil { + } + f, err := os.Create("./test/config.json") + defer f.Close() + if err != nil { + } + testArgs := []string{"create", "--bundle", "./test"} + stub := gostub.Stub(&os.Args, testArgs) + defer stub.Reset() + + stub.Stub(&execRunc, func() error { + t.Log("execute stub") + return nil + }) + + if err := doProcess(); err == nil { + t.Fatalf("%v", err) + } +} + +func TestArgsIsCreateCase4(t *testing.T) { + t.Log("进入测试用例") + + if err := os.Mkdir("./test", 0655); err != nil { + } + f, err := os.Create("./test/config.json") + defer f.Close() + if err != nil { + } + testArgs := []string{"spec", "--bundle", "./test"} + stub := gostub.Stub(&os.Args, testArgs) + defer stub.Reset() + + stub.Stub(&execRunc, func() error { + t.Log("execute stub") + return nil + }) + + if err := doProcess(); err == nil { + t.Fatalf("%v", err) + } +} + +func TestModifySpecFile(t *testing.T) { + if err := modifySpecFile("./test/config.json"); err != nil { + t.Log("run modifySpecFile failed") + } +} + +func TestModifySpecFileCase1(t *testing.T) { + var file string = "./test" + if err := os.Mkdir("./test", 0400); err != nil { + + } + + if err := modifySpecFile(file); err != nil { + t.Log("run modifySpecFile failed") + } + if err := os.Remove(file); err != nil { + + } +} + +func TestModifySpecFileCase2(t *testing.T) { + var file string = "./test.json" + f, err := os.Create(file) + defer f.Close() + if err != nil { + t.Log("create file error") + } + + if err := modifySpecFile(file); err != nil { + t.Log("run modifySpecFile failed") + } + if err := os.Remove(file); err != nil { + + } +} + +func TestModifySpecFileCase3(t *testing.T) { + var file string = "./test_spec.json" + if err := modifySpecFile(file); err != nil { + t.Log("run modifySpecFile failed") + } +} + +func TestAddHook(t *testing.T) { + var specArgs = &specs.Spec{} + if err := addHook(specArgs); err != nil { + } +} + +func TestAddHookCase1(t *testing.T) { + var specArgs = &specs.Spec{} + stub := gostub.Stub(&hookCliPath, ".") + defer stub.Reset() + + if err := addHook(specArgs); err != nil { + } +} + +func TestAddHookCase2(t *testing.T) { + var specArgs = &specs.Spec{} + stub := gostub.Stub(&hookCliPath, ".") + defer stub.Reset() + stub.Stub(&hookDefaultFile, ".") + if err := addHook(specArgs); err != nil { + } +} + +func TestAddHookCase3(t *testing.T) { + var file string = "/usr/local/bin/ascend-docker-hook" + var filenew string = "/usr/local/bin/ascend-docker-hook-1" + + if err := os.Rename(file, filenew); err != nil { + t.Log("rename ", file) + } + var specArgs = &specs.Spec{} + if err := addHook(specArgs); err != nil { + } + if err := os.Rename(filenew, file); err != nil { + t.Log("rename ", file) + } +} + +func TestExecRunc(t *testing.T) { + stub := gostub.Stub(&dockerRuncName, "abc-runc") + stub.Stub(&runcName, "runc123") + defer stub.Reset() + + if err := execRunc(); err != nil { + + } +} \ No newline at end of file