db_test.go 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322
  1. // Copyright (C) 2025 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package sqlite
  7. import (
  8. "context"
  9. "crypto/sha256"
  10. "encoding/binary"
  11. "errors"
  12. "iter"
  13. "os"
  14. "path"
  15. "path/filepath"
  16. "sync"
  17. "testing"
  18. "time"
  19. "github.com/syncthing/syncthing/internal/db"
  20. "github.com/syncthing/syncthing/internal/itererr"
  21. "github.com/syncthing/syncthing/internal/timeutil"
  22. "github.com/syncthing/syncthing/lib/build"
  23. "github.com/syncthing/syncthing/lib/config"
  24. "github.com/syncthing/syncthing/lib/protocol"
  25. )
  26. const (
  27. folderID = "test"
  28. blockSize = 128 << 10
  29. dirSize = 128
  30. )
  31. func TestBasics(t *testing.T) {
  32. t.Parallel()
  33. sdb, err := Open(t.TempDir())
  34. if err != nil {
  35. t.Fatal(err)
  36. }
  37. t.Cleanup(func() {
  38. if err := sdb.Close(); err != nil {
  39. t.Fatal(err)
  40. }
  41. })
  42. // Some local files
  43. local := []protocol.FileInfo{
  44. genFile("test1", 1, 0),
  45. genDir("test2", 0),
  46. genFile("test2/a", 2, 0),
  47. genFile("test2/b", 3, 0),
  48. }
  49. err = sdb.Update(folderID, protocol.LocalDeviceID, local)
  50. if err != nil {
  51. t.Fatal(err)
  52. }
  53. // Some remote files
  54. remote := []protocol.FileInfo{
  55. genFile("test3", 3, 101),
  56. genFile("test4", 4, 102),
  57. genFile("test1", 5, 103),
  58. }
  59. // All newer than the local ones
  60. for i := range remote {
  61. remote[i].Version = remote[i].Version.Update(42)
  62. }
  63. err = sdb.Update(folderID, protocol.DeviceID{42}, remote)
  64. if err != nil {
  65. t.Fatal(err)
  66. }
  67. const (
  68. localSize = (1+2+3)*blockSize + dirSize
  69. remoteSize = (3 + 4 + 5) * blockSize
  70. globalSize = (2+3+3+4+5)*blockSize + dirSize
  71. needSizeLocal = remoteSize
  72. needSizeRemote = (2+3)*blockSize + dirSize
  73. )
  74. t.Run("SchemaVersion", func(t *testing.T) {
  75. tx, err := sdb.sql.Beginx()
  76. if err != nil {
  77. t.Fatal(err)
  78. }
  79. defer tx.Rollback()
  80. ver, err := sdb.getAppliedSchemaVersion(tx)
  81. if err != nil {
  82. t.Fatal(err)
  83. }
  84. if ver.SchemaVersion != currentSchemaVersion {
  85. t.Log(ver)
  86. t.Error("should be version 1")
  87. }
  88. if d := time.Since(ver.AppliedTime()); d > time.Minute || d < 0 {
  89. t.Log(ver)
  90. t.Error("suspicious applied tim")
  91. }
  92. })
  93. t.Run("Local", func(t *testing.T) {
  94. t.Parallel()
  95. fi, ok, err := sdb.GetDeviceFile(folderID, protocol.LocalDeviceID, "test2/a") // exists
  96. if err != nil {
  97. t.Fatal(err)
  98. }
  99. if !ok {
  100. t.Fatal("not found")
  101. }
  102. if fi.Name != filepath.FromSlash("test2/a") {
  103. t.Fatal("should have got test2/a")
  104. }
  105. if len(fi.Blocks) != 2 {
  106. t.Fatal("expected two blocks")
  107. }
  108. _, ok, err = sdb.GetDeviceFile(folderID, protocol.LocalDeviceID, "test3") // does not exist
  109. if err != nil {
  110. t.Fatal(err)
  111. }
  112. if ok {
  113. t.Fatal("should be not found")
  114. }
  115. })
  116. t.Run("Global", func(t *testing.T) {
  117. t.Parallel()
  118. fi, ok, err := sdb.GetGlobalFile(folderID, "test1")
  119. if err != nil {
  120. t.Fatal(err)
  121. }
  122. if !ok {
  123. t.Fatal("not found")
  124. }
  125. if fi.Size != 5*blockSize {
  126. t.Fatal("should be the remote file")
  127. }
  128. })
  129. t.Run("AllLocal", func(t *testing.T) {
  130. t.Parallel()
  131. have := mustCollect[protocol.FileInfo](t)(sdb.AllLocalFiles(folderID, protocol.LocalDeviceID))
  132. if len(have) != 4 {
  133. t.Log(have)
  134. t.Error("expected four files")
  135. }
  136. have = mustCollect[protocol.FileInfo](t)(sdb.AllLocalFiles(folderID, protocol.DeviceID{42}))
  137. if len(have) != 3 {
  138. t.Log(have)
  139. t.Error("expected three files")
  140. }
  141. })
  142. t.Run("AllNeededNamesLocal", func(t *testing.T) {
  143. t.Parallel()
  144. need := fiNames(mustCollect[protocol.FileInfo](t)(sdb.AllNeededGlobalFiles(folderID, protocol.LocalDeviceID, config.PullOrderAlphabetic, 0, 0)))
  145. if len(need) != 3 || need[0] != "test1" {
  146. t.Log(need)
  147. t.Error("expected three files, ordered alphabetically")
  148. }
  149. need = fiNames(mustCollect[protocol.FileInfo](t)(sdb.AllNeededGlobalFiles(folderID, protocol.LocalDeviceID, config.PullOrderAlphabetic, 1, 0)))
  150. if len(need) != 1 || need[0] != "test1" {
  151. t.Log(need)
  152. t.Error("expected one file, limited, ordered alphabetically")
  153. }
  154. need = fiNames(mustCollect[protocol.FileInfo](t)(sdb.AllNeededGlobalFiles(folderID, protocol.LocalDeviceID, config.PullOrderLargestFirst, 0, 0)))
  155. if len(need) != 3 || need[0] != "test1" { // largest
  156. t.Log(need)
  157. t.Error("expected three files, ordered largest to smallest")
  158. }
  159. need = fiNames(mustCollect[protocol.FileInfo](t)(sdb.AllNeededGlobalFiles(folderID, protocol.LocalDeviceID, config.PullOrderSmallestFirst, 0, 0)))
  160. if len(need) != 3 || need[0] != "test3" { // smallest
  161. t.Log(need)
  162. t.Error("expected three files, ordered smallest to largest")
  163. }
  164. need = fiNames(mustCollect[protocol.FileInfo](t)(sdb.AllNeededGlobalFiles(folderID, protocol.LocalDeviceID, config.PullOrderNewestFirst, 0, 0)))
  165. if len(need) != 3 || need[0] != "test1" { // newest
  166. t.Log(need)
  167. t.Error("expected three files, ordered newest to oldest")
  168. }
  169. need = fiNames(mustCollect[protocol.FileInfo](t)(sdb.AllNeededGlobalFiles(folderID, protocol.LocalDeviceID, config.PullOrderOldestFirst, 0, 0)))
  170. if len(need) != 3 || need[0] != "test3" { // oldest
  171. t.Log(need)
  172. t.Error("expected three files, ordered oldest to newest")
  173. }
  174. })
  175. t.Run("LocalSize", func(t *testing.T) {
  176. t.Parallel()
  177. // Local device
  178. c, err := sdb.CountLocal(folderID, protocol.LocalDeviceID)
  179. if err != nil {
  180. t.Fatal(err)
  181. }
  182. if c.Files != 3 {
  183. t.Log(c)
  184. t.Error("one file expected")
  185. }
  186. if c.Directories != 1 {
  187. t.Log(c)
  188. t.Error("one directory expected")
  189. }
  190. if c.Bytes != localSize {
  191. t.Log(c)
  192. t.Error("size unexpected")
  193. }
  194. // Other device
  195. c, err = sdb.CountLocal(folderID, protocol.DeviceID{42})
  196. if err != nil {
  197. t.Fatal(err)
  198. }
  199. if c.Files != 3 {
  200. t.Log(c)
  201. t.Error("three files expected")
  202. }
  203. if c.Directories != 0 {
  204. t.Log(c)
  205. t.Error("no directories expected")
  206. }
  207. if c.Bytes != remoteSize {
  208. t.Log(c)
  209. t.Error("size unexpected")
  210. }
  211. })
  212. t.Run("GlobalSize", func(t *testing.T) {
  213. t.Parallel()
  214. c, err := sdb.CountGlobal(folderID)
  215. if err != nil {
  216. t.Fatal(err)
  217. }
  218. if c.Files != 5 {
  219. t.Log(c)
  220. t.Error("five files expected")
  221. }
  222. if c.Directories != 1 {
  223. t.Log(c)
  224. t.Error("one directory expected")
  225. }
  226. if c.Bytes != int64(globalSize) {
  227. t.Log(c)
  228. t.Error("size unexpected")
  229. }
  230. })
  231. t.Run("NeedSizeLocal", func(t *testing.T) {
  232. t.Parallel()
  233. c, err := sdb.CountNeed(folderID, protocol.LocalDeviceID)
  234. if err != nil {
  235. t.Fatal(err)
  236. }
  237. if c.Files != 3 {
  238. t.Log(c)
  239. t.Error("three files expected")
  240. }
  241. if c.Directories != 0 {
  242. t.Log(c)
  243. t.Error("no directories expected")
  244. }
  245. if c.Bytes != needSizeLocal {
  246. t.Log(c)
  247. t.Error("size unexpected")
  248. }
  249. })
  250. t.Run("NeedSizeRemote", func(t *testing.T) {
  251. t.Parallel()
  252. c, err := sdb.CountNeed(folderID, protocol.DeviceID{42})
  253. if err != nil {
  254. t.Fatal(err)
  255. }
  256. if c.Files != 2 {
  257. t.Log(c)
  258. t.Error("two files expected")
  259. }
  260. if c.Directories != 1 {
  261. t.Log(c)
  262. t.Error("one directory expected")
  263. }
  264. if c.Bytes != needSizeRemote {
  265. t.Log(c)
  266. t.Error("size unexpected")
  267. }
  268. })
  269. t.Run("Folders", func(t *testing.T) {
  270. t.Parallel()
  271. folders, err := sdb.ListFolders()
  272. if err != nil {
  273. t.Fatal(err)
  274. }
  275. if len(folders) != 1 || folders[0] != folderID {
  276. t.Log(folders)
  277. t.Error("expected one folder")
  278. }
  279. })
  280. t.Run("DevicesForFolder", func(t *testing.T) {
  281. t.Parallel()
  282. devs, err := sdb.ListDevicesForFolder("test")
  283. if err != nil {
  284. t.Fatal(err)
  285. }
  286. if len(devs) != 1 || devs[0] != (protocol.DeviceID{42}) {
  287. t.Log(devs)
  288. t.Error("expected one device")
  289. }
  290. })
  291. t.Run("Sequence", func(t *testing.T) {
  292. t.Parallel()
  293. iid, err := sdb.GetIndexID(folderID, protocol.LocalDeviceID)
  294. if err != nil {
  295. t.Fatal(err)
  296. }
  297. if iid == 0 {
  298. t.Log(iid)
  299. t.Fatal("expected index ID")
  300. }
  301. if seq, err := sdb.GetDeviceSequence(folderID, protocol.LocalDeviceID); err != nil {
  302. t.Fatal(err)
  303. } else if seq != 4 {
  304. t.Log(seq)
  305. t.Error("expected local sequence to match number of files inserted")
  306. }
  307. if seq, err := sdb.GetDeviceSequence(folderID, protocol.DeviceID{42}); err != nil {
  308. t.Fatal(err)
  309. } else if seq != 103 {
  310. t.Log(seq)
  311. t.Error("expected remote sequence to match highest sent")
  312. }
  313. // Non-existent should be zero and no error
  314. if seq, err := sdb.GetDeviceSequence("trolol", protocol.LocalDeviceID); err != nil {
  315. t.Fatal(err)
  316. } else if seq != 0 {
  317. t.Log(seq)
  318. t.Error("expected zero sequence")
  319. }
  320. if seq, err := sdb.GetDeviceSequence("trolol", protocol.DeviceID{42}); err != nil {
  321. t.Fatal(err)
  322. } else if seq != 0 {
  323. t.Log(seq)
  324. t.Error("expected zero sequence")
  325. }
  326. if seq, err := sdb.GetDeviceSequence(folderID, protocol.DeviceID{99}); err != nil {
  327. t.Fatal(err)
  328. } else if seq != 0 {
  329. t.Log(seq)
  330. t.Error("expected zero sequence")
  331. }
  332. })
  333. t.Run("AllGlobalPrefix", func(t *testing.T) {
  334. t.Parallel()
  335. vals := mustCollect[db.FileMetadata](t)(sdb.AllGlobalFilesPrefix(folderID, "test2"))
  336. // Vals should be test2, test2/a, test2/b
  337. if len(vals) != 3 {
  338. t.Log(vals)
  339. t.Error("expected three items")
  340. } else if vals[0].Name != "test2" {
  341. t.Error(vals)
  342. }
  343. // Empty prefix should be all the files
  344. vals = mustCollect[db.FileMetadata](t)(sdb.AllGlobalFilesPrefix(folderID, ""))
  345. if len(vals) != 6 {
  346. t.Log(vals)
  347. t.Error("expected six items")
  348. }
  349. })
  350. t.Run("AllLocalPrefix", func(t *testing.T) {
  351. t.Parallel()
  352. vals := mustCollect[protocol.FileInfo](t)(sdb.AllLocalFilesWithPrefix(folderID, protocol.LocalDeviceID, "test2"))
  353. // Vals should be test2, test2/a, test2/b
  354. if len(vals) != 3 {
  355. t.Log(vals)
  356. t.Error("expected three items")
  357. } else if vals[0].Name != "test2" {
  358. t.Error(vals)
  359. }
  360. // Empty prefix should be all the files
  361. vals = mustCollect[protocol.FileInfo](t)(sdb.AllLocalFilesWithPrefix(folderID, protocol.LocalDeviceID, ""))
  362. if len(vals) != 4 {
  363. t.Log(vals)
  364. t.Error("expected four items")
  365. }
  366. })
  367. t.Run("AllLocalSequenced", func(t *testing.T) {
  368. t.Parallel()
  369. vals := mustCollect[protocol.FileInfo](t)(sdb.AllLocalFilesBySequence(folderID, protocol.LocalDeviceID, 3, 0))
  370. // Vals should be test2/a, test2/b
  371. if len(vals) != 2 {
  372. t.Log(vals)
  373. t.Error("expected three items")
  374. } else if vals[0].Name != filepath.FromSlash("test2/a") || vals[0].Sequence != 3 {
  375. t.Error(vals)
  376. }
  377. })
  378. }
  379. func TestPrefixGlobbing(t *testing.T) {
  380. t.Parallel()
  381. sdb, err := Open(t.TempDir())
  382. if err != nil {
  383. t.Fatal(err)
  384. }
  385. t.Cleanup(func() {
  386. if err := sdb.Close(); err != nil {
  387. t.Fatal(err)
  388. }
  389. })
  390. // Some local files
  391. local := []protocol.FileInfo{
  392. genFile("test1", 1, 0),
  393. genDir("test2", 0),
  394. genFile("test2/a", 2, 0),
  395. genDir("test2/b", 0),
  396. genFile("test2/b/c", 3, 0),
  397. }
  398. err = sdb.Update(folderID, protocol.LocalDeviceID, local)
  399. if err != nil {
  400. t.Fatal(err)
  401. }
  402. vals := mustCollect[protocol.FileInfo](t)(sdb.AllLocalFilesWithPrefix(folderID, protocol.LocalDeviceID, "test2"))
  403. // Vals should be test2, test2/a, test2/b, test2/b/c
  404. if len(vals) != 4 {
  405. t.Log(vals)
  406. t.Error("expected four items")
  407. } else if vals[0].Name != "test2" || vals[3].Name != filepath.FromSlash("test2/b/c") {
  408. t.Error(vals)
  409. }
  410. // Empty prefix should be all the files
  411. vals = mustCollect[protocol.FileInfo](t)(sdb.AllLocalFilesWithPrefix(folderID, protocol.LocalDeviceID, ""))
  412. if len(vals) != 5 {
  413. t.Log(vals)
  414. t.Error("expected five items")
  415. }
  416. // Same as partial prefix
  417. vals = mustCollect[protocol.FileInfo](t)(sdb.AllLocalFilesWithPrefix(folderID, protocol.LocalDeviceID, "tes"))
  418. if len(vals) != 5 {
  419. t.Log(vals)
  420. t.Error("expected five items")
  421. }
  422. // Prefix should be case sensitive, so no match here
  423. vals = mustCollect[protocol.FileInfo](t)(sdb.AllLocalFilesWithPrefix(folderID, protocol.LocalDeviceID, "tEsT2"))
  424. if len(vals) != 0 {
  425. t.Log(vals)
  426. t.Error("expected no items")
  427. }
  428. // Subdir should match
  429. vals = mustCollect[protocol.FileInfo](t)(sdb.AllLocalFilesWithPrefix(folderID, protocol.LocalDeviceID, "test2/b"))
  430. if len(vals) != 2 {
  431. t.Log(vals)
  432. t.Error("expected two items")
  433. }
  434. }
  435. func TestPrefixGlobbingStar(t *testing.T) {
  436. t.Parallel()
  437. sdb, err := Open(t.TempDir())
  438. if err != nil {
  439. t.Fatal(err)
  440. }
  441. t.Cleanup(func() {
  442. if err := sdb.Close(); err != nil {
  443. t.Fatal(err)
  444. }
  445. })
  446. // Some local files
  447. local := []protocol.FileInfo{
  448. genFile("test1a", 1, 0),
  449. genFile("test*a", 2, 0),
  450. genFile("test2a", 3, 0),
  451. }
  452. err = sdb.Update(folderID, protocol.LocalDeviceID, local)
  453. if err != nil {
  454. t.Fatal(err)
  455. }
  456. vals := mustCollect[protocol.FileInfo](t)(sdb.AllLocalFilesWithPrefix(folderID, protocol.LocalDeviceID, "test*a"))
  457. // Vals should be test*a
  458. if len(vals) != 1 {
  459. t.Log(vals)
  460. t.Error("expected one item")
  461. } else if vals[0].Name != "test*a" {
  462. t.Error(vals)
  463. }
  464. }
  465. func TestAvailability(t *testing.T) {
  466. db, err := Open(t.TempDir())
  467. if err != nil {
  468. t.Fatal(err)
  469. }
  470. const folderID = "test"
  471. // Some local files
  472. err = db.Update(folderID, protocol.LocalDeviceID, []protocol.FileInfo{
  473. genFile("test1", 1, 0),
  474. genFile("test2", 2, 0),
  475. })
  476. if err != nil {
  477. t.Fatal(err)
  478. }
  479. // Some remote files
  480. err = db.Update(folderID, protocol.DeviceID{42}, []protocol.FileInfo{
  481. genFile("test2", 2, 1),
  482. genFile("test3", 3, 2),
  483. })
  484. if err != nil {
  485. t.Fatal(err)
  486. }
  487. // Further remote files
  488. err = db.Update(folderID, protocol.DeviceID{45}, []protocol.FileInfo{
  489. genFile("test3", 3, 1),
  490. genFile("test4", 4, 2),
  491. })
  492. if err != nil {
  493. t.Fatal(err)
  494. }
  495. a, err := db.GetGlobalAvailability(folderID, "test1")
  496. if err != nil {
  497. t.Fatal(err)
  498. }
  499. if len(a) != 0 {
  500. t.Log(a)
  501. t.Error("expected no availability (only local)")
  502. }
  503. a, err = db.GetGlobalAvailability(folderID, "test2")
  504. if err != nil {
  505. t.Fatal(err)
  506. }
  507. if len(a) != 1 || a[0] != (protocol.DeviceID{42}) {
  508. t.Log(a)
  509. t.Error("expected one availability (only 42)")
  510. }
  511. a, err = db.GetGlobalAvailability(folderID, "test3")
  512. if err != nil {
  513. t.Fatal(err)
  514. }
  515. if len(a) != 2 || a[0] != (protocol.DeviceID{42}) || a[1] != (protocol.DeviceID{45}) {
  516. t.Log(a)
  517. t.Error("expected two availabilities (both remotes)")
  518. }
  519. if err := db.Close(); err != nil {
  520. t.Fatal(err)
  521. }
  522. }
  523. func TestDropFilesNamed(t *testing.T) {
  524. db, err := Open(t.TempDir())
  525. if err != nil {
  526. t.Fatal(err)
  527. }
  528. t.Cleanup(func() {
  529. if err := db.Close(); err != nil {
  530. t.Fatal(err)
  531. }
  532. })
  533. const folderID = "test"
  534. // Some local files
  535. err = db.Update(folderID, protocol.LocalDeviceID, []protocol.FileInfo{
  536. genFile("test1", 1, 0),
  537. genFile("test2", 2, 0),
  538. })
  539. if err != nil {
  540. t.Fatal(err)
  541. }
  542. // Drop test1
  543. if err := db.DropFilesNamed(folderID, protocol.LocalDeviceID, []string{"test1"}); err != nil {
  544. t.Fatal(err)
  545. }
  546. // Check
  547. if _, ok, err := db.GetDeviceFile(folderID, protocol.LocalDeviceID, "test1"); err != nil || ok {
  548. t.Log(err, ok)
  549. t.Error("expected to not exist")
  550. }
  551. if c, err := db.CountLocal(folderID, protocol.LocalDeviceID); err != nil {
  552. t.Fatal(err)
  553. } else if c.Files != 1 {
  554. t.Log(c)
  555. t.Error("expected count to be one")
  556. }
  557. if _, ok, err := db.GetDeviceFile(folderID, protocol.LocalDeviceID, "test2"); err != nil || !ok {
  558. t.Log(err, ok)
  559. t.Error("expected to exist")
  560. }
  561. }
  562. func TestDropFolder(t *testing.T) {
  563. db, err := Open(t.TempDir())
  564. if err != nil {
  565. t.Fatal(err)
  566. }
  567. t.Cleanup(func() {
  568. if err := db.Close(); err != nil {
  569. t.Fatal(err)
  570. }
  571. })
  572. // Some local files
  573. // Folder A
  574. err = db.Update("a", protocol.LocalDeviceID, []protocol.FileInfo{
  575. genFile("test1", 1, 0),
  576. genFile("test2", 2, 0),
  577. })
  578. if err != nil {
  579. t.Fatal(err)
  580. }
  581. // Folder B
  582. err = db.Update("b", protocol.LocalDeviceID, []protocol.FileInfo{
  583. genFile("test1", 1, 0),
  584. genFile("test2", 2, 0),
  585. })
  586. if err != nil {
  587. t.Fatal(err)
  588. }
  589. // Drop A
  590. if err := db.DropFolder("a"); err != nil {
  591. t.Fatal(err)
  592. }
  593. // Check
  594. if _, ok, err := db.GetDeviceFile("a", protocol.LocalDeviceID, "test1"); err != nil || ok {
  595. t.Log(err, ok)
  596. t.Error("expected to not exist")
  597. }
  598. if c, err := db.CountLocal("a", protocol.LocalDeviceID); err != nil {
  599. t.Fatal(err)
  600. } else if c.Files != 0 {
  601. t.Log(c)
  602. t.Error("expected count to be zero")
  603. }
  604. if _, ok, err := db.GetDeviceFile("b", protocol.LocalDeviceID, "test1"); err != nil || !ok {
  605. t.Log(err, ok)
  606. t.Error("expected to exist")
  607. }
  608. if c, err := db.CountLocal("b", protocol.LocalDeviceID); err != nil {
  609. t.Fatal(err)
  610. } else if c.Files != 2 {
  611. t.Log(c)
  612. t.Error("expected count to be two")
  613. }
  614. }
  615. func TestDropDevice(t *testing.T) {
  616. db, err := Open(t.TempDir())
  617. if err != nil {
  618. t.Fatal(err)
  619. }
  620. t.Cleanup(func() {
  621. if err := db.Close(); err != nil {
  622. t.Fatal(err)
  623. }
  624. })
  625. // Some local files
  626. // Device 1
  627. err = db.Update("a", protocol.DeviceID{1}, []protocol.FileInfo{
  628. genFile("test1", 1, 1),
  629. genFile("test2", 2, 2),
  630. })
  631. if err != nil {
  632. t.Fatal(err)
  633. }
  634. // Device 2
  635. err = db.Update("a", protocol.DeviceID{2}, []protocol.FileInfo{
  636. genFile("test1", 1, 1),
  637. genFile("test2", 2, 2),
  638. })
  639. if err != nil {
  640. t.Fatal(err)
  641. }
  642. // Drop 1
  643. if err := db.DropDevice(protocol.DeviceID{1}); err != nil {
  644. t.Fatal(err)
  645. }
  646. // Check
  647. if _, ok, err := db.GetDeviceFile("a", protocol.DeviceID{1}, "test1"); err != nil || ok {
  648. t.Log(err, ok)
  649. t.Error("expected to not exist")
  650. }
  651. if c, err := db.CountLocal("a", protocol.DeviceID{1}); err != nil {
  652. t.Fatal(err)
  653. } else if c.Files != 0 {
  654. t.Log(c)
  655. t.Error("expected count to be zero")
  656. }
  657. if _, ok, err := db.GetDeviceFile("a", protocol.DeviceID{2}, "test1"); err != nil || !ok {
  658. t.Log(err, ok)
  659. t.Error("expected to exist")
  660. }
  661. if c, err := db.CountLocal("a", protocol.DeviceID{2}); err != nil {
  662. t.Fatal(err)
  663. } else if c.Files != 2 {
  664. t.Log(c)
  665. t.Error("expected count to be two")
  666. }
  667. // Drop something that doesn't exist
  668. if err := db.DropDevice(protocol.DeviceID{99}); err != nil {
  669. t.Fatal(err)
  670. }
  671. }
  672. func TestDropAllFiles(t *testing.T) {
  673. db, err := Open(t.TempDir())
  674. if err != nil {
  675. t.Fatal(err)
  676. }
  677. t.Cleanup(func() {
  678. if err := db.Close(); err != nil {
  679. t.Fatal(err)
  680. }
  681. })
  682. // Some local files
  683. // Device 1 folder A
  684. err = db.Update("a", protocol.DeviceID{1}, []protocol.FileInfo{
  685. genFile("test1", 1, 1),
  686. genFile("test2", 2, 2),
  687. })
  688. if err != nil {
  689. t.Fatal(err)
  690. }
  691. // Device 1 folder B
  692. err = db.Update("b", protocol.DeviceID{1}, []protocol.FileInfo{
  693. genFile("test1", 1, 1),
  694. genFile("test2", 2, 2),
  695. })
  696. if err != nil {
  697. t.Fatal(err)
  698. }
  699. // Drop folder A
  700. if err := db.DropAllFiles("a", protocol.DeviceID{1}); err != nil {
  701. t.Fatal(err)
  702. }
  703. // Check
  704. if _, ok, err := db.GetDeviceFile("a", protocol.DeviceID{1}, "test1"); err != nil || ok {
  705. t.Log(err, ok)
  706. t.Error("expected to not exist")
  707. }
  708. if c, err := db.CountLocal("a", protocol.DeviceID{1}); err != nil {
  709. t.Fatal(err)
  710. } else if c.Files != 0 {
  711. t.Log(c)
  712. t.Error("expected count to be zero")
  713. }
  714. if _, ok, err := db.GetDeviceFile("b", protocol.DeviceID{1}, "test1"); err != nil || !ok {
  715. t.Log(err, ok)
  716. t.Error("expected to exist")
  717. }
  718. if c, err := db.CountLocal("b", protocol.DeviceID{1}); err != nil {
  719. t.Fatal(err)
  720. } else if c.Files != 2 {
  721. t.Log(c)
  722. t.Error("expected count to be two")
  723. }
  724. // Drop things that don't exist
  725. if err := db.DropAllFiles("a", protocol.DeviceID{99}); err != nil {
  726. t.Fatal(err)
  727. }
  728. if err := db.DropAllFiles("trolol", protocol.DeviceID{1}); err != nil {
  729. t.Fatal(err)
  730. }
  731. if err := db.DropAllFiles("trolol", protocol.DeviceID{99}); err != nil {
  732. t.Fatal(err)
  733. }
  734. }
  735. func TestConcurrentUpdate(t *testing.T) {
  736. t.Parallel()
  737. db, err := Open(filepath.Join(t.TempDir(), "db"))
  738. if err != nil {
  739. t.Fatal(err)
  740. }
  741. t.Cleanup(func() {
  742. if err := db.Close(); err != nil {
  743. t.Fatal(err)
  744. }
  745. })
  746. const folderID = "test"
  747. files := []protocol.FileInfo{
  748. genFile("test1", 1, 1),
  749. genFile("test2", 2, 2),
  750. genFile("test3", 3, 3),
  751. genFile("test4", 4, 4),
  752. }
  753. const n = 32
  754. res := make([]error, n)
  755. var wg sync.WaitGroup
  756. wg.Add(n)
  757. for i := range n {
  758. go func() {
  759. res[i] = db.Update(folderID, protocol.DeviceID{byte(i), byte(i), byte(i)}, files)
  760. wg.Done()
  761. }()
  762. }
  763. wg.Wait()
  764. for i, err := range res {
  765. if err != nil {
  766. t.Errorf("%d: %v", i, err)
  767. }
  768. }
  769. }
  770. func TestConcurrentUpdateSelect(t *testing.T) {
  771. t.Parallel()
  772. db, err := Open(filepath.Join(t.TempDir(), "db"))
  773. if err != nil {
  774. t.Fatal(err)
  775. }
  776. t.Cleanup(func() {
  777. if err := db.Close(); err != nil {
  778. t.Fatal(err)
  779. }
  780. })
  781. const folderID = "test"
  782. // Some local files
  783. files := []protocol.FileInfo{
  784. genFile("test1", 1, 1),
  785. genFile("test2", 2, 2),
  786. genFile("test3", 3, 3),
  787. genFile("test4", 4, 4),
  788. }
  789. // Insert the files for a remote device
  790. if err := db.Update(folderID, protocol.DeviceID{42}, files); err != nil {
  791. t.Fatal()
  792. }
  793. // Iterate over handled files and insert them for the local device.
  794. // This is similar to a pattern we have in other places and should
  795. // work.
  796. handled := 0
  797. it, errFn := db.AllNeededGlobalFiles(folderID, protocol.LocalDeviceID, config.PullOrderAlphabetic, 0, 0)
  798. for glob := range it {
  799. glob.Version = glob.Version.Update(1)
  800. if err := db.Update(folderID, protocol.LocalDeviceID, []protocol.FileInfo{glob}); err != nil {
  801. t.Fatal(err)
  802. }
  803. handled++
  804. }
  805. if err := errFn(); err != nil {
  806. t.Fatal(err)
  807. }
  808. if handled != len(files) {
  809. t.Log(handled)
  810. t.Error("should have handled all the files")
  811. }
  812. }
  813. func TestAllForBlocksHash(t *testing.T) {
  814. t.Parallel()
  815. sdb, err := Open(t.TempDir())
  816. if err != nil {
  817. t.Fatal(err)
  818. }
  819. t.Cleanup(func() {
  820. if err := sdb.Close(); err != nil {
  821. t.Fatal(err)
  822. }
  823. })
  824. // test1 is unique, while test2 and test3 have the same blocks and hence
  825. // the same blocks hash
  826. files := []protocol.FileInfo{
  827. genFile("test1", 1, 1),
  828. genFile("test2", 2, 2),
  829. genFile("test3", 3, 3),
  830. }
  831. files[2].Blocks = files[1].Blocks
  832. if err := sdb.Update(folderID, protocol.LocalDeviceID, files); err != nil {
  833. t.Fatal(err)
  834. }
  835. // Check test1
  836. test1, ok, err := sdb.GetDeviceFile(folderID, protocol.LocalDeviceID, "test1")
  837. if err != nil || !ok {
  838. t.Fatal("expected to exist")
  839. }
  840. vals := mustCollect[db.FileMetadata](t)(sdb.AllLocalFilesWithBlocksHash(folderID, test1.BlocksHash))
  841. if len(vals) != 1 {
  842. t.Log(vals)
  843. t.Fatal("expected one file to match")
  844. }
  845. // Check test2 which also matches test3
  846. test2, ok, err := sdb.GetDeviceFile(folderID, protocol.LocalDeviceID, "test2")
  847. if err != nil || !ok {
  848. t.Fatal("expected to exist")
  849. }
  850. vals = mustCollect[db.FileMetadata](t)(sdb.AllLocalFilesWithBlocksHash(folderID, test2.BlocksHash))
  851. if len(vals) != 2 {
  852. t.Log(vals)
  853. t.Fatal("expected two files to match")
  854. }
  855. if vals[0].Name != "test2" {
  856. t.Log(vals[0])
  857. t.Error("expected test2")
  858. }
  859. if vals[1].Name != "test3" {
  860. t.Log(vals[1])
  861. t.Error("expected test3")
  862. }
  863. }
  864. func TestBlocklistGarbageCollection(t *testing.T) {
  865. t.Parallel()
  866. sdb, err := Open(t.TempDir())
  867. if err != nil {
  868. t.Fatal(err)
  869. }
  870. t.Cleanup(func() {
  871. if err := sdb.Close(); err != nil {
  872. t.Fatal(err)
  873. }
  874. })
  875. svc := sdb.Service(time.Hour).(*Service)
  876. // Add three files
  877. files := []protocol.FileInfo{
  878. genFile("test1", 1, 1),
  879. genFile("test2", 2, 2),
  880. genFile("test3", 3, 3),
  881. }
  882. if err := sdb.Update(folderID, protocol.LocalDeviceID, files); err != nil {
  883. t.Fatal(err)
  884. }
  885. // There should exist three blockslists and six blocks
  886. fdb, err := sdb.getFolderDB(folderID, false)
  887. if err != nil {
  888. t.Fatal(err)
  889. }
  890. var count int
  891. if err := fdb.sql.Get(&count, `SELECT count(*) FROM blocklists`); err != nil {
  892. t.Fatal(err)
  893. }
  894. if count != 3 {
  895. t.Log(count)
  896. t.Fatal("expected 3 blocklists")
  897. }
  898. if err := fdb.sql.Get(&count, `SELECT count(*) FROM blocks`); err != nil {
  899. t.Fatal(err)
  900. }
  901. if count != 6 {
  902. t.Log(count)
  903. t.Fatal("expected 6 blocks")
  904. }
  905. // Mark test3 as deleted, it's blocks and blocklist are now eligible for collection
  906. files = files[2:]
  907. files[0].SetDeleted(42)
  908. if err := sdb.Update(folderID, protocol.LocalDeviceID, files); err != nil {
  909. t.Fatal(err)
  910. }
  911. // Run garbage collection
  912. if err := svc.periodic(context.Background()); err != nil {
  913. t.Fatal(err)
  914. }
  915. // There should exist two blockslists and four blocks
  916. if err := fdb.sql.Get(&count, `SELECT count(*) FROM blocklists`); err != nil {
  917. t.Fatal(err)
  918. }
  919. if count != 2 {
  920. t.Log(count)
  921. t.Error("expected 2 blocklists")
  922. }
  923. if err := fdb.sql.Get(&count, `SELECT count(*) FROM blocks`); err != nil {
  924. t.Fatal(err)
  925. }
  926. if count != 3 {
  927. t.Log(count)
  928. t.Error("expected 3 blocks")
  929. }
  930. }
  931. func TestInsertLargeFile(t *testing.T) {
  932. t.Parallel()
  933. sdb, err := Open(t.TempDir())
  934. if err != nil {
  935. t.Fatal(err)
  936. }
  937. t.Cleanup(func() {
  938. if err := sdb.Close(); err != nil {
  939. t.Fatal(err)
  940. }
  941. })
  942. // Add a large file (many blocks)
  943. files := []protocol.FileInfo{genFile("test1", 16000, 1)}
  944. if err := sdb.Update(folderID, protocol.LocalDeviceID, files); err != nil {
  945. t.Fatal(err)
  946. }
  947. // Verify all the blocks are here
  948. for i, block := range files[0].Blocks {
  949. bs, err := itererr.Collect(sdb.AllLocalBlocksWithHash(folderID, block.Hash))
  950. if err != nil {
  951. t.Fatal(err)
  952. }
  953. if len(bs) == 0 {
  954. t.Error("missing blocks for", i)
  955. }
  956. }
  957. }
  958. func TestErrorWrap(t *testing.T) {
  959. if wrap(nil, "foo") != nil {
  960. t.Fatal("nil should wrap to nil")
  961. }
  962. fooErr := errors.New("foo")
  963. if err := wrap(fooErr); err.Error() != "testerrorwrap: foo" {
  964. t.Fatalf("%q", err)
  965. }
  966. if err := wrap(fooErr, "bar", "baz"); err.Error() != "testerrorwrap (bar, baz): foo" {
  967. t.Fatalf("%q", err)
  968. }
  969. }
  970. func TestStrangeDeletedGlobalBug(t *testing.T) {
  971. // This exercises an edge case with serialisation and ordering of
  972. // version vectors. It does not need to make sense, it just needs to
  973. // pass.
  974. t.Parallel()
  975. sdb, err := Open(t.TempDir())
  976. if err != nil {
  977. t.Fatal(err)
  978. }
  979. t.Cleanup(func() {
  980. if err := sdb.Close(); err != nil {
  981. t.Fatal(err)
  982. }
  983. })
  984. // One remote device announces the original version of the file
  985. file := genFile("test", 1, 1)
  986. file.Version = protocol.Vector{Counters: []protocol.Counter{{ID: 35494436325452, Value: 1742900373}}}
  987. t.Log("orig", file.Version)
  988. sdb.Update(folderID, protocol.DeviceID{42}, []protocol.FileInfo{file})
  989. // Another one announces a newer one that is deleted
  990. del := file
  991. del.SetDeleted(43)
  992. del.Version = protocol.Vector{Counters: []protocol.Counter{{ID: 55445057455644, Value: 1742918457}, {ID: 35494436325452, Value: 1742900373}}}
  993. t.Log("del", del.Version)
  994. sdb.Update(folderID, protocol.DeviceID{43}, []protocol.FileInfo{del})
  995. // We have an instance of the original file
  996. sdb.Update(folderID, protocol.LocalDeviceID, []protocol.FileInfo{file})
  997. // Which one is the global? It should be the deleted one, clearly.
  998. g, _, err := sdb.GetGlobalFile(folderID, "test")
  999. if err != nil {
  1000. t.Fatal(err)
  1001. }
  1002. if !g.Deleted {
  1003. t.Log(g)
  1004. t.Fatal("should be deleted")
  1005. }
  1006. }
  1007. func TestOpenSpecialName(t *testing.T) {
  1008. dir := t.TempDir()
  1009. // Create a "base" dir that is in the way if the path becomes
  1010. // incorrectly truncated in the next steps.
  1011. base := path.Join(dir, "test")
  1012. if err := os.Mkdir(base, 0o755); err != nil {
  1013. t.Fatal(err)
  1014. }
  1015. // Should be able to open a path with a hash sign in it.
  1016. p1 := base + "#foo"
  1017. db, err := Open(p1)
  1018. if err != nil {
  1019. t.Fatal(err)
  1020. }
  1021. t.Log(db.path)
  1022. db.Close()
  1023. if !build.IsWindows {
  1024. // Should be able to open a path with something that looks like
  1025. // query params.
  1026. p2 := base + "?foo=bar"
  1027. db, err = Open(p2)
  1028. if err != nil {
  1029. t.Fatal(err)
  1030. }
  1031. t.Log(db.path)
  1032. db.Close()
  1033. }
  1034. // Better not a have problem with a single ampersand either.
  1035. p2 := base + "&foo"
  1036. db, err = Open(p2)
  1037. if err != nil {
  1038. t.Fatal(err)
  1039. }
  1040. t.Log(db.path)
  1041. db.Close()
  1042. }
  1043. func TestBlocksInserted(t *testing.T) {
  1044. // Verifies that blocks are inserted after syncing a file
  1045. t.Parallel()
  1046. sdb, err := Open(t.TempDir())
  1047. if err != nil {
  1048. t.Fatal(err)
  1049. }
  1050. t.Cleanup(func() {
  1051. if err := sdb.Close(); err != nil {
  1052. t.Fatal(err)
  1053. }
  1054. })
  1055. // Add remote file
  1056. files := []protocol.FileInfo{genFile("test1", 100, 1)}
  1057. if err := sdb.Update(folderID, protocol.DeviceID{42}, files); err != nil {
  1058. t.Fatal(err)
  1059. }
  1060. // Add the same file locally
  1061. if err := sdb.Update(folderID, protocol.LocalDeviceID, files); err != nil {
  1062. t.Fatal(err)
  1063. }
  1064. // Verify all the blocks are here
  1065. for i, block := range files[0].Blocks {
  1066. bs, err := itererr.Collect(sdb.AllLocalBlocksWithHash(folderID, block.Hash))
  1067. if err != nil {
  1068. t.Fatal(err)
  1069. }
  1070. if len(bs) == 0 {
  1071. t.Error("missing blocks for", i)
  1072. }
  1073. }
  1074. }
  1075. func mustCollect[T any](t *testing.T) func(it iter.Seq[T], errFn func() error) []T {
  1076. t.Helper()
  1077. return func(it iter.Seq[T], errFn func() error) []T {
  1078. t.Helper()
  1079. vals, err := itererr.Collect(it, errFn)
  1080. if err != nil {
  1081. t.Fatal(err)
  1082. }
  1083. return vals
  1084. }
  1085. }
  1086. func fiNames(fs []protocol.FileInfo) []string {
  1087. names := make([]string, len(fs))
  1088. for i, fi := range fs {
  1089. names[i] = fi.Name
  1090. }
  1091. return names
  1092. }
  1093. func genDir(name string, seq int) protocol.FileInfo {
  1094. return protocol.FileInfo{
  1095. Name: name,
  1096. Type: protocol.FileInfoTypeDirectory,
  1097. ModifiedS: time.Now().Unix(),
  1098. ModifiedBy: 1,
  1099. Sequence: int64(seq),
  1100. Version: protocol.Vector{}.Update(1),
  1101. Permissions: 0o755,
  1102. ModifiedNs: 12345678,
  1103. }
  1104. }
  1105. func genFile(name string, numBlocks int, seq int) protocol.FileInfo {
  1106. ts := timeutil.StrictlyMonotonicNanos()
  1107. s := ts / 1e9
  1108. ns := int32(ts % 1e9)
  1109. return protocol.FileInfo{
  1110. Name: name,
  1111. Size: int64(numBlocks) * blockSize,
  1112. ModifiedS: s,
  1113. ModifiedBy: 1,
  1114. Version: protocol.Vector{}.Update(1),
  1115. Sequence: int64(seq),
  1116. Blocks: genBlocks(name, 0, numBlocks),
  1117. Permissions: 0o644,
  1118. ModifiedNs: ns,
  1119. RawBlockSize: blockSize,
  1120. }
  1121. }
  1122. func genBlocks(name string, seed, count int) []protocol.BlockInfo {
  1123. b := make([]protocol.BlockInfo, count)
  1124. for i := range b {
  1125. b[i].Hash = genBlockHash(name, seed, i)
  1126. b[i].Size = blockSize
  1127. b[i].Offset = (blockSize) * int64(i)
  1128. }
  1129. return b
  1130. }
  1131. func genBlockHash(name string, seed, index int) []byte {
  1132. bs := sha256.Sum256([]byte(name))
  1133. ebs := binary.LittleEndian.AppendUint64(nil, uint64(seed))
  1134. for i := range ebs {
  1135. bs[i] ^= ebs[i]
  1136. }
  1137. ebs = binary.LittleEndian.AppendUint64(nil, uint64(index))
  1138. for i := range ebs {
  1139. bs[i] ^= ebs[i]
  1140. }
  1141. return bs[:]
  1142. }