local_install_test.go 22 KB

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