Skip to content

Commit fdeb1b1

Browse files
authored
Add builder tests (apple#1154)
- Adds test for apple#1094. - Closes apple#933 (with apple/container-builder-shim#62). - Closes apple#425 (with apple/container-builder-shim#63).
1 parent fabfc55 commit fdeb1b1

1 file changed

Lines changed: 226 additions & 0 deletions

File tree

Tests/CLITests/Subcommands/Build/CLIBuilderTest.swift

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,232 @@ extension TestCLIBuildBase {
525525
#expect(try self.inspectImage(imageName) == imageName, "expected to have successfully built \(imageName)")
526526
}
527527

528+
@Test func testLowercaseDockerfile() throws {
529+
// Test 1: COPY with uppercase
530+
let tempDir1: URL = try createTempDir()
531+
let dockerfile1 =
532+
"""
533+
FROM ghcr.io/linuxcontainers/alpine:3.20
534+
COPY . /app
535+
RUN test -f /app/testfile.txt
536+
"""
537+
let context1: [FileSystemEntry] = [
538+
.file("testfile.txt", content: .data("test".data(using: .utf8)!))
539+
]
540+
try createContext(tempDir: tempDir1, dockerfile: dockerfile1, context: context1)
541+
let imageName1 = "registry.local/copy-uppercase:\(UUID().uuidString)"
542+
try self.build(tag: imageName1, tempDir: tempDir1)
543+
#expect(try self.inspectImage(imageName1) == imageName1, "expected COPY to work")
544+
545+
// Test 2: copy with lowercase
546+
let tempDir2: URL = try createTempDir()
547+
let dockerfile2 =
548+
"""
549+
FROM ghcr.io/linuxcontainers/alpine:3.20
550+
copy . /app
551+
RUN test -f /app/testfile.txt
552+
"""
553+
let context2: [FileSystemEntry] = [
554+
.file("testfile.txt", content: .data("test".data(using: .utf8)!))
555+
]
556+
try createContext(tempDir: tempDir2, dockerfile: dockerfile2, context: context2)
557+
let imageName2 = "registry.local/copy-lowercase:\(UUID().uuidString)"
558+
try self.build(tag: imageName2, tempDir: tempDir2)
559+
#expect(try self.inspectImage(imageName2) == imageName2, "expected copy to work")
560+
561+
// Test 3: ADD with uppercase
562+
let tempDir3: URL = try createTempDir()
563+
let dockerfile3 =
564+
"""
565+
FROM ghcr.io/linuxcontainers/alpine:3.20
566+
ADD . /app
567+
RUN test -f /app/testfile.txt
568+
"""
569+
let context3: [FileSystemEntry] = [
570+
.file("testfile.txt", content: .data("test".data(using: .utf8)!))
571+
]
572+
try createContext(tempDir: tempDir3, dockerfile: dockerfile3, context: context3)
573+
let imageName3 = "registry.local/add-uppercase:\(UUID().uuidString)"
574+
try self.build(tag: imageName3, tempDir: tempDir3)
575+
#expect(try self.inspectImage(imageName3) == imageName3, "expected ADD to work")
576+
577+
// Test 4: add with lowercase
578+
let tempDir4: URL = try createTempDir()
579+
let dockerfile4 =
580+
"""
581+
FROM ghcr.io/linuxcontainers/alpine:3.20
582+
add . /app
583+
RUN test -f /app/testfile.txt
584+
"""
585+
let context4: [FileSystemEntry] = [
586+
.file("testfile.txt", content: .data("test".data(using: .utf8)!))
587+
]
588+
try createContext(tempDir: tempDir4, dockerfile: dockerfile4, context: context4)
589+
let imageName4 = "registry.local/add-lowercase:\(UUID().uuidString)"
590+
try self.build(tag: imageName4, tempDir: tempDir4)
591+
#expect(try self.inspectImage(imageName4) == imageName4, "expected add to work")
592+
}
593+
594+
@Test func testRunWithBindMount() throws {
595+
let tempDir: URL = try createTempDir()
596+
let dockerfile =
597+
"""
598+
FROM ghcr.io/linuxcontainers/alpine:3.20
599+
600+
# Use bind mount to access build context during RUN
601+
RUN --mount=type=bind,source=.,target=/mnt/context \
602+
set -e; \
603+
echo "Checking files in bind mount..."; \
604+
ls -la /mnt/context/; \
605+
\
606+
echo "Verifying files are accessible in mount..."; \
607+
if [ ! -f /mnt/context/app.py ]; then \
608+
echo "ERROR: app.py should be in bind mount!"; \
609+
exit 1; \
610+
fi; \
611+
if [ ! -f /mnt/context/config.yaml ]; then \
612+
echo "ERROR: config.yaml should be in bind mount!"; \
613+
exit 1; \
614+
fi; \
615+
\
616+
echo "RUN --mount bind check passed!"; \
617+
cp /mnt/context/app.py /app.py
618+
619+
RUN cat /app.py
620+
"""
621+
622+
let context: [FileSystemEntry] = [
623+
.file("app.py", content: .data("print('Hello from bind mount')".data(using: .utf8)!)),
624+
.file("config.yaml", content: .data("key: value".data(using: .utf8)!)),
625+
]
626+
627+
try createContext(tempDir: tempDir, dockerfile: dockerfile, context: context)
628+
let imageName = "registry.local/bind-mount-test:\(UUID().uuidString)"
629+
try self.build(tag: imageName, tempDir: tempDir)
630+
#expect(try self.inspectImage(imageName) == imageName, "expected to have successfully built \(imageName)")
631+
}
632+
633+
@Test func testBuildDockerIgnore() throws {
634+
let tempDir: URL = try createTempDir()
635+
let dockerfile =
636+
"""
637+
FROM ghcr.io/linuxcontainers/alpine:3.20
638+
639+
# Copy all files - should respect .dockerignore
640+
COPY . /app
641+
642+
# Verify specific files are excluded
643+
RUN set -e; \
644+
echo "Checking specific file exclusion..."; \
645+
if [ -f /app/secret.txt ]; then \
646+
echo "ERROR: secret.txt should be excluded!"; \
647+
exit 1; \
648+
fi
649+
650+
# Verify wildcard *.log files are excluded
651+
RUN set -e; \
652+
echo "Checking *.log exclusion..."; \
653+
if [ -f /app/debug.log ]; then \
654+
echo "ERROR: debug.log should be excluded by *.log pattern!"; \
655+
exit 1; \
656+
fi; \
657+
if ls /app/logs/*.log 2>/dev/null; then \
658+
echo "ERROR: logs/*.log files should be excluded!"; \
659+
exit 1; \
660+
fi
661+
662+
# Verify exception pattern (!important.log) works
663+
RUN set -e; \
664+
echo "Checking exception pattern..."; \
665+
if [ ! -f /app/important.log ]; then \
666+
echo "ERROR: important.log should be included (exception with !)"; \
667+
exit 1; \
668+
fi
669+
670+
# Verify *.tmp files are excluded
671+
RUN set -e; \
672+
echo "Checking *.tmp exclusion..."; \
673+
if find /app -name "*.tmp" | grep .; then \
674+
echo "ERROR: .tmp files should be excluded!"; \
675+
exit 1; \
676+
fi
677+
678+
# Verify directories are excluded
679+
RUN set -e; \
680+
echo "Checking directory exclusion..."; \
681+
if [ -d /app/temp ]; then \
682+
echo "ERROR: temp/ directory should be excluded!"; \
683+
exit 1; \
684+
fi; \
685+
if [ -d /app/node_modules ]; then \
686+
echo "ERROR: node_modules/ should be excluded!"; \
687+
exit 1; \
688+
fi
689+
690+
# Verify included files ARE present
691+
RUN set -e; \
692+
echo "Checking included files..."; \
693+
if [ ! -f /app/main.go ]; then \
694+
echo "ERROR: main.go should be included!"; \
695+
exit 1; \
696+
fi; \
697+
if [ ! -f /app/README.md ]; then \
698+
echo "ERROR: README.md should be included!"; \
699+
exit 1; \
700+
fi; \
701+
if [ ! -f /app/src/app.go ]; then \
702+
echo "ERROR: src/app.go should be included!"; \
703+
exit 1; \
704+
fi; \
705+
echo "All .dockerignore checks passed!"
706+
"""
707+
708+
let dockerignore =
709+
"""
710+
# Exclude specific files
711+
secret.txt
712+
713+
# Exclude all log files
714+
*.log
715+
**/*.log
716+
717+
# But make an exception for important.log
718+
!important.log
719+
720+
# Exclude all temporary files
721+
*.tmp
722+
**/*.tmp
723+
724+
# Exclude directories
725+
temp/
726+
node_modules/
727+
"""
728+
729+
let context: [FileSystemEntry] = [
730+
.file(".dockerignore", content: .data(dockerignore.data(using: .utf8)!)),
731+
.file("secret.txt", content: .data("secret content".data(using: .utf8)!)),
732+
.file("debug.log", content: .data("debug log content".data(using: .utf8)!)),
733+
.file("important.log", content: .data("important log content".data(using: .utf8)!)),
734+
.file("cache.tmp", content: .data("cache".data(using: .utf8)!)),
735+
.file("main.go", content: .data("package main".data(using: .utf8)!)),
736+
.file("README.md", content: .data("# README".data(using: .utf8)!)),
737+
.directory("temp"),
738+
.file("temp/cache.tmp", content: .data("temp cache".data(using: .utf8)!)),
739+
.directory("logs"),
740+
.file("logs/app.log", content: .data("app log".data(using: .utf8)!)),
741+
.directory("node_modules"),
742+
.file("node_modules/package.json", content: .data("{}".data(using: .utf8)!)),
743+
.directory("src"),
744+
.file("src/app.go", content: .data("package src".data(using: .utf8)!)),
745+
.file("src/test.tmp", content: .data("temp".data(using: .utf8)!)),
746+
]
747+
748+
try createContext(tempDir: tempDir, dockerfile: dockerfile, context: context)
749+
let imageName = "registry.local/dockerignore-test:\(UUID().uuidString)"
750+
try self.build(tag: imageName, tempDir: tempDir)
751+
#expect(try self.inspectImage(imageName) == imageName, "expected to have successfully built \(imageName)")
752+
}
753+
528754
@Test func testBuildNoCachePullLatestImage() throws {
529755
let tempDir: URL = try createTempDir()
530756
let dockerfile =

0 commit comments

Comments
 (0)