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 android
16
17import (
18	"path/filepath"
19	"strings"
20)
21
22func init() {
23	RegisterParallelSingletonType("testsuites", testSuiteFilesFactory)
24}
25
26func testSuiteFilesFactory() Singleton {
27	return &testSuiteFiles{}
28}
29
30type testSuiteFiles struct {
31	robolectric []Path
32	ravenwood   []Path
33}
34
35type TestSuiteModule interface {
36	Module
37	TestSuites() []string
38}
39
40func (t *testSuiteFiles) GenerateBuildActions(ctx SingletonContext) {
41	files := make(map[string]map[string]InstallPaths)
42
43	ctx.VisitAllModules(func(m Module) {
44		if tsm, ok := m.(TestSuiteModule); ok {
45			for _, testSuite := range tsm.TestSuites() {
46				if files[testSuite] == nil {
47					files[testSuite] = make(map[string]InstallPaths)
48				}
49				name := ctx.ModuleName(m)
50				files[testSuite][name] = append(files[testSuite][name], tsm.FilesToInstall()...)
51			}
52		}
53	})
54
55	t.robolectric = robolectricTestSuite(ctx, files["robolectric-tests"])
56	ctx.Phony("robolectric-tests", t.robolectric...)
57
58	t.ravenwood = ravenwoodTestSuite(ctx, files["ravenwood-tests"])
59	ctx.Phony("ravenwood-tests", t.ravenwood...)
60}
61
62func (t *testSuiteFiles) MakeVars(ctx MakeVarsContext) {
63	ctx.DistForGoal("robolectric-tests", t.robolectric...)
64	ctx.DistForGoal("ravenwood-tests", t.ravenwood...)
65}
66
67func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) []Path {
68	var installedPaths InstallPaths
69	for _, module := range SortedKeys(files) {
70		installedPaths = append(installedPaths, files[module]...)
71	}
72
73	outputFile := pathForPackaging(ctx, "robolectric-tests.zip")
74	rule := NewRuleBuilder(pctx, ctx)
75	rule.Command().BuiltTool("soong_zip").
76		FlagWithOutput("-o ", outputFile).
77		FlagWithArg("-P ", "host/testcases").
78		FlagWithArg("-C ", pathForTestCases(ctx).String()).
79		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()).
80		Flag("-sha256") // necessary to save cas_uploader's time
81
82	testList := buildTestList(ctx, "robolectric-tests_list", installedPaths)
83	testListZipOutputFile := pathForPackaging(ctx, "robolectric-tests_list.zip")
84
85	rule.Command().BuiltTool("soong_zip").
86		FlagWithOutput("-o ", testListZipOutputFile).
87		FlagWithArg("-C ", pathForPackaging(ctx).String()).
88		FlagWithInput("-f ", testList).
89		Flag("-sha256")
90
91	rule.Build("robolectric_tests_zip", "robolectric-tests.zip")
92
93	return []Path{outputFile, testListZipOutputFile}
94}
95
96func ravenwoodTestSuite(ctx SingletonContext, files map[string]InstallPaths) []Path {
97	var installedPaths InstallPaths
98	for _, module := range SortedKeys(files) {
99		installedPaths = append(installedPaths, files[module]...)
100	}
101
102	outputFile := pathForPackaging(ctx, "ravenwood-tests.zip")
103	rule := NewRuleBuilder(pctx, ctx)
104	rule.Command().BuiltTool("soong_zip").
105		FlagWithOutput("-o ", outputFile).
106		FlagWithArg("-P ", "host/testcases").
107		FlagWithArg("-C ", pathForTestCases(ctx).String()).
108		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()).
109		Flag("-sha256") // necessary to save cas_uploader's time
110
111	testList := buildTestList(ctx, "ravenwood-tests_list", installedPaths)
112	testListZipOutputFile := pathForPackaging(ctx, "ravenwood-tests_list.zip")
113
114	rule.Command().BuiltTool("soong_zip").
115		FlagWithOutput("-o ", testListZipOutputFile).
116		FlagWithArg("-C ", pathForPackaging(ctx).String()).
117		FlagWithInput("-f ", testList).
118		Flag("-sha256")
119
120	rule.Build("ravenwood_tests_zip", "ravenwood-tests.zip")
121
122	return []Path{outputFile, testListZipOutputFile}
123}
124
125func buildTestList(ctx SingletonContext, listFile string, installedPaths InstallPaths) Path {
126	buf := &strings.Builder{}
127	for _, p := range installedPaths {
128		if p.Ext() != ".config" {
129			continue
130		}
131		pc, err := toTestListPath(p.String(), pathForTestCases(ctx).String(), "host/testcases")
132		if err != nil {
133			ctx.Errorf("Failed to convert path: %s, %v", p.String(), err)
134			continue
135		}
136		buf.WriteString(pc)
137		buf.WriteString("\n")
138	}
139	outputFile := pathForPackaging(ctx, listFile)
140	WriteFileRuleVerbatim(ctx, outputFile, buf.String())
141	return outputFile
142}
143
144func toTestListPath(path, relativeRoot, prefix string) (string, error) {
145	dest, err := filepath.Rel(relativeRoot, path)
146	if err != nil {
147		return "", err
148	}
149	return filepath.Join(prefix, dest), nil
150}
151
152func pathForPackaging(ctx PathContext, pathComponents ...string) OutputPath {
153	pathComponents = append([]string{"packaging"}, pathComponents...)
154	return PathForOutput(ctx, pathComponents...)
155}
156
157func pathForTestCases(ctx PathContext) InstallPath {
158	return pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases")
159}
160