为了在特定条件下发现 Linux 命名空间,我的开源 Golang 包lxkns需要重新执行它作为新子进程使用的应用程序,以便能够在 Golang 运行时启动之前切换挂载命名空间。Linux挂载命名空间的工作方式使得在运行时启动 OS 线程后无法从 Golang 应用程序切换它们。
这意味着原始进程“P”重新运行自己的副本作为子“C”(reexec包),通过子环境传递一个特殊指示,该指示向子进程发出信号,只运行属于的特定“动作”函数到包含的“lxkns”包(详见下文),而不是正常运行整个应用程序(避免无休止的递归产生子代)。
forkchild := exec.Command("/proc/self/exe")
forkchild.Start()
...
forkchild.Wait()
目前,我从 VisualStudio Code 调用覆盖测试,它运行:
go test -timeout 30s -coverprofile=/tmp/vscode-goXXXXX/go-code-cover github.com/thediveo/lxkns
因此,“P”重新执行自身的副本“C”,并告诉它运行一些动作“A”,将一些结果打印到标准输出,然后立即终止。“P”等待“C”的输出,对其进行解析,然后继续其程序流程。
模块测试使用 Ginkgo/Gomega 和一个专用TestMain的,以便在测试作为子项重新执行时捕获,以便仅运行请求的“动作”功能。
package lxkns
import (
"os"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/thediveo/gons/reexec"
)
func TestMain(m *testing.M) {
// Ensure that the registered handler is run in the re-executed child. This
// won't trigger the handler while we're in the parent, because the
// parent's Arg[0] won't match the name of our handler.
reexec.CheckAction()
os.Exit(m.Run())
}
func TestLinuxKernelNamespaces(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "lxkns package")
}
我还想从重新执行的子进程创建代码覆盖率数据。
是否可以从被测程序本身启用代码覆盖,以及如何实现?
是否可以将子进程写入的代码覆盖率数据附加到父进程“P”的覆盖率数据中?
Golang 运行时是否仅在退出时写入覆盖率数据并覆盖指定的文件,还是追加?(我已经很高兴有一个指向相应运行时源的指针。)
注意:在我的测试用例中,切换挂载命名空间不会与在新挂载命名空间中创建覆盖文件冲突。原因是这些测试挂载命名空间是初始挂载命名空间的副本,因此创建新文件也会正常显示在文件系统中。
杨魅力
相关分类