fakeconns_test.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Copyright (C) 2014 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 model
  7. import (
  8. "bytes"
  9. "context"
  10. "sync"
  11. "time"
  12. "github.com/syncthing/syncthing/internal/timeutil"
  13. "github.com/syncthing/syncthing/lib/protocol"
  14. protocolmocks "github.com/syncthing/syncthing/lib/protocol/mocks"
  15. "github.com/syncthing/syncthing/lib/rand"
  16. "github.com/syncthing/syncthing/lib/scanner"
  17. )
  18. type downloadProgressMessage struct {
  19. folder string
  20. updates []protocol.FileDownloadProgressUpdate
  21. }
  22. func newFakeConnection(id protocol.DeviceID, model Model) *fakeConnection {
  23. f := &fakeConnection{
  24. Connection: new(protocolmocks.Connection),
  25. id: id,
  26. model: model,
  27. closed: make(chan struct{}),
  28. }
  29. f.RequestCalls(func(ctx context.Context, req *protocol.Request) ([]byte, error) {
  30. return f.fileData[req.Name], nil
  31. })
  32. f.DeviceIDReturns(id)
  33. f.ConnectionIDReturns(rand.String(16))
  34. f.CloseCalls(func(err error) {
  35. f.closeOnce.Do(func() {
  36. close(f.closed)
  37. model.Closed(f, err)
  38. })
  39. f.ClosedReturns(f.closed)
  40. })
  41. f.StringReturns(rand.String(8))
  42. return f
  43. }
  44. type fakeConnection struct {
  45. *protocolmocks.Connection
  46. id protocol.DeviceID
  47. downloadProgressMessages []downloadProgressMessage
  48. files []protocol.FileInfo
  49. fileData map[string][]byte
  50. folder string
  51. model Model
  52. closed chan struct{}
  53. closeOnce sync.Once
  54. mut sync.Mutex
  55. }
  56. func (f *fakeConnection) setIndexFn(fn func(_ context.Context, folder string, fs []protocol.FileInfo) error) {
  57. f.IndexCalls(func(ctx context.Context, idx *protocol.Index) error { return fn(ctx, idx.Folder, idx.Files) })
  58. f.IndexUpdateCalls(func(ctx context.Context, idxUp *protocol.IndexUpdate) error {
  59. return fn(ctx, idxUp.Folder, idxUp.Files)
  60. })
  61. }
  62. func (f *fakeConnection) DownloadProgress(_ context.Context, dp *protocol.DownloadProgress) {
  63. f.downloadProgressMessages = append(f.downloadProgressMessages, downloadProgressMessage{
  64. folder: dp.Folder,
  65. updates: dp.Updates,
  66. })
  67. }
  68. func (f *fakeConnection) addFileLocked(name string, flags uint32, ftype protocol.FileInfoType, data []byte, version protocol.Vector, localFlags protocol.FlagLocal) {
  69. blockSize := protocol.BlockSize(int64(len(data)))
  70. blocks, _ := scanner.Blocks(context.TODO(), bytes.NewReader(data), blockSize, int64(len(data)), nil)
  71. file := protocol.FileInfo{
  72. Name: name,
  73. Type: ftype,
  74. Version: version,
  75. Sequence: timeutil.StrictlyMonotonicNanos(),
  76. LocalFlags: localFlags,
  77. }
  78. switch ftype {
  79. case protocol.FileInfoTypeFile, protocol.FileInfoTypeDirectory:
  80. file.ModifiedS = time.Now().Unix()
  81. file.Permissions = flags
  82. if ftype == protocol.FileInfoTypeFile {
  83. file.Size = int64(len(data))
  84. file.RawBlockSize = int32(blockSize)
  85. file.Blocks = blocks
  86. }
  87. default: // Symlink
  88. file.Name = name
  89. file.Type = ftype
  90. file.Version = version
  91. file.SymlinkTarget = data
  92. file.NoPermissions = true
  93. }
  94. f.files = append(f.files, file)
  95. if f.fileData == nil {
  96. f.fileData = make(map[string][]byte)
  97. }
  98. f.fileData[name] = data
  99. }
  100. func (f *fakeConnection) addFile(name string, flags uint32, ftype protocol.FileInfoType, data []byte) {
  101. f.mut.Lock()
  102. defer f.mut.Unlock()
  103. var version protocol.Vector
  104. version = version.Update(f.id.Short())
  105. f.addFileLocked(name, flags, ftype, data, version, 0)
  106. }
  107. func (f *fakeConnection) updateFile(name string, flags uint32, ftype protocol.FileInfoType, data []byte) {
  108. f.mut.Lock()
  109. defer f.mut.Unlock()
  110. for i, fi := range f.files {
  111. if fi.Name == name {
  112. f.files = append(f.files[:i], f.files[i+1:]...)
  113. f.addFileLocked(name, flags, ftype, data, fi.Version.Update(f.id.Short()), 0)
  114. return
  115. }
  116. }
  117. }
  118. func (f *fakeConnection) deleteFile(name string) {
  119. f.mut.Lock()
  120. defer f.mut.Unlock()
  121. for i, fi := range f.files {
  122. if fi.Name == name {
  123. fi.Deleted = true
  124. fi.ModifiedS = time.Now().Unix()
  125. fi.Version = fi.Version.Update(f.id.Short())
  126. fi.Sequence = timeutil.StrictlyMonotonicNanos()
  127. fi.Blocks = nil
  128. f.files = append(append(f.files[:i], f.files[i+1:]...), fi)
  129. return
  130. }
  131. }
  132. }
  133. func (f *fakeConnection) sendIndexUpdate() {
  134. toSend := make([]protocol.FileInfo, len(f.files))
  135. for i := range f.files {
  136. toSend[i] = prepareFileInfoForIndex(f.files[i])
  137. }
  138. f.model.IndexUpdate(f, &protocol.IndexUpdate{Folder: f.folder, Files: toSend})
  139. }
  140. func addFakeConn(m *testModel, dev protocol.DeviceID, folderID string) *fakeConnection {
  141. fc := newFakeConnection(dev, m)
  142. fc.folder = folderID
  143. m.AddConnection(fc, protocol.Hello{})
  144. m.ClusterConfig(fc, &protocol.ClusterConfig{
  145. Folders: []protocol.Folder{
  146. {
  147. ID: folderID,
  148. Devices: []protocol.Device{
  149. {ID: myID},
  150. {ID: dev},
  151. },
  152. },
  153. },
  154. })
  155. return fc
  156. }