sync_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  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. NewInstallEngine: true,
  96. RemoveMake: "no",
  97. Runtime: &settings.Runtime{
  98. Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("\n"), true, "test"),
  99. CmdBuilder: cmdBuilder,
  100. VCSStore: &vcs.Mock{},
  101. AURCache: &mockaur.MockAUR{
  102. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  103. return []aur.Pkg{}, nil
  104. },
  105. },
  106. },
  107. }
  108. err = handleCmd(context.Background(), cfg, 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. cfg := &settings.Configuration{
  194. NewInstallEngine: true,
  195. RemoveMake: "no",
  196. Runtime: &settings.Runtime{
  197. Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"),
  198. CmdBuilder: cmdBuilder,
  199. VCSStore: &vcs.Mock{},
  200. AURCache: &mockaur.MockAUR{
  201. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  202. return []aur.Pkg{}, nil
  203. },
  204. },
  205. },
  206. }
  207. err = handleCmd(context.Background(), cfg, cmdArgs, db)
  208. require.NoError(t, err)
  209. wantCapture := []string{}
  210. wantShow := []string{
  211. "pacman -S -y --config /etc/pacman.conf --",
  212. }
  213. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  214. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  215. for i, call := range mockRunner.ShowCalls {
  216. show := call.Args[0].(*exec.Cmd).String()
  217. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  218. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  219. show = strings.ReplaceAll(show, gitBin, "pacman")
  220. // options are in a different order on different systems and on CI root user is used
  221. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  222. }
  223. }
  224. func TestSyncUpgrade_IgnoreOne(t *testing.T) {
  225. t.Parallel()
  226. makepkgBin := t.TempDir() + "/makepkg"
  227. pacmanBin := t.TempDir() + "/pacman"
  228. gitBin := t.TempDir() + "/git"
  229. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  230. require.NoError(t, err)
  231. require.NoError(t, f.Close())
  232. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  233. require.NoError(t, err)
  234. require.NoError(t, f.Close())
  235. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  236. require.NoError(t, err)
  237. require.NoError(t, f.Close())
  238. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  239. return "", "", nil
  240. }
  241. showOverride := func(cmd *exec.Cmd) error {
  242. return nil
  243. }
  244. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  245. cmdBuilder := &exe.CmdBuilder{
  246. MakepkgBin: makepkgBin,
  247. SudoBin: "su",
  248. PacmanBin: pacmanBin,
  249. PacmanConfigPath: "/etc/pacman.conf",
  250. GitBin: "git",
  251. Runner: mockRunner,
  252. SudoLoopEnabled: false,
  253. }
  254. cmdArgs := parser.MakeArguments()
  255. cmdArgs.AddArg("S")
  256. cmdArgs.AddArg("y")
  257. cmdArgs.AddArg("u")
  258. dbName := mock.NewDB("core")
  259. db := &mock.DBExecutor{
  260. AlpmArchitecturesFn: func() ([]string, error) {
  261. return []string{"x86_64"}, nil
  262. },
  263. RefreshHandleFn: func() error {
  264. return nil
  265. },
  266. ReposFn: func() []string {
  267. return []string{"core"}
  268. },
  269. InstalledRemotePackagesFn: func() map[string]alpm.IPackage {
  270. return map[string]alpm.IPackage{}
  271. },
  272. InstalledRemotePackageNamesFn: func() []string {
  273. return []string{}
  274. },
  275. SyncUpgradesFn: func(
  276. bool,
  277. ) (map[string]db.SyncUpgrade, error) {
  278. return map[string]db.SyncUpgrade{
  279. "gcc": {
  280. Package: &mock.Package{
  281. PName: "gcc",
  282. PVersion: "6.0.0",
  283. PDB: dbName,
  284. },
  285. LocalVersion: "5.0.0",
  286. Reason: alpm.PkgReasonExplicit,
  287. },
  288. "linux": {
  289. Package: &mock.Package{
  290. PName: "linux",
  291. PVersion: "5.10.0",
  292. PDB: dbName,
  293. },
  294. LocalVersion: "4.3.0",
  295. Reason: alpm.PkgReasonExplicit,
  296. },
  297. "linux-headers": {
  298. Package: &mock.Package{
  299. PName: "linux-headers",
  300. PVersion: "5.10.0",
  301. PDB: dbName,
  302. },
  303. LocalVersion: "4.3.0",
  304. Reason: alpm.PkgReasonDepend,
  305. },
  306. }, nil
  307. },
  308. }
  309. cfg := &settings.Configuration{
  310. NewInstallEngine: true,
  311. RemoveMake: "no",
  312. Runtime: &settings.Runtime{
  313. Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"),
  314. CmdBuilder: cmdBuilder,
  315. VCSStore: &vcs.Mock{},
  316. AURCache: &mockaur.MockAUR{
  317. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  318. return []aur.Pkg{}, nil
  319. },
  320. },
  321. },
  322. }
  323. err = handleCmd(context.Background(), cfg, cmdArgs, db)
  324. require.NoError(t, err)
  325. wantCapture := []string{}
  326. wantShow := []string{
  327. "pacman -S -y --config /etc/pacman.conf --",
  328. "pacman -S -y -u --config /etc/pacman.conf --ignore linux-headers --",
  329. }
  330. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  331. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  332. for i, call := range mockRunner.ShowCalls {
  333. show := call.Args[0].(*exec.Cmd).String()
  334. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  335. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  336. show = strings.ReplaceAll(show, gitBin, "pacman")
  337. // options are in a different order on different systems and on CI root user is used
  338. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  339. }
  340. }
  341. // Pinned deps with rollup
  342. func TestSyncUpgradeAURPinnedSplitPackage(t *testing.T) {
  343. t.Parallel()
  344. makepkgBin := t.TempDir() + "/makepkg"
  345. pacmanBin := t.TempDir() + "/pacman"
  346. tmpDir := t.TempDir()
  347. gitBin := t.TempDir() + "/git"
  348. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  349. require.NoError(t, err)
  350. require.NoError(t, f.Close())
  351. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  352. require.NoError(t, err)
  353. require.NoError(t, f.Close())
  354. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  355. require.NoError(t, err)
  356. require.NoError(t, f.Close())
  357. pkgBuildDir := tmpDir + "/vosk-api"
  358. os.Mkdir(pkgBuildDir, 0o755)
  359. fSource, err := os.OpenFile(pkgBuildDir+"/.SRCINFO", os.O_RDWR|os.O_CREATE, 0o666)
  360. require.NoError(t, err)
  361. n, errF := fSource.WriteString(`pkgbase = vosk-api
  362. pkgdesc = Offline speech recognition toolkit
  363. pkgver = 0.3.45
  364. pkgrel = 1
  365. url = https://alphacephei.com/vosk/
  366. arch = x86_64
  367. license = Apache
  368. pkgname = vosk-api
  369. pkgdesc = vosk-api
  370. pkgname = python-vosk
  371. pkgdesc = Python module for vosk-api
  372. depends = vosk-api=0.3.45`)
  373. require.NoError(t, errF)
  374. require.Greater(t, n, 0)
  375. require.NoError(t, fSource.Close())
  376. tars := []string{
  377. tmpDir + "/vosk-api-0.3.45-1-x86_64.pkg.tar.zst",
  378. tmpDir + "/python-vosk-0.3.45-1-x86_64.pkg.tar.zst",
  379. }
  380. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  381. return strings.Join(tars, "\n"), "", nil
  382. }
  383. once := sync.Once{}
  384. showOverride := func(cmd *exec.Cmd) error {
  385. once.Do(func() {
  386. for _, tar := range tars {
  387. f, err := os.OpenFile(tar, os.O_RDONLY|os.O_CREATE, 0o666)
  388. require.NoError(t, err)
  389. require.NoError(t, f.Close())
  390. }
  391. })
  392. if sanitizeCall(cmd.String(), tmpDir, makepkgBin,
  393. pacmanBin, gitBin) == "pacman -U --config /etc/pacman.conf -- /testdir/vosk-api-0.3.45-1-x86_64.pkg.tar.zst" {
  394. return errors.New("Unsatisfied dependency")
  395. }
  396. return nil
  397. }
  398. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  399. cmdBuilder := &exe.CmdBuilder{
  400. MakepkgBin: makepkgBin,
  401. SudoBin: "su",
  402. PacmanBin: pacmanBin,
  403. PacmanConfigPath: "/etc/pacman.conf",
  404. GitBin: "git",
  405. Runner: mockRunner,
  406. SudoLoopEnabled: false,
  407. }
  408. cmdArgs := parser.MakeArguments()
  409. cmdArgs.AddArg("S")
  410. cmdArgs.AddArg("y")
  411. cmdArgs.AddArg("u")
  412. db := &mock.DBExecutor{
  413. AlpmArchitecturesFn: func() ([]string, error) {
  414. return []string{"x86_64"}, nil
  415. },
  416. RefreshHandleFn: func() error {
  417. return nil
  418. },
  419. ReposFn: func() []string {
  420. return []string{"core"}
  421. },
  422. SyncSatisfierFn: func(s string) mock.IPackage {
  423. return nil
  424. },
  425. InstalledRemotePackagesFn: func() map[string]alpm.IPackage {
  426. return map[string]alpm.IPackage{
  427. "vosk-api": &mock.Package{
  428. PName: "vosk-api",
  429. PVersion: "0.3.43-1",
  430. PBase: "vosk-api",
  431. PReason: alpm.PkgReasonDepend,
  432. },
  433. "python-vosk": &mock.Package{
  434. PName: "python-vosk",
  435. PVersion: "0.3.43-1",
  436. PBase: "python-vosk",
  437. PReason: alpm.PkgReasonExplicit,
  438. // TODO: fix mock Depends
  439. },
  440. }
  441. },
  442. InstalledRemotePackageNamesFn: func() []string {
  443. return []string{"vosk-api", "python-vosk"}
  444. },
  445. LocalSatisfierExistsFn: func(s string) bool {
  446. return false
  447. },
  448. SyncUpgradesFn: func(
  449. bool,
  450. ) (map[string]db.SyncUpgrade, error) {
  451. return map[string]db.SyncUpgrade{}, nil
  452. },
  453. }
  454. cfg := &settings.Configuration{
  455. DoubleConfirm: true,
  456. NewInstallEngine: true,
  457. RemoveMake: "no",
  458. BuildDir: tmpDir,
  459. Runtime: &settings.Runtime{
  460. Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("\n\n\n\n"), true, "test"),
  461. CmdBuilder: cmdBuilder,
  462. VCSStore: &vcs.Mock{},
  463. AURCache: &mockaur.MockAUR{
  464. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  465. return []aur.Pkg{
  466. {
  467. Name: "vosk-api",
  468. PackageBase: "vosk-api",
  469. Version: "0.3.45-1",
  470. },
  471. {
  472. Name: "python-vosk",
  473. PackageBase: "vosk-api",
  474. Version: "0.3.45-1",
  475. Depends: []string{
  476. "vosk-api=0.3.45",
  477. },
  478. },
  479. }, nil
  480. },
  481. },
  482. },
  483. }
  484. err = handleCmd(context.Background(), cfg, cmdArgs, db)
  485. require.NoError(t, err)
  486. wantCapture := []string{
  487. "/usr/bin/git -C /testdir/vosk-api reset --hard HEAD",
  488. "/usr/bin/git -C /testdir/vosk-api merge --no-edit --ff",
  489. "makepkg --packagelist", "makepkg --packagelist",
  490. "makepkg --packagelist",
  491. }
  492. wantShow := []string{
  493. "pacman -S -y --config /etc/pacman.conf --",
  494. "makepkg --verifysource -Ccf", "makepkg --nobuild -fC --ignorearch",
  495. "makepkg -c --nobuild --noextract --ignorearch",
  496. "pacman -U --config /etc/pacman.conf -- /testdir/vosk-api-0.3.45-1-x86_64.pkg.tar.zst",
  497. "makepkg --nobuild -fC --ignorearch", "makepkg -c --nobuild --noextract --ignorearch",
  498. "makepkg --nobuild -fC --ignorearch", "makepkg -c --nobuild --noextract --ignorearch",
  499. "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",
  500. "pacman -D -q --asdeps --config /etc/pacman.conf -- vosk-api",
  501. "pacman -D -q --asexplicit --config /etc/pacman.conf -- python-vosk",
  502. }
  503. require.Len(t, mockRunner.ShowCalls, len(wantShow),
  504. fmt.Sprintf("%#v", sanitizeCalls(mockRunner.ShowCalls, tmpDir, makepkgBin, pacmanBin, gitBin)))
  505. require.Len(t, mockRunner.CaptureCalls, len(wantCapture),
  506. fmt.Sprintf("%#v", sanitizeCalls(mockRunner.CaptureCalls, tmpDir, makepkgBin, pacmanBin, gitBin)))
  507. for i, call := range mockRunner.ShowCalls {
  508. show := call.Args[0].(*exec.Cmd).String()
  509. show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path
  510. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  511. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  512. show = strings.ReplaceAll(show, gitBin, "pacman")
  513. // options are in a different order on different systems and on CI root user is used
  514. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  515. }
  516. }
  517. func sanitizeCalls(calls []exe.Call, tmpDir, makepkg, pacman, git string) []string {
  518. san := make([]string, 0, len(calls))
  519. for _, c := range calls {
  520. s := c.Args[0].(*exec.Cmd).String()
  521. san = append(san, sanitizeCall(s, tmpDir, makepkg, pacman, git))
  522. }
  523. return san
  524. }
  525. func sanitizeCall(s, tmpDir, makepkg, pacman, git string) string {
  526. _, after, found := strings.Cut(s, makepkg)
  527. if found {
  528. s = "makepkg" + after
  529. }
  530. _, after, found = strings.Cut(s, pacman)
  531. if found {
  532. s = "pacman" + after
  533. }
  534. _, after, found = strings.Cut(s, git)
  535. if found {
  536. s = "git" + after
  537. }
  538. s = strings.ReplaceAll(s, tmpDir, "/testdir")
  539. return s
  540. }
  541. func TestSyncUpgrade_NoCombinedUpgrade(t *testing.T) {
  542. t.Parallel()
  543. testCases := []struct {
  544. name string
  545. combinedUpgrade bool
  546. want []string
  547. }{
  548. {
  549. name: "combined upgrade",
  550. combinedUpgrade: true,
  551. want: []string{"pacman -S -y -u --config /etc/pacman.conf --"},
  552. },
  553. {
  554. name: "no combined upgrade",
  555. combinedUpgrade: false,
  556. want: []string{"pacman -S -y --config /etc/pacman.conf --"},
  557. },
  558. }
  559. for _, tc := range testCases {
  560. tc := tc
  561. t.Run(tc.name, func(t *testing.T) {
  562. t.Parallel()
  563. makepkgBin := t.TempDir() + "/makepkg"
  564. pacmanBin := t.TempDir() + "/pacman"
  565. gitBin := t.TempDir() + "/git"
  566. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  567. require.NoError(t, err)
  568. require.NoError(t, f.Close())
  569. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  570. require.NoError(t, err)
  571. require.NoError(t, f.Close())
  572. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  573. require.NoError(t, err)
  574. require.NoError(t, f.Close())
  575. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  576. return "", "", nil
  577. }
  578. showOverride := func(cmd *exec.Cmd) error {
  579. return nil
  580. }
  581. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  582. cmdBuilder := &exe.CmdBuilder{
  583. MakepkgBin: makepkgBin,
  584. SudoBin: "su",
  585. PacmanBin: pacmanBin,
  586. PacmanConfigPath: "/etc/pacman.conf",
  587. GitBin: "git",
  588. Runner: mockRunner,
  589. SudoLoopEnabled: false,
  590. }
  591. cmdArgs := parser.MakeArguments()
  592. cmdArgs.AddArg("S")
  593. cmdArgs.AddArg("y")
  594. cmdArgs.AddArg("u")
  595. db := &mock.DBExecutor{
  596. AlpmArchitecturesFn: func() ([]string, error) {
  597. return []string{"x86_64"}, nil
  598. },
  599. RefreshHandleFn: func() error {
  600. return nil
  601. },
  602. ReposFn: func() []string {
  603. return []string{"core"}
  604. },
  605. InstalledRemotePackagesFn: func() map[string]alpm.IPackage {
  606. return map[string]alpm.IPackage{}
  607. },
  608. InstalledRemotePackageNamesFn: func() []string {
  609. return []string{}
  610. },
  611. SyncUpgradesFn: func(
  612. bool,
  613. ) (map[string]db.SyncUpgrade, error) {
  614. return map[string]db.SyncUpgrade{}, nil
  615. },
  616. }
  617. cfg := &settings.Configuration{
  618. NewInstallEngine: true,
  619. RemoveMake: "no",
  620. CombinedUpgrade: false,
  621. Runtime: &settings.Runtime{
  622. Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"),
  623. CmdBuilder: cmdBuilder,
  624. VCSStore: &vcs.Mock{},
  625. AURCache: &mockaur.MockAUR{
  626. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  627. return []aur.Pkg{}, nil
  628. },
  629. },
  630. },
  631. }
  632. err = handleCmd(context.Background(), cfg, cmdArgs, db)
  633. require.NoError(t, err)
  634. require.Len(t, mockRunner.ShowCalls, len(tc.want))
  635. require.Len(t, mockRunner.CaptureCalls, 0)
  636. for i, call := range mockRunner.ShowCalls {
  637. show := call.Args[0].(*exec.Cmd).String()
  638. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  639. // options are in a different order on different systems and on CI root user is used
  640. assert.Subset(t, strings.Split(show, " "), strings.Split(tc.want[i], " "), fmt.Sprintf("%d - %s", i, show))
  641. }
  642. })
  643. }
  644. }