sync_test.go 20 KB

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