Skip to content

Commit 1740b52

Browse files
authored
DEV: Improve assertions of cli_build_test.go (#844)
This commit improves the assertions by testing against the entire command string and env so that we can be sure of the full command we are running.
1 parent 83c7e4e commit 1740b52

File tree

5 files changed

+133
-33
lines changed

5 files changed

+133
-33
lines changed

launcher_go/v2/cli_build.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ package main
33
import (
44
"context"
55
"errors"
6+
"flag"
7+
"os"
8+
"strings"
9+
610
"github.com/discourse/discourse_docker/launcher_go/v2/config"
711
"github.com/discourse/discourse_docker/launcher_go/v2/docker"
812
"github.com/discourse/discourse_docker/launcher_go/v2/utils"
913
"github.com/google/uuid"
10-
"os"
11-
"strings"
1214
)
1315

1416
/*
@@ -66,7 +68,16 @@ func (r *DockerConfigureCmd) Run(cli *Cli, ctx *context.Context) error {
6668
return errors.New("YAML syntax error. Please check your containers/*.yml config files.")
6769
}
6870

69-
containerId := "discourse-build-" + uuid.NewString()
71+
var uuidString string
72+
73+
if flag.Lookup("test.v") == nil {
74+
uuidString = uuid.NewString()
75+
} else {
76+
uuidString = "test"
77+
}
78+
79+
containerId := "discourse-build-" + uuidString
80+
7081
pups := docker.DockerPupsRunner{
7182
Config: config,
7283
PupsArgs: "--tags=db,precompile",
@@ -75,6 +86,7 @@ func (r *DockerConfigureCmd) Run(cli *Cli, ctx *context.Context) error {
7586
Ctx: ctx,
7687
ContainerId: containerId,
7788
}
89+
7890
return pups.Run()
7991
}
8092

launcher_go/v2/cli_build_test.go

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,33 +59,89 @@ var _ = Describe("Build", func() {
5959
}
6060

6161
var checkConfigureCmd = func(cmd exec.Cmd) {
62-
Expect(cmd.String()).To(ContainSubstring("docker run"))
63-
Expect(cmd.String()).To(ContainSubstring("--env DISCOURSE_DEVELOPER_EMAILS"))
64-
Expect(cmd.String()).To(ContainSubstring("--env SKIP_EMBER_CLI_COMPILE=1"))
65-
// we commit, we need the container to stick around after it is stopped.
66-
Expect(cmd.String()).ToNot(ContainSubstring("--rm"))
67-
68-
// we don't expose ports on configure command
69-
Expect(cmd.String()).ToNot(ContainSubstring("-p 80"))
70-
Expect(cmd.Env).To(ContainElement("DISCOURSE_DB_PASSWORD=SOME_SECRET"))
62+
Expect(cmd.String()).To(Equal(
63+
"/usr/local/bin/docker run " +
64+
"--env DISCOURSE_DB_HOST " +
65+
"--env DISCOURSE_DB_PASSWORD " +
66+
"--env DISCOURSE_DB_PORT " +
67+
"--env DISCOURSE_DB_SOCKET " +
68+
"--env DISCOURSE_DEVELOPER_EMAILS " +
69+
"--env DISCOURSE_HOSTNAME " +
70+
"--env DISCOURSE_REDIS_HOST " +
71+
"--env DISCOURSE_SMTP_ADDRESS " +
72+
"--env DISCOURSE_SMTP_PASSWORD " +
73+
"--env DISCOURSE_SMTP_USER_NAME " +
74+
"--env LANG " +
75+
"--env LANGUAGE " +
76+
"--env LC_ALL " +
77+
"--env MULTI " +
78+
"--env RAILS_ENV " +
79+
"--env REPLACED " +
80+
"--env RUBY_GC_HEAP_GROWTH_MAX_SLOTS " +
81+
"--env RUBY_GC_HEAP_INIT_SLOTS " +
82+
"--env RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR " +
83+
"--env UNICORN_SIDEKIQS " +
84+
"--env UNICORN_WORKERS " +
85+
"--env SKIP_EMBER_CLI_COMPILE=1 " +
86+
"--volume /var/discourse/shared/web-only:/shared " +
87+
"--volume /var/discourse/shared/web-only/log/var-log:/var/log " +
88+
"--link data:data " +
89+
"--shm-size=512m " +
90+
"--restart=no " +
91+
"--interactive " +
92+
"--expose 100 " +
93+
"--name discourse-build-test " +
94+
"local_discourse/test /bin/bash -c /usr/local/bin/pups --stdin --tags=db,precompile",
95+
))
96+
97+
Expect(cmd.Env).To(Equal([]string{
98+
"DISCOURSE_DB_HOST=data",
99+
"DISCOURSE_DB_PASSWORD=SOME_SECRET",
100+
"DISCOURSE_DB_PORT=",
101+
"DISCOURSE_DB_SOCKET=",
102+
103+
"DISCOURSE_HOSTNAME=discourse.example.com",
104+
"DISCOURSE_REDIS_HOST=data",
105+
"DISCOURSE_SMTP_ADDRESS=smtp.example.com",
106+
"DISCOURSE_SMTP_PASSWORD=pa$$word",
107+
108+
"LANG=en_US.UTF-8",
109+
"LANGUAGE=en_US.UTF-8",
110+
"LC_ALL=en_US.UTF-8",
111+
"MULTI=test\nmultiline with some spaces\nvar\n",
112+
"RAILS_ENV=production",
113+
"REPLACED=test/test/test",
114+
"RUBY_GC_HEAP_GROWTH_MAX_SLOTS=40000",
115+
"RUBY_GC_HEAP_INIT_SLOTS=400000",
116+
"RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=1.5",
117+
"UNICORN_SIDEKIQS=1",
118+
"UNICORN_WORKERS=3",
119+
}))
120+
71121
buf := new(strings.Builder)
72122
io.Copy(buf, cmd.Stdin)
73123
// docker run's stdin is a pups config
124+
125+
// web.template.yml is merged with the test config
74126
Expect(buf.String()).To(ContainSubstring("path: /etc/service/nginx/run"))
127+
Expect(buf.String()).To(ContainSubstring(`exec: echo "custom test command"`))
75128
}
76129

77130
// commit on configure
78131
var checkConfigureCommit = func(cmd exec.Cmd) {
79-
Expect(cmd.String()).To(ContainSubstring("docker commit"))
80-
Expect(cmd.String()).To(ContainSubstring("--change CMD [\"/sbin/boot\"]"))
81-
Expect(cmd.String()).To(ContainSubstring("discourse-build"))
82-
Expect(cmd.String()).To(ContainSubstring("local_discourse/test"))
83-
Expect(cmd.Env).ToNot(ContainElement("DISCOURSE_DB_PASSWORD=SOME_SECRET"))
132+
Expect(cmd.String()).To(MatchRegexp(
133+
"/usr/local/bin/docker commit " +
134+
`--change LABEL org\.opencontainers\.image\.created="[\d\-T:+]+" ` +
135+
`--change CMD \["/sbin/boot"\] ` +
136+
"discourse-build-test local_discourse/test",
137+
))
138+
139+
Expect(cmd.Env).To(BeNil())
84140
}
85141

86142
// configure also cleans up
87143
var checkConfigureClean = func(cmd exec.Cmd) {
88-
Expect(cmd.String()).To(ContainSubstring("docker rm -f discourse-build-"))
144+
Expect(cmd.String()).To(Equal("/usr/local/bin/docker rm --force discourse-build-test"))
89145
}
90146

91147
It("Should run docker build with correct arguments", func() {
@@ -99,6 +155,7 @@ var _ = Describe("Build", func() {
99155
runner := ddocker.DockerConfigureCmd{Config: "test"}
100156
runner.Run(cli, &ctx)
101157
Expect(len(RanCmds)).To(Equal(3))
158+
102159
checkConfigureCmd(RanCmds[0])
103160
checkConfigureCommit(RanCmds[1])
104161
checkConfigureClean(RanCmds[2])

launcher_go/v2/config/config.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
package config
22

33
import (
4-
"dario.cat/mergo"
54
"errors"
65
"fmt"
7-
"github.com/discourse/discourse_docker/launcher_go/v2/utils"
86
"os"
97
"regexp"
108
"runtime"
119
"slices"
1210
"strings"
1311

12+
"dario.cat/mergo"
13+
"github.com/discourse/discourse_docker/launcher_go/v2/utils"
14+
1415
"gopkg.in/yaml.v3"
1516
)
1617

@@ -77,7 +78,9 @@ func LoadConfig(dir string, configName string, includeTemplates bool, templatesD
7778
Boot_Command: defaultBootCommand,
7879
Base_Image: DefaultBaseImage(),
7980
}
81+
8082
matched, _ := regexp.MatchString("[[:upper:]/ !@#$%^&*()+~`=]", configName)
83+
8184
if matched {
8285
msg := "ERROR: Config name '" + configName + "' must not contain upper case characters, spaces or special characters. Correct config name and rerun."
8386
fmt.Println(msg)
@@ -86,12 +89,14 @@ func LoadConfig(dir string, configName string, includeTemplates bool, templatesD
8689

8790
config_filename := string(strings.TrimRight(dir, "/") + "/" + config.Name + ".yml")
8891
content, err := os.ReadFile(config_filename)
92+
8993
if err != nil {
9094
if os.IsNotExist(err) {
9195
fmt.Println("config file does not exist: " + config_filename)
9296
}
9397
return nil, err
9498
}
99+
95100
baseConfig := &Config{}
96101

97102
if err := yaml.Unmarshal(content, baseConfig); err != nil {
@@ -105,10 +110,13 @@ func LoadConfig(dir string, configName string, includeTemplates bool, templatesD
105110
}
106111
}
107112
}
113+
108114
if err := mergo.Merge(config, baseConfig, mergo.WithOverride); err != nil {
109115
return nil, err
110116
}
117+
111118
config.rawYaml = append(config.rawYaml, string(content[:]))
119+
112120
if err != nil {
113121
return nil, err
114122
}

launcher_go/v2/docker/commands.go

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"os/exec"
99
"runtime"
10+
"sort"
1011
"strings"
1112
"syscall"
1213
"time"
@@ -94,19 +95,28 @@ func (r *DockerRunner) Run() error {
9495
}
9596

9697
cmd.Env = r.Config.EnvArray(true)
98+
envKeys := make([]string, 0, len(r.Config.Env))
99+
100+
for envKey := range r.Config.Env {
101+
envKeys = append(envKeys, envKey)
102+
}
103+
104+
sort.Strings(envKeys)
97105

98106
if r.DryRun {
99107
// multi-line env doesn't work super great from CLI, but we can print out the rest.
100-
for k, v := range r.Config.Env {
101-
if !strings.Contains(v, "\n") {
108+
for _, envKey := range envKeys {
109+
value := r.Config.Env[envKey]
110+
111+
if !strings.Contains(value, "\n") {
102112
cmd.Args = append(cmd.Args, "--env")
103-
cmd.Args = append(cmd.Args, k+"="+shellwords.Escape(v))
113+
cmd.Args = append(cmd.Args, envKey+"="+shellwords.Escape(value))
104114
}
105115
}
106116
} else {
107-
for k, _ := range r.Config.Env {
117+
for _, envKey := range envKeys {
108118
cmd.Args = append(cmd.Args, "--env")
109-
cmd.Args = append(cmd.Args, k)
119+
cmd.Args = append(cmd.Args, envKey)
110120
}
111121
}
112122

@@ -156,10 +166,10 @@ func (r *DockerRunner) Run() error {
156166
}
157167

158168
if r.Detatch {
159-
cmd.Args = append(cmd.Args, "-d")
169+
cmd.Args = append(cmd.Args, "--detach")
160170
}
161171

162-
cmd.Args = append(cmd.Args, "-i")
172+
cmd.Args = append(cmd.Args, "--interactive")
163173

164174
// Docker args override settings above
165175
for _, f := range r.Config.DockerArgs() {
@@ -170,8 +180,11 @@ func (r *DockerRunner) Run() error {
170180
cmd.Args = append(cmd.Args, f)
171181
}
172182

173-
cmd.Args = append(cmd.Args, "-h")
174-
cmd.Args = append(cmd.Args, r.Hostname)
183+
if r.Hostname != "" {
184+
cmd.Args = append(cmd.Args, "--hostname")
185+
cmd.Args = append(cmd.Args, r.Hostname)
186+
}
187+
175188
cmd.Args = append(cmd.Args, "--name")
176189
cmd.Args = append(cmd.Args, r.ContainerId)
177190

@@ -216,21 +229,26 @@ func (r *DockerPupsRunner) Run() error {
216229
rm := false
217230
// remove : in case docker tag is blank, and use default latest tag
218231
r.SavedImageName = strings.TrimRight(r.SavedImageName, ":")
232+
219233
if r.SavedImageName == "" {
220234
rm = true
221235
}
236+
222237
defer func(rm bool) {
223238
if !rm {
224239
time.Sleep(utils.CommitWait)
225240
runCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
226-
cmd := exec.CommandContext(runCtx, utils.DockerPath, "rm", "-f", r.ContainerId)
241+
cmd := exec.CommandContext(runCtx, utils.DockerPath, "rm", "--force", r.ContainerId)
227242
utils.CmdRunner(cmd).Run()
228243
cancel()
229244
}
230245
}(rm)
231-
commands := []string{"/bin/bash",
246+
247+
commands := []string{
248+
"/bin/bash",
232249
"-c",
233-
"/usr/local/bin/pups --stdin " + r.PupsArgs}
250+
"/usr/local/bin/pups --stdin " + r.PupsArgs,
251+
}
234252

235253
runner := DockerRunner{Config: r.Config,
236254
Ctx: r.Ctx,
@@ -248,6 +266,7 @@ func (r *DockerPupsRunner) Run() error {
248266

249267
if len(r.SavedImageName) > 0 {
250268
time.Sleep(utils.CommitWait)
269+
251270
cmd := exec.Command("docker",
252271
"commit",
253272
"--change",
@@ -257,13 +276,16 @@ func (r *DockerPupsRunner) Run() error {
257276
r.ContainerId,
258277
r.SavedImageName,
259278
)
279+
260280
cmd.Stdout = os.Stdout
261281
cmd.Stderr = os.Stderr
262282

263283
fmt.Fprintln(utils.Out, cmd)
284+
264285
if err := utils.CmdRunner(cmd).Run(); err != nil {
265286
return err
266287
}
267288
}
289+
268290
return nil
269291
}

launcher_go/v2/test/containers/test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ env:
8181
## The http or https CDN address for this Discourse instance (configured to pull)
8282
## see https://meta.discourse.org/t/14857 for details
8383
#DISCOURSE_CDN_URL: https://discourse-cdn.example.com
84-
84+
8585
## The maxmind geolocation IP address key for IP address lookup
8686
## see https://meta.discourse.org/t/-/137387/23 for details
8787
#DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456
@@ -105,6 +105,7 @@ hooks:
105105

106106
## Remember, this is YAML syntax - you can only have one block with a name
107107
run:
108+
- exec: echo "custom test command"
108109
- exec: echo "Beginning of custom commands"
109110

110111
## If you want to configure password login for root, uncomment and change:

0 commit comments

Comments
 (0)