sync_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. package main
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "os"
  8. "os/exec"
  9. "strings"
  10. "sync"
  11. "testing"
  12. "github.com/Jguer/aur"
  13. alpm "github.com/Jguer/go-alpm/v2"
  14. "github.com/stretchr/testify/assert"
  15. "github.com/stretchr/testify/require"
  16. "github.com/Jguer/yay/v12/pkg/db"
  17. "github.com/Jguer/yay/v12/pkg/db/mock"
  18. mockaur "github.com/Jguer/yay/v12/pkg/dep/mock"
  19. "github.com/Jguer/yay/v12/pkg/settings"
  20. "github.com/Jguer/yay/v12/pkg/settings/exe"
  21. "github.com/Jguer/yay/v12/pkg/settings/parser"
  22. "github.com/Jguer/yay/v12/pkg/text"
  23. "github.com/Jguer/yay/v12/pkg/vcs"
  24. )
  25. func TestSyncUpgrade(t *testing.T) {
  26. t.Parallel()
  27. makepkgBin := t.TempDir() + "/makepkg"
  28. pacmanBin := t.TempDir() + "/pacman"
  29. gitBin := t.TempDir() + "/git"
  30. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  31. require.NoError(t, err)
  32. require.NoError(t, f.Close())
  33. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  34. require.NoError(t, err)
  35. require.NoError(t, f.Close())
  36. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  37. require.NoError(t, err)
  38. require.NoError(t, f.Close())
  39. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  40. return "", "", nil
  41. }
  42. showOverride := func(cmd *exec.Cmd) error {
  43. return nil
  44. }
  45. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  46. cmdBuilder := &exe.CmdBuilder{
  47. MakepkgBin: makepkgBin,
  48. SudoBin: "su",
  49. PacmanBin: pacmanBin,
  50. PacmanConfigPath: "/etc/pacman.conf",
  51. GitBin: "git",
  52. Runner: mockRunner,
  53. SudoLoopEnabled: false,
  54. }
  55. cmdArgs := parser.MakeArguments()
  56. cmdArgs.AddArg("S")
  57. cmdArgs.AddArg("y")
  58. cmdArgs.AddArg("u")
  59. dbName := mock.NewDB("core")
  60. db := &mock.DBExecutor{
  61. AlpmArchitecturesFn: func() ([]string, error) {
  62. return []string{"x86_64"}, nil
  63. },
  64. RefreshHandleFn: func() error {
  65. return nil
  66. },
  67. ReposFn: func() []string {
  68. return []string{"core"}
  69. },
  70. InstalledRemotePackagesFn: func() map[string]alpm.IPackage {
  71. return map[string]alpm.IPackage{}
  72. },
  73. InstalledRemotePackageNamesFn: func() []string {
  74. return []string{}
  75. },
  76. SyncUpgradesFn: func(
  77. bool,
  78. ) (map[string]db.SyncUpgrade, error) {
  79. return map[string]db.SyncUpgrade{
  80. "linux": {
  81. Package: &mock.Package{
  82. PName: "linux",
  83. PVersion: "5.10.0",
  84. PDB: dbName,
  85. },
  86. LocalVersion: "4.3.0",
  87. Reason: alpm.PkgReasonExplicit,
  88. },
  89. }, nil
  90. },
  91. }
  92. cfg := &settings.Configuration{
  93. NewInstallEngine: true,
  94. RemoveMake: "no",
  95. Runtime: &settings.Runtime{
  96. Logger: text.NewLogger(io.Discard, strings.NewReader("\n"), true, "test"),
  97. CmdBuilder: cmdBuilder,
  98. VCSStore: &vcs.Mock{},
  99. AURCache: &mockaur.MockAUR{
  100. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  101. return []aur.Pkg{}, nil
  102. },
  103. },
  104. },
  105. }
  106. err = handleCmd(context.Background(), cfg, cmdArgs, db)
  107. require.NoError(t, err)
  108. wantCapture := []string{}
  109. wantShow := []string{
  110. "pacman -S -y --config /etc/pacman.conf --",
  111. "pacman -S -y -u --config /etc/pacman.conf --",
  112. }
  113. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  114. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  115. for i, call := range mockRunner.ShowCalls {
  116. show := call.Args[0].(*exec.Cmd).String()
  117. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  118. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  119. show = strings.ReplaceAll(show, gitBin, "pacman")
  120. // options are in a different order on different systems and on CI root user is used
  121. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  122. }
  123. }
  124. func TestSyncUpgrade_IgnoreAll(t *testing.T) {
  125. t.Parallel()
  126. makepkgBin := t.TempDir() + "/makepkg"
  127. pacmanBin := t.TempDir() + "/pacman"
  128. gitBin := t.TempDir() + "/git"
  129. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  130. require.NoError(t, err)
  131. require.NoError(t, f.Close())
  132. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  133. require.NoError(t, err)
  134. require.NoError(t, f.Close())
  135. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  136. require.NoError(t, err)
  137. require.NoError(t, f.Close())
  138. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  139. return "", "", nil
  140. }
  141. showOverride := func(cmd *exec.Cmd) error {
  142. return nil
  143. }
  144. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  145. cmdBuilder := &exe.CmdBuilder{
  146. MakepkgBin: makepkgBin,
  147. SudoBin: "su",
  148. PacmanBin: pacmanBin,
  149. PacmanConfigPath: "/etc/pacman.conf",
  150. GitBin: "git",
  151. Runner: mockRunner,
  152. SudoLoopEnabled: false,
  153. }
  154. cmdArgs := parser.MakeArguments()
  155. cmdArgs.AddArg("S")
  156. cmdArgs.AddArg("y")
  157. cmdArgs.AddArg("u")
  158. dbName := mock.NewDB("core")
  159. db := &mock.DBExecutor{
  160. AlpmArchitecturesFn: func() ([]string, error) {
  161. return []string{"x86_64"}, nil
  162. },
  163. RefreshHandleFn: func() error {
  164. return nil
  165. },
  166. ReposFn: func() []string {
  167. return []string{"core"}
  168. },
  169. InstalledRemotePackagesFn: func() map[string]alpm.IPackage {
  170. return map[string]alpm.IPackage{}
  171. },
  172. InstalledRemotePackageNamesFn: func() []string {
  173. return []string{}
  174. },
  175. SyncUpgradesFn: func(
  176. bool,
  177. ) (map[string]db.SyncUpgrade, error) {
  178. return map[string]db.SyncUpgrade{
  179. "linux": {
  180. Package: &mock.Package{
  181. PName: "linux",
  182. PVersion: "5.10.0",
  183. PDB: dbName,
  184. },
  185. LocalVersion: "4.3.0",
  186. Reason: alpm.PkgReasonExplicit,
  187. },
  188. }, nil
  189. },
  190. }
  191. cfg := &settings.Configuration{
  192. NewInstallEngine: true,
  193. RemoveMake: "no",
  194. Runtime: &settings.Runtime{
  195. Logger: text.NewLogger(io.Discard, strings.NewReader("1\n"), true, "test"),
  196. CmdBuilder: cmdBuilder,
  197. VCSStore: &vcs.Mock{},
  198. AURCache: &mockaur.MockAUR{
  199. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  200. return []aur.Pkg{}, nil
  201. },
  202. },
  203. },
  204. }
  205. err = handleCmd(context.Background(), cfg, cmdArgs, db)
  206. require.NoError(t, err)
  207. wantCapture := []string{}
  208. wantShow := []string{
  209. "pacman -S -y --config /etc/pacman.conf --",
  210. }
  211. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  212. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  213. for i, call := range mockRunner.ShowCalls {
  214. show := call.Args[0].(*exec.Cmd).String()
  215. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  216. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  217. show = strings.ReplaceAll(show, gitBin, "pacman")
  218. // options are in a different order on different systems and on CI root user is used
  219. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  220. }
  221. }
  222. func TestSyncUpgrade_IgnoreOne(t *testing.T) {
  223. t.Parallel()
  224. makepkgBin := t.TempDir() + "/makepkg"
  225. pacmanBin := t.TempDir() + "/pacman"
  226. gitBin := t.TempDir() + "/git"
  227. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  228. require.NoError(t, err)
  229. require.NoError(t, f.Close())
  230. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  231. require.NoError(t, err)
  232. require.NoError(t, f.Close())
  233. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  234. require.NoError(t, err)
  235. require.NoError(t, f.Close())
  236. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  237. return "", "", nil
  238. }
  239. showOverride := func(cmd *exec.Cmd) error {
  240. return nil
  241. }
  242. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  243. cmdBuilder := &exe.CmdBuilder{
  244. MakepkgBin: makepkgBin,
  245. SudoBin: "su",
  246. PacmanBin: pacmanBin,
  247. PacmanConfigPath: "/etc/pacman.conf",
  248. GitBin: "git",
  249. Runner: mockRunner,
  250. SudoLoopEnabled: false,
  251. }
  252. cmdArgs := parser.MakeArguments()
  253. cmdArgs.AddArg("S")
  254. cmdArgs.AddArg("y")
  255. cmdArgs.AddArg("u")
  256. dbName := mock.NewDB("core")
  257. db := &mock.DBExecutor{
  258. AlpmArchitecturesFn: func() ([]string, error) {
  259. return []string{"x86_64"}, nil
  260. },
  261. RefreshHandleFn: func() error {
  262. return nil
  263. },
  264. ReposFn: func() []string {
  265. return []string{"core"}
  266. },
  267. InstalledRemotePackagesFn: func() map[string]alpm.IPackage {
  268. return map[string]alpm.IPackage{}
  269. },
  270. InstalledRemotePackageNamesFn: func() []string {
  271. return []string{}
  272. },
  273. SyncUpgradesFn: func(
  274. bool,
  275. ) (map[string]db.SyncUpgrade, error) {
  276. return map[string]db.SyncUpgrade{
  277. "gcc": {
  278. Package: &mock.Package{
  279. PName: "gcc",
  280. PVersion: "6.0.0",
  281. PDB: dbName,
  282. },
  283. LocalVersion: "5.0.0",
  284. Reason: alpm.PkgReasonExplicit,
  285. },
  286. "linux": {
  287. Package: &mock.Package{
  288. PName: "linux",
  289. PVersion: "5.10.0",
  290. PDB: dbName,
  291. },
  292. LocalVersion: "4.3.0",
  293. Reason: alpm.PkgReasonExplicit,
  294. },
  295. "linux-headers": {
  296. Package: &mock.Package{
  297. PName: "linux-headers",
  298. PVersion: "5.10.0",
  299. PDB: dbName,
  300. },
  301. LocalVersion: "4.3.0",
  302. Reason: alpm.PkgReasonDepend,
  303. },
  304. }, nil
  305. },
  306. }
  307. cfg := &settings.Configuration{
  308. NewInstallEngine: true,
  309. RemoveMake: "no",
  310. Runtime: &settings.Runtime{
  311. Logger: text.NewLogger(io.Discard, strings.NewReader("1\n"), true, "test"),
  312. CmdBuilder: cmdBuilder,
  313. VCSStore: &vcs.Mock{},
  314. AURCache: &mockaur.MockAUR{
  315. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  316. return []aur.Pkg{}, nil
  317. },
  318. },
  319. },
  320. }
  321. err = handleCmd(context.Background(), cfg, cmdArgs, db)
  322. require.NoError(t, err)
  323. wantCapture := []string{}
  324. wantShow := []string{
  325. "pacman -S -y --config /etc/pacman.conf --",
  326. "pacman -S -y -u --config /etc/pacman.conf --ignore linux-headers --",
  327. }
  328. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  329. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  330. for i, call := range mockRunner.ShowCalls {
  331. show := call.Args[0].(*exec.Cmd).String()
  332. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  333. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  334. show = strings.ReplaceAll(show, gitBin, "pacman")
  335. // options are in a different order on different systems and on CI root user is used
  336. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  337. }
  338. }
  339. // Pinned deps with rollup
  340. func TestSyncUpgradeAURPinnedSplitPackage(t *testing.T) {
  341. t.Parallel()
  342. makepkgBin := t.TempDir() + "/makepkg"
  343. pacmanBin := t.TempDir() + "/pacman"
  344. tmpDir := t.TempDir()
  345. gitBin := t.TempDir() + "/git"
  346. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  347. require.NoError(t, err)
  348. require.NoError(t, f.Close())
  349. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  350. require.NoError(t, err)
  351. require.NoError(t, f.Close())
  352. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  353. require.NoError(t, err)
  354. require.NoError(t, f.Close())
  355. pkgBuildDir := tmpDir + "/vosk-api"
  356. os.Mkdir(pkgBuildDir, 0o755)
  357. fSource, err := os.OpenFile(pkgBuildDir+"/.SRCINFO", os.O_RDWR|os.O_CREATE, 0o666)
  358. require.NoError(t, err)
  359. n, errF := fSource.WriteString(`pkgbase = vosk-api
  360. pkgdesc = Offline speech recognition toolkit
  361. pkgver = 0.3.45
  362. pkgrel = 1
  363. url = https://alphacephei.com/vosk/
  364. arch = x86_64
  365. license = Apache
  366. pkgname = vosk-api
  367. pkgdesc = vosk-api
  368. pkgname = python-vosk
  369. pkgdesc = Python module for vosk-api
  370. depends = vosk-api=0.3.45`)
  371. require.NoError(t, errF)
  372. require.Greater(t, n, 0)
  373. require.NoError(t, fSource.Close())
  374. tars := []string{
  375. tmpDir + "/vosk-api-0.3.45-1-x86_64.pkg.tar.zst",
  376. tmpDir + "/python-vosk-0.3.45-1-x86_64.pkg.tar.zst",
  377. }
  378. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  379. return strings.Join(tars, "\n"), "", nil
  380. }
  381. once := sync.Once{}
  382. showOverride := func(cmd *exec.Cmd) error {
  383. once.Do(func() {
  384. for _, tar := range tars {
  385. f, err := os.OpenFile(tar, os.O_RDONLY|os.O_CREATE, 0o666)
  386. require.NoError(t, err)
  387. require.NoError(t, f.Close())
  388. }
  389. })
  390. if sanitizeCall(cmd.String(), tmpDir, makepkgBin,
  391. pacmanBin, gitBin) == "pacman -U --config /etc/pacman.conf -- /testdir/vosk-api-0.3.45-1-x86_64.pkg.tar.zst" {
  392. return errors.New("Unsatisfied dependency")
  393. }
  394. return nil
  395. }
  396. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  397. cmdBuilder := &exe.CmdBuilder{
  398. MakepkgBin: makepkgBin,
  399. SudoBin: "su",
  400. PacmanBin: pacmanBin,
  401. PacmanConfigPath: "/etc/pacman.conf",
  402. GitBin: "git",
  403. Runner: mockRunner,
  404. SudoLoopEnabled: false,
  405. }
  406. cmdArgs := parser.MakeArguments()
  407. cmdArgs.AddArg("S")
  408. cmdArgs.AddArg("y")
  409. cmdArgs.AddArg("u")
  410. db := &mock.DBExecutor{
  411. AlpmArchitecturesFn: func() ([]string, error) {
  412. return []string{"x86_64"}, nil
  413. },
  414. RefreshHandleFn: func() error {
  415. return nil
  416. },
  417. ReposFn: func() []string {
  418. return []string{"core"}
  419. },
  420. SyncSatisfierFn: func(s string) mock.IPackage {
  421. return nil
  422. },
  423. InstalledRemotePackagesFn: func() map[string]alpm.IPackage {
  424. return map[string]alpm.IPackage{
  425. "vosk-api": &mock.Package{
  426. PName: "vosk-api",
  427. PVersion: "0.3.43-1",
  428. PBase: "vosk-api",
  429. PReason: alpm.PkgReasonDepend,
  430. },
  431. "python-vosk": &mock.Package{
  432. PName: "python-vosk",
  433. PVersion: "0.3.43-1",
  434. PBase: "python-vosk",
  435. PReason: alpm.PkgReasonExplicit,
  436. // TODO: fix mock Depends
  437. },
  438. }
  439. },
  440. InstalledRemotePackageNamesFn: func() []string {
  441. return []string{"vosk-api", "python-vosk"}
  442. },
  443. LocalSatisfierExistsFn: func(s string) bool {
  444. return false
  445. },
  446. SyncUpgradesFn: func(
  447. bool,
  448. ) (map[string]db.SyncUpgrade, error) {
  449. return map[string]db.SyncUpgrade{}, nil
  450. },
  451. }
  452. cfg := &settings.Configuration{
  453. NewInstallEngine: true,
  454. RemoveMake: "no",
  455. BuildDir: tmpDir,
  456. Runtime: &settings.Runtime{
  457. Logger: text.NewLogger(io.Discard, strings.NewReader("\n\n\n\n"), true, "test"),
  458. CmdBuilder: cmdBuilder,
  459. VCSStore: &vcs.Mock{},
  460. AURCache: &mockaur.MockAUR{
  461. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  462. return []aur.Pkg{
  463. {
  464. Name: "vosk-api",
  465. PackageBase: "vosk-api",
  466. Version: "0.3.45-1",
  467. },
  468. {
  469. Name: "python-vosk",
  470. PackageBase: "vosk-api",
  471. Version: "0.3.45-1",
  472. Depends: []string{
  473. "vosk-api=0.3.45",
  474. },
  475. },
  476. }, nil
  477. },
  478. },
  479. },
  480. }
  481. err = handleCmd(context.Background(), cfg, cmdArgs, db)
  482. require.NoError(t, err)
  483. wantCapture := []string{
  484. "/usr/bin/git -C /testdir/vosk-api reset --hard HEAD",
  485. "/usr/bin/git -C /testdir/vosk-api merge --no-edit --ff",
  486. "makepkg --packagelist", "makepkg --packagelist",
  487. "makepkg --packagelist",
  488. }
  489. wantShow := []string{
  490. "pacman -S -y --config /etc/pacman.conf --",
  491. "makepkg --verifysource -Ccf", "makepkg --nobuild -fC --ignorearch",
  492. "makepkg -c --nobuild --noextract --ignorearch",
  493. "pacman -U --config /etc/pacman.conf -- /testdir/vosk-api-0.3.45-1-x86_64.pkg.tar.zst",
  494. "makepkg --nobuild -fC --ignorearch", "makepkg -c --nobuild --noextract --ignorearch",
  495. "makepkg --nobuild -fC --ignorearch", "makepkg -c --nobuild --noextract --ignorearch",
  496. "pacman -U --config /etc/pacman.conf -- /testdir/vosk-api-0.3.45-1-x86_64.pkg.tar.zst /testdir/python-vosk-0.3.45-1-x86_64.pkg.tar.zst",
  497. "pacman -D -q --asdeps --config /etc/pacman.conf -- vosk-api",
  498. "pacman -D -q --asexplicit --config /etc/pacman.conf -- python-vosk",
  499. }
  500. require.Len(t, mockRunner.ShowCalls, len(wantShow),
  501. fmt.Sprintf("%#v", sanitizeCalls(mockRunner.ShowCalls, tmpDir, makepkgBin, pacmanBin, gitBin)))
  502. require.Len(t, mockRunner.CaptureCalls, len(wantCapture),
  503. fmt.Sprintf("%#v", sanitizeCalls(mockRunner.CaptureCalls, tmpDir, makepkgBin, pacmanBin, gitBin)))
  504. for i, call := range mockRunner.ShowCalls {
  505. show := call.Args[0].(*exec.Cmd).String()
  506. show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path
  507. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  508. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  509. show = strings.ReplaceAll(show, gitBin, "pacman")
  510. // options are in a different order on different systems and on CI root user is used
  511. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  512. }
  513. }
  514. func sanitizeCalls(calls []exe.Call, tmpDir, makepkg, pacman, git string) []string {
  515. san := make([]string, 0, len(calls))
  516. for _, c := range calls {
  517. s := c.Args[0].(*exec.Cmd).String()
  518. san = append(san, sanitizeCall(s, tmpDir, makepkg, pacman, git))
  519. }
  520. return san
  521. }
  522. func sanitizeCall(s, tmpDir, makepkg, pacman, git string) string {
  523. _, after, found := strings.Cut(s, makepkg)
  524. if found {
  525. s = "makepkg" + after
  526. }
  527. _, after, found = strings.Cut(s, pacman)
  528. if found {
  529. s = "pacman" + after
  530. }
  531. _, after, found = strings.Cut(s, git)
  532. if found {
  533. s = "git" + after
  534. }
  535. s = strings.ReplaceAll(s, tmpDir, "/testdir")
  536. return s
  537. }
  538. func TestSyncUpgrade_NoCombinedUpgrade(t *testing.T) {
  539. t.Parallel()
  540. testCases := []struct {
  541. name string
  542. combinedUpgrade bool
  543. want []string
  544. }{
  545. {
  546. name: "combined upgrade",
  547. combinedUpgrade: true,
  548. want: []string{"pacman -S -y -u --config /etc/pacman.conf --"},
  549. },
  550. {
  551. name: "no combined upgrade",
  552. combinedUpgrade: false,
  553. want: []string{"pacman -S -y --config /etc/pacman.conf --"},
  554. },
  555. }
  556. for _, tc := range testCases {
  557. tc := tc
  558. t.Run(tc.name, func(t *testing.T) {
  559. t.Parallel()
  560. makepkgBin := t.TempDir() + "/makepkg"
  561. pacmanBin := t.TempDir() + "/pacman"
  562. gitBin := t.TempDir() + "/git"
  563. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  564. require.NoError(t, err)
  565. require.NoError(t, f.Close())
  566. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  567. require.NoError(t, err)
  568. require.NoError(t, f.Close())
  569. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  570. require.NoError(t, err)
  571. require.NoError(t, f.Close())
  572. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  573. return "", "", nil
  574. }
  575. showOverride := func(cmd *exec.Cmd) error {
  576. return nil
  577. }
  578. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  579. cmdBuilder := &exe.CmdBuilder{
  580. MakepkgBin: makepkgBin,
  581. SudoBin: "su",
  582. PacmanBin: pacmanBin,
  583. PacmanConfigPath: "/etc/pacman.conf",
  584. GitBin: "git",
  585. Runner: mockRunner,
  586. SudoLoopEnabled: false,
  587. }
  588. cmdArgs := parser.MakeArguments()
  589. cmdArgs.AddArg("S")
  590. cmdArgs.AddArg("y")
  591. cmdArgs.AddArg("u")
  592. db := &mock.DBExecutor{
  593. AlpmArchitecturesFn: func() ([]string, error) {
  594. return []string{"x86_64"}, nil
  595. },
  596. RefreshHandleFn: func() error {
  597. return nil
  598. },
  599. ReposFn: func() []string {
  600. return []string{"core"}
  601. },
  602. InstalledRemotePackagesFn: func() map[string]alpm.IPackage {
  603. return map[string]alpm.IPackage{}
  604. },
  605. InstalledRemotePackageNamesFn: func() []string {
  606. return []string{}
  607. },
  608. SyncUpgradesFn: func(
  609. bool,
  610. ) (map[string]db.SyncUpgrade, error) {
  611. return map[string]db.SyncUpgrade{}, nil
  612. },
  613. }
  614. cfg := &settings.Configuration{
  615. NewInstallEngine: true,
  616. RemoveMake: "no",
  617. CombinedUpgrade: false,
  618. Runtime: &settings.Runtime{
  619. Logger: text.NewLogger(io.Discard, strings.NewReader("1\n"), true, "test"),
  620. CmdBuilder: cmdBuilder,
  621. VCSStore: &vcs.Mock{},
  622. AURCache: &mockaur.MockAUR{
  623. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  624. return []aur.Pkg{}, nil
  625. },
  626. },
  627. },
  628. }
  629. err = handleCmd(context.Background(), cfg, cmdArgs, db)
  630. require.NoError(t, err)
  631. require.Len(t, mockRunner.ShowCalls, len(tc.want))
  632. require.Len(t, mockRunner.CaptureCalls, 0)
  633. for i, call := range mockRunner.ShowCalls {
  634. show := call.Args[0].(*exec.Cmd).String()
  635. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  636. // options are in a different order on different systems and on CI root user is used
  637. assert.Subset(t, strings.Split(show, " "), strings.Split(tc.want[i], " "), fmt.Sprintf("%d - %s", i, show))
  638. }
  639. })
  640. }
  641. }