blob: 1245ca1842b97296e4c2ded686a13b041b929828 [file] [log] [blame]
Nan Zhangdb0b9a32017-02-27 10:12:13 -08001// Copyright 2017 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 python
16
17import (
18 "errors"
19 "fmt"
20 "io/ioutil"
21 "os"
22 "path/filepath"
23 "reflect"
24 "sort"
25 "strings"
26 "testing"
27
28 "android/soong/android"
Nan Zhangdb0b9a32017-02-27 10:12:13 -080029)
30
Colin Cross98be1bb2019-12-13 20:41:13 -080031var buildDir string
32
Nan Zhangd4e641b2017-07-12 12:55:28 -070033type pyModule struct {
Nan Zhang1db85402017-12-18 13:20:23 -080034 name string
35 actualVersion string
36 pyRunfiles []string
37 srcsZip string
38 depsSrcsZips []string
Nan Zhangdb0b9a32017-02-27 10:12:13 -080039}
40
41var (
42 buildNamePrefix = "soong_python_test"
43 moduleVariantErrTemplate = "%s: module %q variant %q: "
44 pkgPathErrTemplate = moduleVariantErrTemplate +
Nan Zhangd4e641b2017-07-12 12:55:28 -070045 "pkg_path: %q must be a relative path contained in par file."
Nan Zhangdb0b9a32017-02-27 10:12:13 -080046 badIdentifierErrTemplate = moduleVariantErrTemplate +
47 "srcs: the path %q contains invalid token %q."
48 dupRunfileErrTemplate = moduleVariantErrTemplate +
Nan Zhangbea09752018-05-31 12:49:33 -070049 "found two files to be placed at the same location within zip %q." +
Nan Zhangdb0b9a32017-02-27 10:12:13 -080050 " First file: in module %s at path %q." +
51 " Second file: in module %s at path %q."
52 noSrcFileErr = moduleVariantErrTemplate + "doesn't have any source files!"
Nan Zhangb8fa1972017-12-22 16:12:00 -080053 badSrcFileExtErr = moduleVariantErrTemplate + "srcs: found non (.py|.proto) file: %q!"
54 badDataFileExtErr = moduleVariantErrTemplate + "data: found (.py|.proto) file: %q!"
Colin Cross98be1bb2019-12-13 20:41:13 -080055 bpFile = "Android.bp"
Nan Zhangdb0b9a32017-02-27 10:12:13 -080056
57 data = []struct {
58 desc string
59 mockFiles map[string][]byte
60
61 errors []string
Nan Zhangd4e641b2017-07-12 12:55:28 -070062 expectedBinaries []pyModule
Nan Zhangdb0b9a32017-02-27 10:12:13 -080063 }{
64 {
65 desc: "module without any src files",
66 mockFiles: map[string][]byte{
67 bpFile: []byte(`subdirs = ["dir"]`),
68 filepath.Join("dir", bpFile): []byte(
69 `python_library_host {
70 name: "lib1",
71 }`,
72 ),
73 },
74 errors: []string{
75 fmt.Sprintf(noSrcFileErr,
Colin Cross98be1bb2019-12-13 20:41:13 -080076 "dir/Android.bp:1:1", "lib1", "PY3"),
Nan Zhangdb0b9a32017-02-27 10:12:13 -080077 },
78 },
79 {
80 desc: "module with bad src file ext",
81 mockFiles: map[string][]byte{
82 bpFile: []byte(`subdirs = ["dir"]`),
83 filepath.Join("dir", bpFile): []byte(
84 `python_library_host {
85 name: "lib1",
86 srcs: [
87 "file1.exe",
88 ],
89 }`,
90 ),
91 "dir/file1.exe": nil,
92 },
93 errors: []string{
94 fmt.Sprintf(badSrcFileExtErr,
Colin Cross98be1bb2019-12-13 20:41:13 -080095 "dir/Android.bp:3:11", "lib1", "PY3", "dir/file1.exe"),
Nan Zhangdb0b9a32017-02-27 10:12:13 -080096 },
97 },
98 {
99 desc: "module with bad data file ext",
100 mockFiles: map[string][]byte{
101 bpFile: []byte(`subdirs = ["dir"]`),
102 filepath.Join("dir", bpFile): []byte(
103 `python_library_host {
104 name: "lib1",
105 srcs: [
106 "file1.py",
107 ],
108 data: [
109 "file2.py",
110 ],
111 }`,
112 ),
113 "dir/file1.py": nil,
114 "dir/file2.py": nil,
115 },
116 errors: []string{
117 fmt.Sprintf(badDataFileExtErr,
Colin Cross98be1bb2019-12-13 20:41:13 -0800118 "dir/Android.bp:6:11", "lib1", "PY3", "dir/file2.py"),
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800119 },
120 },
121 {
122 desc: "module with bad pkg_path format",
123 mockFiles: map[string][]byte{
124 bpFile: []byte(`subdirs = ["dir"]`),
125 filepath.Join("dir", bpFile): []byte(
126 `python_library_host {
127 name: "lib1",
128 pkg_path: "a/c/../../",
129 srcs: [
130 "file1.py",
131 ],
132 }
133
134 python_library_host {
135 name: "lib2",
136 pkg_path: "a/c/../../../",
137 srcs: [
138 "file1.py",
139 ],
140 }
141
142 python_library_host {
143 name: "lib3",
144 pkg_path: "/a/c/../../",
145 srcs: [
146 "file1.py",
147 ],
148 }`,
149 ),
150 "dir/file1.py": nil,
151 },
152 errors: []string{
153 fmt.Sprintf(pkgPathErrTemplate,
Colin Cross98be1bb2019-12-13 20:41:13 -0800154 "dir/Android.bp:11:15", "lib2", "PY3", "a/c/../../../"),
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800155 fmt.Sprintf(pkgPathErrTemplate,
Colin Cross98be1bb2019-12-13 20:41:13 -0800156 "dir/Android.bp:19:15", "lib3", "PY3", "/a/c/../../"),
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800157 },
158 },
159 {
160 desc: "module with bad runfile src path format",
161 mockFiles: map[string][]byte{
162 bpFile: []byte(`subdirs = ["dir"]`),
163 filepath.Join("dir", bpFile): []byte(
164 `python_library_host {
165 name: "lib1",
166 pkg_path: "a/b/c/",
167 srcs: [
168 ".file1.py",
169 "123/file1.py",
170 "-e/f/file1.py",
171 ],
172 }`,
173 ),
174 "dir/.file1.py": nil,
175 "dir/123/file1.py": nil,
176 "dir/-e/f/file1.py": nil,
177 },
178 errors: []string{
Colin Cross98be1bb2019-12-13 20:41:13 -0800179 fmt.Sprintf(badIdentifierErrTemplate, "dir/Android.bp:4:11",
Nan Zhangbea09752018-05-31 12:49:33 -0700180 "lib1", "PY3", "a/b/c/-e/f/file1.py", "-e"),
Colin Cross98be1bb2019-12-13 20:41:13 -0800181 fmt.Sprintf(badIdentifierErrTemplate, "dir/Android.bp:4:11",
Nan Zhangbea09752018-05-31 12:49:33 -0700182 "lib1", "PY3", "a/b/c/.file1.py", ".file1"),
Colin Cross98be1bb2019-12-13 20:41:13 -0800183 fmt.Sprintf(badIdentifierErrTemplate, "dir/Android.bp:4:11",
Nan Zhangbea09752018-05-31 12:49:33 -0700184 "lib1", "PY3", "a/b/c/123/file1.py", "123"),
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800185 },
186 },
187 {
188 desc: "module with duplicate runfile path",
189 mockFiles: map[string][]byte{
190 bpFile: []byte(`subdirs = ["dir"]`),
191 filepath.Join("dir", bpFile): []byte(
192 `python_library_host {
193 name: "lib1",
194 pkg_path: "a/b/",
195 srcs: [
196 "c/file1.py",
197 ],
198 }
199
200 python_library_host {
201 name: "lib2",
202 pkg_path: "a/b/c/",
203 srcs: [
204 "file1.py",
205 ],
206 libs: [
207 "lib1",
208 ],
209 }
210 `,
211 ),
212 "dir/c/file1.py": nil,
213 "dir/file1.py": nil,
214 },
215 errors: []string{
Colin Cross98be1bb2019-12-13 20:41:13 -0800216 fmt.Sprintf(dupRunfileErrTemplate, "dir/Android.bp:9:6",
Nan Zhangbea09752018-05-31 12:49:33 -0700217 "lib2", "PY3", "a/b/c/file1.py", "lib2", "dir/file1.py",
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800218 "lib1", "dir/c/file1.py"),
219 },
220 },
221 {
222 desc: "module for testing dependencies",
223 mockFiles: map[string][]byte{
224 bpFile: []byte(`subdirs = ["dir"]`),
225 filepath.Join("dir", bpFile): []byte(
Nan Zhanga3fc4ba2017-07-20 17:43:37 -0700226 `python_defaults {
227 name: "default_lib",
228 srcs: [
229 "default.py",
230 ],
231 version: {
232 py2: {
233 enabled: true,
234 srcs: [
235 "default_py2.py",
236 ],
237 },
238 py3: {
239 enabled: false,
240 srcs: [
241 "default_py3.py",
242 ],
243 },
244 },
245 }
246
247 python_library_host {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800248 name: "lib5",
249 pkg_path: "a/b/",
250 srcs: [
251 "file1.py",
252 ],
253 version: {
254 py2: {
255 enabled: true,
256 },
257 py3: {
258 enabled: true,
259 },
260 },
261 }
262
263 python_library_host {
264 name: "lib6",
265 pkg_path: "c/d/",
266 srcs: [
267 "file2.py",
268 ],
269 libs: [
270 "lib5",
271 ],
272 }
273
274 python_binary_host {
275 name: "bin",
Nan Zhanga3fc4ba2017-07-20 17:43:37 -0700276 defaults: ["default_lib"],
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800277 pkg_path: "e/",
278 srcs: [
279 "bin.py",
280 ],
281 libs: [
282 "lib5",
283 ],
284 version: {
285 py3: {
286 enabled: true,
287 srcs: [
288 "file4.py",
289 ],
290 libs: [
291 "lib6",
292 ],
293 },
294 },
295 }`,
296 ),
Nan Zhanga3fc4ba2017-07-20 17:43:37 -0700297 filepath.Join("dir", "default.py"): nil,
298 filepath.Join("dir", "default_py2.py"): nil,
299 filepath.Join("dir", "default_py3.py"): nil,
300 filepath.Join("dir", "file1.py"): nil,
301 filepath.Join("dir", "file2.py"): nil,
302 filepath.Join("dir", "bin.py"): nil,
303 filepath.Join("dir", "file4.py"): nil,
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800304 stubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
305 MAIN_FILE = '%main%'`),
306 },
Nan Zhangd4e641b2017-07-12 12:55:28 -0700307 expectedBinaries: []pyModule{
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800308 {
309 name: "bin",
310 actualVersion: "PY3",
311 pyRunfiles: []string{
Nan Zhangbea09752018-05-31 12:49:33 -0700312 "e/default.py",
313 "e/bin.py",
314 "e/default_py3.py",
315 "e/file4.py",
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800316 },
Nan Zhangb8fa1972017-12-22 16:12:00 -0800317 srcsZip: "@prefix@/.intermediates/dir/bin/PY3/bin.py.srcszip",
Nan Zhang1db85402017-12-18 13:20:23 -0800318 depsSrcsZips: []string{
Nan Zhangb8fa1972017-12-22 16:12:00 -0800319 "@prefix@/.intermediates/dir/lib5/PY3/lib5.py.srcszip",
320 "@prefix@/.intermediates/dir/lib6/PY3/lib6.py.srcszip",
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800321 },
322 },
323 },
324 },
325 }
326)
327
328func TestPythonModule(t *testing.T) {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800329 for _, d := range data {
330 t.Run(d.desc, func(t *testing.T) {
Colin Cross98be1bb2019-12-13 20:41:13 -0800331 config := android.TestConfig(buildDir, nil, "", d.mockFiles)
Colin Crosscec81712017-07-13 14:43:27 -0700332 ctx := android.NewTestContext()
333 ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
334 ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
335 })
Colin Cross4b49b762019-11-22 15:25:03 -0800336 ctx.RegisterModuleType("python_library_host", PythonLibraryHostFactory)
337 ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
338 ctx.RegisterModuleType("python_defaults", defaultsFactory)
Nan Zhanga3fc4ba2017-07-20 17:43:37 -0700339 ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
Colin Cross98be1bb2019-12-13 20:41:13 -0800340 ctx.Register(config)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800341 _, testErrs := ctx.ParseBlueprintsFiles(bpFile)
Logan Chien42039712018-03-12 16:29:17 +0800342 android.FailIfErrored(t, testErrs)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800343 _, actErrs := ctx.PrepareBuildActions(config)
344 if len(actErrs) > 0 {
345 testErrs = append(testErrs, expectErrors(t, actErrs, d.errors)...)
346 } else {
347 for _, e := range d.expectedBinaries {
348 testErrs = append(testErrs,
349 expectModule(t, ctx, buildDir, e.name,
350 e.actualVersion,
Nan Zhang1db85402017-12-18 13:20:23 -0800351 e.srcsZip,
352 e.pyRunfiles,
353 e.depsSrcsZips)...)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800354 }
355 }
Logan Chien42039712018-03-12 16:29:17 +0800356 android.FailIfErrored(t, testErrs)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800357 })
358 }
359}
360
361func expectErrors(t *testing.T, actErrs []error, expErrs []string) (testErrs []error) {
362 actErrStrs := []string{}
363 for _, v := range actErrs {
364 actErrStrs = append(actErrStrs, v.Error())
365 }
366 sort.Strings(actErrStrs)
367 if len(actErrStrs) != len(expErrs) {
368 t.Errorf("got (%d) errors, expected (%d) errors!", len(actErrStrs), len(expErrs))
369 for _, v := range actErrStrs {
370 testErrs = append(testErrs, errors.New(v))
371 }
372 } else {
373 sort.Strings(expErrs)
374 for i, v := range actErrStrs {
375 if v != expErrs[i] {
376 testErrs = append(testErrs, errors.New(v))
377 }
378 }
379 }
380
381 return
382}
383
Nan Zhang1db85402017-12-18 13:20:23 -0800384func expectModule(t *testing.T, ctx *android.TestContext, buildDir, name, variant, expectedSrcsZip string,
385 expectedPyRunfiles, expectedDepsSrcsZips []string) (testErrs []error) {
Colin Crosscec81712017-07-13 14:43:27 -0700386 module := ctx.ModuleForTests(name, variant)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800387
Nan Zhangd4e641b2017-07-12 12:55:28 -0700388 base, baseOk := module.Module().(*Module)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800389 if !baseOk {
390 t.Fatalf("%s is not Python module!", name)
391 }
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800392
Nan Zhang1db85402017-12-18 13:20:23 -0800393 actualPyRunfiles := []string{}
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800394 for _, path := range base.srcsPathMappings {
Nan Zhang1db85402017-12-18 13:20:23 -0800395 actualPyRunfiles = append(actualPyRunfiles, path.dest)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800396 }
397
Nan Zhang1db85402017-12-18 13:20:23 -0800398 if !reflect.DeepEqual(actualPyRunfiles, expectedPyRunfiles) {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800399 testErrs = append(testErrs, errors.New(fmt.Sprintf(
400 `binary "%s" variant "%s" has unexpected pyRunfiles: %q!`,
401 base.Name(),
Nan Zhangd4e641b2017-07-12 12:55:28 -0700402 base.properties.Actual_version,
Nan Zhang1db85402017-12-18 13:20:23 -0800403 actualPyRunfiles)))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800404 }
405
Nan Zhang1db85402017-12-18 13:20:23 -0800406 if base.srcsZip.String() != strings.Replace(expectedSrcsZip, "@prefix@", buildDir, 1) {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800407 testErrs = append(testErrs, errors.New(fmt.Sprintf(
Nan Zhang1db85402017-12-18 13:20:23 -0800408 `binary "%s" variant "%s" has unexpected srcsZip: %q!`,
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800409 base.Name(),
Nan Zhangd4e641b2017-07-12 12:55:28 -0700410 base.properties.Actual_version,
Nan Zhang1db85402017-12-18 13:20:23 -0800411 base.srcsZip)))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800412 }
413
Nan Zhang1db85402017-12-18 13:20:23 -0800414 for i, _ := range expectedDepsSrcsZips {
415 expectedDepsSrcsZips[i] = strings.Replace(expectedDepsSrcsZips[i], "@prefix@", buildDir, 1)
416 }
417 if !reflect.DeepEqual(base.depsSrcsZips.Strings(), expectedDepsSrcsZips) {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800418 testErrs = append(testErrs, errors.New(fmt.Sprintf(
Nan Zhang1db85402017-12-18 13:20:23 -0800419 `binary "%s" variant "%s" has unexpected depsSrcsZips: %q!`,
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800420 base.Name(),
Nan Zhangd4e641b2017-07-12 12:55:28 -0700421 base.properties.Actual_version,
Nan Zhang1db85402017-12-18 13:20:23 -0800422 base.depsSrcsZips)))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800423 }
424
425 return
426}
427
Colin Cross98be1bb2019-12-13 20:41:13 -0800428func setUp() {
429 var err error
430 buildDir, err = ioutil.TempDir("", "soong_python_test")
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800431 if err != nil {
Colin Cross98be1bb2019-12-13 20:41:13 -0800432 panic(err)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800433 }
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800434}
435
Colin Cross98be1bb2019-12-13 20:41:13 -0800436func tearDown() {
Nan Zhangaac67d32017-06-12 10:49:42 -0700437 os.RemoveAll(buildDir)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800438}
Colin Cross98be1bb2019-12-13 20:41:13 -0800439
440func TestMain(m *testing.M) {
441 run := func() int {
442 setUp()
443 defer tearDown()
444
445 return m.Run()
446 }
447
448 os.Exit(run())
449}