Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6d601ee

Browse files
committed
add agentproc tests
1 parentae138bf commit6d601ee

File tree

7 files changed

+359
-58
lines changed

7 files changed

+359
-58
lines changed

‎agent/agent.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1317,7 +1317,7 @@ func (a *agent) manageProcessPriorityLoop(ctx context.Context) {
13171317
continue
13181318
}
13191319

1320-
score,err:=proc.Nice(a.syscaller)
1320+
score,err:=proc.Niceness(a.syscaller)
13211321
iferr!=nil {
13221322
a.logger.Error(ctx,"unable to get proc niceness",
13231323
slog.F("name",proc.Name()),
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package agentproctest
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/spf13/afero"
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/coder/coder/v2/agent/agentproc"
11+
"github.com/coder/coder/v2/cryptorand"
12+
)
13+
14+
funcGenerateProcess(t*testing.T,fs afero.Fs,dirstring) agentproc.Process {
15+
t.Helper()
16+
17+
pid,err:=cryptorand.Intn(1<<31-1)
18+
require.NoError(t,err)
19+
20+
err=fs.MkdirAll(fmt.Sprintf("/%s/%d",dir,pid),0555)
21+
require.NoError(t,err)
22+
23+
arg1,err:=cryptorand.String(5)
24+
require.NoError(t,err)
25+
26+
arg2,err:=cryptorand.String(5)
27+
require.NoError(t,err)
28+
29+
arg3,err:=cryptorand.String(5)
30+
require.NoError(t,err)
31+
32+
cmdline:=fmt.Sprintf("%s\x00%s\x00%s",arg1,arg2,arg3)
33+
34+
err=afero.WriteFile(fs,fmt.Sprintf("/%s/%d/cmdline",dir,pid), []byte(cmdline),0444)
35+
require.NoError(t,err)
36+
37+
return agentproc.Process{
38+
PID:int32(pid),
39+
CmdLine:cmdline,
40+
Dir:fmt.Sprintf("%s/%d",dir,pid),
41+
FS:fs,
42+
}
43+
44+
}

‎agent/agentproc/doc.go‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
// Package agentproc contains logic for interfacing with local
22
// processes running in the same context as the agent.
33
package agentproc
4+
5+
//go:generate mockgen -destination ./syscallermock_test.go -package agentproc_test github.com/coder/coder/v2/agent/agentproc Syscaller

‎agent/agentproc/proc.go‎

Lines changed: 18 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,28 @@
11
package agentproc
22

33
import (
4+
"errors"
45
"path/filepath"
56
"strconv"
67
"strings"
78
"syscall"
89

910
"github.com/spf13/afero"
10-
"golang.org/x/sys/unix"
1111
"golang.org/x/xerrors"
1212
)
1313

1414
constDefaultProcDir="/proc"
1515

16-
typeSyscallerinterface {
17-
SetPriority(pidint32,priorityint)error
18-
GetPriority(pidint32) (int,error)
19-
Kill(pidint32,sig syscall.Signal)error
20-
}
21-
22-
typeUnixSyscallerstruct{}
23-
24-
func (UnixSyscaller)SetPriority(pidint32,niceint)error {
25-
err:=unix.Setpriority(unix.PRIO_PROCESS,int(pid),nice)
26-
iferr!=nil {
27-
returnxerrors.Errorf("set priority: %w",err)
28-
}
29-
returnnil
30-
}
31-
32-
func (UnixSyscaller)GetPriority(pidint32) (int,error) {
33-
nice,err:=unix.Getpriority(0,int(pid))
34-
iferr!=nil {
35-
return0,xerrors.Errorf("get priority: %w",err)
36-
}
37-
returnnice,nil
38-
}
39-
40-
func (UnixSyscaller)Kill(pidint,sig syscall.Signal)error {
41-
err:=syscall.Kill(pid,sig)
42-
iferr!=nil {
43-
returnxerrors.Errorf("kill: %w",err)
44-
}
45-
46-
returnnil
47-
}
48-
4916
typeProcessstruct {
5017
Dirstring
5118
CmdLinestring
5219
PIDint32
53-
fs afero.Fs
20+
FS afero.Fs
5421
}
5522

5623
func (p*Process)SetOOMAdj(scoreint)error {
5724
path:=filepath.Join(p.Dir,"oom_score_adj")
58-
err:=afero.WriteFile(p.fs,
25+
err:=afero.WriteFile(p.FS,
5926
path,
6027
[]byte(strconv.Itoa(score)),
6128
0644,
@@ -67,20 +34,20 @@ func (p *Process) SetOOMAdj(score int) error {
6734
returnnil
6835
}
6936

70-
func (p*Process)SetNiceness(scSyscaller,scoreint)error {
71-
err:=sc.SetPriority(p.PID,score)
37+
func (p*Process)Niceness(scSyscaller) (int,error) {
38+
nice,err:=sc.GetPriority(p.PID)
7239
iferr!=nil {
73-
returnxerrors.Errorf("set priority for %q: %w",p.CmdLine,err)
40+
return0,xerrors.Errorf("get priority for %q: %w",p.CmdLine,err)
7441
}
75-
returnnil
42+
returnnice,nil
7643
}
7744

78-
func (p*Process)Nice(scSyscaller) (int,error) {
79-
nice,err:=sc.GetPriority(p.PID)
45+
func (p*Process)SetNiceness(scSyscaller,scoreint)error {
46+
err:=sc.SetPriority(p.PID,score)
8047
iferr!=nil {
81-
return0,xerrors.Errorf("get priority for %q: %w",p.CmdLine,err)
48+
returnxerrors.Errorf("set priority for %q: %w",p.CmdLine,err)
8249
}
83-
returnnice,nil
50+
returnnil
8451
}
8552

8653
func (p*Process)Name()string {
@@ -108,7 +75,7 @@ func List(fs afero.Fs, syscaller Syscaller, dir string) ([]*Process, error) {
10875
}
10976

11077
// Check that the process still exists.
111-
exists,err:=isProcessExist(syscaller,int32(pid),syscall.Signal(0))
78+
exists,err:=isProcessExist(syscaller,int32(pid))
11279
iferr!=nil {
11380
returnnil,xerrors.Errorf("check process exists: %w",err)
11481
}
@@ -128,26 +95,27 @@ func List(fs afero.Fs, syscaller Syscaller, dir string) ([]*Process, error) {
12895
PID:int32(pid),
12996
CmdLine:string(cmdline),
13097
Dir:filepath.Join(dir,entry),
131-
fs:fs,
98+
FS:fs,
13299
})
133100
}
134101

135102
returnprocesses,nil
136103
}
137104

138-
funcisProcessExist(syscallerSyscaller,pidint32,sig syscall.Signal) (bool,error) {
139-
err:=syscaller.Kill(pid,sig)
105+
funcisProcessExist(syscallerSyscaller,pidint32) (bool,error) {
106+
err:=syscaller.Kill(pid,syscall.Signal(0))
140107
iferr==nil {
141108
returntrue,nil
142109
}
143110
iferr.Error()=="os: process already finished" {
144111
returnfalse,nil
145112
}
146113

147-
errno,ok:=err.(syscall.Errno)
148-
if!ok {
114+
varerrnosyscall.Errno
115+
if!errors.As(err,&errno) {
149116
returnfalse,err
150117
}
118+
151119
switcherrno {
152120
casesyscall.ESRCH:
153121
returnfalse,nil

‎agent/agentproc/proc_test.go‎

Lines changed: 175 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,180 @@
11
package agentproc_test
22

3-
typemockSyscallerstruct {
4-
SetPriorityFnfunc(int32,int)error
3+
import (
4+
"fmt"
5+
"strings"
6+
"syscall"
7+
"testing"
8+
9+
"github.com/golang/mock/gomock"
10+
"github.com/spf13/afero"
11+
"github.com/stretchr/testify/require"
12+
"golang.org/x/xerrors"
13+
14+
"github.com/coder/coder/v2/agent/agentproc"
15+
"github.com/coder/coder/v2/agent/agentproc/agentproctest"
16+
)
17+
18+
funcTestList(t*testing.T) {
19+
t.Parallel()
20+
21+
t.Run("OK",func(t*testing.T) {
22+
t.Parallel()
23+
24+
var (
25+
fs=afero.NewMemMapFs()
26+
sc=NewMockSyscaller(gomock.NewController(t))
27+
expectedProcs=make(map[int32]agentproc.Process)
28+
rootDir=agentproc.DefaultProcDir
29+
)
30+
31+
fori:=0;i<4;i++ {
32+
proc:=agentproctest.GenerateProcess(t,fs,rootDir)
33+
expectedProcs[proc.PID]=proc
34+
35+
sc.EXPECT().
36+
Kill(proc.PID,syscall.Signal(0)).
37+
Return(nil)
38+
}
39+
40+
actualProcs,err:=agentproc.List(fs,sc,rootDir)
41+
require.NoError(t,err)
42+
require.Len(t,actualProcs,4)
43+
for_,proc:=rangeactualProcs {
44+
expected,ok:=expectedProcs[proc.PID]
45+
require.True(t,ok)
46+
require.Equal(t,expected.PID,proc.PID)
47+
require.Equal(t,expected.CmdLine,proc.CmdLine)
48+
require.Equal(t,expected.Dir,proc.Dir)
49+
}
50+
})
51+
52+
t.Run("FinishedProcess",func(t*testing.T) {
53+
t.Parallel()
54+
55+
var (
56+
fs=afero.NewMemMapFs()
57+
sc=NewMockSyscaller(gomock.NewController(t))
58+
expectedProcs=make(map[int32]agentproc.Process)
59+
rootDir=agentproc.DefaultProcDir
60+
)
61+
62+
fori:=0;i<3;i++ {
63+
proc:=agentproctest.GenerateProcess(t,fs,rootDir)
64+
expectedProcs[proc.PID]=proc
65+
66+
sc.EXPECT().
67+
Kill(proc.PID,syscall.Signal(0)).
68+
Return(nil)
69+
}
70+
71+
// Create a process that's already finished. We're not adding
72+
// it to the map because it should be skipped over.
73+
proc:=agentproctest.GenerateProcess(t,fs,rootDir)
74+
sc.EXPECT().
75+
Kill(proc.PID,syscall.Signal(0)).
76+
Return(xerrors.New("os: process already finished"))
77+
78+
actualProcs,err:=agentproc.List(fs,sc,rootDir)
79+
require.NoError(t,err)
80+
require.Len(t,actualProcs,3)
81+
for_,proc:=rangeactualProcs {
82+
expected,ok:=expectedProcs[proc.PID]
83+
require.True(t,ok)
84+
require.Equal(t,expected.PID,proc.PID)
85+
require.Equal(t,expected.CmdLine,proc.CmdLine)
86+
require.Equal(t,expected.Dir,proc.Dir)
87+
}
88+
})
89+
90+
t.Run("NoSuchProcess",func(t*testing.T) {
91+
t.Parallel()
92+
93+
var (
94+
fs=afero.NewMemMapFs()
95+
sc=NewMockSyscaller(gomock.NewController(t))
96+
expectedProcs=make(map[int32]agentproc.Process)
97+
rootDir=agentproc.DefaultProcDir
98+
)
99+
100+
fori:=0;i<3;i++ {
101+
proc:=agentproctest.GenerateProcess(t,fs,rootDir)
102+
expectedProcs[proc.PID]=proc
103+
104+
sc.EXPECT().
105+
Kill(proc.PID,syscall.Signal(0)).
106+
Return(nil)
107+
}
108+
109+
// Create a process that doesn't exist. We're not adding
110+
// it to the map because it should be skipped over.
111+
proc:=agentproctest.GenerateProcess(t,fs,rootDir)
112+
sc.EXPECT().
113+
Kill(proc.PID,syscall.Signal(0)).
114+
Return(syscall.ESRCH)
115+
116+
actualProcs,err:=agentproc.List(fs,sc,rootDir)
117+
require.NoError(t,err)
118+
require.Len(t,actualProcs,3)
119+
for_,proc:=rangeactualProcs {
120+
expected,ok:=expectedProcs[proc.PID]
121+
require.True(t,ok)
122+
require.Equal(t,expected.PID,proc.PID)
123+
require.Equal(t,expected.CmdLine,proc.CmdLine)
124+
require.Equal(t,expected.Dir,proc.Dir)
125+
}
126+
})
5127
}
6128

7-
func (fmockSyscaller)SetPriority(pidint32,niceint)error {
8-
iff.SetPriorityFn==nil {
9-
returnnil
10-
}
11-
returnf.SetPriorityFn(pid,nice)
129+
// These tests are not very interesting but they provide some modicum of
130+
// confidence.
131+
funcTestProcess(t*testing.T) {
132+
t.Parallel()
133+
134+
t.Run("SetOOMAdj",func(t*testing.T) {
135+
t.Parallel()
136+
137+
var (
138+
fs=afero.NewMemMapFs()
139+
dir=agentproc.DefaultProcDir
140+
proc=agentproctest.GenerateProcess(t,fs,agentproc.DefaultProcDir)
141+
expectedScore=-1000
142+
)
143+
144+
err:=proc.SetOOMAdj(expectedScore)
145+
require.NoError(t,err)
146+
147+
actualScore,err:=afero.ReadFile(fs,fmt.Sprintf("%s/%d/oom_score_adj",dir,proc.PID))
148+
require.NoError(t,err)
149+
require.Equal(t,fmt.Sprintf("%d",expectedScore),strings.TrimSpace(string(actualScore)))
150+
})
151+
152+
t.Run("SetNiceness",func(t*testing.T) {
153+
t.Parallel()
154+
155+
var (
156+
sc=NewMockSyscaller(gomock.NewController(t))
157+
proc=&agentproc.Process{
158+
PID:32,
159+
}
160+
score=20
161+
)
162+
163+
sc.EXPECT().SetPriority(proc.PID,score).Return(nil)
164+
err:=proc.SetNiceness(sc,score)
165+
require.NoError(t,err)
166+
})
167+
168+
t.Run("Name",func(t*testing.T) {
169+
t.Parallel()
170+
171+
var (
172+
proc=&agentproc.Process{
173+
CmdLine:"helloworld\x00--arg1\x00--arg2",
174+
}
175+
expectedName="helloworld"
176+
)
177+
178+
require.Equal(t,expectedName,proc.Name())
179+
})
12180
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp