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	"android/soong/java"
20	"strings"
21)
22
23var (
24	pctx = android.NewPackageContext("android/soong/csuite")
25)
26
27func init() {
28	android.RegisterModuleType("csuite_test", CSuiteTestFactory)
29}
30
31type csuiteTestProperties struct {
32	// Local path to a default module template xml file.
33	// The content of the template will be used to generate test modules at runtime.
34	Test_config_template *string `android:"path"`
35
36	// Local paths to extra module template xml files.
37	Extra_test_config_templates []string `android:"path"`
38
39	// Local path to a test plan config xml to be included in the generated plan.
40	Test_plan_include *string `android:"path"`
41}
42
43type CSuiteTest struct {
44	// Java TestHost.
45	java.TestHost
46
47	// C-Suite test properties struct.
48	csuiteTestProperties csuiteTestProperties
49}
50
51func (cSuiteTest *CSuiteTest) buildCopyConfigTemplateCommand(ctx android.ModuleContext, rule *android.RuleBuilder, templatePath string) string {
52	if !strings.HasSuffix(templatePath, xmlFileExtension) {
53		ctx.ModuleErrorf(`Config template path should ends with ` + xmlFileExtension)
54	}
55
56	inputPath := android.PathForModuleSrc(ctx, templatePath)
57	genPath := android.PathForModuleGen(ctx, configDirName, ctx.ModuleName(), inputPath.Rel()+configTemplateFileExtension)
58	rule.Command().Textf("cp").Input(inputPath).Output(genPath)
59	cSuiteTest.AddExtraResource(genPath)
60	return genPath.Rel()
61}
62
63func (cSuiteTest *CSuiteTest) buildCopyExtraConfigTemplatesCommand(ctx android.ModuleContext, rule *android.RuleBuilder) []string {
64	output := make([]string, len(cSuiteTest.csuiteTestProperties.Extra_test_config_templates))
65
66	for idx, templatePath := range cSuiteTest.csuiteTestProperties.Extra_test_config_templates {
67		output[idx] = cSuiteTest.buildCopyConfigTemplateCommand(ctx, rule, templatePath)
68	}
69
70	return output
71}
72
73func (cSuiteTest *CSuiteTest) buildCopyPlanIncludeCommand(ctx android.ModuleContext, rule *android.RuleBuilder) string {
74	if cSuiteTest.csuiteTestProperties.Test_plan_include == nil {
75		return emptyPlanIncludePath
76	}
77	inputPath := android.PathForModuleSrc(ctx, *cSuiteTest.csuiteTestProperties.Test_plan_include)
78	genPath := android.PathForModuleGen(ctx, configDirName, "includes", ctx.ModuleName()+".xml")
79	rule.Command().Textf("cp").Input(inputPath).Output(genPath)
80	cSuiteTest.AddExtraResource(genPath)
81	return strings.Replace(genPath.Rel(), "config/", "", -1)
82}
83
84func (cSuiteTest *CSuiteTest) buildWritePlanConfigRule(ctx android.ModuleContext, configTemplatePath string, extraConfigTemplatePaths []string, planIncludePath string) {
85	planName := ctx.ModuleName()
86	content := strings.Replace(planTemplate, "{planName}", planName, -1)
87	content = strings.Replace(content, "{templatePath}", configTemplatePath, -1)
88	content = strings.Replace(content, "{templateRoot}", android.PathForModuleGen(ctx, configDirName, ctx.ModuleName()).Rel(), -1)
89	content = strings.Replace(content, "{planInclude}", planIncludePath, -1)
90
91	extraTemplateConfigLines := ""
92	for _, extraPath := range extraConfigTemplatePaths {
93		extraTemplateConfigLines += strings.Replace(extraTemplatePathsTemplate, "{templatePath}", extraPath, -1)
94	}
95	content = strings.Replace(content, "{extraTemplatePaths}", extraTemplateConfigLines, -1)
96
97	genPath := android.PathForModuleGen(ctx, configDirName, planName+xmlFileExtension)
98	android.WriteFileRule(ctx, genPath, content)
99	cSuiteTest.AddExtraResource(genPath)
100}
101
102func (cSuiteTest *CSuiteTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
103	rule := android.NewRuleBuilder(pctx, ctx)
104
105	if cSuiteTest.csuiteTestProperties.Test_config_template == nil {
106		ctx.ModuleErrorf(`'test_config_template' is missing.`)
107		return
108	}
109
110	configTemplatePath := cSuiteTest.buildCopyConfigTemplateCommand(ctx, rule, *cSuiteTest.csuiteTestProperties.Test_config_template)
111	extraConfigTemplatePaths := cSuiteTest.buildCopyExtraConfigTemplatesCommand(ctx, rule)
112	planIncludePath := cSuiteTest.buildCopyPlanIncludeCommand(ctx, rule)
113	cSuiteTest.buildWritePlanConfigRule(ctx, configTemplatePath, extraConfigTemplatePaths, planIncludePath)
114
115	rule.Build("CSuite", "generate C-Suite config files")
116	cSuiteTest.TestHost.GenerateAndroidBuildActions(ctx)
117}
118
119func CSuiteTestFactory() android.Module {
120	module := &CSuiteTest{}
121	module.AddProperties(&module.csuiteTestProperties)
122	installable := true
123	autoGenConfig := false
124	java.InitTestHost(&module.TestHost, &installable, []string{"csuite"}, &autoGenConfig)
125
126	java.InitJavaModuleMultiTargets(module, android.HostSupported)
127
128	return module
129}
130
131const (
132	emptyPlanIncludePath        = `empty`
133	configDirName               = `config`
134	configTemplateFileExtension = `.template`
135	xmlFileExtension            = `.xml`
136	extraTemplatePathsTemplate  = `
137          <option name="extra-templates" value="{templatePath}"/>`
138	planTemplate = `<?xml version="1.0" encoding="utf-8"?>
139<!-- Copyright (C) 2020 The Android Open Source Project
140
141     Licensed under the Apache License, Version 2.0 (the "License");
142     you may not use this file except in compliance with the License.
143     You may obtain a copy of the License at
144
145          http://www.apache.org/licenses/LICENSE-2.0
146
147     Unless required by applicable law or agreed to in writing, software
148     distributed under the License is distributed on an "AS IS" BASIS,
149     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
150     See the License for the specific language governing permissions and
151     limitations under the License.
152-->
153<configuration>
154     <!-- Generates module files in the beginning of the test. -->
155     <test class="com.android.csuite.core.ModuleGenerator" />
156     <!-- Cleans the generated module files after the test. -->
157     <target_preparer class="com.android.csuite.core.ModuleGenerator" />
158     <object type="MODULE_TEMPLATE_PROVIDER" class="com.android.csuite.core.ModuleTemplate" >
159        <option name="template-root" value="{templateRoot}" />
160        <option name="default-template" value="{templatePath}" />{extraTemplatePaths}
161    </object>
162
163     <include name="csuite-base" />
164     <include name="{planInclude}" />
165     <option name="plan" value="{planName}" />
166</configuration>
167`
168)
169