config_test.go 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241
  1. // 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. package build
  15. import (
  16. "bytes"
  17. "context"
  18. "fmt"
  19. "io/ioutil"
  20. "os"
  21. "path/filepath"
  22. "reflect"
  23. "strings"
  24. "testing"
  25. "android/soong/ui/logger"
  26. smpb "android/soong/ui/metrics/metrics_proto"
  27. "android/soong/ui/status"
  28. "google.golang.org/protobuf/encoding/prototext"
  29. "google.golang.org/protobuf/proto"
  30. )
  31. func testContext() Context {
  32. return Context{&ContextImpl{
  33. Context: context.Background(),
  34. Logger: logger.New(&bytes.Buffer{}),
  35. Writer: &bytes.Buffer{},
  36. Status: &status.Status{},
  37. }}
  38. }
  39. func TestConfigParseArgsJK(t *testing.T) {
  40. ctx := testContext()
  41. testCases := []struct {
  42. args []string
  43. parallel int
  44. keepGoing int
  45. remaining []string
  46. }{
  47. {nil, -1, -1, nil},
  48. {[]string{"-j"}, -1, -1, nil},
  49. {[]string{"-j1"}, 1, -1, nil},
  50. {[]string{"-j1234"}, 1234, -1, nil},
  51. {[]string{"-j", "1"}, 1, -1, nil},
  52. {[]string{"-j", "1234"}, 1234, -1, nil},
  53. {[]string{"-j", "1234", "abc"}, 1234, -1, []string{"abc"}},
  54. {[]string{"-j", "abc"}, -1, -1, []string{"abc"}},
  55. {[]string{"-j", "1abc"}, -1, -1, []string{"1abc"}},
  56. {[]string{"-k"}, -1, 0, nil},
  57. {[]string{"-k0"}, -1, 0, nil},
  58. {[]string{"-k1"}, -1, 1, nil},
  59. {[]string{"-k1234"}, -1, 1234, nil},
  60. {[]string{"-k", "0"}, -1, 0, nil},
  61. {[]string{"-k", "1"}, -1, 1, nil},
  62. {[]string{"-k", "1234"}, -1, 1234, nil},
  63. {[]string{"-k", "1234", "abc"}, -1, 1234, []string{"abc"}},
  64. {[]string{"-k", "abc"}, -1, 0, []string{"abc"}},
  65. {[]string{"-k", "1abc"}, -1, 0, []string{"1abc"}},
  66. // TODO: These are supported in Make, should we support them?
  67. //{[]string{"-kj"}, -1, 0},
  68. //{[]string{"-kj8"}, 8, 0},
  69. // -jk is not valid in Make
  70. }
  71. for _, tc := range testCases {
  72. t.Run(strings.Join(tc.args, " "), func(t *testing.T) {
  73. defer logger.Recover(func(err error) {
  74. t.Fatal(err)
  75. })
  76. env := Environment([]string{})
  77. c := &configImpl{
  78. environ: &env,
  79. parallel: -1,
  80. keepGoing: -1,
  81. }
  82. c.parseArgs(ctx, tc.args)
  83. if c.parallel != tc.parallel {
  84. t.Errorf("for %q, parallel:\nwant: %d\n got: %d\n",
  85. strings.Join(tc.args, " "),
  86. tc.parallel, c.parallel)
  87. }
  88. if c.keepGoing != tc.keepGoing {
  89. t.Errorf("for %q, keep going:\nwant: %d\n got: %d\n",
  90. strings.Join(tc.args, " "),
  91. tc.keepGoing, c.keepGoing)
  92. }
  93. if !reflect.DeepEqual(c.arguments, tc.remaining) {
  94. t.Errorf("for %q, remaining arguments:\nwant: %q\n got: %q\n",
  95. strings.Join(tc.args, " "),
  96. tc.remaining, c.arguments)
  97. }
  98. })
  99. }
  100. }
  101. func TestConfigParseArgsVars(t *testing.T) {
  102. ctx := testContext()
  103. testCases := []struct {
  104. env []string
  105. args []string
  106. expectedEnv []string
  107. remaining []string
  108. }{
  109. {},
  110. {
  111. env: []string{"A=bc"},
  112. expectedEnv: []string{"A=bc"},
  113. },
  114. {
  115. args: []string{"abc"},
  116. remaining: []string{"abc"},
  117. },
  118. {
  119. args: []string{"A=bc"},
  120. expectedEnv: []string{"A=bc"},
  121. },
  122. {
  123. env: []string{"A=a"},
  124. args: []string{"A=bc"},
  125. expectedEnv: []string{"A=bc"},
  126. },
  127. {
  128. env: []string{"A=a"},
  129. args: []string{"A=", "=b"},
  130. expectedEnv: []string{"A="},
  131. remaining: []string{"=b"},
  132. },
  133. }
  134. for _, tc := range testCases {
  135. t.Run(strings.Join(tc.args, " "), func(t *testing.T) {
  136. defer logger.Recover(func(err error) {
  137. t.Fatal(err)
  138. })
  139. e := Environment(tc.env)
  140. c := &configImpl{
  141. environ: &e,
  142. }
  143. c.parseArgs(ctx, tc.args)
  144. if !reflect.DeepEqual([]string(*c.environ), tc.expectedEnv) {
  145. t.Errorf("for env=%q args=%q, environment:\nwant: %q\n got: %q\n",
  146. tc.env, tc.args,
  147. tc.expectedEnv, []string(*c.environ))
  148. }
  149. if !reflect.DeepEqual(c.arguments, tc.remaining) {
  150. t.Errorf("for env=%q args=%q, remaining arguments:\nwant: %q\n got: %q\n",
  151. tc.env, tc.args,
  152. tc.remaining, c.arguments)
  153. }
  154. })
  155. }
  156. }
  157. func TestConfigCheckTopDir(t *testing.T) {
  158. ctx := testContext()
  159. buildRootDir := filepath.Dir(srcDirFileCheck)
  160. expectedErrStr := fmt.Sprintf("Current working directory must be the source tree. %q not found.", srcDirFileCheck)
  161. tests := []struct {
  162. // ********* Setup *********
  163. // Test description.
  164. description string
  165. // ********* Action *********
  166. // If set to true, the build root file is created.
  167. rootBuildFile bool
  168. // The current path where Soong is being executed.
  169. path string
  170. // ********* Validation *********
  171. // Expecting error and validate the error string against expectedErrStr.
  172. wantErr bool
  173. }{{
  174. description: "current directory is the root source tree",
  175. rootBuildFile: true,
  176. path: ".",
  177. wantErr: false,
  178. }, {
  179. description: "one level deep in the source tree",
  180. rootBuildFile: true,
  181. path: "1",
  182. wantErr: true,
  183. }, {
  184. description: "very deep in the source tree",
  185. rootBuildFile: true,
  186. path: "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/7",
  187. wantErr: true,
  188. }, {
  189. description: "outside of source tree",
  190. rootBuildFile: false,
  191. path: "1/2/3/4/5",
  192. wantErr: true,
  193. }}
  194. for _, tt := range tests {
  195. t.Run(tt.description, func(t *testing.T) {
  196. defer logger.Recover(func(err error) {
  197. if !tt.wantErr {
  198. t.Fatalf("Got unexpected error: %v", err)
  199. }
  200. if expectedErrStr != err.Error() {
  201. t.Fatalf("expected %s, got %s", expectedErrStr, err.Error())
  202. }
  203. })
  204. // Create the root source tree.
  205. rootDir, err := ioutil.TempDir("", "")
  206. if err != nil {
  207. t.Fatal(err)
  208. }
  209. defer os.RemoveAll(rootDir)
  210. // Create the build root file. This is to test if topDir returns an error if the build root
  211. // file does not exist.
  212. if tt.rootBuildFile {
  213. dir := filepath.Join(rootDir, buildRootDir)
  214. if err := os.MkdirAll(dir, 0755); err != nil {
  215. t.Errorf("failed to create %s directory: %v", dir, err)
  216. }
  217. f := filepath.Join(rootDir, srcDirFileCheck)
  218. if err := ioutil.WriteFile(f, []byte{}, 0644); err != nil {
  219. t.Errorf("failed to create file %s: %v", f, err)
  220. }
  221. }
  222. // Next block of code is to set the current directory.
  223. dir := rootDir
  224. if tt.path != "" {
  225. dir = filepath.Join(dir, tt.path)
  226. if err := os.MkdirAll(dir, 0755); err != nil {
  227. t.Errorf("failed to create %s directory: %v", dir, err)
  228. }
  229. }
  230. curDir, err := os.Getwd()
  231. if err != nil {
  232. t.Fatalf("failed to get the current directory: %v", err)
  233. }
  234. defer func() { os.Chdir(curDir) }()
  235. if err := os.Chdir(dir); err != nil {
  236. t.Fatalf("failed to change directory to %s: %v", dir, err)
  237. }
  238. checkTopDir(ctx)
  239. })
  240. }
  241. }
  242. func TestConfigConvertToTarget(t *testing.T) {
  243. tests := []struct {
  244. // ********* Setup *********
  245. // Test description.
  246. description string
  247. // ********* Action *********
  248. // The current directory where Soong is being executed.
  249. dir string
  250. // The current prefix string to be pre-appended to the target.
  251. prefix string
  252. // ********* Validation *********
  253. // The expected target to be invoked in ninja.
  254. expectedTarget string
  255. }{{
  256. description: "one level directory in source tree",
  257. dir: "test1",
  258. prefix: "MODULES-IN-",
  259. expectedTarget: "MODULES-IN-test1",
  260. }, {
  261. description: "multiple level directories in source tree",
  262. dir: "test1/test2/test3/test4",
  263. prefix: "GET-INSTALL-PATH-IN-",
  264. expectedTarget: "GET-INSTALL-PATH-IN-test1-test2-test3-test4",
  265. }}
  266. for _, tt := range tests {
  267. t.Run(tt.description, func(t *testing.T) {
  268. target := convertToTarget(tt.dir, tt.prefix)
  269. if target != tt.expectedTarget {
  270. t.Errorf("expected %s, got %s for target", tt.expectedTarget, target)
  271. }
  272. })
  273. }
  274. }
  275. func setTop(t *testing.T, dir string) func() {
  276. curDir, err := os.Getwd()
  277. if err != nil {
  278. t.Fatalf("failed to get current directory: %v", err)
  279. }
  280. if err := os.Chdir(dir); err != nil {
  281. t.Fatalf("failed to change directory to top dir %s: %v", dir, err)
  282. }
  283. return func() { os.Chdir(curDir) }
  284. }
  285. func createBuildFiles(t *testing.T, topDir string, buildFiles []string) {
  286. for _, buildFile := range buildFiles {
  287. buildFile = filepath.Join(topDir, buildFile)
  288. if err := ioutil.WriteFile(buildFile, []byte{}, 0644); err != nil {
  289. t.Errorf("failed to create file %s: %v", buildFile, err)
  290. }
  291. }
  292. }
  293. func createDirectories(t *testing.T, topDir string, dirs []string) {
  294. for _, dir := range dirs {
  295. dir = filepath.Join(topDir, dir)
  296. if err := os.MkdirAll(dir, 0755); err != nil {
  297. t.Errorf("failed to create %s directory: %v", dir, err)
  298. }
  299. }
  300. }
  301. func TestConfigGetTargets(t *testing.T) {
  302. ctx := testContext()
  303. tests := []struct {
  304. // ********* Setup *********
  305. // Test description.
  306. description string
  307. // Directories that exist in the source tree.
  308. dirsInTrees []string
  309. // Build files that exists in the source tree.
  310. buildFiles []string
  311. // ********* Action *********
  312. // Directories passed in to soong_ui.
  313. dirs []string
  314. // Current directory that the user executed the build action command.
  315. curDir string
  316. // ********* Validation *********
  317. // Expected targets from the function.
  318. expectedTargets []string
  319. // Expecting error from running test case.
  320. errStr string
  321. }{{
  322. description: "one target dir specified",
  323. dirsInTrees: []string{"0/1/2/3"},
  324. buildFiles: []string{"0/1/2/3/Android.bp"},
  325. dirs: []string{"1/2/3"},
  326. curDir: "0",
  327. expectedTargets: []string{"MODULES-IN-0-1-2-3"},
  328. }, {
  329. description: "one target dir specified, build file does not exist",
  330. dirsInTrees: []string{"0/1/2/3"},
  331. buildFiles: []string{},
  332. dirs: []string{"1/2/3"},
  333. curDir: "0",
  334. errStr: "Build file not found for 0/1/2/3 directory",
  335. }, {
  336. description: "one target dir specified, invalid targets specified",
  337. dirsInTrees: []string{"0/1/2/3"},
  338. buildFiles: []string{},
  339. dirs: []string{"1/2/3:t1:t2"},
  340. curDir: "0",
  341. errStr: "1/2/3:t1:t2 not in proper directory:target1,target2,... format (\":\" was specified more than once)",
  342. }, {
  343. description: "one target dir specified, no targets specified but has colon",
  344. dirsInTrees: []string{"0/1/2/3"},
  345. buildFiles: []string{"0/1/2/3/Android.bp"},
  346. dirs: []string{"1/2/3:"},
  347. curDir: "0",
  348. expectedTargets: []string{"MODULES-IN-0-1-2-3"},
  349. }, {
  350. description: "one target dir specified, two targets specified",
  351. dirsInTrees: []string{"0/1/2/3"},
  352. buildFiles: []string{"0/1/2/3/Android.bp"},
  353. dirs: []string{"1/2/3:t1,t2"},
  354. curDir: "0",
  355. expectedTargets: []string{"t1", "t2"},
  356. }, {
  357. description: "one target dir specified, no targets and has a comma",
  358. dirsInTrees: []string{"0/1/2/3"},
  359. buildFiles: []string{"0/1/2/3/Android.bp"},
  360. dirs: []string{"1/2/3:,"},
  361. curDir: "0",
  362. errStr: "0/1/2/3 not in proper directory:target1,target2,... format",
  363. }, {
  364. description: "one target dir specified, improper targets defined",
  365. dirsInTrees: []string{"0/1/2/3"},
  366. buildFiles: []string{"0/1/2/3/Android.bp"},
  367. dirs: []string{"1/2/3:,t1"},
  368. curDir: "0",
  369. errStr: "0/1/2/3 not in proper directory:target1,target2,... format",
  370. }, {
  371. description: "one target dir specified, blank target",
  372. dirsInTrees: []string{"0/1/2/3"},
  373. buildFiles: []string{"0/1/2/3/Android.bp"},
  374. dirs: []string{"1/2/3:t1,"},
  375. curDir: "0",
  376. errStr: "0/1/2/3 not in proper directory:target1,target2,... format",
  377. }, {
  378. description: "one target dir specified, many targets specified",
  379. dirsInTrees: []string{"0/1/2/3"},
  380. buildFiles: []string{"0/1/2/3/Android.bp"},
  381. dirs: []string{"1/2/3:t1,t2,t3,t4,t5,t6,t7,t8,t9,t10"},
  382. curDir: "0",
  383. expectedTargets: []string{"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10"},
  384. }, {
  385. description: "one target dir specified, one target specified, build file does not exist",
  386. dirsInTrees: []string{"0/1/2/3"},
  387. buildFiles: []string{},
  388. dirs: []string{"1/2/3:t1"},
  389. curDir: "0",
  390. errStr: "Couldn't locate a build file from 0/1/2/3 directory",
  391. }, {
  392. description: "one target dir specified, one target specified, build file not in target dir",
  393. dirsInTrees: []string{"0/1/2/3"},
  394. buildFiles: []string{"0/1/2/Android.mk"},
  395. dirs: []string{"1/2/3:t1"},
  396. curDir: "0",
  397. errStr: "Couldn't locate a build file from 0/1/2/3 directory",
  398. }, {
  399. description: "one target dir specified, build file not in target dir",
  400. dirsInTrees: []string{"0/1/2/3"},
  401. buildFiles: []string{"0/1/2/Android.mk"},
  402. dirs: []string{"1/2/3"},
  403. curDir: "0",
  404. expectedTargets: []string{"MODULES-IN-0-1-2"},
  405. }, {
  406. description: "multiple targets dir specified, targets specified",
  407. dirsInTrees: []string{"0/1/2/3", "0/3/4"},
  408. buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
  409. dirs: []string{"1/2/3:t1,t2", "3/4:t3,t4,t5"},
  410. curDir: "0",
  411. expectedTargets: []string{"t1", "t2", "t3", "t4", "t5"},
  412. }, {
  413. description: "multiple targets dir specified, one directory has targets specified",
  414. dirsInTrees: []string{"0/1/2/3", "0/3/4"},
  415. buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
  416. dirs: []string{"1/2/3:t1,t2", "3/4"},
  417. curDir: "0",
  418. expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
  419. }, {
  420. description: "two dirs specified, only one dir exist",
  421. dirsInTrees: []string{"0/1/2/3"},
  422. buildFiles: []string{"0/1/2/3/Android.mk"},
  423. dirs: []string{"1/2/3:t1", "3/4"},
  424. curDir: "0",
  425. errStr: "couldn't find directory 0/3/4",
  426. }, {
  427. description: "multiple targets dirs specified at root source tree",
  428. dirsInTrees: []string{"0/1/2/3", "0/3/4"},
  429. buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
  430. dirs: []string{"0/1/2/3:t1,t2", "0/3/4"},
  431. curDir: ".",
  432. expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
  433. }, {
  434. description: "no directories specified",
  435. dirsInTrees: []string{"0/1/2/3", "0/3/4"},
  436. buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
  437. dirs: []string{},
  438. curDir: ".",
  439. }}
  440. for _, tt := range tests {
  441. t.Run(tt.description, func(t *testing.T) {
  442. defer logger.Recover(func(err error) {
  443. if tt.errStr == "" {
  444. t.Fatalf("Got unexpected error: %v", err)
  445. }
  446. if tt.errStr != err.Error() {
  447. t.Errorf("expected %s, got %s", tt.errStr, err.Error())
  448. }
  449. })
  450. // Create the root source tree.
  451. topDir, err := ioutil.TempDir("", "")
  452. if err != nil {
  453. t.Fatalf("failed to create temp dir: %v", err)
  454. }
  455. defer os.RemoveAll(topDir)
  456. createDirectories(t, topDir, tt.dirsInTrees)
  457. createBuildFiles(t, topDir, tt.buildFiles)
  458. r := setTop(t, topDir)
  459. defer r()
  460. targets := getTargetsFromDirs(ctx, tt.curDir, tt.dirs, "MODULES-IN-")
  461. if !reflect.DeepEqual(targets, tt.expectedTargets) {
  462. t.Errorf("expected %v, got %v for targets", tt.expectedTargets, targets)
  463. }
  464. // If the execution reached here and there was an expected error code, the unit test case failed.
  465. if tt.errStr != "" {
  466. t.Errorf("expecting error %s", tt.errStr)
  467. }
  468. })
  469. }
  470. }
  471. func TestConfigFindBuildFile(t *testing.T) {
  472. ctx := testContext()
  473. tests := []struct {
  474. // ********* Setup *********
  475. // Test description.
  476. description string
  477. // Array of build files to create in dir.
  478. buildFiles []string
  479. // Directories that exist in the source tree.
  480. dirsInTrees []string
  481. // ********* Action *********
  482. // The base directory is where findBuildFile is invoked.
  483. dir string
  484. // ********* Validation *********
  485. // Expected build file path to find.
  486. expectedBuildFile string
  487. }{{
  488. description: "build file exists at leaf directory",
  489. buildFiles: []string{"1/2/3/Android.bp"},
  490. dirsInTrees: []string{"1/2/3"},
  491. dir: "1/2/3",
  492. expectedBuildFile: "1/2/3/Android.mk",
  493. }, {
  494. description: "build file exists in all directory paths",
  495. buildFiles: []string{"1/Android.mk", "1/2/Android.mk", "1/2/3/Android.mk"},
  496. dirsInTrees: []string{"1/2/3"},
  497. dir: "1/2/3",
  498. expectedBuildFile: "1/2/3/Android.mk",
  499. }, {
  500. description: "build file does not exist in all directory paths",
  501. buildFiles: []string{},
  502. dirsInTrees: []string{"1/2/3"},
  503. dir: "1/2/3",
  504. expectedBuildFile: "",
  505. }, {
  506. description: "build file exists only at top directory",
  507. buildFiles: []string{"Android.bp"},
  508. dirsInTrees: []string{"1/2/3"},
  509. dir: "1/2/3",
  510. expectedBuildFile: "",
  511. }, {
  512. description: "build file exist in a subdirectory",
  513. buildFiles: []string{"1/2/Android.bp"},
  514. dirsInTrees: []string{"1/2/3"},
  515. dir: "1/2/3",
  516. expectedBuildFile: "1/2/Android.mk",
  517. }, {
  518. description: "build file exists in a subdirectory",
  519. buildFiles: []string{"1/Android.mk"},
  520. dirsInTrees: []string{"1/2/3"},
  521. dir: "1/2/3",
  522. expectedBuildFile: "1/Android.mk",
  523. }, {
  524. description: "top directory",
  525. buildFiles: []string{"Android.bp"},
  526. dirsInTrees: []string{},
  527. dir: ".",
  528. expectedBuildFile: "",
  529. }, {
  530. description: "build file exists in subdirectory",
  531. buildFiles: []string{"1/2/3/Android.bp", "1/2/4/Android.bp"},
  532. dirsInTrees: []string{"1/2/3", "1/2/4"},
  533. dir: "1/2",
  534. expectedBuildFile: "1/2/Android.mk",
  535. }, {
  536. description: "build file exists in parent subdirectory",
  537. buildFiles: []string{"1/5/Android.bp"},
  538. dirsInTrees: []string{"1/2/3", "1/2/4", "1/5"},
  539. dir: "1/2",
  540. expectedBuildFile: "1/Android.mk",
  541. }, {
  542. description: "build file exists in deep parent's subdirectory.",
  543. buildFiles: []string{"1/5/6/Android.bp"},
  544. dirsInTrees: []string{"1/2/3", "1/2/4", "1/5/6", "1/5/7"},
  545. dir: "1/2",
  546. expectedBuildFile: "1/Android.mk",
  547. }}
  548. for _, tt := range tests {
  549. t.Run(tt.description, func(t *testing.T) {
  550. defer logger.Recover(func(err error) {
  551. t.Fatalf("Got unexpected error: %v", err)
  552. })
  553. topDir, err := ioutil.TempDir("", "")
  554. if err != nil {
  555. t.Fatalf("failed to create temp dir: %v", err)
  556. }
  557. defer os.RemoveAll(topDir)
  558. createDirectories(t, topDir, tt.dirsInTrees)
  559. createBuildFiles(t, topDir, tt.buildFiles)
  560. curDir, err := os.Getwd()
  561. if err != nil {
  562. t.Fatalf("Could not get working directory: %v", err)
  563. }
  564. defer func() { os.Chdir(curDir) }()
  565. if err := os.Chdir(topDir); err != nil {
  566. t.Fatalf("Could not change top dir to %s: %v", topDir, err)
  567. }
  568. buildFile := findBuildFile(ctx, tt.dir)
  569. if buildFile != tt.expectedBuildFile {
  570. t.Errorf("expected %q, got %q for build file", tt.expectedBuildFile, buildFile)
  571. }
  572. })
  573. }
  574. }
  575. func TestConfigSplitArgs(t *testing.T) {
  576. tests := []struct {
  577. // ********* Setup *********
  578. // Test description.
  579. description string
  580. // ********* Action *********
  581. // Arguments passed in to soong_ui.
  582. args []string
  583. // ********* Validation *********
  584. // Expected newArgs list after extracting the directories.
  585. expectedNewArgs []string
  586. // Expected directories
  587. expectedDirs []string
  588. }{{
  589. description: "flags but no directories specified",
  590. args: []string{"showcommands", "-j", "-k"},
  591. expectedNewArgs: []string{"showcommands", "-j", "-k"},
  592. expectedDirs: []string{},
  593. }, {
  594. description: "flags and one directory specified",
  595. args: []string{"snod", "-j", "dir:target1,target2"},
  596. expectedNewArgs: []string{"snod", "-j"},
  597. expectedDirs: []string{"dir:target1,target2"},
  598. }, {
  599. description: "flags and directories specified",
  600. args: []string{"dist", "-k", "dir1", "dir2:target1,target2"},
  601. expectedNewArgs: []string{"dist", "-k"},
  602. expectedDirs: []string{"dir1", "dir2:target1,target2"},
  603. }, {
  604. description: "only directories specified",
  605. args: []string{"dir1", "dir2", "dir3:target1,target2"},
  606. expectedNewArgs: []string{},
  607. expectedDirs: []string{"dir1", "dir2", "dir3:target1,target2"},
  608. }}
  609. for _, tt := range tests {
  610. t.Run(tt.description, func(t *testing.T) {
  611. args, dirs := splitArgs(tt.args)
  612. if !reflect.DeepEqual(tt.expectedNewArgs, args) {
  613. t.Errorf("expected %v, got %v for arguments", tt.expectedNewArgs, args)
  614. }
  615. if !reflect.DeepEqual(tt.expectedDirs, dirs) {
  616. t.Errorf("expected %v, got %v for directories", tt.expectedDirs, dirs)
  617. }
  618. })
  619. }
  620. }
  621. type envVar struct {
  622. name string
  623. value string
  624. }
  625. type buildActionTestCase struct {
  626. // ********* Setup *********
  627. // Test description.
  628. description string
  629. // Directories that exist in the source tree.
  630. dirsInTrees []string
  631. // Build files that exists in the source tree.
  632. buildFiles []string
  633. // Create root symlink that points to topDir.
  634. rootSymlink bool
  635. // ********* Action *********
  636. // Arguments passed in to soong_ui.
  637. args []string
  638. // Directory where the build action was invoked.
  639. curDir string
  640. // WITH_TIDY_ONLY environment variable specified.
  641. tidyOnly string
  642. // ********* Validation *********
  643. // Expected arguments to be in Config instance.
  644. expectedArgs []string
  645. // Expecting error from running test case.
  646. expectedErrStr string
  647. }
  648. func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction) {
  649. ctx := testContext()
  650. defer logger.Recover(func(err error) {
  651. if tt.expectedErrStr == "" {
  652. t.Fatalf("Got unexpected error: %v", err)
  653. }
  654. if tt.expectedErrStr != err.Error() {
  655. t.Errorf("expected %s, got %s", tt.expectedErrStr, err.Error())
  656. }
  657. })
  658. // Environment variables to set it to blank on every test case run.
  659. resetEnvVars := []string{
  660. "WITH_TIDY_ONLY",
  661. }
  662. for _, name := range resetEnvVars {
  663. if err := os.Unsetenv(name); err != nil {
  664. t.Fatalf("failed to unset environment variable %s: %v", name, err)
  665. }
  666. }
  667. if tt.tidyOnly != "" {
  668. if err := os.Setenv("WITH_TIDY_ONLY", tt.tidyOnly); err != nil {
  669. t.Errorf("failed to set WITH_TIDY_ONLY to %s: %v", tt.tidyOnly, err)
  670. }
  671. }
  672. // Create the root source tree.
  673. topDir, err := ioutil.TempDir("", "")
  674. if err != nil {
  675. t.Fatalf("failed to create temp dir: %v", err)
  676. }
  677. defer os.RemoveAll(topDir)
  678. createDirectories(t, topDir, tt.dirsInTrees)
  679. createBuildFiles(t, topDir, tt.buildFiles)
  680. if tt.rootSymlink {
  681. // Create a secondary root source tree which points to the true root source tree.
  682. symlinkTopDir, err := ioutil.TempDir("", "")
  683. if err != nil {
  684. t.Fatalf("failed to create symlink temp dir: %v", err)
  685. }
  686. defer os.RemoveAll(symlinkTopDir)
  687. symlinkTopDir = filepath.Join(symlinkTopDir, "root")
  688. err = os.Symlink(topDir, symlinkTopDir)
  689. if err != nil {
  690. t.Fatalf("failed to create symlink: %v", err)
  691. }
  692. topDir = symlinkTopDir
  693. }
  694. r := setTop(t, topDir)
  695. defer r()
  696. // The next block is to create the root build file.
  697. rootBuildFileDir := filepath.Dir(srcDirFileCheck)
  698. if err := os.MkdirAll(rootBuildFileDir, 0755); err != nil {
  699. t.Fatalf("Failed to create %s directory: %v", rootBuildFileDir, err)
  700. }
  701. if err := ioutil.WriteFile(srcDirFileCheck, []byte{}, 0644); err != nil {
  702. t.Fatalf("failed to create %s file: %v", srcDirFileCheck, err)
  703. }
  704. args := getConfigArgs(action, tt.curDir, ctx, tt.args)
  705. if !reflect.DeepEqual(tt.expectedArgs, args) {
  706. t.Fatalf("expected %v, got %v for config arguments", tt.expectedArgs, args)
  707. }
  708. // If the execution reached here and there was an expected error code, the unit test case failed.
  709. if tt.expectedErrStr != "" {
  710. t.Errorf("expecting error %s", tt.expectedErrStr)
  711. }
  712. }
  713. func TestGetConfigArgsBuildModules(t *testing.T) {
  714. tests := []buildActionTestCase{{
  715. description: "normal execution from the root source tree directory",
  716. dirsInTrees: []string{"0/1/2", "0/2", "0/3"},
  717. buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp", "0/3/Android.mk"},
  718. args: []string{"-j", "fake_module", "fake_module2"},
  719. curDir: ".",
  720. tidyOnly: "",
  721. expectedArgs: []string{"-j", "fake_module", "fake_module2"},
  722. }, {
  723. description: "normal execution in deep directory",
  724. dirsInTrees: []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
  725. buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
  726. args: []string{"-j", "fake_module", "fake_module2", "-k"},
  727. curDir: "1/2/3/4/5/6/7/8/9",
  728. tidyOnly: "",
  729. expectedArgs: []string{"-j", "fake_module", "fake_module2", "-k"},
  730. }, {
  731. description: "normal execution in deep directory, no targets",
  732. dirsInTrees: []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
  733. buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
  734. args: []string{"-j", "-k"},
  735. curDir: "1/2/3/4/5/6/7/8/9",
  736. tidyOnly: "",
  737. expectedArgs: []string{"-j", "-k"},
  738. }, {
  739. description: "normal execution in root source tree, no args",
  740. dirsInTrees: []string{"0/1/2", "0/2", "0/3"},
  741. buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp"},
  742. args: []string{},
  743. curDir: "0/2",
  744. tidyOnly: "",
  745. expectedArgs: []string{},
  746. }, {
  747. description: "normal execution in symlink root source tree, no args",
  748. dirsInTrees: []string{"0/1/2", "0/2", "0/3"},
  749. buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp"},
  750. rootSymlink: true,
  751. args: []string{},
  752. curDir: "0/2",
  753. tidyOnly: "",
  754. expectedArgs: []string{},
  755. }}
  756. for _, tt := range tests {
  757. t.Run("build action BUILD_MODULES with dependencies, "+tt.description, func(t *testing.T) {
  758. testGetConfigArgs(t, tt, BUILD_MODULES)
  759. })
  760. }
  761. }
  762. func TestGetConfigArgsBuildModulesInDirectory(t *testing.T) {
  763. tests := []buildActionTestCase{{
  764. description: "normal execution in a directory",
  765. dirsInTrees: []string{"0/1/2"},
  766. buildFiles: []string{"0/1/2/Android.mk"},
  767. args: []string{"fake-module"},
  768. curDir: "0/1/2",
  769. tidyOnly: "",
  770. expectedArgs: []string{"fake-module", "MODULES-IN-0-1-2"},
  771. }, {
  772. description: "build file in parent directory",
  773. dirsInTrees: []string{"0/1/2"},
  774. buildFiles: []string{"0/1/Android.mk"},
  775. args: []string{},
  776. curDir: "0/1/2",
  777. tidyOnly: "",
  778. expectedArgs: []string{"MODULES-IN-0-1"},
  779. },
  780. {
  781. description: "build file in parent directory, multiple module names passed in",
  782. dirsInTrees: []string{"0/1/2"},
  783. buildFiles: []string{"0/1/Android.mk"},
  784. args: []string{"fake-module1", "fake-module2", "fake-module3"},
  785. curDir: "0/1/2",
  786. tidyOnly: "",
  787. expectedArgs: []string{"fake-module1", "fake-module2", "fake-module3", "MODULES-IN-0-1"},
  788. }, {
  789. description: "build file in 2nd level parent directory",
  790. dirsInTrees: []string{"0/1/2"},
  791. buildFiles: []string{"0/Android.bp"},
  792. args: []string{},
  793. curDir: "0/1/2",
  794. tidyOnly: "",
  795. expectedArgs: []string{"MODULES-IN-0"},
  796. }, {
  797. description: "build action executed at root directory",
  798. dirsInTrees: []string{},
  799. buildFiles: []string{},
  800. rootSymlink: false,
  801. args: []string{},
  802. curDir: ".",
  803. tidyOnly: "",
  804. expectedArgs: []string{},
  805. }, {
  806. description: "multitree build action executed at root directory",
  807. dirsInTrees: []string{},
  808. buildFiles: []string{},
  809. rootSymlink: false,
  810. args: []string{"--multitree-build"},
  811. curDir: ".",
  812. tidyOnly: "",
  813. expectedArgs: []string{"--multitree-build"},
  814. }, {
  815. description: "build action executed at root directory in symlink",
  816. dirsInTrees: []string{},
  817. buildFiles: []string{},
  818. rootSymlink: true,
  819. args: []string{},
  820. curDir: ".",
  821. tidyOnly: "",
  822. expectedArgs: []string{},
  823. }, {
  824. description: "build file not found",
  825. dirsInTrees: []string{"0/1/2"},
  826. buildFiles: []string{},
  827. args: []string{},
  828. curDir: "0/1/2",
  829. tidyOnly: "",
  830. expectedArgs: []string{"MODULES-IN-0-1-2"},
  831. expectedErrStr: "Build file not found for 0/1/2 directory",
  832. }, {
  833. description: "GET-INSTALL-PATH specified,",
  834. dirsInTrees: []string{"0/1/2"},
  835. buildFiles: []string{"0/1/Android.mk"},
  836. args: []string{"GET-INSTALL-PATH", "-j", "-k", "GET-INSTALL-PATH"},
  837. curDir: "0/1/2",
  838. tidyOnly: "",
  839. expectedArgs: []string{"-j", "-k", "GET-INSTALL-PATH-IN-0-1"},
  840. }, {
  841. description: "tidy only environment variable specified,",
  842. dirsInTrees: []string{"0/1/2"},
  843. buildFiles: []string{"0/1/Android.mk"},
  844. args: []string{"GET-INSTALL-PATH"},
  845. curDir: "0/1/2",
  846. tidyOnly: "true",
  847. expectedArgs: []string{"tidy_only"},
  848. }, {
  849. description: "normal execution in root directory with args",
  850. dirsInTrees: []string{},
  851. buildFiles: []string{},
  852. args: []string{"-j", "-k", "fake_module"},
  853. curDir: "",
  854. tidyOnly: "",
  855. expectedArgs: []string{"-j", "-k", "fake_module"},
  856. }}
  857. for _, tt := range tests {
  858. t.Run("build action BUILD_MODULES_IN_DIR, "+tt.description, func(t *testing.T) {
  859. testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY)
  860. })
  861. }
  862. }
  863. func TestGetConfigArgsBuildModulesInDirectories(t *testing.T) {
  864. tests := []buildActionTestCase{{
  865. description: "normal execution in a directory",
  866. dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
  867. buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
  868. args: []string{"3.1/", "3.2/", "3.3/"},
  869. curDir: "0/1/2",
  870. tidyOnly: "",
  871. expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-2-3.3"},
  872. }, {
  873. description: "GET-INSTALL-PATH specified",
  874. dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3"},
  875. buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/Android.bp"},
  876. args: []string{"GET-INSTALL-PATH", "2/3.1/", "2/3.2", "3"},
  877. curDir: "0/1",
  878. tidyOnly: "",
  879. expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1-2-3.1", "GET-INSTALL-PATH-IN-0-1-2-3.2", "GET-INSTALL-PATH-IN-0-1"},
  880. }, {
  881. description: "tidy only environment variable specified",
  882. dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
  883. buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
  884. args: []string{"GET-INSTALL-PATH", "3.1/", "3.2/", "3.3"},
  885. curDir: "0/1/2",
  886. tidyOnly: "1",
  887. expectedArgs: []string{"tidy_only"},
  888. }, {
  889. description: "normal execution from top dir directory",
  890. dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
  891. buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/3/Android.bp", "0/2/Android.bp"},
  892. rootSymlink: false,
  893. args: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
  894. curDir: ".",
  895. tidyOnly: "",
  896. expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-3", "MODULES-IN-0-2"},
  897. }, {
  898. description: "normal execution from top dir directory in symlink",
  899. dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
  900. buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/3/Android.bp", "0/2/Android.bp"},
  901. rootSymlink: true,
  902. args: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
  903. curDir: ".",
  904. tidyOnly: "",
  905. expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-3", "MODULES-IN-0-2"},
  906. }}
  907. for _, tt := range tests {
  908. t.Run("build action BUILD_MODULES_IN_DIRS, "+tt.description, func(t *testing.T) {
  909. testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES)
  910. })
  911. }
  912. }
  913. func TestBuildConfig(t *testing.T) {
  914. tests := []struct {
  915. name string
  916. environ Environment
  917. arguments []string
  918. useBazel bool
  919. bazelProdMode bool
  920. bazelStagingMode bool
  921. expectedBuildConfig *smpb.BuildConfig
  922. }{
  923. {
  924. name: "none set",
  925. environ: Environment{},
  926. expectedBuildConfig: &smpb.BuildConfig{
  927. ForceUseGoma: proto.Bool(false),
  928. UseGoma: proto.Bool(false),
  929. UseRbe: proto.Bool(false),
  930. BazelMixedBuild: proto.Bool(false),
  931. ForceDisableBazelMixedBuild: proto.Bool(false),
  932. NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
  933. },
  934. },
  935. {
  936. name: "force use goma",
  937. environ: Environment{"FORCE_USE_GOMA=1"},
  938. expectedBuildConfig: &smpb.BuildConfig{
  939. ForceUseGoma: proto.Bool(true),
  940. UseGoma: proto.Bool(false),
  941. UseRbe: proto.Bool(false),
  942. BazelMixedBuild: proto.Bool(false),
  943. ForceDisableBazelMixedBuild: proto.Bool(false),
  944. NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
  945. },
  946. },
  947. {
  948. name: "use goma",
  949. environ: Environment{"USE_GOMA=1"},
  950. expectedBuildConfig: &smpb.BuildConfig{
  951. ForceUseGoma: proto.Bool(false),
  952. UseGoma: proto.Bool(true),
  953. UseRbe: proto.Bool(false),
  954. BazelMixedBuild: proto.Bool(false),
  955. ForceDisableBazelMixedBuild: proto.Bool(false),
  956. NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
  957. },
  958. },
  959. {
  960. name: "use rbe",
  961. environ: Environment{"USE_RBE=1"},
  962. expectedBuildConfig: &smpb.BuildConfig{
  963. ForceUseGoma: proto.Bool(false),
  964. UseGoma: proto.Bool(false),
  965. UseRbe: proto.Bool(true),
  966. BazelMixedBuild: proto.Bool(false),
  967. ForceDisableBazelMixedBuild: proto.Bool(false),
  968. NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
  969. },
  970. },
  971. {
  972. name: "disable mixed builds",
  973. environ: Environment{"BUILD_BROKEN_DISABLE_BAZEL=1"},
  974. expectedBuildConfig: &smpb.BuildConfig{
  975. ForceUseGoma: proto.Bool(false),
  976. UseGoma: proto.Bool(false),
  977. UseRbe: proto.Bool(false),
  978. BazelMixedBuild: proto.Bool(false),
  979. ForceDisableBazelMixedBuild: proto.Bool(true),
  980. NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
  981. },
  982. },
  983. {
  984. name: "use bazel as ninja",
  985. environ: Environment{},
  986. useBazel: true,
  987. expectedBuildConfig: &smpb.BuildConfig{
  988. ForceUseGoma: proto.Bool(false),
  989. UseGoma: proto.Bool(false),
  990. UseRbe: proto.Bool(false),
  991. BazelMixedBuild: proto.Bool(false),
  992. ForceDisableBazelMixedBuild: proto.Bool(false),
  993. NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
  994. },
  995. },
  996. {
  997. name: "bazel mixed build from prod mode",
  998. environ: Environment{},
  999. bazelProdMode: true,
  1000. expectedBuildConfig: &smpb.BuildConfig{
  1001. ForceUseGoma: proto.Bool(false),
  1002. UseGoma: proto.Bool(false),
  1003. UseRbe: proto.Bool(false),
  1004. BazelMixedBuild: proto.Bool(true),
  1005. ForceDisableBazelMixedBuild: proto.Bool(false),
  1006. NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
  1007. },
  1008. },
  1009. {
  1010. name: "bazel mixed build from staging mode",
  1011. environ: Environment{},
  1012. bazelStagingMode: true,
  1013. expectedBuildConfig: &smpb.BuildConfig{
  1014. ForceUseGoma: proto.Bool(false),
  1015. UseGoma: proto.Bool(false),
  1016. UseRbe: proto.Bool(false),
  1017. BazelMixedBuild: proto.Bool(true),
  1018. ForceDisableBazelMixedBuild: proto.Bool(false),
  1019. NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
  1020. },
  1021. },
  1022. {
  1023. name: "specified targets",
  1024. environ: Environment{},
  1025. useBazel: true,
  1026. arguments: []string{"droid", "dist"},
  1027. expectedBuildConfig: &smpb.BuildConfig{
  1028. ForceUseGoma: proto.Bool(false),
  1029. UseGoma: proto.Bool(false),
  1030. UseRbe: proto.Bool(false),
  1031. BazelMixedBuild: proto.Bool(false),
  1032. Targets: []string{"droid", "dist"},
  1033. ForceDisableBazelMixedBuild: proto.Bool(false),
  1034. NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
  1035. },
  1036. },
  1037. {
  1038. name: "all set",
  1039. environ: Environment{
  1040. "FORCE_USE_GOMA=1",
  1041. "USE_GOMA=1",
  1042. "USE_RBE=1",
  1043. "BUILD_BROKEN_DISABLE_BAZEL=1",
  1044. },
  1045. useBazel: true,
  1046. bazelProdMode: true,
  1047. expectedBuildConfig: &smpb.BuildConfig{
  1048. ForceUseGoma: proto.Bool(true),
  1049. UseGoma: proto.Bool(true),
  1050. UseRbe: proto.Bool(true),
  1051. BazelMixedBuild: proto.Bool(true),
  1052. ForceDisableBazelMixedBuild: proto.Bool(true),
  1053. NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
  1054. },
  1055. },
  1056. }
  1057. ctx := testContext()
  1058. for _, tc := range tests {
  1059. t.Run(tc.name, func(t *testing.T) {
  1060. c := &configImpl{
  1061. environ: &tc.environ,
  1062. bazelProdMode: tc.bazelProdMode,
  1063. bazelStagingMode: tc.bazelStagingMode,
  1064. arguments: tc.arguments,
  1065. }
  1066. config := Config{c}
  1067. checkBazelMode(ctx, config)
  1068. actualBuildConfig := buildConfig(config)
  1069. if expected := tc.expectedBuildConfig; !proto.Equal(expected, actualBuildConfig) {
  1070. t.Errorf("Build config mismatch.\n"+
  1071. "Expected build config: %#v\n"+
  1072. "Actual build config: %#v", prototext.Format(expected), prototext.Format(actualBuildConfig))
  1073. }
  1074. })
  1075. }
  1076. }
  1077. func TestGetMetricsUploaderApp(t *testing.T) {
  1078. metricsUploaderDir := "metrics_uploader_dir"
  1079. metricsUploaderBinary := "metrics_uploader_binary"
  1080. metricsUploaderPath := filepath.Join(metricsUploaderDir, metricsUploaderBinary)
  1081. tests := []struct {
  1082. description string
  1083. environ Environment
  1084. createFiles bool
  1085. expected string
  1086. }{{
  1087. description: "Uploader binary exist",
  1088. environ: Environment{"METRICS_UPLOADER=" + metricsUploaderPath},
  1089. createFiles: true,
  1090. expected: metricsUploaderPath,
  1091. }, {
  1092. description: "Uploader binary not exist",
  1093. environ: Environment{"METRICS_UPLOADER=" + metricsUploaderPath},
  1094. createFiles: false,
  1095. expected: "",
  1096. }, {
  1097. description: "Uploader binary variable not set",
  1098. createFiles: true,
  1099. expected: "",
  1100. }}
  1101. for _, tt := range tests {
  1102. t.Run(tt.description, func(t *testing.T) {
  1103. defer logger.Recover(func(err error) {
  1104. t.Fatalf("got unexpected error: %v", err)
  1105. })
  1106. // Create the root source tree.
  1107. topDir, err := ioutil.TempDir("", "")
  1108. if err != nil {
  1109. t.Fatalf("failed to create temp dir: %v", err)
  1110. }
  1111. defer os.RemoveAll(topDir)
  1112. expected := tt.expected
  1113. if len(expected) > 0 {
  1114. expected = filepath.Join(topDir, expected)
  1115. }
  1116. if tt.createFiles {
  1117. if err := os.MkdirAll(filepath.Join(topDir, metricsUploaderDir), 0755); err != nil {
  1118. t.Errorf("failed to create %s directory: %v", metricsUploaderDir, err)
  1119. }
  1120. if err := ioutil.WriteFile(filepath.Join(topDir, metricsUploaderPath), []byte{}, 0644); err != nil {
  1121. t.Errorf("failed to create file %s: %v", expected, err)
  1122. }
  1123. }
  1124. actual := GetMetricsUploader(topDir, &tt.environ)
  1125. if actual != expected {
  1126. t.Errorf("expecting: %s, actual: %s", expected, actual)
  1127. }
  1128. })
  1129. }
  1130. }