sync_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  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/runtime"
  22. "github.com/Jguer/yay/v12/pkg/settings"
  23. "github.com/Jguer/yay/v12/pkg/settings/exe"
  24. "github.com/Jguer/yay/v12/pkg/settings/parser"
  25. "github.com/Jguer/yay/v12/pkg/text"
  26. "github.com/Jguer/yay/v12/pkg/vcs"
  27. )
  28. func TestSyncUpgrade(t *testing.T) {
  29. t.Parallel()
  30. makepkgBin := t.TempDir() + "/makepkg"
  31. pacmanBin := t.TempDir() + "/pacman"
  32. gitBin := t.TempDir() + "/git"
  33. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  34. require.NoError(t, err)
  35. require.NoError(t, f.Close())
  36. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  37. require.NoError(t, err)
  38. require.NoError(t, f.Close())
  39. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  40. require.NoError(t, err)
  41. require.NoError(t, f.Close())
  42. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  43. return "", "", nil
  44. }
  45. showOverride := func(cmd *exec.Cmd) error {
  46. return nil
  47. }
  48. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  49. cmdBuilder := &exe.CmdBuilder{
  50. MakepkgBin: makepkgBin,
  51. SudoBin: "su",
  52. PacmanBin: pacmanBin,
  53. PacmanConfigPath: "/etc/pacman.conf",
  54. GitBin: "git",
  55. Runner: mockRunner,
  56. SudoLoopEnabled: false,
  57. }
  58. cmdArgs := parser.MakeArguments()
  59. cmdArgs.AddArg("S")
  60. cmdArgs.AddArg("y")
  61. cmdArgs.AddArg("u")
  62. dbName := mock.NewDB("core")
  63. db := &mock.DBExecutor{
  64. AlpmArchitecturesFn: func() ([]string, error) {
  65. return []string{"x86_64"}, nil
  66. },
  67. RefreshHandleFn: func() error {
  68. return nil
  69. },
  70. ReposFn: func() []string {
  71. return []string{"core"}
  72. },
  73. InstalledRemotePackagesFn: func() map[string]alpm.IPackage {
  74. return map[string]alpm.IPackage{}
  75. },
  76. InstalledRemotePackageNamesFn: func() []string {
  77. return []string{}
  78. },
  79. SyncUpgradesFn: func(
  80. bool,
  81. ) (map[string]db.SyncUpgrade, error) {
  82. return map[string]db.SyncUpgrade{
  83. "linux": {
  84. Package: &mock.Package{
  85. PName: "linux",
  86. PVersion: "5.10.0",
  87. PDB: dbName,
  88. },
  89. LocalVersion: "4.3.0",
  90. Reason: alpm.PkgReasonExplicit,
  91. },
  92. }, nil
  93. },
  94. }
  95. run := &runtime.Runtime{
  96. Cfg: &settings.Configuration{
  97. RemoveMake: "no",
  98. },
  99. Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("\n"), true, "test"),
  100. CmdBuilder: cmdBuilder,
  101. VCSStore: &vcs.Mock{},
  102. AURClient: &mockaur.MockAUR{
  103. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  104. return []aur.Pkg{}, nil
  105. },
  106. },
  107. }
  108. err = handleCmd(context.Background(), run, cmdArgs, db)
  109. require.NoError(t, err)
  110. wantCapture := []string{}
  111. wantShow := []string{
  112. "pacman -S -y --config /etc/pacman.conf --",
  113. "pacman -S -y -u --config /etc/pacman.conf --",
  114. }
  115. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  116. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  117. for i, call := range mockRunner.ShowCalls {
  118. show := call.Args[0].(*exec.Cmd).String()
  119. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  120. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  121. show = strings.ReplaceAll(show, gitBin, "pacman")
  122. // options are in a different order on different systems and on CI root user is used
  123. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  124. }
  125. }
  126. func TestSyncUpgrade_IgnoreAll(t *testing.T) {
  127. t.Parallel()
  128. makepkgBin := t.TempDir() + "/makepkg"
  129. pacmanBin := t.TempDir() + "/pacman"
  130. gitBin := t.TempDir() + "/git"
  131. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  132. require.NoError(t, err)
  133. require.NoError(t, f.Close())
  134. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  135. require.NoError(t, err)
  136. require.NoError(t, f.Close())
  137. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  138. require.NoError(t, err)
  139. require.NoError(t, f.Close())
  140. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  141. return "", "", nil
  142. }
  143. showOverride := func(cmd *exec.Cmd) error {
  144. return nil
  145. }
  146. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  147. cmdBuilder := &exe.CmdBuilder{
  148. MakepkgBin: makepkgBin,
  149. SudoBin: "su",
  150. PacmanBin: pacmanBin,
  151. PacmanConfigPath: "/etc/pacman.conf",
  152. GitBin: "git",
  153. Runner: mockRunner,
  154. SudoLoopEnabled: false,
  155. }
  156. cmdArgs := parser.MakeArguments()
  157. cmdArgs.AddArg("S")
  158. cmdArgs.AddArg("y")
  159. cmdArgs.AddArg("u")
  160. dbName := mock.NewDB("core")
  161. db := &mock.DBExecutor{
  162. AlpmArchitecturesFn: func() ([]string, error) {
  163. return []string{"x86_64"}, nil
  164. },
  165. RefreshHandleFn: func() error {
  166. return nil
  167. },
  168. ReposFn: func() []string {
  169. return []string{"core"}
  170. },
  171. InstalledRemotePackagesFn: func() map[string]alpm.IPackage {
  172. return map[string]alpm.IPackage{}
  173. },
  174. InstalledRemotePackageNamesFn: func() []string {
  175. return []string{}
  176. },
  177. SyncUpgradesFn: func(
  178. bool,
  179. ) (map[string]db.SyncUpgrade, error) {
  180. return map[string]db.SyncUpgrade{
  181. "linux": {
  182. Package: &mock.Package{
  183. PName: "linux",
  184. PVersion: "5.10.0",
  185. PDB: dbName,
  186. },
  187. LocalVersion: "4.3.0",
  188. Reason: alpm.PkgReasonExplicit,
  189. },
  190. }, nil
  191. },
  192. }
  193. run := &runtime.Runtime{
  194. Cfg: &settings.Configuration{
  195. RemoveMake: "no",
  196. },
  197. Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"),
  198. CmdBuilder: cmdBuilder,
  199. VCSStore: &vcs.Mock{},
  200. AURClient: &mockaur.MockAUR{
  201. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  202. return []aur.Pkg{}, nil
  203. },
  204. },
  205. }
  206. err = handleCmd(context.Background(), run, cmdArgs, db)
  207. require.NoError(t, err)
  208. wantCapture := []string{}
  209. wantShow := []string{
  210. "pacman -S -y --config /etc/pacman.conf --",
  211. }
  212. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  213. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  214. for i, call := range mockRunner.ShowCalls {
  215. show := call.Args[0].(*exec.Cmd).String()
  216. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  217. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  218. show = strings.ReplaceAll(show, gitBin, "pacman")
  219. // options are in a different order on different systems and on CI root user is used
  220. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  221. }
  222. }
  223. func TestSyncUpgrade_IgnoreOne(t *testing.T) {
  224. t.Parallel()
  225. makepkgBin := t.TempDir() + "/makepkg"
  226. pacmanBin := t.TempDir() + "/pacman"
  227. gitBin := t.TempDir() + "/git"
  228. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  229. require.NoError(t, err)
  230. require.NoError(t, f.Close())
  231. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  232. require.NoError(t, err)
  233. require.NoError(t, f.Close())
  234. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  235. require.NoError(t, err)
  236. require.NoError(t, f.Close())
  237. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  238. return "", "", nil
  239. }
  240. showOverride := func(cmd *exec.Cmd) error {
  241. return nil
  242. }
  243. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  244. cmdBuilder := &exe.CmdBuilder{
  245. MakepkgBin: makepkgBin,
  246. SudoBin: "su",
  247. PacmanBin: pacmanBin,
  248. PacmanConfigPath: "/etc/pacman.conf",
  249. GitBin: "git",
  250. Runner: mockRunner,
  251. SudoLoopEnabled: false,
  252. }
  253. cmdArgs := parser.MakeArguments()
  254. cmdArgs.AddArg("S")
  255. cmdArgs.AddArg("y")
  256. cmdArgs.AddArg("u")
  257. dbName := mock.NewDB("core")
  258. db := &mock.DBExecutor{
  259. AlpmArchitecturesFn: func() ([]string, error) {
  260. return []string{"x86_64"}, nil
  261. },
  262. RefreshHandleFn: func() error {
  263. return nil
  264. },
  265. ReposFn: func() []string {
  266. return []string{"core"}
  267. },
  268. InstalledRemotePackagesFn: func() map[string]alpm.IPackage {
  269. return map[string]alpm.IPackage{}
  270. },
  271. InstalledRemotePackageNamesFn: func() []string {
  272. return []string{}
  273. },
  274. SyncUpgradesFn: func(
  275. bool,
  276. ) (map[string]db.SyncUpgrade, error) {
  277. return map[string]db.SyncUpgrade{
  278. "gcc": {
  279. Package: &mock.Package{
  280. PName: "gcc",
  281. PVersion: "6.0.0",
  282. PDB: dbName,
  283. },
  284. LocalVersion: "5.0.0",
  285. Reason: alpm.PkgReasonExplicit,
  286. },
  287. "linux": {
  288. Package: &mock.Package{
  289. PName: "linux",
  290. PVersion: "5.10.0",
  291. PDB: dbName,
  292. },
  293. LocalVersion: "4.3.0",
  294. Reason: alpm.PkgReasonExplicit,
  295. },
  296. "linux-headers": {
  297. Package: &mock.Package{
  298. PName: "linux-headers",
  299. PVersion: "5.10.0",
  300. PDB: dbName,
  301. },
  302. LocalVersion: "4.3.0",
  303. Reason: alpm.PkgReasonDepend,
  304. },
  305. }, nil
  306. },
  307. }
  308. run := &runtime.Runtime{
  309. Cfg: &settings.Configuration{
  310. RemoveMake: "no",
  311. },
  312. Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"),
  313. CmdBuilder: cmdBuilder,
  314. VCSStore: &vcs.Mock{},
  315. AURClient: &mockaur.MockAUR{
  316. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  317. return []aur.Pkg{}, nil
  318. },
  319. },
  320. }
  321. err = handleCmd(context.Background(), run, 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. run := &runtime.Runtime{
  453. Cfg: &settings.Configuration{
  454. DoubleConfirm: true,
  455. RemoveMake: "no",
  456. BuildDir: tmpDir,
  457. },
  458. Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("\n\n\n\n"), true, "test"),
  459. CmdBuilder: cmdBuilder,
  460. VCSStore: &vcs.Mock{},
  461. AURClient: &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. err = handleCmd(context.Background(), run, 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",
  487. "makepkg --packagelist",
  488. }
  489. wantShow := []string{
  490. "pacman -S -y --config /etc/pacman.conf --",
  491. "makepkg --verifysource --skippgpcheck -f -Cc", "makepkg --nobuild -f -C --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 -f -C --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. run := &runtime.Runtime{
  614. Cfg: &settings.Configuration{
  615. RemoveMake: "no",
  616. CombinedUpgrade: false,
  617. },
  618. Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"),
  619. CmdBuilder: cmdBuilder,
  620. VCSStore: &vcs.Mock{},
  621. AURClient: &mockaur.MockAUR{
  622. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  623. return []aur.Pkg{}, nil
  624. },
  625. },
  626. }
  627. err = handleCmd(context.Background(), run, 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. }