sync_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  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, os.Stderr, 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, os.Stderr, 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, os.Stderr, 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. DoubleConfirm: true,
  454. NewInstallEngine: true,
  455. RemoveMake: "no",
  456. BuildDir: tmpDir,
  457. Runtime: &settings.Runtime{
  458. Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("\n\n\n\n"), true, "test"),
  459. CmdBuilder: cmdBuilder,
  460. VCSStore: &vcs.Mock{},
  461. AURCache: &mockaur.MockAUR{
  462. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  463. return []aur.Pkg{
  464. {
  465. Name: "vosk-api",
  466. PackageBase: "vosk-api",
  467. Version: "0.3.45-1",
  468. },
  469. {
  470. Name: "python-vosk",
  471. PackageBase: "vosk-api",
  472. Version: "0.3.45-1",
  473. Depends: []string{
  474. "vosk-api=0.3.45",
  475. },
  476. },
  477. }, nil
  478. },
  479. },
  480. },
  481. }
  482. err = handleCmd(context.Background(), cfg, cmdArgs, db)
  483. require.NoError(t, err)
  484. wantCapture := []string{
  485. "/usr/bin/git -C /testdir/vosk-api reset --hard HEAD",
  486. "/usr/bin/git -C /testdir/vosk-api merge --no-edit --ff",
  487. "makepkg --packagelist", "makepkg --packagelist",
  488. "makepkg --packagelist",
  489. }
  490. wantShow := []string{
  491. "pacman -S -y --config /etc/pacman.conf --",
  492. "makepkg --verifysource -Ccf", "makepkg --nobuild -fC --ignorearch",
  493. "makepkg -c --nobuild --noextract --ignorearch",
  494. "pacman -U --config /etc/pacman.conf -- /testdir/vosk-api-0.3.45-1-x86_64.pkg.tar.zst",
  495. "makepkg --nobuild -fC --ignorearch", "makepkg -c --nobuild --noextract --ignorearch",
  496. "makepkg --nobuild -fC --ignorearch", "makepkg -c --nobuild --noextract --ignorearch",
  497. "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",
  498. "pacman -D -q --asdeps --config /etc/pacman.conf -- vosk-api",
  499. "pacman -D -q --asexplicit --config /etc/pacman.conf -- python-vosk",
  500. }
  501. require.Len(t, mockRunner.ShowCalls, len(wantShow),
  502. fmt.Sprintf("%#v", sanitizeCalls(mockRunner.ShowCalls, tmpDir, makepkgBin, pacmanBin, gitBin)))
  503. require.Len(t, mockRunner.CaptureCalls, len(wantCapture),
  504. fmt.Sprintf("%#v", sanitizeCalls(mockRunner.CaptureCalls, tmpDir, makepkgBin, pacmanBin, gitBin)))
  505. for i, call := range mockRunner.ShowCalls {
  506. show := call.Args[0].(*exec.Cmd).String()
  507. show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path
  508. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  509. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  510. show = strings.ReplaceAll(show, gitBin, "pacman")
  511. // options are in a different order on different systems and on CI root user is used
  512. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  513. }
  514. }
  515. func sanitizeCalls(calls []exe.Call, tmpDir, makepkg, pacman, git string) []string {
  516. san := make([]string, 0, len(calls))
  517. for _, c := range calls {
  518. s := c.Args[0].(*exec.Cmd).String()
  519. san = append(san, sanitizeCall(s, tmpDir, makepkg, pacman, git))
  520. }
  521. return san
  522. }
  523. func sanitizeCall(s, tmpDir, makepkg, pacman, git string) string {
  524. _, after, found := strings.Cut(s, makepkg)
  525. if found {
  526. s = "makepkg" + after
  527. }
  528. _, after, found = strings.Cut(s, pacman)
  529. if found {
  530. s = "pacman" + after
  531. }
  532. _, after, found = strings.Cut(s, git)
  533. if found {
  534. s = "git" + after
  535. }
  536. s = strings.ReplaceAll(s, tmpDir, "/testdir")
  537. return s
  538. }
  539. func TestSyncUpgrade_NoCombinedUpgrade(t *testing.T) {
  540. t.Parallel()
  541. testCases := []struct {
  542. name string
  543. combinedUpgrade bool
  544. want []string
  545. }{
  546. {
  547. name: "combined upgrade",
  548. combinedUpgrade: true,
  549. want: []string{"pacman -S -y -u --config /etc/pacman.conf --"},
  550. },
  551. {
  552. name: "no combined upgrade",
  553. combinedUpgrade: false,
  554. want: []string{"pacman -S -y --config /etc/pacman.conf --"},
  555. },
  556. }
  557. for _, tc := range testCases {
  558. tc := tc
  559. t.Run(tc.name, func(t *testing.T) {
  560. t.Parallel()
  561. makepkgBin := t.TempDir() + "/makepkg"
  562. pacmanBin := t.TempDir() + "/pacman"
  563. gitBin := t.TempDir() + "/git"
  564. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  565. require.NoError(t, err)
  566. require.NoError(t, f.Close())
  567. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  568. require.NoError(t, err)
  569. require.NoError(t, f.Close())
  570. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  571. require.NoError(t, err)
  572. require.NoError(t, f.Close())
  573. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  574. return "", "", nil
  575. }
  576. showOverride := func(cmd *exec.Cmd) error {
  577. return nil
  578. }
  579. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  580. cmdBuilder := &exe.CmdBuilder{
  581. MakepkgBin: makepkgBin,
  582. SudoBin: "su",
  583. PacmanBin: pacmanBin,
  584. PacmanConfigPath: "/etc/pacman.conf",
  585. GitBin: "git",
  586. Runner: mockRunner,
  587. SudoLoopEnabled: false,
  588. }
  589. cmdArgs := parser.MakeArguments()
  590. cmdArgs.AddArg("S")
  591. cmdArgs.AddArg("y")
  592. cmdArgs.AddArg("u")
  593. db := &mock.DBExecutor{
  594. AlpmArchitecturesFn: func() ([]string, error) {
  595. return []string{"x86_64"}, nil
  596. },
  597. RefreshHandleFn: func() error {
  598. return nil
  599. },
  600. ReposFn: func() []string {
  601. return []string{"core"}
  602. },
  603. InstalledRemotePackagesFn: func() map[string]alpm.IPackage {
  604. return map[string]alpm.IPackage{}
  605. },
  606. InstalledRemotePackageNamesFn: func() []string {
  607. return []string{}
  608. },
  609. SyncUpgradesFn: func(
  610. bool,
  611. ) (map[string]db.SyncUpgrade, error) {
  612. return map[string]db.SyncUpgrade{}, nil
  613. },
  614. }
  615. cfg := &settings.Configuration{
  616. NewInstallEngine: true,
  617. RemoveMake: "no",
  618. CombinedUpgrade: false,
  619. Runtime: &settings.Runtime{
  620. Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"),
  621. CmdBuilder: cmdBuilder,
  622. VCSStore: &vcs.Mock{},
  623. AURCache: &mockaur.MockAUR{
  624. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  625. return []aur.Pkg{}, nil
  626. },
  627. },
  628. },
  629. }
  630. err = handleCmd(context.Background(), cfg, cmdArgs, db)
  631. require.NoError(t, err)
  632. require.Len(t, mockRunner.ShowCalls, len(tc.want))
  633. require.Len(t, mockRunner.CaptureCalls, 0)
  634. for i, call := range mockRunner.ShowCalls {
  635. show := call.Args[0].(*exec.Cmd).String()
  636. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  637. // options are in a different order on different systems and on CI root user is used
  638. assert.Subset(t, strings.Split(show, " "), strings.Split(tc.want[i], " "), fmt.Sprintf("%d - %s", i, show))
  639. }
  640. })
  641. }
  642. }