github.com/amplia-iiot/yutil@v1.0.1-0.20231229120411-5d96a4c5a136/pkg/merge/files_test.go (about) 1 /* 2 Copyright (c) 2021-2023 amplia-iiot 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to deal 6 in the Software without restriction, including without limitation the rights 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in all 12 copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 SOFTWARE. 21 */ 22 23 package merge 24 25 import ( 26 "fmt" 27 "os" 28 "path" 29 "runtime" 30 "strings" 31 "testing" 32 33 "github.com/amplia-iiot/yutil/internal/io" 34 itesting "github.com/amplia-iiot/yutil/internal/testing" 35 ) 36 37 func init() { 38 // Go to root folder to access testdata/ 39 _, filename, _, _ := runtime.Caller(0) 40 dir := path.Join(path.Dir(filename), "..", "..") 41 err := os.Chdir(dir) 42 if err != nil { 43 panic(err) 44 } 45 // Create tmp folder 46 if !io.Exists("tmp") { 47 err = os.Mkdir("tmp", 0700) 48 if err != nil { 49 panic(err) 50 } 51 } 52 } 53 54 func TestMergeFiles(t *testing.T) { 55 for _, i := range []struct { 56 base string 57 changes string 58 }{ 59 {"base", "dev"}, 60 {"base", "prod"}, 61 } { 62 merged, err := MergeFiles(fileToBeMerged(i.base), fileToBeMerged(i.changes)) 63 if err != nil { 64 t.Fatal(err) 65 } 66 expectedContent := itesting.ReadFile(t, expectedFile([]string{i.base, i.changes})) 67 itesting.AssertEqual(t, format(t, expectedContent), merged) 68 } 69 } 70 71 func TestMergeAllFiles(t *testing.T) { 72 for _, files := range [][]string{ 73 {"base", "dev"}, 74 {"base", "prod"}, 75 {"base", "dev", "docker"}, 76 {"base", "prod", "docker"}, 77 } { 78 merged, err := MergeAllFiles(filesToBeMerged(files)) 79 if err != nil { 80 t.Fatal(err) 81 } 82 expectedContent := itesting.ReadFile(t, expectedFile(files)) 83 itesting.AssertEqual(t, format(t, expectedContent), merged) 84 } 85 } 86 87 func TestMergeFilesInvalid(t *testing.T) { 88 for _, i := range []struct { 89 base string 90 changes string 91 expected string 92 }{ 93 // Parsing error 94 { 95 base: "invalid", 96 changes: "dev", 97 expected: "cannot unmarshal", 98 }, 99 { 100 base: "base", 101 changes: "invalid", 102 expected: "cannot unmarshal", 103 }, 104 // Not exists 105 { 106 base: "not-exists", 107 changes: "dev", 108 expected: "no such file or directory", 109 }, 110 { 111 base: "base", 112 changes: "not-exists", 113 expected: "no such file or directory", 114 }, 115 } { 116 merged, err := MergeFiles(fileToBeMerged(i.base), fileToBeMerged(i.changes)) 117 itesting.AssertError(t, i.expected, err) 118 if merged != "" { 119 t.Fatalf("Should not have merged") 120 } 121 } 122 } 123 124 func TestMergeAllFilesInvalid(t *testing.T) { 125 for _, i := range []struct { 126 files []string 127 expected string 128 }{ 129 // At least two 130 { 131 files: []string{}, 132 expected: "slice must contain at least two files", 133 }, 134 { 135 files: []string{"base"}, 136 expected: "slice must contain at least two files", 137 }, 138 // Parsing error 139 { 140 files: []string{"base", "invalid"}, 141 expected: "cannot unmarshal", 142 }, 143 { 144 files: []string{"invalid", "prod"}, 145 expected: "cannot unmarshal", 146 }, 147 { 148 files: []string{"invalid", "prod", "docker"}, 149 expected: "cannot unmarshal", 150 }, 151 { 152 files: []string{"base", "prod", "invalid"}, 153 expected: "cannot unmarshal", 154 }, 155 // Not exists 156 { 157 files: []string{"base", "not-exists"}, 158 expected: "no such file or directory", 159 }, 160 { 161 files: []string{"base", "prod", "not-exists"}, 162 expected: "no such file or directory", 163 }, 164 } { 165 merged, err := MergeAllFiles(filesToBeMerged(i.files)) 166 itesting.AssertError(t, i.expected, err) 167 if merged != "" { 168 t.Fatalf("Should not have merged") 169 } 170 } 171 } 172 173 func TestMergeStdinWithFiles(t *testing.T) { 174 for _, i := range []struct { 175 stdin string 176 files []string 177 expected string 178 }{ 179 { 180 stdin: "app: {env: {test: true}}", 181 files: []string{"base"}, 182 expected: `app: 183 api: 184 url: http://example.com 185 version: v1 186 cluster: 187 hosts: 188 - http://one.example.com 189 - http://two.example.com 190 description: YAML utils 191 env: 192 test: true 193 long-description: Common functionality for working with YAML files 194 name: yutil 195 version: 1.0.0 196 `, 197 }, 198 { 199 stdin: "app: {env: {test: true}}", 200 files: []string{"base", "dev"}, 201 expected: `app: 202 api: 203 url: http://localhost:8080 204 version: v1-dev 205 cluster: 206 hosts: 207 - http://localhost:8081 208 - http://localhost:8082 209 description: YAML utils 210 env: 211 dev: true 212 test: true 213 long-description: Common functionality for working with YAML files 214 name: yutil 215 version: 1.0.0-alpha 216 `, 217 }, 218 { 219 stdin: "{app: {env: {test: true}}, extra: extra}", 220 files: []string{"base", "prod", "docker"}, 221 expected: `app: 222 api: 223 url: http://service 224 version: v1 225 cluster: 226 hosts: 227 - http://service-1 228 - http://service-2 229 description: YAML utils 230 env: 231 docker: true 232 prod: true 233 test: true 234 long-description: Common functionality for working with YAML files 235 name: yutil 236 version: 1.0.0 237 extra: extra 238 `, 239 }, 240 } { 241 itesting.SimulateStdinContent(t, i.stdin, func() { 242 merged, err := MergeStdinWithFiles(filesToBeMerged(i.files)) 243 if err != nil { 244 t.Fatal(err) 245 } 246 itesting.AssertEqual(t, i.expected, merged) 247 }) 248 } 249 } 250 251 func TestMergeStdinWithFilesInvalid(t *testing.T) { 252 for _, i := range []struct { 253 stdin string 254 stdinFile os.File 255 files []string 256 expected string 257 }{ 258 // At least one file 259 { 260 stdin: "app: {env: {test: true}}", 261 files: []string{}, 262 expected: "slice must contain at least one file", 263 }, 264 // Parsing error 265 { 266 stdin: ";", 267 files: []string{"base"}, 268 expected: "cannot unmarshal", 269 }, 270 // Not exists 271 { 272 stdin: "app: {env: {test: true}}", 273 files: []string{"not-exists"}, 274 expected: "no such file or directory", 275 }, 276 // Stdin error 277 { 278 stdinFile: *os.Stderr, 279 files: []string{"not-exists"}, 280 expected: "bad file descriptor", 281 }, 282 } { 283 test := func() { 284 merged, err := MergeStdinWithFiles(filesToBeMerged(i.files)) 285 itesting.AssertError(t, i.expected, err) 286 if merged != "" { 287 t.Fatalf("Should not have merged") 288 } 289 } 290 if i.stdin != "" { 291 itesting.SimulateStdinContent(t, i.stdin, test) 292 } else { 293 itesting.SimulateStdinFile(i.stdinFile, test) 294 } 295 } 296 } 297 298 func TestMergeAllFilesToFile(t *testing.T) { 299 for _, files := range [][]string{ 300 {"base", "dev"}, 301 {"base", "prod"}, 302 {"base", "dev", "docker"}, 303 {"base", "prod", "docker"}, 304 // Empty values (https://github.com/amplia-iiot/yutil/issues/3) 305 {"issue-3-base", "issue-3-changes"}, 306 } { 307 tmpPath := itesting.TempFilePath(t, "merged-*.yml") 308 defer os.Remove(tmpPath) 309 err := MergeAllFilesToFile(filesToBeMerged(files), tmpPath) 310 if err != nil { 311 t.Fatal(err) 312 } 313 expectedContent := itesting.ReadFile(t, expectedFile(files)) 314 mergedContent := itesting.ReadFile(t, tmpPath) 315 itesting.AssertEqual(t, format(t, expectedContent), mergedContent) 316 } 317 } 318 319 func TestMergeAllFilesToFileInvalid(t *testing.T) { 320 for _, i := range []struct { 321 files []string 322 expected string 323 }{ 324 // At least two file 325 { 326 files: []string{}, 327 expected: "slice must contain at least two files", 328 }, 329 { 330 files: []string{"base"}, 331 expected: "slice must contain at least two files", 332 }, 333 // Parsing error 334 { 335 files: []string{"base", "invalid"}, 336 expected: "cannot unmarshal", 337 }, 338 // Not exists 339 { 340 files: []string{"base", "not-exists"}, 341 expected: "no such file or directory", 342 }, 343 } { 344 tmpPath := itesting.TempFilePath(t, "merged-*.yml") 345 defer os.Remove(tmpPath) 346 err := MergeAllFilesToFile(filesToBeMerged(i.files), tmpPath) 347 itesting.AssertError(t, i.expected, err) 348 if io.Exists(tmpPath) { 349 t.Fatalf("Should not have merged") 350 } 351 } 352 } 353 354 func expectedFile(files []string) string { 355 // fmt.Printf("expected: %v", files) 356 return fmt.Sprintf("testdata/merged/%s.yml", strings.Join(files, "-")) 357 } 358 359 func fileToBeMerged(file string) string { 360 return fmt.Sprintf("testdata/%s.yml", file) 361 } 362 363 func filesToBeMerged(files []string) []string { 364 completeFiles := make([]string, len(files)) 365 for i, file := range files { 366 completeFiles[i] = fileToBeMerged(file) 367 } 368 return completeFiles 369 }