blob: 14d78b2b6553413d441ec7447b993ff30e12508f [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 +
Liz Kammerd737d022020-11-16 15:42:51 -080047 "srcs: the path %q contains invalid subpath %q."
Nan Zhangdb0b9a32017-02-27 10:12:13 -080048 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 }
Paul Duffinc60dd802021-03-17 23:01:06 +0000210
211 python_binary_host {
212 name: "bin",
213 pkg_path: "e/",
214 srcs: [
215 "bin.py",
216 ],
217 libs: [
218 "lib2",
219 ],
220 }
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800221 `,
222 ),
223 "dir/c/file1.py": nil,
224 "dir/file1.py": nil,
Paul Duffinc60dd802021-03-17 23:01:06 +0000225 "dir/bin.py": nil,
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800226 },
227 errors: []string{
Paul Duffinc60dd802021-03-17 23:01:06 +0000228 fmt.Sprintf(dupRunfileErrTemplate, "dir/Android.bp:20:6",
229 "bin", "PY3", "a/b/c/file1.py", "bin", "dir/file1.py",
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800230 "lib1", "dir/c/file1.py"),
231 },
232 },
233 {
234 desc: "module for testing dependencies",
235 mockFiles: map[string][]byte{
236 bpFile: []byte(`subdirs = ["dir"]`),
237 filepath.Join("dir", bpFile): []byte(
Nan Zhanga3fc4ba2017-07-20 17:43:37 -0700238 `python_defaults {
239 name: "default_lib",
240 srcs: [
241 "default.py",
242 ],
243 version: {
244 py2: {
245 enabled: true,
246 srcs: [
247 "default_py2.py",
248 ],
249 },
250 py3: {
251 enabled: false,
252 srcs: [
253 "default_py3.py",
254 ],
255 },
256 },
257 }
258
259 python_library_host {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800260 name: "lib5",
261 pkg_path: "a/b/",
262 srcs: [
263 "file1.py",
264 ],
265 version: {
266 py2: {
267 enabled: true,
268 },
269 py3: {
270 enabled: true,
271 },
272 },
273 }
274
275 python_library_host {
276 name: "lib6",
277 pkg_path: "c/d/",
278 srcs: [
279 "file2.py",
280 ],
281 libs: [
282 "lib5",
283 ],
284 }
285
286 python_binary_host {
287 name: "bin",
Nan Zhanga3fc4ba2017-07-20 17:43:37 -0700288 defaults: ["default_lib"],
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800289 pkg_path: "e/",
290 srcs: [
291 "bin.py",
292 ],
293 libs: [
294 "lib5",
295 ],
296 version: {
297 py3: {
298 enabled: true,
299 srcs: [
300 "file4.py",
301 ],
302 libs: [
303 "lib6",
304 ],
305 },
306 },
307 }`,
308 ),
Nan Zhanga3fc4ba2017-07-20 17:43:37 -0700309 filepath.Join("dir", "default.py"): nil,
310 filepath.Join("dir", "default_py2.py"): nil,
311 filepath.Join("dir", "default_py3.py"): nil,
312 filepath.Join("dir", "file1.py"): nil,
313 filepath.Join("dir", "file2.py"): nil,
314 filepath.Join("dir", "bin.py"): nil,
315 filepath.Join("dir", "file4.py"): nil,
Liz Kammerdd849a82020-06-12 16:38:45 -0700316 StubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800317 MAIN_FILE = '%main%'`),
318 },
Nan Zhangd4e641b2017-07-12 12:55:28 -0700319 expectedBinaries: []pyModule{
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800320 {
321 name: "bin",
322 actualVersion: "PY3",
323 pyRunfiles: []string{
Nan Zhangbea09752018-05-31 12:49:33 -0700324 "e/default.py",
325 "e/bin.py",
326 "e/default_py3.py",
327 "e/file4.py",
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800328 },
Nan Zhangb8fa1972017-12-22 16:12:00 -0800329 srcsZip: "@prefix@/.intermediates/dir/bin/PY3/bin.py.srcszip",
Nan Zhang1db85402017-12-18 13:20:23 -0800330 depsSrcsZips: []string{
Nan Zhangb8fa1972017-12-22 16:12:00 -0800331 "@prefix@/.intermediates/dir/lib5/PY3/lib5.py.srcszip",
332 "@prefix@/.intermediates/dir/lib6/PY3/lib6.py.srcszip",
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800333 },
334 },
335 },
336 },
337 }
338)
339
340func TestPythonModule(t *testing.T) {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800341 for _, d := range data {
342 t.Run(d.desc, func(t *testing.T) {
Colin Cross98be1bb2019-12-13 20:41:13 -0800343 config := android.TestConfig(buildDir, nil, "", d.mockFiles)
Colin Crossae8600b2020-10-29 17:09:13 -0700344 ctx := android.NewTestContext(config)
Liz Kammerdd849a82020-06-12 16:38:45 -0700345 ctx.PreDepsMutators(RegisterPythonPreDepsMutators)
Colin Cross4b49b762019-11-22 15:25:03 -0800346 ctx.RegisterModuleType("python_library_host", PythonLibraryHostFactory)
347 ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
348 ctx.RegisterModuleType("python_defaults", defaultsFactory)
Nan Zhanga3fc4ba2017-07-20 17:43:37 -0700349 ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
Colin Crossae8600b2020-10-29 17:09:13 -0700350 ctx.Register()
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800351 _, testErrs := ctx.ParseBlueprintsFiles(bpFile)
Logan Chien42039712018-03-12 16:29:17 +0800352 android.FailIfErrored(t, testErrs)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800353 _, actErrs := ctx.PrepareBuildActions(config)
Paul Duffinc60dd802021-03-17 23:01:06 +0000354 if len(actErrs) > 0 || len(d.errors) > 0 {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800355 testErrs = append(testErrs, expectErrors(t, actErrs, d.errors)...)
356 } else {
357 for _, e := range d.expectedBinaries {
358 testErrs = append(testErrs,
359 expectModule(t, ctx, buildDir, e.name,
360 e.actualVersion,
Nan Zhang1db85402017-12-18 13:20:23 -0800361 e.srcsZip,
362 e.pyRunfiles,
363 e.depsSrcsZips)...)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800364 }
365 }
Logan Chien42039712018-03-12 16:29:17 +0800366 android.FailIfErrored(t, testErrs)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800367 })
368 }
369}
370
371func expectErrors(t *testing.T, actErrs []error, expErrs []string) (testErrs []error) {
372 actErrStrs := []string{}
373 for _, v := range actErrs {
374 actErrStrs = append(actErrStrs, v.Error())
375 }
376 sort.Strings(actErrStrs)
377 if len(actErrStrs) != len(expErrs) {
378 t.Errorf("got (%d) errors, expected (%d) errors!", len(actErrStrs), len(expErrs))
379 for _, v := range actErrStrs {
380 testErrs = append(testErrs, errors.New(v))
381 }
382 } else {
383 sort.Strings(expErrs)
384 for i, v := range actErrStrs {
Liz Kammerd737d022020-11-16 15:42:51 -0800385 if !strings.Contains(v, expErrs[i]) {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800386 testErrs = append(testErrs, errors.New(v))
387 }
388 }
389 }
390
391 return
392}
393
Nan Zhang1db85402017-12-18 13:20:23 -0800394func expectModule(t *testing.T, ctx *android.TestContext, buildDir, name, variant, expectedSrcsZip string,
395 expectedPyRunfiles, expectedDepsSrcsZips []string) (testErrs []error) {
Colin Crosscec81712017-07-13 14:43:27 -0700396 module := ctx.ModuleForTests(name, variant)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800397
Nan Zhangd4e641b2017-07-12 12:55:28 -0700398 base, baseOk := module.Module().(*Module)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800399 if !baseOk {
400 t.Fatalf("%s is not Python module!", name)
401 }
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800402
Nan Zhang1db85402017-12-18 13:20:23 -0800403 actualPyRunfiles := []string{}
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800404 for _, path := range base.srcsPathMappings {
Nan Zhang1db85402017-12-18 13:20:23 -0800405 actualPyRunfiles = append(actualPyRunfiles, path.dest)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800406 }
407
Nan Zhang1db85402017-12-18 13:20:23 -0800408 if !reflect.DeepEqual(actualPyRunfiles, expectedPyRunfiles) {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800409 testErrs = append(testErrs, errors.New(fmt.Sprintf(
Liz Kammer7e93e5b2020-10-30 15:44:09 -0700410 `binary "%s" variant "%s" has unexpected pyRunfiles: %q! (expected: %q)`,
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800411 base.Name(),
Nan Zhangd4e641b2017-07-12 12:55:28 -0700412 base.properties.Actual_version,
Liz Kammer7e93e5b2020-10-30 15:44:09 -0700413 actualPyRunfiles,
414 expectedPyRunfiles)))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800415 }
416
Nan Zhang1db85402017-12-18 13:20:23 -0800417 if base.srcsZip.String() != strings.Replace(expectedSrcsZip, "@prefix@", buildDir, 1) {
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 srcsZip: %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.srcsZip)))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800423 }
424
Nan Zhang1db85402017-12-18 13:20:23 -0800425 for i, _ := range expectedDepsSrcsZips {
426 expectedDepsSrcsZips[i] = strings.Replace(expectedDepsSrcsZips[i], "@prefix@", buildDir, 1)
427 }
428 if !reflect.DeepEqual(base.depsSrcsZips.Strings(), expectedDepsSrcsZips) {
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800429 testErrs = append(testErrs, errors.New(fmt.Sprintf(
Nan Zhang1db85402017-12-18 13:20:23 -0800430 `binary "%s" variant "%s" has unexpected depsSrcsZips: %q!`,
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800431 base.Name(),
Nan Zhangd4e641b2017-07-12 12:55:28 -0700432 base.properties.Actual_version,
Nan Zhang1db85402017-12-18 13:20:23 -0800433 base.depsSrcsZips)))
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800434 }
435
436 return
437}
438
Colin Cross98be1bb2019-12-13 20:41:13 -0800439func setUp() {
440 var err error
441 buildDir, err = ioutil.TempDir("", "soong_python_test")
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800442 if err != nil {
Colin Cross98be1bb2019-12-13 20:41:13 -0800443 panic(err)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800444 }
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800445}
446
Colin Cross98be1bb2019-12-13 20:41:13 -0800447func tearDown() {
Nan Zhangaac67d32017-06-12 10:49:42 -0700448 os.RemoveAll(buildDir)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800449}
Colin Cross98be1bb2019-12-13 20:41:13 -0800450
451func TestMain(m *testing.M) {
452 run := func() int {
453 setUp()
454 defer tearDown()
455
456 return m.Run()
457 }
458
459 os.Exit(run())
460}