1// Copyright 2020 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package csuite 16 17import ( 18 "android/soong/android" 19 "io/ioutil" 20 "os" 21 "strings" 22 "testing" 23) 24 25var buildDir string 26 27func TestBpContainsTestHostPropsThrowsError(t *testing.T) { 28 ctx, _ := createContextAndConfig(t, ` 29 csuite_test { 30 name: "plan_name", 31 test_config_template: "config_template.xml", 32 data_native_bins: "bin" 33 } 34 `) 35 36 _, errs := ctx.ParseBlueprintsFiles("Android.bp") 37 38 android.FailIfNoMatchingErrors(t, `unrecognized property`, errs) 39} 40 41func TestBpContainsManifestThrowsError(t *testing.T) { 42 ctx, _ := createContextAndConfig(t, ` 43 csuite_test { 44 name: "plan_name", 45 test_config_template: "config_template.xml", 46 test_config: "AndroidTest.xml" 47 } 48 `) 49 50 _, errs := ctx.ParseBlueprintsFiles("Android.bp") 51 52 android.FailIfNoMatchingErrors(t, `unrecognized property`, errs) 53} 54 55func TestBpMissingNameThrowsError(t *testing.T) { 56 ctx, _ := createContextAndConfig(t, ` 57 csuite_test { 58 test_config_template: "config_template.xml" 59 } 60 `) 61 62 _, errs := ctx.ParseBlueprintsFiles("Android.bp") 63 64 android.FailIfNoMatchingErrors(t, `'name' is missing`, errs) 65} 66 67func TestBpMissingTemplatePathThrowsError(t *testing.T) { 68 ctx, config := createContextAndConfig(t, ` 69 csuite_test { 70 name: "plan_name", 71 } 72 `) 73 74 ctx.ParseBlueprintsFiles("Android.bp") 75 _, errs := ctx.PrepareBuildActions(config) 76 77 android.FailIfNoMatchingErrors(t, `'test_config_template' is missing`, errs) 78} 79 80func TestBpTemplatePathUnexpectedFileExtensionThrowsError(t *testing.T) { 81 ctx, config := createContextAndConfig(t, ` 82 csuite_test { 83 name: "plan_name", 84 test_config_template: "config_template.xml.template" 85 } 86 `) 87 88 ctx.ParseBlueprintsFiles("Android.bp") 89 _, errs := ctx.PrepareBuildActions(config) 90 91 android.FailIfNoMatchingErrors(t, `Config template path should ends with .xml`, errs) 92} 93 94func TestBpExtraTemplateUnexpectedFileExtensionThrowsError(t *testing.T) { 95 ctx, config := createContextAndConfig(t, ` 96 csuite_test { 97 name: "plan_name", 98 test_config_template: "config_template.xml", 99 extra_test_config_templates: ["another.xml.template"] 100 } 101 `) 102 103 ctx.ParseBlueprintsFiles("Android.bp") 104 _, errs := ctx.PrepareBuildActions(config) 105 106 android.FailIfNoMatchingErrors(t, `Config template path should ends with .xml`, errs) 107} 108 109func TestBpValidExtraTemplateDoesNotThrowError(t *testing.T) { 110 ctx, config := createContextAndConfig(t, ` 111 csuite_test { 112 name: "plan_name", 113 test_config_template: "config_template.xml", 114 extra_test_config_templates: ["another.xml"] 115 } 116 `) 117 118 parseBpAndBuild(t, ctx, config) 119} 120 121func TestValidBpMissingPlanIncludeDoesNotThrowError(t *testing.T) { 122 ctx, config := createContextAndConfig(t, ` 123 csuite_test { 124 name: "plan_name", 125 test_config_template: "config_template.xml" 126 } 127 `) 128 129 parseBpAndBuild(t, ctx, config) 130} 131 132func TestValidBpMissingPlanIncludeGeneratesPlanXmlWithoutPlaceholders(t *testing.T) { 133 ctx, config := createContextAndConfig(t, ` 134 csuite_test { 135 name: "plan_name", 136 test_config_template: "config_template.xml" 137 } 138 `) 139 140 parseBpAndBuild(t, ctx, config) 141 142 module := ctx.ModuleForTests("plan_name", config.BuildOS.String()+"_common") 143 content := android.ContentFromFileRuleForTests(t, module.Output("config/plan_name.xml")) 144 if strings.Contains(content, "{") || strings.Contains(content, "}") { 145 t.Errorf("The generated plan name contains a placeholder: %s", content) 146 } 147} 148 149func TestGeneratedTestPlanContainsPlanName(t *testing.T) { 150 ctx, config := createContextAndConfig(t, ` 151 csuite_test { 152 name: "plan_name", 153 test_config_template: "config_template.xml" 154 } 155 `) 156 157 parseBpAndBuild(t, ctx, config) 158 159 module := ctx.ModuleForTests("plan_name", config.BuildOS.String()+"_common") 160 content := android.ContentFromFileRuleForTests(t, module.Output("config/plan_name.xml")) 161 if !strings.Contains(content, "plan_name") { 162 t.Errorf("The plan name is missing from the generated plan: %s", content) 163 } 164} 165 166func TestGeneratedTestPlanContainsTemplatePath(t *testing.T) { 167 ctx, config := createContextAndConfig(t, ` 168 csuite_test { 169 name: "plan_name", 170 test_config_template: "config_template.xml" 171 } 172 `) 173 174 parseBpAndBuild(t, ctx, config) 175 176 module := ctx.ModuleForTests("plan_name", config.BuildOS.String()+"_common") 177 content := android.ContentFromFileRuleForTests(t, module.Output("config/plan_name.xml")) 178 if !strings.Contains(content, "config/plan_name/config_template.xml.template") { 179 t.Errorf("The template path is missing from the generated plan: %s", content) 180 } 181} 182 183func TestGeneratedTestPlanContainsExtraTemplatePath(t *testing.T) { 184 ctx, config := createContextAndConfig(t, ` 185 csuite_test { 186 name: "plan_name", 187 test_config_template: "config_template.xml", 188 extra_test_config_templates: ["extra.xml"] 189 } 190 `) 191 192 parseBpAndBuild(t, ctx, config) 193 194 module := ctx.ModuleForTests("plan_name", config.BuildOS.String()+"_common") 195 content := android.ContentFromFileRuleForTests(t, module.Output("config/plan_name.xml")) 196 if !strings.Contains(content, "config/plan_name/extra.xml.template") { 197 t.Errorf("The extra template path is missing from the generated plan: %s", content) 198 } 199 if !strings.Contains(content, "extra-templates") { 200 t.Errorf("The extra-templates param is missing from the generated plan: %s", content) 201 } 202} 203 204func TestGeneratedTestPlanDoesNotContainExtraTemplatePath(t *testing.T) { 205 ctx, config := createContextAndConfig(t, ` 206 csuite_test { 207 name: "plan_name", 208 test_config_template: "config_template.xml" 209 } 210 `) 211 212 parseBpAndBuild(t, ctx, config) 213 214 module := ctx.ModuleForTests("plan_name", config.BuildOS.String()+"_common") 215 content := android.ContentFromFileRuleForTests(t, module.Output("config/plan_name.xml")) 216 if strings.Contains(content, "extra-templates") { 217 t.Errorf("The extra-templates param should not be included in the generated plan: %s", content) 218 } 219} 220 221func TestTemplateFileCopyRuleExists(t *testing.T) { 222 ctx, config := createContextAndConfig(t, ` 223 csuite_test { 224 name: "plan_name", 225 test_config_template: "config_template.xml" 226 } 227 `) 228 229 parseBpAndBuild(t, ctx, config) 230 231 params := ctx.ModuleForTests("plan_name", config.BuildOS.String()+"_common").Rule("CSuite") 232 assertFileCopyRuleExists(t, params, "config_template.xml", "config/plan_name/config_template.xml.template") 233} 234 235func TestExtraTemplateFileCopyRuleExists(t *testing.T) { 236 ctx, config := createContextAndConfig(t, ` 237 csuite_test { 238 name: "plan_name", 239 test_config_template: "config_template.xml", 240 extra_test_config_templates: ["extra.xml"] 241 } 242 `) 243 244 parseBpAndBuild(t, ctx, config) 245 246 params := ctx.ModuleForTests("plan_name", config.BuildOS.String()+"_common").Rule("CSuite") 247 assertFileCopyRuleExists(t, params, "config_template.xml", "config/plan_name/extra.xml.template") 248} 249 250func TestGeneratedTestPlanContainsPlanInclude(t *testing.T) { 251 ctx, config := createContextAndConfig(t, ` 252 csuite_test { 253 name: "plan_name", 254 test_config_template: "config_template.xml", 255 test_plan_include: "include.xml" 256 } 257 `) 258 259 parseBpAndBuild(t, ctx, config) 260 261 module := ctx.ModuleForTests("plan_name", config.BuildOS.String()+"_common") 262 content := android.ContentFromFileRuleForTests(t, module.Output("config/plan_name.xml")) 263 if !strings.Contains(content, `"includes/plan_name.xml"`) { 264 t.Errorf("The plan include path is missing from the generated plan: %s", content) 265 } 266} 267 268func TestPlanIncludeFileCopyRuleExists(t *testing.T) { 269 ctx, config := createContextAndConfig(t, ` 270 csuite_test { 271 name: "plan_name", 272 test_config_template: "config_template.xml", 273 test_plan_include: "include.xml" 274 } 275 `) 276 277 parseBpAndBuild(t, ctx, config) 278 279 params := ctx.ModuleForTests("plan_name", config.BuildOS.String()+"_common").Rule("CSuite") 280 assertFileCopyRuleExists(t, params, "include.xml", "config/includes/plan_name.xml") 281} 282 283func TestMain(m *testing.M) { 284 run := func() int { 285 setUp() 286 defer tearDown() 287 288 return m.Run() 289 } 290 291 os.Exit(run()) 292} 293 294func parseBpAndBuild(t *testing.T, ctx *android.TestContext, config android.Config) { 295 _, parsingErrs := ctx.ParseBlueprintsFiles("Android.bp") 296 _, buildErrs := ctx.PrepareBuildActions(config) 297 298 android.FailIfErrored(t, parsingErrs) 299 android.FailIfErrored(t, buildErrs) 300} 301 302func assertFileCopyRuleExists(t *testing.T, params android.TestingBuildParams, src string, dst string) { 303 assertPathsContains(t, getAllInputPaths(params), src) 304 assertWritablePathsContainsRel(t, getAllOutputPaths(params), dst) 305 if !strings.HasPrefix(params.RuleParams.Command, "cp") { 306 t.Errorf("'cp' command is missing.") 307 } 308} 309 310func assertPathsContains(t *testing.T, paths android.Paths, path string) { 311 for _, p := range paths { 312 if p.String() == path { 313 return 314 } 315 } 316 t.Errorf("Cannot find expected path %s", path) 317} 318 319func assertWritablePathsContainsRel(t *testing.T, paths android.WritablePaths, relPath string) { 320 for _, path := range paths { 321 if path.Rel() == relPath { 322 return 323 } 324 } 325 t.Errorf("Cannot find expected relative path %s", relPath) 326} 327 328func getAllOutputPaths(params android.TestingBuildParams) android.WritablePaths { 329 var paths []android.WritablePath 330 if params.Output != nil { 331 paths = append(paths, params.Output) 332 } 333 if params.ImplicitOutput != nil { 334 paths = append(paths, params.ImplicitOutput) 335 } 336 if params.SymlinkOutput != nil { 337 paths = append(paths, params.SymlinkOutput) 338 } 339 paths = append(paths, params.Outputs...) 340 paths = append(paths, params.ImplicitOutputs...) 341 paths = append(paths, params.SymlinkOutputs...) 342 343 return paths 344} 345 346func getAllInputPaths(params android.TestingBuildParams) android.Paths { 347 var paths []android.Path 348 if params.Input != nil { 349 paths = append(paths, params.Input) 350 } 351 if params.Implicit != nil { 352 paths = append(paths, params.Implicit) 353 } 354 paths = append(paths, params.Inputs...) 355 paths = append(paths, params.Implicits...) 356 357 return paths 358} 359 360func setUp() { 361 var err error 362 buildDir, err = ioutil.TempDir("", "soong_csuite_test") 363 if err != nil { 364 panic(err) 365 } 366} 367 368func tearDown() { 369 os.RemoveAll(buildDir) 370} 371 372func createContextAndConfig(t *testing.T, bp string) (*android.TestContext, android.Config) { 373 t.Helper() 374 config := android.TestArchConfig(buildDir, nil, bp, nil) 375 ctx := android.NewTestArchContext(config) 376 ctx.RegisterModuleType("csuite_test", CSuiteTestFactory) 377 ctx.Register() 378 379 return ctx, config 380} 381