Skip to content

Commit e330f25

Browse files
committed
test.Data to support temp resources manipulation
Many tests require temporary resources (Dockerfiles, compose.yml, etc), and routinely redo the same thing over and over (create separate temp dir, write file, remove temp dir). At best this adds a lot of inconsistent boilerplate / helper functions to the test - at worst, the resources are not properly cleaned-up, or not well isolated from other tests. This PR does introduce a set of helpers to fasttrack temp files manipulation, and rejiggle the Data interface to more clearly separate labels (shared with subtests) and temporary resources. Signed-off-by: apostasie <[email protected]>
1 parent d439da9 commit e330f25

File tree

10 files changed

+292
-91
lines changed

10 files changed

+292
-91
lines changed

docs/testing/tools.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ that this name is then visible in the list of containers.
109109

110110
To achieve that, you should write your own `Manager`, leveraging test `Data`.
111111

112-
Here is an example, where we are using `data.Get("sometestdata")`.
112+
Here is an example, where we are using `data.Labels().Get("sometestdata")`.
113113

114114
```go
115115
package main
@@ -133,7 +133,7 @@ func TestMyThing(t *testing.T) {
133133

134134
// Declare your test
135135
myTest := &test.Case{
136-
Data: test.WithData("sometestdata", "blah"),
136+
Data: test.WithLabels(map[string]string{"sometestdata": "blah"}),
137137
Command: test.Command("info"),
138138
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
139139
return &test.Expected{
@@ -143,7 +143,7 @@ func TestMyThing(t *testing.T) {
143143
errdefs.ErrNotFound,
144144
},
145145
Output: func(stdout string, info string, t *testing.T) {
146-
assert.Assert(t, stdout == data.Get("sometestdata"), info)
146+
assert.Assert(t, stdout == data.Labels().Get("sometestdata"), info)
147147
},
148148
}
149149
},
@@ -157,7 +157,7 @@ func TestMyThing(t *testing.T) {
157157

158158
`Data` is provided to allow storing mutable key-value information that pertain to the test.
159159

160-
While it can be provided through `test.WithData(key string, value string)`,
160+
While it can be provided through `test.WithLabels(map[string]string{key: value})`,
161161
inside the testcase definition, it can also be dynamically manipulated inside `Setup`, or `Command`.
162162

163163
Note that `Data` additionally exposes the following functions:
@@ -244,9 +244,9 @@ func TestMyThing(t *testing.T) {
244244

245245
// Declare your test
246246
myTest := &test.Case{
247-
Data: test.WithData("sometestdata", "blah"),
247+
Data: test.WithLabels(map[string]string{"sometestdata": "blah"}),
248248
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
249-
return helpers.Command("run", "--name", data.Get("sometestdata"))
249+
return helpers.Command("run", "--name", data.Labels().Get("sometestdata"))
250250
},
251251
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
252252
return &test.Expected{
@@ -256,7 +256,7 @@ func TestMyThing(t *testing.T) {
256256
errdefs.ErrNotFound,
257257
},
258258
Output: func(stdout string, info string, t *testing.T) {
259-
assert.Assert(t, stdout == data.Get("sometestdata"), info)
259+
assert.Assert(t, stdout == data.Labels().Get("sometestdata"), info)
260260
},
261261
}
262262
},
@@ -325,7 +325,7 @@ func TestMyThing(t *testing.T) {
325325

326326
// Declare your test
327327
myTest := &test.Case{
328-
Data: test.WithData("sometestdata", "blah"),
328+
Data: test.WithLabels(map[string]string{"sometestdata": "blah"}),
329329
Setup: func(data *test.Data, helpers test.Helpers){
330330
helpers.Ensure("volume", "create", "foo")
331331
helpers.Ensure("volume", "create", "bar")
@@ -335,7 +335,7 @@ func TestMyThing(t *testing.T) {
335335
helpers.Anyhow("volume", "rm", "bar")
336336
},
337337
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
338-
return helpers.Command("run", "--name", data.Identifier()+data.Get("sometestdata"))
338+
return helpers.Command("run", "--name", data.Identifier()+data.Labels().Get("sometestdata"))
339339
},
340340
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
341341
return &test.Expected{
@@ -345,7 +345,7 @@ func TestMyThing(t *testing.T) {
345345
errdefs.ErrNotFound,
346346
},
347347
Output: func(stdout string, info string, t *testing.T) {
348-
assert.Assert(t, stdout == data.Get("sometestdata"), info)
348+
assert.Assert(t, stdout == data.Labels().Get("sometestdata"), info)
349349
},
350350
}
351351
},

mod/tigron/.golangci.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,15 @@ linters:
6161
revive:
6262
enable-all-rules: true
6363
rules:
64+
- name: max-public-structs
65+
# Default is 5
66+
arguments: 7
6467
- name: cognitive-complexity
6568
# Default is 7
66-
arguments: [60]
69+
arguments: [100]
6770
- name: function-length
6871
# Default is 50, 75
69-
arguments: [80, 200]
72+
arguments: [80, 220]
7073
- name: cyclomatic
7174
# Default is 10
7275
arguments: [30]

mod/tigron/expect/doc.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ To achieve that, you should write your own `test.Manager` instead of using the h
169169
A manager is a simple function which only role is to return a `test.Expected` struct.
170170
The `test.Manager` signature makes available `test.Data` and `test.Helpers` to you.
171171

172-
Here is an example, where we are using `data.Get("sometestdata")`.
172+
Here is an example, where we are using `data.Labels().Get("sometestdata")`.
173173

174174
```go
175175
package main
@@ -191,7 +191,7 @@ func TestMyThing(t *testing.T) {
191191
// Do things...
192192
// ...
193193
// Save this for later
194-
data.Set("something", "lalala")
194+
data.Labels().Set("something", "lalala")
195195
}
196196

