fakeconns_test.go 4.9 KB

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