@@ -4,14 +4,16 @@ import (
4
4
"fmt"
5
5
"os/user"
6
6
"path/filepath"
7
+ "regexp"
8
+ "strings"
7
9
"testing"
8
10
9
11
"github.com/github/git-bundle-server/internal/daemon"
10
12
"github.com/stretchr/testify/assert"
11
13
"github.com/stretchr/testify/mock"
12
14
)
13
15
14
- var systemdCreateTests = []struct {
16
+ var systemdCreateBehaviorTests = []struct {
15
17
title string
16
18
17
19
// Inputs
@@ -64,6 +66,43 @@ var systemdCreateTests = []struct {
64
66
},
65
67
}
66
68
69
+ var systemdCreateServiceUnitTests = []struct {
70
+ title string
71
+
72
+ // Inputs
73
+ config * daemon.DaemonConfig
74
+
75
+ // Expected values
76
+ expectedServiceUnitLines []string
77
+ }{
78
+ {
79
+ title : "Created service unit contents are correct" ,
80
+ config : & basicDaemonConfig ,
81
+ expectedServiceUnitLines : []string {
82
+ "[Unit]" ,
83
+ fmt .Sprintf ("Description=%s" , basicDaemonConfig .Description ),
84
+ "[Service]" ,
85
+ "Type=simple" ,
86
+ fmt .Sprintf ("ExecStart='%s'" , basicDaemonConfig .Program ),
87
+ },
88
+ },
89
+ {
90
+ title : "Service unit ExecStart with space is quoted" ,
91
+ config : & daemon.DaemonConfig {
92
+ Label : "test-quoting" ,
93
+ Description : "My program's description (double quotes \" are ok too)" ,
94
+ Program : "/path/to/the/program with a space" ,
95
+ },
96
+ expectedServiceUnitLines : []string {
97
+ "[Unit]" ,
98
+ "Description=My program's description (double quotes \" are ok too)" ,
99
+ "[Service]" ,
100
+ "Type=simple" ,
101
+ "ExecStart='/path/to/the/program with a space'" ,
102
+ },
103
+ },
104
+ }
105
+
67
106
func TestSystemd_Create (t * testing.T ) {
68
107
// Set up mocks
69
108
testUser := & user.User {
@@ -80,7 +119,7 @@ func TestSystemd_Create(t *testing.T) {
80
119
81
120
systemd := daemon .NewSystemdProvider (testUserProvider , testCommandExecutor , testFileSystem )
82
121
83
- for _ , tt := range systemdCreateTests {
122
+ for _ , tt := range systemdCreateBehaviorTests {
84
123
forceArg := tt .force .toBoolList ()
85
124
for _ , force := range forceArg {
86
125
t .Run (fmt .Sprintf ("%s (force='%t')" , tt .title , force ), func (t * testing.T ) {
@@ -122,45 +161,54 @@ func TestSystemd_Create(t *testing.T) {
122
161
}
123
162
124
163
// Verify content of created file
125
- t .Run ("Created file content and path are correct" , func (t * testing.T ) {
126
- var actualFilename string
127
- var actualFileBytes []byte
128
-
129
- // Mock responses for successful fresh write
130
- testCommandExecutor .On ("Run" ,
131
- "systemctl" ,
132
- []string {"--user" , "daemon-reload" },
133
- ).Return (0 , nil ).Once ()
134
- testFileSystem .On ("FileExists" ,
135
- mock .AnythingOfType ("string" ),
136
- ).Return (false , nil ).Once ()
137
-
138
- // Use mock to save off input args
139
- testFileSystem .On ("WriteFile" ,
140
- mock .MatchedBy (func (filename string ) bool {
141
- actualFilename = filename
142
- return true
143
- }),
144
- mock .MatchedBy (func (fileBytes any ) bool {
145
- // Save off value and always match
146
- actualFileBytes = fileBytes .([]byte )
147
- return true
148
- }),
149
- ).Return (nil ).Once ()
150
-
151
- err := systemd .Create (& basicDaemonConfig , false )
152
- assert .Nil (t , err )
153
- mock .AssertExpectationsForObjects (t , testCommandExecutor , testFileSystem )
154
-
155
- // Check filename
156
- expectedFilename := filepath .Clean (fmt .Sprintf ("/my/test/dir/.config/systemd/user/%s.service" , basicDaemonConfig .Label ))
157
- assert .Equal (t , expectedFilename , actualFilename )
158
-
159
- // Check file contents
160
- fileContents := string (actualFileBytes )
161
- assert .Contains (t , fileContents , fmt .Sprintf ("ExecStart=%s" , basicDaemonConfig .Program ))
162
- assert .Contains (t , fileContents , fmt .Sprintf ("Description=%s" , basicDaemonConfig .Description ))
163
- })
164
+ for _ , tt := range systemdCreateServiceUnitTests {
165
+ t .Run (tt .title , func (t * testing.T ) {
166
+ var actualFilename string
167
+ var actualFileBytes []byte
168
+
169
+ // Mock responses for successful fresh write
170
+ testCommandExecutor .On ("Run" ,
171
+ "systemctl" ,
172
+ []string {"--user" , "daemon-reload" },
173
+ ).Return (0 , nil ).Once ()
174
+ testFileSystem .On ("FileExists" ,
175
+ mock .AnythingOfType ("string" ),
176
+ ).Return (false , nil ).Once ()
177
+
178
+ // Use mock to save off input args
179
+ testFileSystem .On ("WriteFile" ,
180
+ mock .MatchedBy (func (filename string ) bool {
181
+ actualFilename = filename
182
+ return true
183
+ }),
184
+ mock .MatchedBy (func (fileBytes any ) bool {
185
+ // Save off value and always match
186
+ actualFileBytes = fileBytes .([]byte )
187
+ return true
188
+ }),
189
+ ).Return (nil ).Once ()
190
+
191
+ err := systemd .Create (tt .config , false )
192
+ assert .Nil (t , err )
193
+ mock .AssertExpectationsForObjects (t , testCommandExecutor , testFileSystem )
194
+
195
+ // Check filename
196
+ expectedFilename := filepath .Clean (fmt .Sprintf ("/my/test/dir/.config/systemd/user/%s.service" , tt .config .Label ))
197
+ assert .Equal (t , expectedFilename , actualFilename )
198
+
199
+ // Check file contents
200
+ // Ensure there's no more than one newline between each line
201
+ // before splitting the file.
202
+ fileContents := strings .TrimSpace (string (actualFileBytes ))
203
+ serviceUnitLines := strings .Split (
204
+ regexp .MustCompile (`\n+` ).ReplaceAllString (fileContents , "\n " ), "\n " )
205
+ assert .ElementsMatch (t , tt .expectedServiceUnitLines , serviceUnitLines )
206
+
207
+ // Reset mocks
208
+ testCommandExecutor .Mock = mock.Mock {}
209
+ testFileSystem .Mock = mock.Mock {}
210
+ })
211
+ }
164
212
}
165
213
166
214
func TestSystemd_Start (t * testing.T ) {
0 commit comments