Skip to content

Commit c6bec2e

Browse files
idsulikglours
authored andcommitted
add e2e tests
Signed-off-by: Suleiman Dibirov <idsulik@gmail.com> (cherry picked from commit 0c854a6) Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
1 parent 0bd132b commit c6bec2e

4 files changed

Lines changed: 147 additions & 0 deletions

File tree

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
Copyright 2020 Docker Compose CLI 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 e2e
18+
19+
import (
20+
"strings"
21+
"testing"
22+
23+
"gotest.tools/v3/assert"
24+
"gotest.tools/v3/icmd"
25+
)
26+
27+
// TestRunBuildOnce tests that services with pull_policy: build are only built once
28+
// when using 'docker compose run', even when they are dependencies.
29+
// This addresses a bug where dependencies were built twice: once in startDependencies
30+
// and once in ensureImagesExists.
31+
func TestRunBuildOnce(t *testing.T) {
32+
c := NewParallelCLI(t)
33+
34+
t.Run("dependency with pull_policy build is built only once", func(t *testing.T) {
35+
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/build-once.yaml", "down", "--rmi", "local", "--remove-orphans")
36+
res.Assert(t, icmd.Success)
37+
38+
res = c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/build-once.yaml", "run", "--rm", "curl")
39+
res.Assert(t, icmd.Success)
40+
41+
// Count how many times nginx was built by looking for its unique RUN command output
42+
nginxBuilds := strings.Count(res.Combined(), "Building nginx at")
43+
44+
// nginx should build exactly once, not twice
45+
assert.Equal(t, nginxBuilds, 1, "nginx dependency should build once, but built %d times", nginxBuilds)
46+
assert.Assert(t, strings.Contains(res.Combined(), "curl service"))
47+
48+
c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/build-once.yaml", "down", "--remove-orphans")
49+
})
50+
51+
t.Run("nested dependencies build only once each", func(t *testing.T) {
52+
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/build-once-nested.yaml", "down", "--rmi", "local", "--remove-orphans")
53+
res.Assert(t, icmd.Success)
54+
55+
res = c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/build-once-nested.yaml", "run", "--rm", "app")
56+
res.Assert(t, icmd.Success)
57+
58+
output := res.Combined()
59+
60+
// Each service should build exactly once
61+
dbBuilds := strings.Count(output, "DB built at")
62+
apiBuilds := strings.Count(output, "API built at")
63+
appBuilds := strings.Count(output, "App built at")
64+
65+
assert.Equal(t, dbBuilds, 1, "db should build once, built %d times", dbBuilds)
66+
assert.Equal(t, apiBuilds, 1, "api should build once, built %d times", apiBuilds)
67+
assert.Equal(t, appBuilds, 1, "app should build once, built %d times", appBuilds)
68+
assert.Assert(t, strings.Contains(output, "App running"))
69+
70+
c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/build-once-nested.yaml", "down", "--remove-orphans")
71+
})
72+
73+
t.Run("service with no dependencies builds once", func(t *testing.T) {
74+
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/build-once-no-deps.yaml", "down", "--rmi", "local", "--remove-orphans")
75+
res.Assert(t, icmd.Success)
76+
77+
res = c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/build-once-no-deps.yaml", "run", "--rm", "simple")
78+
res.Assert(t, icmd.Success)
79+
80+
// Should build exactly once
81+
simpleBuilds := strings.Count(res.Combined(), "Simple service built at")
82+
assert.Equal(t, simpleBuilds, 1, "simple should build once, built %d times", simpleBuilds)
83+
assert.Assert(t, strings.Contains(res.Combined(), "Simple service"))
84+
85+
c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/build-once-no-deps.yaml", "down", "--remove-orphans")
86+
})
87+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
services:
2+
# Database service with build
3+
db:
4+
pull_policy: build
5+
build:
6+
dockerfile_inline: |
7+
FROM alpine
8+
RUN echo "DB built at $(date)" > /db-build.txt
9+
CMD sleep 3600
10+
11+
# API service that depends on db
12+
api:
13+
pull_policy: build
14+
build:
15+
dockerfile_inline: |
16+
FROM alpine
17+
RUN echo "API built at $(date)" > /api-build.txt
18+
CMD sleep 3600
19+
depends_on:
20+
- db
21+
22+
# App service that depends on api (which depends on db)
23+
app:
24+
pull_policy: build
25+
build:
26+
dockerfile_inline: |
27+
FROM alpine
28+
RUN echo "App built at $(date)" > /app-build.txt
29+
CMD echo "App running"
30+
depends_on:
31+
- api
32+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
services:
2+
# Simple service with no dependencies
3+
simple:
4+
pull_policy: build
5+
build:
6+
dockerfile_inline: |
7+
FROM alpine
8+
RUN echo "Simple service built at $(date)" > /build.txt
9+
CMD echo "Simple service"
10+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
services:
2+
# Service with pull_policy: build to ensure it always rebuilds
3+
# This is the key to testing the bug - without the fix, this would build twice
4+
nginx:
5+
pull_policy: build
6+
build:
7+
dockerfile_inline: |
8+
FROM alpine
9+
RUN echo "Building nginx at $(date)" > /build-time.txt
10+
CMD sleep 3600
11+
12+
# Service that depends on nginx
13+
curl:
14+
image: alpine
15+
depends_on:
16+
- nginx
17+
command: echo "curl service"
18+

0 commit comments

Comments
 (0)