service_test.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969
  1. //go:build !integration
  2. // +build !integration
  3. package upgrade
  4. import (
  5. "context"
  6. "io"
  7. "os"
  8. "strings"
  9. "testing"
  10. "github.com/Jguer/aur"
  11. "github.com/Jguer/go-alpm/v2"
  12. "github.com/stretchr/testify/assert"
  13. "github.com/stretchr/testify/require"
  14. "github.com/Jguer/yay/v12/pkg/db"
  15. "github.com/Jguer/yay/v12/pkg/db/mock"
  16. "github.com/Jguer/yay/v12/pkg/dep"
  17. "github.com/Jguer/yay/v12/pkg/dep/topo"
  18. "github.com/Jguer/yay/v12/pkg/query"
  19. "github.com/Jguer/yay/v12/pkg/settings"
  20. "github.com/Jguer/yay/v12/pkg/settings/exe"
  21. "github.com/Jguer/yay/v12/pkg/settings/parser"
  22. "github.com/Jguer/yay/v12/pkg/text"
  23. "github.com/Jguer/yay/v12/pkg/vcs"
  24. mockaur "github.com/Jguer/yay/v12/pkg/dep/mock"
  25. )
  26. func ptrString(s string) *string {
  27. return &s
  28. }
  29. func TestUpgradeService_GraphUpgrades(t *testing.T) {
  30. t.Parallel()
  31. linuxDepInfo := &dep.InstallInfo{
  32. Reason: dep.Explicit,
  33. Source: dep.Sync,
  34. AURBase: nil,
  35. LocalVersion: "4.5.0-1",
  36. Version: "5.0.0-1",
  37. SyncDBName: ptrString("core"),
  38. Upgrade: true,
  39. Devel: false,
  40. }
  41. exampleDepInfoDevel := &dep.InstallInfo{
  42. Source: dep.AUR,
  43. Reason: dep.Dep,
  44. AURBase: ptrString("example"),
  45. LocalVersion: "2.2.1.r32.41baa362-1",
  46. Version: "latest-commit",
  47. Upgrade: true,
  48. Devel: true,
  49. }
  50. newDepInfo := &dep.InstallInfo{
  51. Source: dep.Sync,
  52. Reason: dep.Dep,
  53. SyncDBName: ptrString("core"),
  54. Version: "3.0.1-2",
  55. LocalVersion: "",
  56. Upgrade: true,
  57. Devel: false,
  58. }
  59. exampleDepInfoAUR := &dep.InstallInfo{
  60. Source: dep.AUR,
  61. Reason: dep.Dep,
  62. AURBase: ptrString("example"),
  63. LocalVersion: "2.2.1.r32.41baa362-1",
  64. Version: "2.2.1.r69.g8a10460-1",
  65. Upgrade: true,
  66. Devel: false,
  67. }
  68. yayDepInfo := &dep.InstallInfo{
  69. Reason: dep.Explicit,
  70. Source: dep.AUR,
  71. AURBase: ptrString("yay"),
  72. LocalVersion: "10.2.3",
  73. Version: "10.2.4",
  74. Upgrade: true,
  75. Devel: false,
  76. }
  77. coreDB := mock.NewDB("core")
  78. dbExe := &mock.DBExecutor{
  79. InstalledRemotePackageNamesFn: func() []string {
  80. return []string{"yay", "example-git"}
  81. },
  82. InstalledRemotePackagesFn: func() map[string]mock.IPackage {
  83. mapRemote := make(map[string]mock.IPackage)
  84. mapRemote["yay"] = &mock.Package{
  85. PName: "yay",
  86. PBase: "yay",
  87. PVersion: "10.2.3",
  88. PReason: alpm.PkgReasonExplicit,
  89. }
  90. mapRemote["example-git"] = &mock.Package{
  91. PName: "example-git",
  92. PBase: "example",
  93. PVersion: "2.2.1.r32.41baa362-1",
  94. PReason: alpm.PkgReasonDepend,
  95. }
  96. return mapRemote
  97. },
  98. LocalSatisfierExistsFn: func(string) bool { return false },
  99. SyncSatisfierFn: func(s string) mock.IPackage {
  100. return &mock.Package{
  101. PName: "new-dep",
  102. PVersion: "3.0.1-2",
  103. PDB: coreDB,
  104. }
  105. },
  106. SyncUpgradesFn: func(bool) (map[string]db.SyncUpgrade, error) {
  107. mapUpgrades := make(map[string]db.SyncUpgrade)
  108. mapUpgrades["linux"] = db.SyncUpgrade{
  109. Package: &mock.Package{
  110. PName: "linux",
  111. PVersion: "5.0.0-1",
  112. PReason: alpm.PkgReasonDepend,
  113. PDB: coreDB,
  114. PDepends: mock.DependList{Depends: []alpm.Depend{
  115. {Name: "new-dep", Version: "3.0.1"},
  116. }},
  117. },
  118. LocalVersion: "4.5.0-1",
  119. Reason: alpm.PkgReasonExplicit,
  120. }
  121. mapUpgrades["new-dep"] = db.SyncUpgrade{
  122. Package: &mock.Package{
  123. PName: "new-dep",
  124. PVersion: "3.0.1-2",
  125. PReason: alpm.PkgReasonDepend,
  126. PDB: coreDB,
  127. },
  128. LocalVersion: "",
  129. Reason: alpm.PkgReasonDepend,
  130. }
  131. return mapUpgrades, nil
  132. },
  133. ReposFn: func() []string { return []string{"core"} },
  134. }
  135. vcsStore := &vcs.Mock{
  136. ToUpgradeReturn: []string{"example-git"},
  137. }
  138. mockAUR := &mockaur.MockAUR{
  139. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  140. return []aur.Pkg{
  141. {Name: "yay", Version: "10.2.4", PackageBase: "yay"},
  142. {
  143. Name: "example-git", Version: "2.2.1.r69.g8a10460-1",
  144. PackageBase: "example", Depends: []string{"new-dep"},
  145. },
  146. }, nil
  147. },
  148. }
  149. type fields struct {
  150. input io.Reader
  151. output io.Writer
  152. noConfirm bool
  153. devel bool
  154. }
  155. type args struct {
  156. graph *topo.Graph[string, *dep.InstallInfo]
  157. enableDowngrade bool
  158. }
  159. tests := []struct {
  160. name string
  161. fields fields
  162. args args
  163. mustExist map[string]*dep.InstallInfo
  164. mustNotExist map[string]bool
  165. wantExclude []string
  166. wantErr bool
  167. }{
  168. {
  169. name: "no input",
  170. fields: fields{
  171. input: strings.NewReader("\n"),
  172. output: io.Discard,
  173. noConfirm: false,
  174. },
  175. args: args{
  176. graph: nil,
  177. enableDowngrade: false,
  178. },
  179. mustExist: map[string]*dep.InstallInfo{
  180. "yay": yayDepInfo,
  181. "linux": linuxDepInfo,
  182. "example-git": exampleDepInfoAUR,
  183. "new-dep": newDepInfo,
  184. },
  185. mustNotExist: map[string]bool{},
  186. wantErr: false,
  187. wantExclude: []string{},
  188. },
  189. {
  190. name: "no input devel",
  191. fields: fields{
  192. input: strings.NewReader("\n"),
  193. output: io.Discard,
  194. noConfirm: false,
  195. devel: true,
  196. },
  197. args: args{
  198. graph: nil,
  199. enableDowngrade: false,
  200. },
  201. mustExist: map[string]*dep.InstallInfo{
  202. "yay": yayDepInfo,
  203. "linux": linuxDepInfo,
  204. "example-git": exampleDepInfoDevel,
  205. },
  206. mustNotExist: map[string]bool{},
  207. wantErr: false,
  208. wantExclude: []string{},
  209. },
  210. {
  211. name: "exclude example-git",
  212. fields: fields{
  213. input: strings.NewReader("2\n"),
  214. output: io.Discard,
  215. noConfirm: false,
  216. },
  217. args: args{
  218. graph: nil,
  219. enableDowngrade: false,
  220. },
  221. mustExist: map[string]*dep.InstallInfo{
  222. "yay": yayDepInfo,
  223. "linux": linuxDepInfo,
  224. },
  225. mustNotExist: map[string]bool{"example-git": true, "new-dep": true},
  226. wantErr: false,
  227. wantExclude: []string{"example-git", "new-dep"},
  228. },
  229. {
  230. name: "exclude new-dep should have no effect",
  231. fields: fields{
  232. input: strings.NewReader("1 3 4\n"),
  233. output: io.Discard,
  234. noConfirm: false,
  235. },
  236. args: args{
  237. graph: nil,
  238. enableDowngrade: false,
  239. },
  240. mustExist: map[string]*dep.InstallInfo{
  241. "example-git": exampleDepInfoAUR,
  242. "new-dep": newDepInfo,
  243. },
  244. mustNotExist: map[string]bool{"linux": true, "yay": true},
  245. wantErr: false,
  246. wantExclude: []string{"linux", "yay"},
  247. },
  248. {
  249. name: "exclude yay",
  250. fields: fields{
  251. input: strings.NewReader("1\n"),
  252. output: io.Discard,
  253. noConfirm: false,
  254. },
  255. args: args{
  256. graph: nil,
  257. enableDowngrade: false,
  258. },
  259. mustExist: map[string]*dep.InstallInfo{
  260. "linux": linuxDepInfo,
  261. "example-git": exampleDepInfoAUR,
  262. },
  263. mustNotExist: map[string]bool{"yay": true},
  264. wantErr: false,
  265. wantExclude: []string{"yay"},
  266. },
  267. {
  268. name: "exclude linux",
  269. fields: fields{
  270. input: strings.NewReader("3\n"),
  271. output: io.Discard,
  272. noConfirm: false,
  273. },
  274. args: args{
  275. graph: nil,
  276. enableDowngrade: false,
  277. },
  278. mustExist: map[string]*dep.InstallInfo{
  279. "yay": yayDepInfo,
  280. "example-git": exampleDepInfoAUR,
  281. "new-dep": newDepInfo,
  282. },
  283. mustNotExist: map[string]bool{"linux": true},
  284. wantErr: false,
  285. wantExclude: []string{"linux"},
  286. },
  287. {
  288. name: "only linux",
  289. fields: fields{
  290. input: strings.NewReader("^3\n"),
  291. output: io.Discard,
  292. noConfirm: false,
  293. },
  294. args: args{
  295. graph: nil,
  296. enableDowngrade: false,
  297. },
  298. mustExist: map[string]*dep.InstallInfo{
  299. "linux": linuxDepInfo,
  300. },
  301. mustNotExist: map[string]bool{"yay": true, "example-git": true},
  302. wantErr: false,
  303. wantExclude: []string{"yay", "example-git", "new-dep"},
  304. },
  305. {
  306. name: "exclude all",
  307. fields: fields{
  308. input: strings.NewReader("1-4\n"),
  309. output: io.Discard,
  310. noConfirm: false,
  311. },
  312. args: args{
  313. graph: nil,
  314. enableDowngrade: false,
  315. },
  316. mustExist: map[string]*dep.InstallInfo{},
  317. mustNotExist: map[string]bool{"yay": true, "example-git": true, "linux": true},
  318. wantErr: false,
  319. wantExclude: []string{"yay", "example-git", "linux", "new-dep"},
  320. },
  321. }
  322. for _, tt := range tests {
  323. t.Run(tt.name, func(t *testing.T) {
  324. grapher := dep.NewGrapher(dbExe, &settings.Configuration{}, mockAUR, &exe.MockBuilder{Runner: &exe.MockRunner{}},
  325. false, true, false, false, false, text.NewLogger(tt.fields.output, os.Stderr,
  326. tt.fields.input, true, "test"))
  327. cfg := &settings.Configuration{
  328. Devel: tt.fields.devel, Mode: parser.ModeAny,
  329. }
  330. logger := text.NewLogger(tt.fields.output, os.Stderr,
  331. tt.fields.input, true, "test")
  332. u := &UpgradeService{
  333. log: logger,
  334. grapher: grapher,
  335. aurCache: mockAUR,
  336. dbExecutor: dbExe,
  337. vcsStore: vcsStore,
  338. cfg: cfg,
  339. noConfirm: tt.fields.noConfirm,
  340. AURWarnings: query.NewWarnings(logger),
  341. }
  342. got, err := u.GraphUpgrades(context.Background(), tt.args.graph, tt.args.enableDowngrade, func(*Upgrade) bool { return true })
  343. if (err != nil) != tt.wantErr {
  344. t.Errorf("UpgradeService.GraphUpgrades() error = %v, wantErr %v", err, tt.wantErr)
  345. return
  346. }
  347. excluded, err := u.UserExcludeUpgrades(got)
  348. require.NoError(t, err)
  349. for node, info := range tt.mustExist {
  350. assert.True(t, got.Exists(node), node)
  351. assert.Equal(t, info, got.GetNodeInfo(node).Value)
  352. }
  353. for node := range tt.mustNotExist {
  354. assert.False(t, got.Exists(node), node)
  355. }
  356. assert.ElementsMatch(t, tt.wantExclude, excluded)
  357. })
  358. }
  359. }
  360. func TestUpgradeService_GraphUpgradesMissingDep(t *testing.T) {
  361. t.Parallel()
  362. newDepMissingInfo := &dep.InstallInfo{
  363. Source: dep.Missing,
  364. Reason: dep.Dep,
  365. Version: "",
  366. }
  367. exampleDepInfoAUR := &dep.InstallInfo{
  368. Source: dep.AUR,
  369. Reason: dep.Dep,
  370. AURBase: ptrString("example"),
  371. LocalVersion: "2.2.1.r32.41baa362-1",
  372. Version: "2.2.1.r69.g8a10460-1",
  373. Upgrade: true,
  374. Devel: false,
  375. }
  376. yayDepInfo := &dep.InstallInfo{
  377. Reason: dep.Explicit,
  378. Source: dep.AUR,
  379. AURBase: ptrString("yay"),
  380. LocalVersion: "10.2.3",
  381. Version: "10.2.4",
  382. Upgrade: true,
  383. Devel: false,
  384. }
  385. dbExe := &mock.DBExecutor{
  386. InstalledRemotePackageNamesFn: func() []string {
  387. return []string{"yay", "example-git"}
  388. },
  389. InstalledRemotePackagesFn: func() map[string]mock.IPackage {
  390. mapRemote := make(map[string]mock.IPackage)
  391. mapRemote["yay"] = &mock.Package{
  392. PName: "yay",
  393. PBase: "yay",
  394. PVersion: "10.2.3",
  395. PReason: alpm.PkgReasonExplicit,
  396. }
  397. mapRemote["example-git"] = &mock.Package{
  398. PName: "example-git",
  399. PBase: "example",
  400. PVersion: "2.2.1.r32.41baa362-1",
  401. PReason: alpm.PkgReasonDepend,
  402. }
  403. return mapRemote
  404. },
  405. LocalSatisfierExistsFn: func(string) bool { return false },
  406. SyncSatisfierFn: func(s string) mock.IPackage { return nil },
  407. SyncUpgradesFn: func(bool) (map[string]db.SyncUpgrade, error) {
  408. return map[string]db.SyncUpgrade{}, nil
  409. },
  410. ReposFn: func() []string { return nil },
  411. }
  412. vcsStore := &vcs.Mock{
  413. ToUpgradeReturn: []string{"example-git"},
  414. }
  415. mockAUR := &mockaur.MockAUR{
  416. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  417. return []aur.Pkg{
  418. {
  419. Name: "yay",
  420. Version: "10.2.4",
  421. PackageBase: "yay",
  422. },
  423. {
  424. Name: "example-git",
  425. Version: "2.2.1.r69.g8a10460-1",
  426. PackageBase: "example",
  427. Depends: []string{"new-dep-missing"},
  428. },
  429. }, nil
  430. },
  431. }
  432. type fields struct {
  433. input io.Reader
  434. output io.Writer
  435. noConfirm bool
  436. devel bool
  437. }
  438. type args struct {
  439. graph *topo.Graph[string, *dep.InstallInfo]
  440. enableDowngrade bool
  441. }
  442. tests := []struct {
  443. name string
  444. fields fields
  445. args args
  446. mustExist map[string]*dep.InstallInfo
  447. mustNotExist map[string]bool
  448. wantExclude []string
  449. wantErr bool
  450. }{
  451. {
  452. name: "no input",
  453. fields: fields{
  454. input: strings.NewReader("\n"),
  455. output: io.Discard,
  456. noConfirm: false,
  457. },
  458. args: args{
  459. graph: nil,
  460. enableDowngrade: false,
  461. },
  462. mustExist: map[string]*dep.InstallInfo{
  463. "yay": yayDepInfo,
  464. "example-git": exampleDepInfoAUR,
  465. "new-dep-missing": newDepMissingInfo,
  466. },
  467. mustNotExist: map[string]bool{},
  468. wantErr: false,
  469. wantExclude: []string{},
  470. },
  471. {
  472. name: "exclude example-git(with missing dep)",
  473. fields: fields{
  474. input: strings.NewReader("2\n"),
  475. output: io.Discard,
  476. noConfirm: false,
  477. },
  478. args: args{
  479. graph: nil,
  480. enableDowngrade: false,
  481. },
  482. mustExist: map[string]*dep.InstallInfo{
  483. "yay": yayDepInfo,
  484. },
  485. mustNotExist: map[string]bool{"example-git": true, "new-dep-missing": true},
  486. wantErr: false,
  487. wantExclude: []string{"example-git", "new-dep-missing"},
  488. },
  489. }
  490. for _, tt := range tests {
  491. t.Run(tt.name, func(t *testing.T) {
  492. grapher := dep.NewGrapher(dbExe, &settings.Configuration{}, mockAUR, &exe.MockBuilder{Runner: &exe.MockRunner{}},
  493. false, true, false, false, false, text.NewLogger(tt.fields.output, os.Stderr,
  494. tt.fields.input, true, "test"))
  495. cfg := &settings.Configuration{
  496. Devel: tt.fields.devel, Mode: parser.ModeAny,
  497. }
  498. logger := text.NewLogger(tt.fields.output, os.Stderr,
  499. tt.fields.input, true, "test")
  500. u := &UpgradeService{
  501. log: logger,
  502. grapher: grapher,
  503. aurCache: mockAUR,
  504. dbExecutor: dbExe,
  505. vcsStore: vcsStore,
  506. cfg: cfg,
  507. noConfirm: tt.fields.noConfirm,
  508. AURWarnings: query.NewWarnings(logger),
  509. }
  510. got, err := u.GraphUpgrades(context.Background(), tt.args.graph, tt.args.enableDowngrade, func(*Upgrade) bool { return true })
  511. if (err != nil) != tt.wantErr {
  512. t.Errorf("UpgradeService.GraphUpgrades() error = %v, wantErr %v", err, tt.wantErr)
  513. return
  514. }
  515. excluded, err := u.UserExcludeUpgrades(got)
  516. require.NoError(t, err)
  517. for node, info := range tt.mustExist {
  518. assert.True(t, got.Exists(node), node)
  519. assert.Equal(t, info, got.GetNodeInfo(node).Value)
  520. }
  521. for node := range tt.mustNotExist {
  522. assert.False(t, got.Exists(node), node)
  523. }
  524. assert.ElementsMatch(t, tt.wantExclude, excluded)
  525. })
  526. }
  527. }
  528. func TestUpgradeService_GraphUpgradesNoUpdates(t *testing.T) {
  529. t.Parallel()
  530. dbExe := &mock.DBExecutor{
  531. InstalledRemotePackageNamesFn: func() []string {
  532. return []string{"yay", "example-git"}
  533. },
  534. InstalledRemotePackagesFn: func() map[string]mock.IPackage {
  535. mapRemote := make(map[string]mock.IPackage)
  536. mapRemote["yay"] = &mock.Package{
  537. PName: "yay",
  538. PBase: "yay",
  539. PVersion: "10.2.3",
  540. PReason: alpm.PkgReasonExplicit,
  541. }
  542. mapRemote["example-git"] = &mock.Package{
  543. PName: "example-git",
  544. PBase: "example",
  545. PVersion: "2.2.1.r32.41baa362-1",
  546. PReason: alpm.PkgReasonDepend,
  547. }
  548. return mapRemote
  549. },
  550. SyncUpgradesFn: func(bool) (map[string]db.SyncUpgrade, error) {
  551. mapUpgrades := make(map[string]db.SyncUpgrade)
  552. return mapUpgrades, nil
  553. },
  554. ReposFn: func() []string { return []string{"core"} },
  555. }
  556. vcsStore := &vcs.Mock{
  557. ToUpgradeReturn: []string{},
  558. }
  559. mockAUR := &mockaur.MockAUR{
  560. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  561. return []aur.Pkg{}, nil
  562. },
  563. }
  564. type fields struct {
  565. input io.Reader
  566. output io.Writer
  567. noConfirm bool
  568. devel bool
  569. }
  570. type args struct {
  571. graph *topo.Graph[string, *dep.InstallInfo]
  572. enableDowngrade bool
  573. }
  574. tests := []struct {
  575. name string
  576. fields fields
  577. args args
  578. mustExist map[string]*dep.InstallInfo
  579. mustNotExist map[string]bool
  580. wantExclude []string
  581. wantErr bool
  582. }{
  583. {
  584. name: "no input",
  585. fields: fields{
  586. input: strings.NewReader(""),
  587. output: io.Discard,
  588. noConfirm: false,
  589. },
  590. args: args{
  591. graph: nil,
  592. enableDowngrade: false,
  593. },
  594. mustExist: map[string]*dep.InstallInfo{},
  595. mustNotExist: map[string]bool{},
  596. wantErr: false,
  597. wantExclude: []string{},
  598. },
  599. }
  600. for _, tt := range tests {
  601. t.Run(tt.name, func(t *testing.T) {
  602. grapher := dep.NewGrapher(dbExe, &settings.Configuration{}, mockAUR, &exe.MockBuilder{Runner: &exe.MockRunner{}},
  603. false, true, false, false, false, text.NewLogger(tt.fields.output, os.Stderr,
  604. tt.fields.input, true, "test"))
  605. cfg := &settings.Configuration{
  606. Devel: tt.fields.devel,
  607. Mode: parser.ModeAny,
  608. }
  609. logger := text.NewLogger(tt.fields.output, os.Stderr,
  610. tt.fields.input, true, "test")
  611. u := &UpgradeService{
  612. log: logger,
  613. grapher: grapher,
  614. aurCache: mockAUR,
  615. dbExecutor: dbExe,
  616. vcsStore: vcsStore,
  617. cfg: cfg,
  618. noConfirm: tt.fields.noConfirm,
  619. AURWarnings: query.NewWarnings(logger),
  620. }
  621. got, err := u.GraphUpgrades(context.Background(), tt.args.graph, tt.args.enableDowngrade, func(*Upgrade) bool { return true })
  622. if (err != nil) != tt.wantErr {
  623. t.Errorf("UpgradeService.GraphUpgrades() error = %v, wantErr %v", err, tt.wantErr)
  624. return
  625. }
  626. excluded, err := u.UserExcludeUpgrades(got)
  627. require.NoError(t, err)
  628. for node, info := range tt.mustExist {
  629. assert.True(t, got.Exists(node), node)
  630. assert.Equal(t, info, got.GetNodeInfo(node).Value)
  631. }
  632. for node := range tt.mustNotExist {
  633. assert.False(t, got.Exists(node), node)
  634. }
  635. assert.ElementsMatch(t, tt.wantExclude, excluded)
  636. })
  637. }
  638. }
  639. func TestUpgradeService_Warnings(t *testing.T) {
  640. t.Parallel()
  641. dbExe := &mock.DBExecutor{
  642. InstalledRemotePackageNamesFn: func() []string {
  643. return []string{"orphan", "outdated", "missing", "orphan-ignored"}
  644. },
  645. InstalledRemotePackagesFn: func() map[string]mock.IPackage {
  646. mapRemote := make(map[string]mock.IPackage)
  647. mapRemote["orphan"] = &mock.Package{
  648. PName: "orphan",
  649. PBase: "orphan",
  650. PVersion: "10.2.3",
  651. PReason: alpm.PkgReasonExplicit,
  652. }
  653. mapRemote["outdated"] = &mock.Package{
  654. PName: "outdated",
  655. PBase: "outdated",
  656. PVersion: "10.2.3",
  657. PReason: alpm.PkgReasonExplicit,
  658. }
  659. mapRemote["missing"] = &mock.Package{
  660. PName: "missing",
  661. PBase: "missing",
  662. PVersion: "10.2.3",
  663. PReason: alpm.PkgReasonExplicit,
  664. }
  665. mapRemote["orphan-ignored"] = &mock.Package{
  666. PName: "orphan-ignored",
  667. PBase: "orphan-ignored",
  668. PVersion: "10.2.3",
  669. PReason: alpm.PkgReasonExplicit,
  670. PShouldIgnore: true,
  671. }
  672. return mapRemote
  673. },
  674. LocalSatisfierExistsFn: func(string) bool { return false },
  675. SyncSatisfierFn: func(s string) mock.IPackage {
  676. return nil
  677. },
  678. SyncUpgradesFn: func(bool) (map[string]db.SyncUpgrade, error) {
  679. mapUpgrades := make(map[string]db.SyncUpgrade)
  680. return mapUpgrades, nil
  681. },
  682. ReposFn: func() []string { return []string{"core"} },
  683. }
  684. vcsStore := &vcs.Mock{
  685. ToUpgradeReturn: []string{},
  686. }
  687. mockAUR := &mockaur.MockAUR{
  688. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  689. return []aur.Pkg{
  690. {
  691. Name: "outdated", Version: "10.2.4", PackageBase: "orphan",
  692. OutOfDate: 100, Maintainer: "bob",
  693. },
  694. {
  695. Name: "orphan", Version: "10.2.4", PackageBase: "orphan",
  696. Maintainer: "",
  697. },
  698. }, nil
  699. },
  700. }
  701. logger := text.NewLogger(io.Discard, os.Stderr,
  702. strings.NewReader("\n"), true, "test")
  703. grapher := dep.NewGrapher(dbExe, &settings.Configuration{}, mockAUR, &exe.MockBuilder{Runner: &exe.MockRunner{}},
  704. false, true, false, false, false, logger)
  705. cfg := &settings.Configuration{
  706. Devel: false, Mode: parser.ModeAUR,
  707. }
  708. u := &UpgradeService{
  709. log: logger,
  710. grapher: grapher,
  711. aurCache: mockAUR,
  712. dbExecutor: dbExe,
  713. vcsStore: vcsStore,
  714. cfg: cfg,
  715. noConfirm: true,
  716. AURWarnings: query.NewWarnings(logger),
  717. }
  718. _, err := u.GraphUpgrades(context.Background(), nil, false, func(*Upgrade) bool { return true })
  719. require.NoError(t, err)
  720. assert.Equal(t, []string{"missing"}, u.AURWarnings.Missing)
  721. assert.Equal(t, []string{"outdated"}, u.AURWarnings.OutOfDate)
  722. assert.Equal(t, []string{"orphan"}, u.AURWarnings.Orphans)
  723. }
  724. func TestUpgradeService_GraphUpgrades_zfs_dkms(t *testing.T) {
  725. t.Parallel()
  726. zfsDKMSInfo := &dep.InstallInfo{
  727. Reason: dep.Explicit,
  728. Source: dep.AUR,
  729. AURBase: ptrString("zfs-dkms"),
  730. LocalVersion: "2.1.10-1",
  731. Version: "2.1.11-1",
  732. Upgrade: true,
  733. Devel: false,
  734. }
  735. zfsUtilsInfo := &dep.InstallInfo{
  736. Reason: dep.Dep,
  737. Source: dep.AUR,
  738. AURBase: ptrString("zfs-utils"),
  739. LocalVersion: "2.1.10-1",
  740. Version: "2.1.11-1",
  741. Upgrade: true,
  742. Devel: false,
  743. }
  744. vcsStore := &vcs.Mock{ToUpgradeReturn: []string{}}
  745. mockAUR := &mockaur.MockAUR{
  746. GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
  747. if len(query.Needles) == 2 {
  748. return []aur.Pkg{
  749. {
  750. Name: "zfs-dkms", Version: "2.1.11-1",
  751. PackageBase: "zfs-dkms", Depends: []string{"zfs-utils=2.1.11"},
  752. },
  753. {Name: "zfs-utils", Version: "2.1.11-1", PackageBase: "zfs-utils"},
  754. }, nil
  755. }
  756. if len(query.Needles) == 1 {
  757. return []aur.Pkg{
  758. {Name: "zfs-utils", Version: "2.1.11-1", PackageBase: "zfs-utils"},
  759. }, nil
  760. }
  761. panic("not implemented")
  762. },
  763. }
  764. type fields struct {
  765. input io.Reader
  766. noConfirm bool
  767. devel bool
  768. }
  769. type args struct {
  770. graph *topo.Graph[string, *dep.InstallInfo]
  771. enableDowngrade bool
  772. }
  773. tests := []struct {
  774. name string
  775. fields fields
  776. args args
  777. mustExist map[string]*dep.InstallInfo
  778. mustNotExist map[string]bool
  779. wantExclude []string
  780. wantErr bool
  781. remotePackages []string
  782. }{
  783. {
  784. name: "no input",
  785. fields: fields{
  786. input: strings.NewReader("\n"),
  787. noConfirm: false,
  788. },
  789. args: args{
  790. graph: nil,
  791. enableDowngrade: false,
  792. },
  793. mustExist: map[string]*dep.InstallInfo{
  794. "zfs-dkms": zfsDKMSInfo,
  795. "zfs-utils": zfsUtilsInfo,
  796. },
  797. remotePackages: []string{"zfs-utils", "zfs-dkms"},
  798. mustNotExist: map[string]bool{},
  799. wantErr: false,
  800. wantExclude: []string{},
  801. },
  802. {
  803. name: "no input - inverted order",
  804. fields: fields{
  805. input: strings.NewReader("\n"),
  806. noConfirm: false,
  807. },
  808. args: args{
  809. graph: nil,
  810. enableDowngrade: false,
  811. },
  812. mustExist: map[string]*dep.InstallInfo{
  813. "zfs-dkms": zfsDKMSInfo,
  814. "zfs-utils": zfsUtilsInfo,
  815. },
  816. remotePackages: []string{"zfs-dkms", "zfs-utils"},
  817. mustNotExist: map[string]bool{},
  818. wantErr: false,
  819. wantExclude: []string{},
  820. },
  821. }
  822. for _, tt := range tests {
  823. tt := tt
  824. t.Run(tt.name, func(t *testing.T) {
  825. t.Parallel()
  826. dbExe := &mock.DBExecutor{
  827. InstalledRemotePackageNamesFn: func() []string {
  828. return tt.remotePackages
  829. },
  830. InstalledRemotePackagesFn: func() map[string]mock.IPackage {
  831. mapRemote := make(map[string]mock.IPackage)
  832. mapRemote["zfs-dkms"] = &mock.Package{
  833. PName: "zfs-dkms",
  834. PBase: "zfs-dkms",
  835. PVersion: "2.1.10-1",
  836. PReason: alpm.PkgReasonExplicit,
  837. PDepends: mock.DependList{Depends: []alpm.Depend{
  838. {Name: "zfs-utils", Version: "2.1.10-1"},
  839. }},
  840. }
  841. mapRemote["zfs-utils"] = &mock.Package{
  842. PName: "zfs-utils",
  843. PBase: "zfs-utils",
  844. PVersion: "2.1.10-1",
  845. PReason: alpm.PkgReasonDepend,
  846. }
  847. return mapRemote
  848. },
  849. LocalSatisfierExistsFn: func(string) bool { return false },
  850. SyncSatisfierFn: func(s string) mock.IPackage {
  851. return nil
  852. },
  853. SyncUpgradesFn: func(bool) (map[string]db.SyncUpgrade, error) {
  854. mapUpgrades := make(map[string]db.SyncUpgrade)
  855. return mapUpgrades, nil
  856. },
  857. ReposFn: func() []string { return []string{"core"} },
  858. }
  859. logger := text.NewLogger(io.Discard, os.Stderr,
  860. tt.fields.input, true, "test")
  861. grapher := dep.NewGrapher(dbExe, &settings.Configuration{}, mockAUR, &exe.MockBuilder{Runner: &exe.MockRunner{}},
  862. false, true, false, false, false, logger)
  863. cfg := &settings.Configuration{
  864. Devel: tt.fields.devel, Mode: parser.ModeAny,
  865. }
  866. u := &UpgradeService{
  867. log: logger,
  868. grapher: grapher,
  869. aurCache: mockAUR,
  870. dbExecutor: dbExe,
  871. vcsStore: vcsStore,
  872. cfg: cfg,
  873. noConfirm: tt.fields.noConfirm,
  874. AURWarnings: query.NewWarnings(logger),
  875. }
  876. got, err := u.GraphUpgrades(context.Background(), tt.args.graph, tt.args.enableDowngrade, func(*Upgrade) bool { return true })
  877. if (err != nil) != tt.wantErr {
  878. t.Errorf("UpgradeService.GraphUpgrades() error = %v, wantErr %v", err, tt.wantErr)
  879. return
  880. }
  881. excluded, err := u.UserExcludeUpgrades(got)
  882. require.NoError(t, err)
  883. for node, info := range tt.mustExist {
  884. assert.True(t, got.Exists(node), node)
  885. assert.Equal(t, info, got.GetNodeInfo(node).Value)
  886. }
  887. for node := range tt.mustNotExist {
  888. assert.False(t, got.Exists(node), node)
  889. }
  890. assert.ElementsMatch(t, tt.wantExclude, excluded)
  891. })
  892. }
  893. }