github.com/SAP/cloud-mta-build-tool@v1.2.27/internal/tpl/makefile_test.go (about) 1 package tpl 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "strings" 9 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/ginkgo/extensions/table" 12 . "github.com/onsi/gomega" 13 "github.com/pkg/errors" 14 15 "github.com/SAP/cloud-mta-build-tool/internal/archive" 16 "github.com/SAP/cloud-mta-build-tool/internal/logs" 17 "github.com/SAP/cloud-mta-build-tool/internal/version" 18 "github.com/SAP/cloud-mta/mta" 19 ) 20 21 const ( 22 makefile = "Makefile.mta" 23 ) 24 25 var _ = BeforeSuite(func() { 26 logs.Logger = logs.NewLogger() 27 }) 28 29 func removeSpecialSymbols(b []byte) string { 30 s := string(b) 31 s = strings.Replace(s, "\r", "", -1) 32 return s 33 } 34 35 func getMakeFileContent(filePath string) string { 36 expected, _ := ioutil.ReadFile(filePath) 37 return removeSpecialSymbols(expected) 38 } 39 40 func escapeProjPath(parts ...string) string { 41 return `"$(PROJ_DIR)/` + filepath.Join(parts...) + `"` 42 } 43 44 var _ = Describe("Makefile", func() { 45 46 var ( 47 tpl = tplCfg{tplContent: makeVerbose, relPath: "", preContent: basePreVerbose, postContent: basePost, depDesc: "dev"} 48 makeFileName = "MakeFileTest.mta" 49 ) 50 51 wd, _ := os.Getwd() 52 expectedMakePath := filepath.Join(wd, "testdata", "ExpectedMakeFile") 53 expectedMakeFileContent := getMakeFileContent(expectedMakePath) 54 makeFileFullPath := filepath.Join(wd, "testdata", makeFileName) 55 56 Describe("MakeFile Generation", func() { 57 BeforeEach(func() { 58 version.VersionConfig = []byte(` 59 cli_version: 0.0.0 60 makefile_version: 0.0.0 61 `) 62 }) 63 AfterEach(func() { 64 Ω(os.RemoveAll(makeFileFullPath)).Should(Succeed()) 65 Ω(os.RemoveAll(filepath.Join(wd, "testdata", "someFolder"))).Should(Succeed()) 66 }) 67 68 Describe("ExecuteMake", func() { 69 AfterEach(func() { 70 Ω(os.RemoveAll(filepath.Join(wd, "testdata", "Makefile.mta"))).Should(Succeed()) 71 }) 72 It("Sanity", func() { 73 Ω(ExecuteMake(filepath.Join(wd, "testdata"), filepath.Join(wd, "testdata"), nil, makefile, "", os.Getwd, true)).Should(Succeed()) 74 Ω(filepath.Join(wd, "testdata", "Makefile.mta")).Should(BeAnExistingFile()) 75 }) 76 It("Fails on location initialization", func() { 77 Ω(ExecuteMake("", filepath.Join(wd, "testdata"), nil, makefile, "", func() (string, error) { 78 return "", errors.New("err") 79 }, true)).Should(HaveOccurred()) 80 }) 81 It("Fails on wrong mode", func() { 82 Ω(ExecuteMake(filepath.Join(wd, "testdata"), filepath.Join(wd, "testdata"), nil, makefile, "wrong", os.Getwd, true)).Should(HaveOccurred()) 83 }) 84 }) 85 86 It("createMakeFile testing", func() { 87 makeFilePath := filepath.Join(wd, "testdata") 88 file, _ := createMakeFile(makeFilePath, makeFileName) 89 Ω(file).ShouldNot(BeNil()) 90 Ω(file.Close()).Should(Succeed()) 91 Ω(makeFilePath).Should(BeAnExistingFile()) 92 _, err := createMakeFile(makeFilePath, makeFileName) 93 Ω(err).Should(HaveOccurred()) 94 }) 95 It("Sanity", func() { 96 ep := dir.Loc{SourcePath: filepath.Join(wd, "testdata"), TargetPath: filepath.Join(wd, "testdata"), Descriptor: "dev"} 97 Ω(makeFile(&ep, &ep, &ep, nil, makeFileName, &tpl, true)).Should(Succeed()) 98 Ω(makeFileFullPath).Should(BeAnExistingFile()) 99 Ω(getMakeFileContent(makeFileFullPath)).Should(Equal(expectedMakeFileContent)) 100 }) 101 It("Create make file in folder that does not exist", func() { 102 ep := dir.Loc{SourcePath: filepath.Join(wd, "testdata"), TargetPath: filepath.Join(wd, "testdata", "someFolder"), Descriptor: "dev"} 103 Ω(makeFile(&ep, &ep, &ep, nil, makeFileName, &tpl, true)).Should(Succeed()) 104 filename := filepath.Join(ep.GetTarget(), makeFileName) 105 Ω(filename).Should(BeAnExistingFile()) 106 Ω(getMakeFileContent(filename)).Should(Equal(expectedMakeFileContent)) 107 }) 108 It("genMakefile testing with wrong mta yaml file", func() { 109 ep := dir.Loc{SourcePath: filepath.Join(wd, "testdata"), TargetPath: filepath.Join(wd, "testdata"), MtaFilename: "xxx.yaml"} 110 Ω(genMakefile(&ep, &ep, &ep, &ep, nil, makefile, "", true)).Should(HaveOccurred()) 111 }) 112 It("genMakefile testing with wrong target folder (file path)", func() { 113 ep := dir.Loc{SourcePath: filepath.Join(wd, "testdata"), TargetPath: filepath.Join(wd, "testdata", "mta.yaml"), MtaFilename: "xxx.yaml"} 114 Ω(genMakefile(&ep, &ep, &ep, &ep, nil, makefile, "", true)).Should(HaveOccurred()) 115 }) 116 It("genMakefile testing with wrong mode", func() { 117 ep := dir.Loc{SourcePath: filepath.Join(wd, "testdata")} 118 Ω(genMakefile(&ep, &ep, &ep, &ep, nil, makefile, "wrongMode", true)).Should(HaveOccurred()) 119 }) 120 121 DescribeTable("genMakefile should fail when there is a circular build dependency between modules", func(mode string) { 122 ep := dir.Loc{SourcePath: filepath.Join(wd, "testdata"), TargetPath: filepath.Join(wd, "testdata"), MtaFilename: "circular.yaml"} 123 Ω(genMakefile(&ep, &ep, &ep, &ep, nil, makefile, mode, true)).Should(HaveOccurred()) 124 }, 125 Entry("in default mode", ""), 126 Entry("in verbose mode", "verbose"), 127 ) 128 129 DescribeTable("generate module build in verbose make file", func(mtaFileName, moduleName, expectedModuleCommandsGen string) { 130 ep := dir.Loc{SourcePath: filepath.Join(wd, "testdata", "modulegen"), TargetPath: filepath.Join(wd, "testdata"), Descriptor: "dev", MtaFilename: mtaFileName} 131 Ω(makeFile(&ep, &ep, &ep, nil, makeFileName, &tpl, true)).Should(Succeed()) 132 Ω(makeFileFullPath).Should(BeAnExistingFile()) 133 makefileContent := getMakeFileContent(makeFileFullPath) 134 135 expectedModuleGen := fmt.Sprintf(`%s: validate 136 @echo 'INFO building the "%s" module...' 137 @%s`, moduleName, moduleName, expectedModuleCommandsGen) 138 Ω(makefileContent).Should(ContainSubstring(removeSpecialSymbols([]byte(expectedModuleGen)))) 139 }, 140 Entry("module with one command", "one_command.yaml", "one_command", `$(MBT) execute -d="$(PROJ_DIR)/one_command" -c=yarn`), 141 Entry("module with no commands and no timeout", 142 "no_commands.yaml", "no_commands", `$(MBT) execute -d="$(PROJ_DIR)/no_commands"`), 143 Entry("module with no commands and with timeout", 144 "no_commands_with_timeout.yaml", "no_commands_with_timeout", `$(MBT) execute -d="$(PROJ_DIR)/no_commands_with_timeout" -t=3m`), 145 Entry("module with multiple commands", 146 "multiple_commands.yaml", "multiple_commands", `$(MBT) execute -d="$(PROJ_DIR)/multiple_commands" -c='npm install' -c=grunt -c='npm prune --production'`), 147 Entry("module with command and timeout", 148 "command_with_timeout.yaml", "command_with_timeout", `$(MBT) execute -d="$(PROJ_DIR)/command_with_timeout" -t=2s -c='sleep 1'`), 149 Entry("module with commands with special characters", 150 "commands_with_special_chars.yaml", "commands_with_special_chars", `$(MBT) execute -d="$(PROJ_DIR)/commands_with_special_chars" -c='sh -c '\''echo "a"'\' -c='echo "a\b"'`), 151 ) 152 153 modulegen := filepath.Join(wd, "testdata", "modulegen") 154 DescribeTable("generate module build with dependencies in verbose make file", func(mtaFileName, moduleName, modulePath, expectedModuleDepNames string, expectedModuleDepCopyCommands string) { 155 ep := dir.Loc{SourcePath: modulegen, TargetPath: filepath.Join(wd, "testdata"), Descriptor: "dev", MtaFilename: mtaFileName} 156 Ω(makeFile(&ep, &ep, &ep, nil, makeFileName, &tpl, true)).Should(Succeed()) 157 Ω(makeFileFullPath).Should(BeAnExistingFile()) 158 makefileContent := getMakeFileContent(makeFileFullPath) 159 160 expectedModuleGen := fmt.Sprintf(`%s: validate %s 161 @echo 'INFO building the "%s" module...'%s 162 @$(MBT) execute -d="$(PROJ_DIR)/%s"`, moduleName, expectedModuleDepNames, moduleName, expectedModuleDepCopyCommands, modulePath) 163 Ω(makefileContent).Should(ContainSubstring(removeSpecialSymbols([]byte(expectedModuleGen)))) 164 }, 165 Entry("dependency with artifacts", "dep_with_patterns.yaml", "module1", "public", `dep`, fmt.Sprintf(` 166 @$(MBT) cp -s=%s -t=%s -p=dist/\* -p=some_dir -p=a\*.txt`, escapeProjPath("client"), escapeProjPath("public"))), 167 Entry("module with two dependencies", "two_deps.yaml", "my_proj_ui_deployer", "my_proj_ui_deployer", `ui5module1 ui5module2`, fmt.Sprintf(` 168 @$(MBT) cp -s=%s -t=%s -p=./\* 169 @$(MBT) cp -s=%s -t=%s -p=./\*`, 170 escapeProjPath("ui5module1", "dist"), escapeProjPath("my_proj_ui_deployer", "resources", "ui5module1"), 171 escapeProjPath("ui5module2", "dist"), escapeProjPath("my_proj_ui_deployer", "resources", "ui5module2"))), 172 Entry("dependency with target-path", "dep_with_artifacts_and_targetpath.yaml", "module1", "public", `module1-dep`, fmt.Sprintf(` 173 @$(MBT) cp -s=%s -t=%s -p=dist/\*`, escapeProjPath("client"), escapeProjPath("public", "client"))), 174 Entry("dependent module with build-result and module with artifacts and target-path", "dep_with_build_results.yaml", "module1", "public", `dep1 dep2`, fmt.Sprintf(` 175 @$(MBT) cp -s=%s -t=%s -p=\* 176 @$(MBT) cp -s=%s -t=%s -p=\*`, 177 escapeProjPath("client1", "dist"), escapeProjPath("public", "dep1_result"), 178 escapeProjPath("client2", "target/*.war"), escapeProjPath("public"))), 179 ) 180 }) 181 182 DescribeTable("Makefile Generation Failed", func(testPath string, testTemplateFilename string) { 183 wd, _ := os.Getwd() 184 testTemplate, _ := ioutil.ReadFile(filepath.Join(wd, "testdata", testTemplateFilename)) 185 ep := dir.Loc{SourcePath: filepath.Join(wd, "testdata"), TargetPath: filepath.Join(wd, "testdata")} 186 Ω(makeFile(&ep, &ep, &ep, nil, makeFileName, &tplCfg{relPath: testPath, tplContent: testTemplate, preContent: basePreVerbose, postContent: basePost, depDesc: "dev"}, true)).Should(HaveOccurred()) 187 }, 188 Entry("Wrong Template", "testdata", filepath.Join("testdata", "WrongMakeTmpl.txt")), 189 Entry("Yaml not exists", "testdata1", "make_default.txt"), 190 ) 191 192 DescribeTable("String in slice search", func(s string, slice []string, expected bool) { 193 Ω(stringInSlice(s, slice)).Should(Equal(expected)) 194 }, 195 Entry("positive test", "test1", []string{"test1", "foo"}, true), 196 Entry("negative test", "test1", []string{"--test", "foo"}, false), 197 ) 198 199 Describe("genMakefile mode tests", func() { 200 DescribeTable("Positive", func(mode string, tpl tplCfg, isDep bool) { 201 Ω(getTplCfg(mode, isDep)).Should(Equal(tpl)) 202 }, 203 Entry("Default mode Dev", "", tplCfg{tplContent: makeDefault, preContent: basePreDefault, postContent: basePost}, false), 204 Entry("Verbose mode Dev", "verbose", tplCfg{tplContent: makeVerbose, preContent: basePreVerbose, postContent: basePost}, false), 205 ) 206 It("unknown mode", func() { 207 _, err := getTplCfg("test", false) 208 Ω(err).Should(MatchError(`the "test" command is not supported`)) 209 }) 210 }) 211 212 var absPath = func(path string) string { 213 s, _ := filepath.Abs(path) 214 return s 215 } 216 sep := string(filepath.Separator) 217 DescribeTable("getExtensionsArg", func(extensions []string, makefileDirPath string, expected string) { 218 Ω(getExtensionsArg(extensions, makefileDirPath, "-e")).Should(Equal(expected)) 219 }, 220 Entry("empty list returns empty string", []string{}, "", ""), 221 Entry("nil returns empty string", nil, "", ""), 222 Entry("extension path is returned relative to the makefile path when it's in the same folder", 223 []string{absPath("my.mtaext")}, absPath("."), ` -e="$(CURDIR)`+sep+`my.mtaext"`), 224 Entry("extension path is returned relative to the makefile path when it's in an inner folder", 225 []string{absPath(filepath.Join("inner", "my.mtaext"))}, absPath("."), ` -e="$(CURDIR)`+sep+"inner"+sep+`my.mtaext"`), 226 Entry("extension path is returned relative to the makefile path when it's in an outer folder", 227 []string{absPath("my.mtaext")}, absPath("inner"), ` -e="$(CURDIR)`+sep+".."+sep+`my.mtaext"`), 228 Entry("extension paths are separated by a comma", 229 []string{absPath("my.mtaext"), absPath("second.mtaext")}, absPath("."), ` -e="$(CURDIR)`+sep+`my.mtaext,$(CURDIR)`+sep+`second.mtaext"`), 230 ) 231 232 It("GetModuleDeps returns error when module doesn't exist", func() { 233 data := templateData{File: mta.MTA{}} 234 _, err := data.GetModuleDeps("unknown") 235 Ω(err).Should(HaveOccurred()) 236 }) 237 238 It("GetModuleDeps returns error when module has dependency that doesn't exist", func() { 239 data := templateData{File: mta.MTA{Modules: []*mta.Module{ 240 { 241 Name: "m1", 242 BuildParams: map[string]interface{}{ 243 "requires": []interface{}{ 244 map[string]interface{}{"name": "unknown"}, 245 }, 246 }, 247 }, 248 }}} 249 _, err := data.GetModuleDeps("m1") 250 Ω(err).Should(HaveOccurred()) 251 }) 252 253 It("IsNoSource fails on not existing module", func() { 254 data := templateData{File: mta.MTA{Modules: []*mta.Module{ 255 { 256 Name: "m1", 257 BuildParams: map[string]interface{}{ 258 "requires": []interface{}{ 259 map[string]interface{}{"name": "unknown"}, 260 }, 261 }, 262 }, 263 }}} 264 _, err := data.IsNoSource("m2") 265 Ω(err).Should(HaveOccurred()) 266 }) 267 268 It("IsNoSource fails on empty path", func() { 269 data := templateData{File: mta.MTA{Modules: []*mta.Module{ 270 { 271 Name: "m1", 272 }, 273 }}} 274 _, err := data.IsNoSource("m1") 275 Ω(err).Should(HaveOccurred()) 276 }) 277 })