service_test.go 24 KB

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