local_install_test.go 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. //go:build !integration
  2. // +build !integration
  3. package main
  4. import (
  5. "context"
  6. "fmt"
  7. "os"
  8. "os/exec"
  9. "path/filepath"
  10. "strings"
  11. "sync"
  12. "testing"
  13. aur "github.com/Jguer/aur"
  14. "github.com/stretchr/testify/assert"
  15. "github.com/stretchr/testify/require"
  16. "github.com/Jguer/yay/v12/pkg/db/mock"
  17. mockaur "github.com/Jguer/yay/v12/pkg/dep/mock"
  18. "github.com/Jguer/yay/v12/pkg/settings"
  19. "github.com/Jguer/yay/v12/pkg/settings/exe"
  20. "github.com/Jguer/yay/v12/pkg/settings/parser"
  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. "pacman -U --config /etc/pacman.conf -- /testdir/jellyfin-server-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-web",
  52. "makepkg --nobuild -fC --ignorearch",
  53. "makepkg -c --nobuild --noextract --ignorearch",
  54. "pacman -U --config /etc/pacman.conf -- /testdir/jellyfin-10.8.4-1-x86_64.pkg.tar.zst",
  55. "pacman -D -q --asexplicit --config /etc/pacman.conf -- jellyfin",
  56. }
  57. wantCapture := []string{
  58. "makepkg --packagelist",
  59. "git -C testdata/jfin git reset --hard HEAD",
  60. "git -C testdata/jfin git merge --no-edit --ff",
  61. "makepkg --packagelist",
  62. "makepkg --packagelist",
  63. }
  64. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  65. return strings.Join(tars, "\n"), "", nil
  66. }
  67. once := sync.Once{}
  68. showOverride := func(cmd *exec.Cmd) error {
  69. once.Do(func() {
  70. for _, tar := range tars {
  71. f, err := os.OpenFile(tar, os.O_RDONLY|os.O_CREATE, 0o666)
  72. require.NoError(t, err)
  73. require.NoError(t, f.Close())
  74. }
  75. })
  76. return nil
  77. }
  78. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  79. cmdBuilder := &exe.CmdBuilder{
  80. MakepkgBin: makepkgBin,
  81. SudoBin: "su",
  82. PacmanBin: pacmanBin,
  83. PacmanConfigPath: "/etc/pacman.conf",
  84. GitBin: "git",
  85. Runner: mockRunner,
  86. SudoLoopEnabled: false,
  87. }
  88. cmdArgs := parser.MakeArguments()
  89. cmdArgs.AddArg("B")
  90. cmdArgs.AddArg("i")
  91. cmdArgs.AddTarget("testdata/jfin")
  92. settings.NoConfirm = true
  93. defer func() { settings.NoConfirm = false }()
  94. db := &mock.DBExecutor{
  95. AlpmArchitecturesFn: func() ([]string, error) {
  96. return []string{"x86_64"}, nil
  97. },
  98. LocalSatisfierExistsFn: func(s string) bool {
  99. switch s {
  100. case "dotnet-sdk>=6", "dotnet-sdk<7", "dotnet-runtime>=6", "dotnet-runtime<7", "jellyfin-server=10.8.4", "jellyfin-web=10.8.4":
  101. return false
  102. }
  103. return true
  104. },
  105. SyncSatisfierFn: func(s string) mock.IPackage {
  106. switch s {
  107. case "dotnet-runtime>=6", "dotnet-runtime<7":
  108. return &mock.Package{
  109. PName: "dotnet-runtime-6.0",
  110. PBase: "dotnet-runtime-6.0",
  111. PVersion: "6.0.100-1",
  112. PDB: mock.NewDB("community"),
  113. }
  114. case "dotnet-sdk>=6", "dotnet-sdk<7":
  115. return &mock.Package{
  116. PName: "dotnet-sdk-6.0",
  117. PBase: "dotnet-sdk-6.0",
  118. PVersion: "6.0.100-1",
  119. PDB: mock.NewDB("community"),
  120. }
  121. }
  122. return nil
  123. },
  124. }
  125. config := &settings.Configuration{
  126. RemoveMake: "no",
  127. Runtime: &settings.Runtime{
  128. Logger: NewTestLogger(),
  129. CmdBuilder: cmdBuilder,
  130. VCSStore: &vcs.Mock{},
  131. AURClient: &mockaur.MockAUR{
  132. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  133. return []aur.Pkg{}, nil
  134. },
  135. },
  136. },
  137. }
  138. err = handleCmd(context.Background(), config, cmdArgs, db)
  139. require.NoError(t, err)
  140. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  141. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  142. for i, call := range mockRunner.ShowCalls {
  143. show := call.Args[0].(*exec.Cmd).String()
  144. show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path
  145. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  146. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  147. show = strings.ReplaceAll(show, gitBin, "pacman")
  148. // options are in a different order on different systems and on CI root user is used
  149. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  150. }
  151. }
  152. func TestIntegrationLocalInstallMissingDep(t *testing.T) {
  153. wantErr := ErrPackagesNotFound
  154. makepkgBin := t.TempDir() + "/makepkg"
  155. pacmanBin := t.TempDir() + "/pacman"
  156. gitBin := t.TempDir() + "/git"
  157. tmpDir := t.TempDir()
  158. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  159. require.NoError(t, err)
  160. require.NoError(t, f.Close())
  161. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  162. require.NoError(t, err)
  163. require.NoError(t, f.Close())
  164. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  165. require.NoError(t, err)
  166. require.NoError(t, f.Close())
  167. tars := []string{
  168. tmpDir + "/jellyfin-10.8.4-1-x86_64.pkg.tar.zst",
  169. tmpDir + "/jellyfin-web-10.8.4-1-x86_64.pkg.tar.zst",
  170. tmpDir + "/jellyfin-server-10.8.4-1-x86_64.pkg.tar.zst",
  171. }
  172. wantShow := []string{}
  173. wantCapture := []string{}
  174. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  175. return strings.Join(tars, "\n"), "", nil
  176. }
  177. once := sync.Once{}
  178. showOverride := func(cmd *exec.Cmd) error {
  179. once.Do(func() {
  180. for _, tar := range tars {
  181. f, err := os.OpenFile(tar, os.O_RDONLY|os.O_CREATE, 0o666)
  182. require.NoError(t, err)
  183. require.NoError(t, f.Close())
  184. }
  185. })
  186. return nil
  187. }
  188. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  189. cmdBuilder := &exe.CmdBuilder{
  190. MakepkgBin: makepkgBin,
  191. SudoBin: "su",
  192. PacmanBin: pacmanBin,
  193. PacmanConfigPath: "/etc/pacman.conf",
  194. GitBin: "git",
  195. Runner: mockRunner,
  196. SudoLoopEnabled: false,
  197. }
  198. cmdArgs := parser.MakeArguments()
  199. cmdArgs.AddArg("B")
  200. cmdArgs.AddArg("i")
  201. cmdArgs.AddTarget("testdata/jfin")
  202. settings.NoConfirm = true
  203. defer func() { settings.NoConfirm = false }()
  204. db := &mock.DBExecutor{
  205. AlpmArchitecturesFn: func() ([]string, error) {
  206. return []string{"x86_64"}, nil
  207. },
  208. LocalSatisfierExistsFn: func(s string) bool {
  209. switch s {
  210. case "dotnet-sdk>=6", "dotnet-sdk<7", "dotnet-runtime>=6", "dotnet-runtime<7", "jellyfin-server=10.8.4", "jellyfin-web=10.8.4":
  211. return false
  212. }
  213. return true
  214. },
  215. SyncSatisfierFn: func(s string) mock.IPackage {
  216. switch s {
  217. case "dotnet-runtime>=6", "dotnet-runtime<7":
  218. return &mock.Package{
  219. PName: "dotnet-runtime-6.0",
  220. PBase: "dotnet-runtime-6.0",
  221. PVersion: "6.0.100-1",
  222. PDB: mock.NewDB("community"),
  223. }
  224. }
  225. return nil
  226. },
  227. }
  228. config := &settings.Configuration{
  229. Runtime: &settings.Runtime{
  230. Logger: NewTestLogger(),
  231. CmdBuilder: cmdBuilder,
  232. VCSStore: &vcs.Mock{},
  233. AURClient: &mockaur.MockAUR{
  234. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  235. return []aur.Pkg{}, nil
  236. },
  237. },
  238. },
  239. }
  240. err = handleCmd(context.Background(), config, cmdArgs, db)
  241. require.ErrorContains(t, err, wantErr.Error())
  242. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  243. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  244. for i, call := range mockRunner.ShowCalls {
  245. show := call.Args[0].(*exec.Cmd).String()
  246. show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path
  247. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  248. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  249. show = strings.ReplaceAll(show, gitBin, "pacman")
  250. // options are in a different order on different systems and on CI root user is used
  251. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  252. }
  253. }
  254. func TestIntegrationLocalInstallNeeded(t *testing.T) {
  255. makepkgBin := t.TempDir() + "/makepkg"
  256. pacmanBin := t.TempDir() + "/pacman"
  257. gitBin := t.TempDir() + "/git"
  258. tmpDir := t.TempDir()
  259. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  260. require.NoError(t, err)
  261. require.NoError(t, f.Close())
  262. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  263. require.NoError(t, err)
  264. require.NoError(t, f.Close())
  265. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  266. require.NoError(t, err)
  267. require.NoError(t, f.Close())
  268. tars := []string{
  269. tmpDir + "/jellyfin-10.8.4-1-x86_64.pkg.tar.zst",
  270. tmpDir + "/jellyfin-web-10.8.4-1-x86_64.pkg.tar.zst",
  271. tmpDir + "/jellyfin-server-10.8.4-1-x86_64.pkg.tar.zst",
  272. }
  273. wantShow := []string{
  274. "makepkg --verifysource -Ccf",
  275. "pacman -S --config /etc/pacman.conf -- community/dotnet-sdk-6.0 community/dotnet-runtime-6.0",
  276. "pacman -D -q --asdeps --config /etc/pacman.conf -- dotnet-runtime-6.0 dotnet-sdk-6.0",
  277. "makepkg --nobuild -fC --ignorearch",
  278. "makepkg -c --nobuild --noextract --ignorearch",
  279. "makepkg --nobuild -fC --ignorearch",
  280. "makepkg -c --nobuild --noextract --ignorearch",
  281. "makepkg --nobuild -fC --ignorearch",
  282. "makepkg -c --nobuild --noextract --ignorearch",
  283. }
  284. wantCapture := []string{
  285. "makepkg --packagelist",
  286. "git -C testdata/jfin git reset --hard HEAD",
  287. "git -C testdata/jfin git merge --no-edit --ff",
  288. "makepkg --packagelist",
  289. "makepkg --packagelist",
  290. }
  291. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  292. return strings.Join(tars, "\n"), "", nil
  293. }
  294. once := sync.Once{}
  295. showOverride := func(cmd *exec.Cmd) error {
  296. once.Do(func() {
  297. for _, tar := range tars {
  298. f, err := os.OpenFile(tar, os.O_RDONLY|os.O_CREATE, 0o666)
  299. require.NoError(t, err)
  300. require.NoError(t, f.Close())
  301. }
  302. })
  303. return nil
  304. }
  305. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  306. cmdBuilder := &exe.CmdBuilder{
  307. MakepkgBin: makepkgBin,
  308. SudoBin: "su",
  309. PacmanBin: pacmanBin,
  310. PacmanConfigPath: "/etc/pacman.conf",
  311. GitBin: "git",
  312. Runner: mockRunner,
  313. SudoLoopEnabled: false,
  314. }
  315. cmdArgs := parser.MakeArguments()
  316. cmdArgs.AddArg("B")
  317. cmdArgs.AddArg("i")
  318. cmdArgs.AddArg("needed")
  319. cmdArgs.AddTarget("testdata/jfin")
  320. settings.NoConfirm = true
  321. defer func() { settings.NoConfirm = false }()
  322. db := &mock.DBExecutor{
  323. AlpmArchitecturesFn: func() ([]string, error) {
  324. return []string{"x86_64"}, nil
  325. },
  326. IsCorrectVersionInstalledFn: func(s1, s2 string) bool {
  327. return true
  328. },
  329. LocalPackageFn: func(s string) mock.IPackage {
  330. if s == "jellyfin-server" {
  331. return &mock.Package{
  332. PName: "jellyfin-server",
  333. PBase: "jellyfin-server",
  334. PVersion: "10.8.4-1",
  335. PDB: mock.NewDB("community"),
  336. }
  337. }
  338. return nil
  339. },
  340. LocalSatisfierExistsFn: func(s string) bool {
  341. switch s {
  342. case "dotnet-sdk>=6", "dotnet-sdk<7", "dotnet-runtime>=6", "dotnet-runtime<7", "jellyfin-server=10.8.4", "jellyfin-web=10.8.4":
  343. return false
  344. }
  345. return true
  346. },
  347. SyncSatisfierFn: func(s string) mock.IPackage {
  348. switch s {
  349. case "dotnet-runtime>=6", "dotnet-runtime<7":
  350. return &mock.Package{
  351. PName: "dotnet-runtime-6.0",
  352. PBase: "dotnet-runtime-6.0",
  353. PVersion: "6.0.100-1",
  354. PDB: mock.NewDB("community"),
  355. }
  356. case "dotnet-sdk>=6", "dotnet-sdk<7":
  357. return &mock.Package{
  358. PName: "dotnet-sdk-6.0",
  359. PBase: "dotnet-sdk-6.0",
  360. PVersion: "6.0.100-1",
  361. PDB: mock.NewDB("community"),
  362. }
  363. }
  364. return nil
  365. },
  366. }
  367. config := &settings.Configuration{
  368. RemoveMake: "no",
  369. Runtime: &settings.Runtime{
  370. Logger: NewTestLogger(),
  371. CmdBuilder: cmdBuilder,
  372. VCSStore: &vcs.Mock{},
  373. AURClient: &mockaur.MockAUR{
  374. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  375. return []aur.Pkg{}, nil
  376. },
  377. },
  378. },
  379. }
  380. err = handleCmd(context.Background(), config, cmdArgs, db)
  381. require.NoError(t, err)
  382. require.Len(t, mockRunner.ShowCalls, len(wantShow), "show calls: %v", mockRunner.ShowCalls)
  383. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  384. for i, call := range mockRunner.ShowCalls {
  385. show := call.Args[0].(*exec.Cmd).String()
  386. show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path
  387. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  388. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  389. show = strings.ReplaceAll(show, gitBin, "pacman")
  390. // options are in a different order on different systems and on CI root user is used
  391. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  392. }
  393. }
  394. func TestIntegrationLocalInstallGenerateSRCINFO(t *testing.T) {
  395. makepkgBin := t.TempDir() + "/makepkg"
  396. pacmanBin := t.TempDir() + "/pacman"
  397. gitBin := t.TempDir() + "/git"
  398. tmpDir := t.TempDir()
  399. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  400. require.NoError(t, err)
  401. require.NoError(t, f.Close())
  402. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  403. require.NoError(t, err)
  404. require.NoError(t, f.Close())
  405. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  406. require.NoError(t, err)
  407. require.NoError(t, f.Close())
  408. srcinfo, err := os.ReadFile("testdata/jfin/.SRCINFO")
  409. require.NoError(t, err)
  410. assert.True(t, strings.HasPrefix(string(srcinfo), "pkgbase = jellyfin"), string(srcinfo))
  411. targetDir := t.TempDir()
  412. f, err = os.OpenFile(filepath.Join(targetDir, "PKGBUILD"), os.O_RDONLY|os.O_CREATE, 0o755)
  413. require.NoError(t, err)
  414. require.NoError(t, f.Close())
  415. tars := []string{
  416. tmpDir + "/jellyfin-10.8.4-1-x86_64.pkg.tar.zst",
  417. tmpDir + "/jellyfin-web-10.8.4-1-x86_64.pkg.tar.zst",
  418. tmpDir + "/jellyfin-server-10.8.4-1-x86_64.pkg.tar.zst",
  419. }
  420. wantShow := []string{
  421. "makepkg --verifysource -Ccf",
  422. "pacman -S --config /etc/pacman.conf -- community/dotnet-sdk-6.0 community/dotnet-runtime-6.0",
  423. "pacman -D -q --asdeps --config /etc/pacman.conf -- dotnet-runtime-6.0 dotnet-sdk-6.0",
  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-web-10.8.4-1-x86_64.pkg.tar.zst",
  429. "pacman -D -q --asexplicit --config /etc/pacman.conf -- jellyfin-server jellyfin-web",
  430. "makepkg --nobuild -fC --ignorearch",
  431. "makepkg -c --nobuild --noextract --ignorearch",
  432. "pacman -U --config /etc/pacman.conf -- /testdir/jellyfin-10.8.4-1-x86_64.pkg.tar.zst",
  433. "pacman -D -q --asexplicit --config /etc/pacman.conf -- jellyfin",
  434. }
  435. wantCapture := []string{
  436. "makepkg --printsrcinfo",
  437. "makepkg --packagelist",
  438. "git -C testdata/jfin git reset --hard HEAD",
  439. "git -C testdata/jfin git merge --no-edit --ff",
  440. "makepkg --packagelist",
  441. "makepkg --packagelist",
  442. }
  443. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  444. for _, arg := range cmd.Args {
  445. if arg == "--printsrcinfo" {
  446. return string(srcinfo), "", nil
  447. }
  448. }
  449. return strings.Join(tars, "\n"), "", nil
  450. }
  451. once := sync.Once{}
  452. showOverride := func(cmd *exec.Cmd) error {
  453. once.Do(func() {
  454. for _, tar := range tars {
  455. f, err := os.OpenFile(tar, os.O_RDONLY|os.O_CREATE, 0o666)
  456. require.NoError(t, err)
  457. require.NoError(t, f.Close())
  458. }
  459. })
  460. return nil
  461. }
  462. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  463. cmdBuilder := &exe.CmdBuilder{
  464. MakepkgBin: makepkgBin,
  465. SudoBin: "su",
  466. PacmanBin: pacmanBin,
  467. PacmanConfigPath: "/etc/pacman.conf",
  468. GitBin: "git",
  469. Runner: mockRunner,
  470. SudoLoopEnabled: false,
  471. }
  472. cmdArgs := parser.MakeArguments()
  473. cmdArgs.AddArg("B")
  474. cmdArgs.AddArg("i")
  475. cmdArgs.AddTarget(targetDir)
  476. settings.NoConfirm = true
  477. defer func() { settings.NoConfirm = false }()
  478. db := &mock.DBExecutor{
  479. AlpmArchitecturesFn: func() ([]string, error) {
  480. return []string{"x86_64"}, nil
  481. },
  482. LocalSatisfierExistsFn: func(s string) bool {
  483. switch s {
  484. case "dotnet-sdk>=6", "dotnet-sdk<7", "dotnet-runtime>=6", "dotnet-runtime<7", "jellyfin-server=10.8.4", "jellyfin-web=10.8.4":
  485. return false
  486. }
  487. return true
  488. },
  489. SyncSatisfierFn: func(s string) mock.IPackage {
  490. switch s {
  491. case "dotnet-runtime>=6", "dotnet-runtime<7":
  492. return &mock.Package{
  493. PName: "dotnet-runtime-6.0",
  494. PBase: "dotnet-runtime-6.0",
  495. PVersion: "6.0.100-1",
  496. PDB: mock.NewDB("community"),
  497. }
  498. case "dotnet-sdk>=6", "dotnet-sdk<7":
  499. return &mock.Package{
  500. PName: "dotnet-sdk-6.0",
  501. PBase: "dotnet-sdk-6.0",
  502. PVersion: "6.0.100-1",
  503. PDB: mock.NewDB("community"),
  504. }
  505. }
  506. return nil
  507. },
  508. }
  509. config := &settings.Configuration{
  510. RemoveMake: "no",
  511. Debug: false,
  512. Runtime: &settings.Runtime{
  513. Logger: NewTestLogger(),
  514. CmdBuilder: cmdBuilder,
  515. VCSStore: &vcs.Mock{},
  516. AURClient: &mockaur.MockAUR{
  517. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  518. return []aur.Pkg{}, nil
  519. },
  520. },
  521. },
  522. }
  523. err = handleCmd(context.Background(), config, cmdArgs, db)
  524. require.NoError(t, err)
  525. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  526. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  527. for i, call := range mockRunner.ShowCalls {
  528. show := call.Args[0].(*exec.Cmd).String()
  529. show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path
  530. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  531. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  532. show = strings.ReplaceAll(show, gitBin, "pacman")
  533. // options are in a different order on different systems and on CI root user is used
  534. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  535. }
  536. }
  537. func TestIntegrationLocalInstallMissingFiles(t *testing.T) {
  538. makepkgBin := t.TempDir() + "/makepkg"
  539. pacmanBin := t.TempDir() + "/pacman"
  540. gitBin := t.TempDir() + "/git"
  541. tmpDir := t.TempDir()
  542. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  543. require.NoError(t, err)
  544. require.NoError(t, f.Close())
  545. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  546. require.NoError(t, err)
  547. require.NoError(t, f.Close())
  548. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  549. require.NoError(t, err)
  550. require.NoError(t, f.Close())
  551. srcinfo, err := os.ReadFile("testdata/jfin/.SRCINFO")
  552. require.NoError(t, err)
  553. targetDir := t.TempDir()
  554. tars := []string{
  555. tmpDir + "/jellyfin-10.8.4-1-x86_64.pkg.tar.zst",
  556. tmpDir + "/jellyfin-web-10.8.4-1-x86_64.pkg.tar.zst",
  557. tmpDir + "/jellyfin-server-10.8.4-1-x86_64.pkg.tar.zst",
  558. }
  559. wantShow := []string{}
  560. wantCapture := []string{}
  561. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  562. fmt.Println(cmd.Args)
  563. if cmd.Args[1] == "--printsrcinfo" {
  564. return string(srcinfo), "", nil
  565. }
  566. return strings.Join(tars, "\n"), "", nil
  567. }
  568. once := sync.Once{}
  569. showOverride := func(cmd *exec.Cmd) error {
  570. once.Do(func() {
  571. for _, tar := range tars {
  572. f, err := os.OpenFile(tar, os.O_RDONLY|os.O_CREATE, 0o666)
  573. require.NoError(t, err)
  574. require.NoError(t, f.Close())
  575. }
  576. })
  577. return nil
  578. }
  579. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  580. cmdBuilder := &exe.CmdBuilder{
  581. MakepkgBin: makepkgBin,
  582. SudoBin: "su",
  583. PacmanBin: pacmanBin,
  584. PacmanConfigPath: "/etc/pacman.conf",
  585. GitBin: "git",
  586. Runner: mockRunner,
  587. SudoLoopEnabled: false,
  588. }
  589. cmdArgs := parser.MakeArguments()
  590. cmdArgs.AddArg("B")
  591. cmdArgs.AddArg("i")
  592. cmdArgs.AddTarget(targetDir)
  593. settings.NoConfirm = true
  594. defer func() { settings.NoConfirm = false }()
  595. db := &mock.DBExecutor{
  596. AlpmArchitecturesFn: func() ([]string, error) {
  597. return []string{"x86_64"}, nil
  598. },
  599. LocalSatisfierExistsFn: func(s string) bool {
  600. switch s {
  601. case "dotnet-sdk>=6", "dotnet-sdk<7", "dotnet-runtime>=6", "dotnet-runtime<7", "jellyfin-server=10.8.4", "jellyfin-web=10.8.4":
  602. return false
  603. }
  604. return true
  605. },
  606. SyncSatisfierFn: func(s string) mock.IPackage {
  607. switch s {
  608. case "dotnet-runtime>=6", "dotnet-runtime<7":
  609. return &mock.Package{
  610. PName: "dotnet-runtime-6.0",
  611. PBase: "dotnet-runtime-6.0",
  612. PVersion: "6.0.100-1",
  613. PDB: mock.NewDB("community"),
  614. }
  615. case "dotnet-sdk>=6", "dotnet-sdk<7":
  616. return &mock.Package{
  617. PName: "dotnet-sdk-6.0",
  618. PBase: "dotnet-sdk-6.0",
  619. PVersion: "6.0.100-1",
  620. PDB: mock.NewDB("community"),
  621. }
  622. }
  623. return nil
  624. },
  625. }
  626. config := &settings.Configuration{
  627. RemoveMake: "no",
  628. Runtime: &settings.Runtime{
  629. Logger: NewTestLogger(),
  630. CmdBuilder: cmdBuilder,
  631. VCSStore: &vcs.Mock{},
  632. AURClient: &mockaur.MockAUR{
  633. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  634. return []aur.Pkg{}, nil
  635. },
  636. },
  637. },
  638. }
  639. err = handleCmd(context.Background(), config, cmdArgs, db)
  640. require.ErrorIs(t, err, ErrNoBuildFiles)
  641. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  642. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  643. for i, call := range mockRunner.ShowCalls {
  644. show := call.Args[0].(*exec.Cmd).String()
  645. show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path
  646. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  647. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  648. show = strings.ReplaceAll(show, gitBin, "pacman")
  649. // options are in a different order on different systems and on CI root user is used
  650. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  651. }
  652. }
  653. func TestIntegrationLocalInstallWithDepsProvides(t *testing.T) {
  654. makepkgBin := t.TempDir() + "/makepkg"
  655. pacmanBin := t.TempDir() + "/pacman"
  656. gitBin := t.TempDir() + "/git"
  657. tmpDir := t.TempDir()
  658. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  659. require.NoError(t, err)
  660. require.NoError(t, f.Close())
  661. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  662. require.NoError(t, err)
  663. require.NoError(t, f.Close())
  664. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  665. require.NoError(t, err)
  666. require.NoError(t, f.Close())
  667. tars := []string{
  668. tmpDir + "/ceph-bin-17.2.6-2-x86_64.pkg.tar.zst",
  669. tmpDir + "/ceph-libs-bin-17.2.6-2-x86_64.pkg.tar.zst",
  670. }
  671. wantShow := []string{
  672. "makepkg --verifysource -Ccf",
  673. "makepkg --nobuild -fC --ignorearch",
  674. "makepkg -c --nobuild --noextract --ignorearch",
  675. "pacman -U --config /etc/pacman.conf -- /testdir/ceph-libs-bin-17.2.6-2-x86_64.pkg.tar.zst",
  676. "pacman -D -q --asexplicit --config /etc/pacman.conf -- ceph-libs-bin",
  677. "makepkg --nobuild -fC --ignorearch",
  678. "makepkg -c --nobuild --noextract --ignorearch",
  679. "pacman -U --config /etc/pacman.conf -- /testdir/ceph-bin-17.2.6-2-x86_64.pkg.tar.zst",
  680. "pacman -D -q --asexplicit --config /etc/pacman.conf -- ceph-bin",
  681. }
  682. wantCapture := []string{
  683. "git -C testdata/cephbin git reset --hard HEAD",
  684. "git -C testdata/cephbin git merge --no-edit --ff",
  685. "makepkg --packagelist",
  686. "makepkg --packagelist",
  687. }
  688. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  689. return strings.Join(tars, "\n"), "", nil
  690. }
  691. once := sync.Once{}
  692. showOverride := func(cmd *exec.Cmd) error {
  693. once.Do(func() {
  694. for _, tar := range tars {
  695. f, err := os.OpenFile(tar, os.O_RDONLY|os.O_CREATE, 0o666)
  696. require.NoError(t, err)
  697. require.NoError(t, f.Close())
  698. }
  699. })
  700. return nil
  701. }
  702. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  703. cmdBuilder := &exe.CmdBuilder{
  704. MakepkgBin: makepkgBin,
  705. SudoBin: "su",
  706. PacmanBin: pacmanBin,
  707. PacmanConfigPath: "/etc/pacman.conf",
  708. GitBin: "git",
  709. Runner: mockRunner,
  710. SudoLoopEnabled: false,
  711. }
  712. cmdArgs := parser.MakeArguments()
  713. cmdArgs.AddArg("B")
  714. cmdArgs.AddArg("i")
  715. cmdArgs.AddTarget("testdata/cephbin")
  716. settings.NoConfirm = true
  717. defer func() { settings.NoConfirm = false }()
  718. db := &mock.DBExecutor{
  719. AlpmArchitecturesFn: func() ([]string, error) {
  720. return []string{"x86_64"}, nil
  721. },
  722. LocalSatisfierExistsFn: func(s string) bool {
  723. switch s {
  724. case "ceph=17.2.6-2", "ceph-libs=17.2.6-2":
  725. return false
  726. }
  727. return true
  728. },
  729. SyncSatisfierFn: func(s string) mock.IPackage {
  730. return nil
  731. },
  732. }
  733. config := &settings.Configuration{
  734. RemoveMake: "no",
  735. Runtime: &settings.Runtime{
  736. Logger: NewTestLogger(),
  737. CmdBuilder: cmdBuilder,
  738. VCSStore: &vcs.Mock{},
  739. AURClient: &mockaur.MockAUR{
  740. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  741. return []aur.Pkg{}, nil
  742. },
  743. },
  744. },
  745. }
  746. err = handleCmd(context.Background(), config, cmdArgs, db)
  747. require.NoError(t, err)
  748. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  749. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  750. for i, call := range mockRunner.ShowCalls {
  751. show := call.Args[0].(*exec.Cmd).String()
  752. show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path
  753. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  754. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  755. show = strings.ReplaceAll(show, gitBin, "pacman")
  756. // options are in a different order on different systems and on CI root user is used
  757. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  758. }
  759. }
  760. func TestIntegrationLocalInstallTwoSrcInfosWithDeps(t *testing.T) {
  761. makepkgBin := t.TempDir() + "/makepkg"
  762. pacmanBin := t.TempDir() + "/pacman"
  763. gitBin := t.TempDir() + "/git"
  764. tmpDir1 := t.TempDir()
  765. tmpDir2 := t.TempDir()
  766. f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
  767. require.NoError(t, err)
  768. require.NoError(t, f.Close())
  769. f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
  770. require.NoError(t, err)
  771. require.NoError(t, f.Close())
  772. f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
  773. require.NoError(t, err)
  774. require.NoError(t, f.Close())
  775. pkgsTars := []string{
  776. tmpDir1 + "/libzip-git-1.9.2.r166.gd2c47d0f-1-x86_64.pkg.tar.zst",
  777. tmpDir2 + "/gourou-0.8.1-4-x86_64.pkg.tar.zst",
  778. }
  779. wantShow := []string{
  780. "makepkg --verifysource -Ccf",
  781. "makepkg --verifysource -Ccf",
  782. "makepkg --nobuild -fC --ignorearch",
  783. "makepkg -c --nobuild --noextract --ignorearch",
  784. "pacman -U --config /etc/pacman.conf -- /testdir1/libzip-git-1.9.2.r166.gd2c47d0f-1-x86_64.pkg.tar.zst",
  785. "pacman -D -q --asexplicit --config /etc/pacman.conf -- libzip-git",
  786. "makepkg --nobuild -fC --ignorearch",
  787. "makepkg -c --nobuild --noextract --ignorearch",
  788. "pacman -U --config /etc/pacman.conf -- /testdir2/gourou-0.8.1-4-x86_64.pkg.tar.zst",
  789. "pacman -D -q --asexplicit --config /etc/pacman.conf -- gourou",
  790. }
  791. wantCapture := []string{
  792. "git -C testdata/gourou git reset --hard HEAD",
  793. "git -C testdata/gourou git merge --no-edit --ff",
  794. "git -C testdata/libzip-git git reset --hard HEAD",
  795. "git -C testdata/libzip-git git merge --no-edit --ff",
  796. "makepkg --packagelist",
  797. "makepkg --packagelist",
  798. }
  799. captureCounter := 0
  800. captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
  801. captureCounter++
  802. switch captureCounter {
  803. case 5:
  804. return pkgsTars[0] + "\n", "", nil
  805. case 6:
  806. return pkgsTars[1] + "\n", "", nil
  807. default:
  808. return "", "", nil
  809. }
  810. }
  811. once := sync.Once{}
  812. showOverride := func(cmd *exec.Cmd) error {
  813. once.Do(func() {
  814. for _, tar := range pkgsTars {
  815. f, err := os.OpenFile(tar, os.O_RDONLY|os.O_CREATE, 0o666)
  816. require.NoError(t, err)
  817. require.NoError(t, f.Close())
  818. }
  819. })
  820. return nil
  821. }
  822. mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
  823. cmdBuilder := &exe.CmdBuilder{
  824. MakepkgBin: makepkgBin,
  825. SudoBin: "su",
  826. PacmanBin: pacmanBin,
  827. PacmanConfigPath: "/etc/pacman.conf",
  828. GitBin: "git",
  829. Runner: mockRunner,
  830. SudoLoopEnabled: false,
  831. }
  832. cmdArgs := parser.MakeArguments()
  833. cmdArgs.AddArg("B")
  834. cmdArgs.AddArg("i")
  835. cmdArgs.AddTarget("testdata/gourou")
  836. cmdArgs.AddTarget("testdata/libzip-git")
  837. settings.NoConfirm = true
  838. defer func() { settings.NoConfirm = false }()
  839. db := &mock.DBExecutor{
  840. AlpmArchitecturesFn: func() ([]string, error) {
  841. return []string{"x86_64"}, nil
  842. },
  843. LocalSatisfierExistsFn: func(s string) bool {
  844. switch s {
  845. case "gourou", "libzip", "libzip-git":
  846. return false
  847. }
  848. return true
  849. },
  850. SyncSatisfierFn: func(s string) mock.IPackage {
  851. return nil
  852. },
  853. }
  854. config := &settings.Configuration{
  855. RemoveMake: "no",
  856. Runtime: &settings.Runtime{
  857. Logger: NewTestLogger(),
  858. CmdBuilder: cmdBuilder,
  859. VCSStore: &vcs.Mock{},
  860. AURClient: &mockaur.MockAUR{
  861. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  862. return []aur.Pkg{}, nil
  863. },
  864. },
  865. },
  866. }
  867. err = handleCmd(context.Background(), config, cmdArgs, db)
  868. require.NoError(t, err)
  869. require.Len(t, mockRunner.ShowCalls, len(wantShow))
  870. require.Len(t, mockRunner.CaptureCalls, len(wantCapture))
  871. for i, call := range mockRunner.ShowCalls {
  872. show := call.Args[0].(*exec.Cmd).String()
  873. show = strings.ReplaceAll(show, tmpDir1, "/testdir1") // replace the temp dir with a static path
  874. show = strings.ReplaceAll(show, tmpDir2, "/testdir2") // replace the temp dir with a static path
  875. show = strings.ReplaceAll(show, makepkgBin, "makepkg")
  876. show = strings.ReplaceAll(show, pacmanBin, "pacman")
  877. show = strings.ReplaceAll(show, gitBin, "pacman")
  878. // options are in a different order on different systems and on CI root user is used
  879. assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
  880. }
  881. }