197197
// Attach a command to run
@@ -210,7 +210,7 @@ func TestMyThing(t *testing.T) {
210210
t.Helper()
211211

212212
// Retrieve the data that was set during the Setup phase.
213-
assert.Assert(t, stdout == data.Get("sometestdata"), info)
213+
assert.Assert(t, stdout == data.Labels().Get("sometestdata"), info)
214214
},
215215
}
216216
}

mod/tigron/test/case.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ package test
1919
import (
2020
"encoding/json"
2121
"fmt"
22+
"os"
2223
"slices"
24+
"strings"
2325
"testing"
2426

2527
"github.com/containerd/nerdctl/mod/tigron/internal/assertive"
@@ -71,6 +73,7 @@ const (
7173
setupDecorator = "🏗"
7274
subinDecorator = "⤵️"
7375
suboutDecorator = "↩️"
76+
tempDecorator = "⏳"
7477
)
7578

7679
// Run prepares and executes the test, and any possible subtests.
@@ -115,7 +118,7 @@ func (test *Case) Run(t *testing.T) {
115118
}
116119

117120
// Inherit and attach Data and Config
118-
test.Data = configureData(test.t, test.Data, parentData)
121+
test.Data = newData(test.t, test.Data, parentData)
119122
test.Config = configureConfig(test.Config, parentConfig)
120123

121124
var custCom CustomizableCommand
@@ -125,9 +128,13 @@ func (test *Case) Run(t *testing.T) {
125128
custCom = registeredTestable.CustomCommand(test, test.t)
126129
}
127130

128-
custCom.WithCwd(test.Data.TempDir())
131+
// Separate cwd from the temp directory
132+
custCom.WithCwd(test.t.TempDir())
129133
custCom.withT(test.t)
130-
custCom.withTempDir(test.Data.TempDir())
134+
// Set the command tempdir to another temp location.
135+
// This is required for the current extension mechanism to allow creation of command dependent configuration
136+
// assets. Note that this is a different location than both CWD and Data.Temp().Path().
137+
custCom.withTempDir(test.t.TempDir())
131138
custCom.withEnv(test.Env)
132139
custCom.withConfig(test.Config)
133140

@@ -229,18 +236,28 @@ func (test *Case) Run(t *testing.T) {
229236
debugConfig, _ := json.MarshalIndent(test.Config.(*config).config, "", " ")
230237
debugData, _ := json.MarshalIndent(test.Data.(*data).labels, "", " ")
231238

239+
// Show the files in the temp directory BEFORE the command is executed
240+
tempFiles := []string{}
241+
242+
if files, err := os.ReadDir(test.Data.Temp().Path()); err == nil {
243+
for _, file := range files {
244+
tempFiles = append(tempFiles, file.Name())
245+
}
246+
}
247+
232248
test.t.Log(
233249
"\n\n" + formatter.Table(
234250
[][]any{
235251
{startDecorator, fmt.Sprintf("%q: starting test!", test.t.Name())},
236-
{"temp", test.Data.TempDir()},
252+
{tempDecorator, test.Data.Temp().Dir()},
253+
{"", strings.Join(tempFiles, "\n")},
237254
{"config", string(debugConfig)},
238-
{"data", string(debugData)},
255+
{"labels", string(debugData)},
239256
},
240257
"=",
241258
) + "\n",
242259
)
243-
260+
// FIXME: so, the expected function will run BEFORE the command
244261
cmd.Run(test.Expected(test.Data, test.helpers))
245262
}
246263

mod/tigron/test/command.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ type CustomizableCommand interface {
6565
// Note that this will override any variable defined in the embedding environment
6666
withEnv(env map[string]string)
6767
// withTempDir specifies a temporary directory to use
68+
// FIXME: this is only required because of the current command extension mechanism
6869
withTempDir(path string)
6970
// WithConfig allows passing custom config properties from the test to the base command
7071
withConfig(config Config)

mod/tigron/test/consts.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package test
18+
19+
const (
20+
// FilePermissionsDefault specifies the default creation mode for temporary files.
21+
// Note that umask will affect these.
22+
FilePermissionsDefault = 0o644
23+
// DirPermissionsDefault specifies the default creation mode for temporary directories.
24+
// Note that umask will affect these.
25+
DirPermissionsDefault = 0o755
26+
)

0 commit comments

Comments
 (0)