local_install_test.go 22 KB

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