1+ // Copyright 2026 Nydus Developers. All rights reserved.
2+ //
3+ // SPDX-License-Identifier: Apache-2.0
4+
5+ package build
6+
7+ import (
8+ "bytes"
9+ "os"
10+ "path/filepath"
11+ "strings"
12+ "testing"
13+
14+ "github.com/stretchr/testify/require"
15+ )
16+
17+ func createFakeBinary (t * testing.T ) (string , string , string ) {
18+ t .Helper ()
19+
20+ tempDir := t .TempDir ()
21+ argsPath := filepath .Join (tempDir , "args.txt" )
22+ stdinPath := filepath .Join (tempDir , "stdin.txt" )
23+ binaryPath := filepath .Join (tempDir , "fake-nydus-image.sh" )
24+
25+ script := "#!/bin/sh\n " +
26+ "printf '%s\\ n' \" $@\" > \" $NYDUS_ARGS_FILE\" \n " +
27+ "cat > \" $NYDUS_STDIN_FILE\" \n "
28+
29+ require .NoError (t , os .WriteFile (binaryPath , []byte (script ), 0o755 ))
30+ t .Setenv ("NYDUS_ARGS_FILE" , argsPath )
31+ t .Setenv ("NYDUS_STDIN_FILE" , stdinPath )
32+
33+ return binaryPath , argsPath , stdinPath
34+ }
35+
36+ func readLines (t * testing.T , path string ) []string {
37+ t .Helper ()
38+
39+ content , err := os .ReadFile (path )
40+ require .NoError (t , err )
41+ text := strings .TrimSpace (string (content ))
42+ if text == "" {
43+ return nil
44+ }
45+
46+ return strings .Split (text , "\n " )
47+ }
48+
49+ func TestNewBuilderUsesStdStreams (t * testing.T ) {
50+ builder := NewBuilder ("/usr/bin/nydus-image" )
51+ require .Equal (t , "/usr/bin/nydus-image" , builder .binaryPath )
52+ require .Equal (t , os .Stdout , builder .stdout )
53+ require .Equal (t , os .Stderr , builder .stderr )
54+ }
55+
56+ func TestBuilderRunBuildCommand (t * testing.T ) {
57+ binaryPath , argsPath , stdinPath := createFakeBinary (t )
58+ builder := NewBuilder (binaryPath )
59+ builder .stdout = & bytes.Buffer {}
60+ builder .stderr = & bytes.Buffer {}
61+
62+ err := builder .Run (BuilderOption {
63+ ParentBootstrapPath : "/tmp/parent.boot" ,
64+ ChunkDict : "/tmp/chunk.dict" ,
65+ BootstrapPath : "/tmp/bootstrap.boot" ,
66+ RootfsPath : "/tmp/rootfs" ,
67+ WhiteoutSpec : "overlayfs" ,
68+ OutputJSONPath : "/tmp/output.json" ,
69+ PrefetchPatterns : "/etc\n /usr/bin" ,
70+ BlobPath : "/tmp/blob.data" ,
71+ AlignedChunk : true ,
72+ Compressor : "zstd" ,
73+ ChunkSize : "0x200000" ,
74+ FsVersion : "6" ,
75+ })
76+ require .NoError (t , err )
77+
78+ require .Equal (t , []string {
79+ "create" ,
80+ "--parent-bootstrap" ,
81+ "/tmp/parent.boot" ,
82+ "--aligned-chunk" ,
83+ "--chunk-dict" ,
84+ "/tmp/chunk.dict" ,
85+ "--bootstrap" ,
86+ "/tmp/bootstrap.boot" ,
87+ "--log-level" ,
88+ "warn" ,
89+ "--whiteout-spec" ,
90+ "overlayfs" ,
91+ "--output-json" ,
92+ "/tmp/output.json" ,
93+ "--blob" ,
94+ "/tmp/blob.data" ,
95+ "--fs-version" ,
96+ "6" ,
97+ "--compressor" ,
98+ "zstd" ,
99+ "--prefetch-policy" ,
100+ "fs" ,
101+ "--chunk-size" ,
102+ "0x200000" ,
103+ "/tmp/rootfs" ,
104+ }, readLines (t , argsPath ))
105+
106+ stdinContent , err := os .ReadFile (stdinPath )
107+ require .NoError (t , err )
108+ require .Equal (t , "/etc\n /usr/bin" , string (stdinContent ))
109+ }
110+
111+ func TestBuilderCompactAndGenerateCommands (t * testing.T ) {
112+ binaryPath , argsPath , stdinPath := createFakeBinary (t )
113+ builder := NewBuilder (binaryPath )
114+ builder .stdout = & bytes.Buffer {}
115+ builder .stderr = & bytes.Buffer {}
116+
117+ err := builder .Compact (CompactOption {
118+ ChunkDict : "/tmp/chunk.dict" ,
119+ BootstrapPath : "/tmp/bootstrap.boot" ,
120+ OutputBootstrapPath : "/tmp/output.boot" ,
121+ BackendType : "oss" ,
122+ BackendConfigPath : "/tmp/backend.json" ,
123+ OutputJSONPath : "/tmp/output.json" ,
124+ MinUsedRatio : "30" ,
125+ CompactBlobSize : "1048576" ,
126+ MaxCompactSize : "2097152" ,
127+ LayersToCompact : "2" ,
128+ BlobsDir : "/tmp/blobs" ,
129+ })
130+ require .NoError (t , err )
131+ require .Equal (t , []string {
132+ "compact" ,
133+ "--bootstrap" ,
134+ "/tmp/bootstrap.boot" ,
135+ "--blob-dir" ,
136+ "/tmp/blobs" ,
137+ "--min-used-ratio" ,
138+ "30" ,
139+ "--compact-blob-size" ,
140+ "1048576" ,
141+ "--max-compact-size" ,
142+ "2097152" ,
143+ "--layers-to-compact" ,
144+ "2" ,
145+ "--backend-type" ,
146+ "oss" ,
147+ "--backend-config-file" ,
148+ "/tmp/backend.json" ,
149+ "--log-level" ,
150+ "info" ,
151+ "--output-json" ,
152+ "/tmp/output.json" ,
153+ "--output-bootstrap" ,
154+ "/tmp/output.boot" ,
155+ "--chunk-dict" ,
156+ "/tmp/chunk.dict" ,
157+ }, readLines (t , argsPath ))
158+ require .Empty (t , readLines (t , stdinPath ))
159+
160+ err = builder .Generate (GenerateOption {
161+ BootstrapPaths : []string {"/tmp/layer1.boot" , "/tmp/layer2.boot" },
162+ DatabasePath : "/tmp/chunk.db" ,
163+ ChunkdictBootstrapPath : "/tmp/chunkdict.boot" ,
164+ OutputPath : "/tmp/chunkdict.json" ,
165+ })
166+ require .NoError (t , err )
167+ require .Equal (t , []string {
168+ "chunkdict" ,
169+ "generate" ,
170+ "--log-level" ,
171+ "warn" ,
172+ "--bootstrap" ,
173+ "/tmp/chunkdict.boot" ,
174+ "--database" ,
175+ "/tmp/chunk.db" ,
176+ "--output-json" ,
177+ "/tmp/chunkdict.json" ,
178+ "/tmp/layer1.boot" ,
179+ "/tmp/layer2.boot" ,
180+ }, readLines (t , argsPath ))
181+ }
0 commit comments