forked from security/hakurei
container: remove custom cmd initialisation
This part of the interface is very unintuitive and only used for testing, even in testing it is inelegant and can be done better. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -35,9 +35,6 @@ type (
|
|||||||
// with behaviour identical to its [exec.Cmd] counterpart.
|
// with behaviour identical to its [exec.Cmd] counterpart.
|
||||||
ExtraFiles []*os.File
|
ExtraFiles []*os.File
|
||||||
|
|
||||||
// Custom [exec.Cmd] initialisation function.
|
|
||||||
CommandContext func(ctx context.Context) (cmd *exec.Cmd)
|
|
||||||
|
|
||||||
// param encoder for shim and init
|
// param encoder for shim and init
|
||||||
setup *gob.Encoder
|
setup *gob.Encoder
|
||||||
// cancels cmd
|
// cancels cmd
|
||||||
@@ -122,13 +119,8 @@ func (p *Container) Start() error {
|
|||||||
p.SeccompPresets |= seccomp.PresetDenyTTY
|
p.SeccompPresets |= seccomp.PresetDenyTTY
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.CommandContext != nil {
|
p.cmd = exec.CommandContext(ctx, MustExecutable())
|
||||||
p.cmd = p.CommandContext(ctx)
|
p.cmd.Args = []string{"init"}
|
||||||
} else {
|
|
||||||
p.cmd = exec.CommandContext(ctx, MustExecutable())
|
|
||||||
p.cmd.Args = []string{"init"}
|
|
||||||
}
|
|
||||||
|
|
||||||
p.cmd.Stdin, p.cmd.Stdout, p.cmd.Stderr = p.Stdin, p.Stdout, p.Stderr
|
p.cmd.Stdin, p.cmd.Stdout, p.cmd.Stderr = p.Stdin, p.Stdout, p.Stderr
|
||||||
p.cmd.WaitDelay = p.WaitDelay
|
p.cmd.WaitDelay = p.WaitDelay
|
||||||
if p.Cancel != nil {
|
if p.Cancel != nil {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -26,6 +25,11 @@ const (
|
|||||||
ignoreV = -1
|
ignoreV = -1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
container.TryArgv0(hlog.Output{}, hlog.Prepare, internal.InstallOutput)
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
func TestContainer(t *testing.T) {
|
func TestContainer(t *testing.T) {
|
||||||
{
|
{
|
||||||
oldVerbose := hlog.Load()
|
oldVerbose := hlog.Load()
|
||||||
@@ -96,7 +100,6 @@ func TestContainer(t *testing.T) {
|
|||||||
c.Uid = 1000
|
c.Uid = 1000
|
||||||
c.Gid = 100
|
c.Gid = 100
|
||||||
c.Hostname = tc.host
|
c.Hostname = tc.host
|
||||||
c.CommandContext = commandContext
|
|
||||||
c.Stdout, c.Stderr = os.Stdout, os.Stderr
|
c.Stdout, c.Stderr = os.Stdout, os.Stderr
|
||||||
c.Ops = tc.ops
|
c.Ops = tc.ops
|
||||||
c.SeccompRules = tc.rules
|
c.SeccompRules = tc.rules
|
||||||
@@ -121,11 +124,7 @@ func TestContainer(t *testing.T) {
|
|||||||
Place("/etc/hostname", []byte(c.Args[5]))
|
Place("/etc/hostname", []byte(c.Args[5]))
|
||||||
// in case test has cgo enabled
|
// in case test has cgo enabled
|
||||||
var libPaths []string
|
var libPaths []string
|
||||||
if entries, err := ldd.ExecFilter(ctx,
|
if entries, err := ldd.Exec(ctx, os.Args[0]); err != nil {
|
||||||
commandContext,
|
|
||||||
func(v []byte) []byte {
|
|
||||||
return bytes.SplitN(v, []byte("TestHelperInit\n"), 2)[1]
|
|
||||||
}, os.Args[0]); err != nil {
|
|
||||||
log.Fatalf("ldd: %v", err)
|
log.Fatalf("ldd: %v", err)
|
||||||
} else {
|
} else {
|
||||||
libPaths = ldd.Path(entries)
|
libPaths = ldd.Path(entries)
|
||||||
@@ -197,14 +196,6 @@ func TestContainerString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHelperInit(t *testing.T) {
|
|
||||||
if len(os.Args) != 5 || os.Args[4] != "init" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container.SetOutput(hlog.Output{})
|
|
||||||
container.Init(hlog.Prepare, internal.InstallOutput)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHelperCheckContainer(t *testing.T) {
|
func TestHelperCheckContainer(t *testing.T) {
|
||||||
if len(os.Args) != 6 || os.Args[4] != "check" {
|
if len(os.Args) != 6 || os.Args[4] != "check" {
|
||||||
return
|
return
|
||||||
@@ -274,8 +265,3 @@ func TestHelperCheckContainer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func commandContext(ctx context.Context) *exec.Cmd {
|
|
||||||
return exec.CommandContext(ctx, os.Args[0], "-test.v",
|
|
||||||
"-test.run=TestHelperInit", "--", "init")
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,13 +4,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
"hakurei.app/helper"
|
"hakurei.app/helper"
|
||||||
"hakurei.app/internal"
|
|
||||||
"hakurei.app/internal/hlog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestContainer(t *testing.T) {
|
func TestContainer(t *testing.T) {
|
||||||
@@ -36,20 +33,8 @@ func TestContainer(t *testing.T) {
|
|||||||
testHelper(t, func(ctx context.Context, setOutput func(stdoutP, stderrP *io.Writer), stat bool) helper.Helper {
|
testHelper(t, func(ctx context.Context, setOutput func(stdoutP, stderrP *io.Writer), stat bool) helper.Helper {
|
||||||
return helper.New(ctx, os.Args[0], argsWt, stat, argF, func(z *container.Container) {
|
return helper.New(ctx, os.Args[0], argsWt, stat, argF, func(z *container.Container) {
|
||||||
setOutput(&z.Stdout, &z.Stderr)
|
setOutput(&z.Stdout, &z.Stderr)
|
||||||
z.CommandContext = func(ctx context.Context) (cmd *exec.Cmd) {
|
|
||||||
return exec.CommandContext(ctx, os.Args[0], "-test.v",
|
|
||||||
"-test.run=TestHelperInit", "--", "init")
|
|
||||||
}
|
|
||||||
z.Bind("/", "/", 0).Proc("/proc").Dev("/dev")
|
z.Bind("/", "/", 0).Proc("/proc").Dev("/dev")
|
||||||
}, nil)
|
}, nil)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHelperInit(t *testing.T) {
|
|
||||||
if len(os.Args) != 5 || os.Args[4] != "init" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container.SetOutput(hlog.Output{})
|
|
||||||
container.Init(hlog.Prepare, func(bool) { internal.InstallOutput(false) })
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ func argF(argsFd, statFd int) []string {
|
|||||||
|
|
||||||
func argFChecked(argsFd, statFd int) (args []string) {
|
func argFChecked(argsFd, statFd int) (args []string) {
|
||||||
args = make([]string, 0, 6)
|
args = make([]string, 0, 6)
|
||||||
args = append(args, "-test.run=TestHelperStub", "--")
|
|
||||||
if argsFd > -1 {
|
if argsFd > -1 {
|
||||||
args = append(args, "--args", strconv.Itoa(argsFd))
|
args = append(args, "--args", strconv.Itoa(argsFd))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func InternalHelperStub() {
|
|||||||
sp = v
|
sp = v
|
||||||
}
|
}
|
||||||
|
|
||||||
genericStub(flagRestoreFiles(3, ap, sp))
|
genericStub(flagRestoreFiles(1, ap, sp))
|
||||||
|
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
package helper_test
|
package helper_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"hakurei.app/container"
|
||||||
"hakurei.app/helper"
|
"hakurei.app/helper"
|
||||||
|
"hakurei.app/internal"
|
||||||
|
"hakurei.app/internal/hlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHelperStub(t *testing.T) { helper.InternalHelperStub() }
|
func TestMain(m *testing.M) {
|
||||||
|
container.TryArgv0(hlog.Output{}, hlog.Prepare, internal.InstallOutput)
|
||||||
|
helper.InternalHelperStub()
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|||||||
12
ldd/exec.go
12
ldd/exec.go
@@ -5,7 +5,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
@@ -19,16 +18,10 @@ var (
|
|||||||
msgStaticGlibc = []byte("not a dynamic executable")
|
msgStaticGlibc = []byte("not a dynamic executable")
|
||||||
)
|
)
|
||||||
|
|
||||||
func Exec(ctx context.Context, p string) ([]*Entry, error) { return ExecFilter(ctx, nil, nil, p) }
|
func Exec(ctx context.Context, p string) ([]*Entry, error) {
|
||||||
|
|
||||||
func ExecFilter(ctx context.Context,
|
|
||||||
commandContext func(context.Context) *exec.Cmd,
|
|
||||||
f func([]byte) []byte,
|
|
||||||
p string) ([]*Entry, error) {
|
|
||||||
c, cancel := context.WithTimeout(ctx, lddTimeout)
|
c, cancel := context.WithTimeout(ctx, lddTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
z := container.New(c, "ldd", p)
|
z := container.New(c, "ldd", p)
|
||||||
z.CommandContext = commandContext
|
|
||||||
z.Hostname = "hakurei-ldd"
|
z.Hostname = "hakurei-ldd"
|
||||||
z.SeccompFlags |= seccomp.AllowMultiarch
|
z.SeccompFlags |= seccomp.AllowMultiarch
|
||||||
z.SeccompPresets |= seccomp.PresetStrict
|
z.SeccompPresets |= seccomp.PresetStrict
|
||||||
@@ -54,8 +47,5 @@ func ExecFilter(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
v := stdout.Bytes()
|
v := stdout.Bytes()
|
||||||
if f != nil {
|
|
||||||
v = f(v)
|
|
||||||
}
|
|
||||||
return Parse(v)
|
return Parse(v)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,17 @@
|
|||||||
package dbus_test
|
package dbus_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/container"
|
|
||||||
"hakurei.app/helper"
|
"hakurei.app/helper"
|
||||||
"hakurei.app/internal"
|
|
||||||
"hakurei.app/internal/hlog"
|
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -64,20 +59,23 @@ func TestFinalise(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestProxyStartWaitCloseString(t *testing.T) {
|
func TestProxyStartWaitCloseString(t *testing.T) {
|
||||||
oldWaitDelay := helper.WaitDelay
|
t.Run("sandbox", func(t *testing.T) { testProxyFinaliseStartWaitCloseString(t, true) })
|
||||||
helper.WaitDelay = 16 * time.Second
|
|
||||||
t.Cleanup(func() { helper.WaitDelay = oldWaitDelay })
|
|
||||||
|
|
||||||
t.Run("sandbox", func(t *testing.T) {
|
|
||||||
proxyName := dbus.ProxyName
|
|
||||||
dbus.ProxyName = os.Args[0]
|
|
||||||
t.Cleanup(func() { dbus.ProxyName = proxyName })
|
|
||||||
testProxyFinaliseStartWaitCloseString(t, true)
|
|
||||||
})
|
|
||||||
t.Run("direct", func(t *testing.T) { testProxyFinaliseStartWaitCloseString(t, false) })
|
t.Run("direct", func(t *testing.T) { testProxyFinaliseStartWaitCloseString(t, false) })
|
||||||
}
|
}
|
||||||
|
|
||||||
func testProxyFinaliseStartWaitCloseString(t *testing.T, useSandbox bool) {
|
func testProxyFinaliseStartWaitCloseString(t *testing.T, useSandbox bool) {
|
||||||
|
{
|
||||||
|
oldWaitDelay := helper.WaitDelay
|
||||||
|
helper.WaitDelay = 16 * time.Second
|
||||||
|
t.Cleanup(func() { helper.WaitDelay = oldWaitDelay })
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
proxyName := dbus.ProxyName
|
||||||
|
dbus.ProxyName = os.Args[0]
|
||||||
|
t.Cleanup(func() { dbus.ProxyName = proxyName })
|
||||||
|
}
|
||||||
|
|
||||||
var p *dbus.Proxy
|
var p *dbus.Proxy
|
||||||
|
|
||||||
t.Run("string for nil proxy", func(t *testing.T) {
|
t.Run("string for nil proxy", func(t *testing.T) {
|
||||||
@@ -122,35 +120,12 @@ func testProxyFinaliseStartWaitCloseString(t *testing.T, useSandbox bool) {
|
|||||||
|
|
||||||
ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if !useSandbox {
|
|
||||||
p = dbus.NewDirect(ctx, final, nil)
|
|
||||||
} else {
|
|
||||||
p = dbus.New(ctx, final, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.CommandContext = func(ctx context.Context) (cmd *exec.Cmd) {
|
|
||||||
return exec.CommandContext(ctx, os.Args[0], "-test.v",
|
|
||||||
"-test.run=TestHelperInit", "--", "init")
|
|
||||||
}
|
|
||||||
p.CmdF = func(v any) {
|
|
||||||
if useSandbox {
|
|
||||||
z := v.(*container.Container)
|
|
||||||
if z.Args[0] != dbus.ProxyName {
|
|
||||||
panic(fmt.Sprintf("unexpected argv0 %q", os.Args[0]))
|
|
||||||
}
|
|
||||||
z.Args = append([]string{os.Args[0], "-test.run=TestHelperStub", "--"}, z.Args[1:]...)
|
|
||||||
} else {
|
|
||||||
cmd := v.(*exec.Cmd)
|
|
||||||
if cmd.Args[0] != dbus.ProxyName {
|
|
||||||
panic(fmt.Sprintf("unexpected argv0 %q", os.Args[0]))
|
|
||||||
}
|
|
||||||
cmd.Err = nil
|
|
||||||
cmd.Path = os.Args[0]
|
|
||||||
cmd.Args = append([]string{os.Args[0], "-test.run=TestHelperStub", "--"}, cmd.Args[1:]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.FilterF = func(v []byte) []byte { return bytes.SplitN(v, []byte("TestHelperInit\n"), 2)[1] }
|
|
||||||
output := new(strings.Builder)
|
output := new(strings.Builder)
|
||||||
|
if !useSandbox {
|
||||||
|
p = dbus.NewDirect(ctx, final, output)
|
||||||
|
} else {
|
||||||
|
p = dbus.New(ctx, final, output)
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("invalid wait", func(t *testing.T) {
|
t.Run("invalid wait", func(t *testing.T) {
|
||||||
wantErr := "dbus: not started"
|
wantErr := "dbus: not started"
|
||||||
@@ -176,9 +151,9 @@ func testProxyFinaliseStartWaitCloseString(t *testing.T, useSandbox bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.Run("string", func(t *testing.T) {
|
t.Run("string", func(t *testing.T) {
|
||||||
wantSubstr := fmt.Sprintf("%s -test.run=TestHelperStub -- --args=3 --fd=4", os.Args[0])
|
wantSubstr := fmt.Sprintf("%s --args=3 --fd=4", os.Args[0])
|
||||||
if useSandbox {
|
if useSandbox {
|
||||||
wantSubstr = fmt.Sprintf(`argv: ["%s" "-test.run=TestHelperStub" "--" "--args=3" "--fd=4"], filter: true, rules: 0, flags: 0x1, presets: 0xf`, os.Args[0])
|
wantSubstr = fmt.Sprintf(`argv: ["%s" "--args=3" "--fd=4"], filter: true, rules: 0, flags: 0x1, presets: 0xf`, os.Args[0])
|
||||||
}
|
}
|
||||||
if got := p.String(); !strings.Contains(got, wantSubstr) {
|
if got := p.String(); !strings.Contains(got, wantSubstr) {
|
||||||
t.Errorf("String: %q, want %q",
|
t.Errorf("String: %q, want %q",
|
||||||
@@ -203,11 +178,3 @@ func testProxyFinaliseStartWaitCloseString(t *testing.T, useSandbox bool) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHelperInit(t *testing.T) {
|
|
||||||
if len(os.Args) != 5 || os.Args[4] != "init" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container.SetOutput(hlog.Output{})
|
|
||||||
container.Init(hlog.Prepare, internal.InstallOutput)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -36,9 +36,6 @@ func (p *Proxy) Start() error {
|
|||||||
|
|
||||||
if !p.useSandbox {
|
if !p.useSandbox {
|
||||||
p.helper = helper.NewDirect(ctx, p.name, p.final, true, argF, func(cmd *exec.Cmd) {
|
p.helper = helper.NewDirect(ctx, p.name, p.final, true, argF, func(cmd *exec.Cmd) {
|
||||||
if p.CmdF != nil {
|
|
||||||
p.CmdF(cmd)
|
|
||||||
}
|
|
||||||
if p.output != nil {
|
if p.output != nil {
|
||||||
cmd.Stdout, cmd.Stderr = p.output, p.output
|
cmd.Stdout, cmd.Stderr = p.output, p.output
|
||||||
}
|
}
|
||||||
@@ -56,7 +53,7 @@ func (p *Proxy) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var libPaths []string
|
var libPaths []string
|
||||||
if entries, err := ldd.ExecFilter(ctx, p.CommandContext, p.FilterF, toolPath); err != nil {
|
if entries, err := ldd.Exec(ctx, toolPath); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
libPaths = ldd.Path(entries)
|
libPaths = ldd.Path(entries)
|
||||||
@@ -69,15 +66,10 @@ func (p *Proxy) Start() error {
|
|||||||
z.SeccompFlags |= seccomp.AllowMultiarch
|
z.SeccompFlags |= seccomp.AllowMultiarch
|
||||||
z.SeccompPresets |= seccomp.PresetStrict
|
z.SeccompPresets |= seccomp.PresetStrict
|
||||||
z.Hostname = "hakurei-dbus"
|
z.Hostname = "hakurei-dbus"
|
||||||
z.CommandContext = p.CommandContext
|
|
||||||
if p.output != nil {
|
if p.output != nil {
|
||||||
z.Stdout, z.Stderr = p.output, p.output
|
z.Stdout, z.Stderr = p.output, p.output
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.CmdF != nil {
|
|
||||||
p.CmdF(z)
|
|
||||||
}
|
|
||||||
|
|
||||||
// these lib paths are unpredictable, so mount them first so they cannot cover anything
|
// these lib paths are unpredictable, so mount them first so they cannot cover anything
|
||||||
for _, name := range libPaths {
|
for _, name := range libPaths {
|
||||||
z.Bind(name, name, 0)
|
z.Bind(name, name, 0)
|
||||||
|
|||||||
17
system/dbus/proc_test.go
Normal file
17
system/dbus/proc_test.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package dbus_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"hakurei.app/container"
|
||||||
|
"hakurei.app/helper"
|
||||||
|
"hakurei.app/internal"
|
||||||
|
"hakurei.app/internal/hlog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
container.TryArgv0(hlog.Output{}, hlog.Prepare, internal.InstallOutput)
|
||||||
|
helper.InternalHelperStub()
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os/exec"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
@@ -37,10 +36,6 @@ type Proxy struct {
|
|||||||
useSandbox bool
|
useSandbox bool
|
||||||
|
|
||||||
name string
|
name string
|
||||||
CmdF func(any)
|
|
||||||
|
|
||||||
CommandContext func(ctx context.Context) (cmd *exec.Cmd)
|
|
||||||
FilterF func([]byte) []byte
|
|
||||||
|
|
||||||
mu, pmu sync.RWMutex
|
mu, pmu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
package dbus_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"hakurei.app/helper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHelperStub(t *testing.T) { helper.InternalHelperStub() }
|
|
||||||
Reference in New Issue
Block a user