model_test.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
  2. // All rights reserved. Use of this source code is governed by an MIT-style
  3. // license that can be found in the LICENSE file.
  4. package model
  5. import (
  6. "bytes"
  7. "fmt"
  8. "os"
  9. "testing"
  10. "time"
  11. "github.com/syncthing/syncthing/config"
  12. "github.com/syncthing/syncthing/protocol"
  13. "github.com/syndtr/goleveldb/leveldb"
  14. "github.com/syndtr/goleveldb/leveldb/storage"
  15. )
  16. var node1, node2 protocol.NodeID
  17. func init() {
  18. node1, _ = protocol.NodeIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
  19. node2, _ = protocol.NodeIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY")
  20. }
  21. var testDataExpected = map[string]protocol.FileInfo{
  22. "foo": protocol.FileInfo{
  23. Name: "foo",
  24. Flags: 0,
  25. Modified: 0,
  26. Blocks: []protocol.BlockInfo{{Offset: 0x0, Size: 0x7, Hash: []uint8{0xae, 0xc0, 0x70, 0x64, 0x5f, 0xe5, 0x3e, 0xe3, 0xb3, 0x76, 0x30, 0x59, 0x37, 0x61, 0x34, 0xf0, 0x58, 0xcc, 0x33, 0x72, 0x47, 0xc9, 0x78, 0xad, 0xd1, 0x78, 0xb6, 0xcc, 0xdf, 0xb0, 0x1, 0x9f}}},
  27. },
  28. "empty": protocol.FileInfo{
  29. Name: "empty",
  30. Flags: 0,
  31. Modified: 0,
  32. Blocks: []protocol.BlockInfo{{Offset: 0x0, Size: 0x0, Hash: []uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}},
  33. },
  34. "bar": protocol.FileInfo{
  35. Name: "bar",
  36. Flags: 0,
  37. Modified: 0,
  38. Blocks: []protocol.BlockInfo{{Offset: 0x0, Size: 0xa, Hash: []uint8{0x2f, 0x72, 0xcc, 0x11, 0xa6, 0xfc, 0xd0, 0x27, 0x1e, 0xce, 0xf8, 0xc6, 0x10, 0x56, 0xee, 0x1e, 0xb1, 0x24, 0x3b, 0xe3, 0x80, 0x5b, 0xf9, 0xa9, 0xdf, 0x98, 0xf9, 0x2f, 0x76, 0x36, 0xb0, 0x5c}}},
  39. },
  40. }
  41. func init() {
  42. // Fix expected test data to match reality
  43. for n, f := range testDataExpected {
  44. fi, _ := os.Stat("testdata/" + n)
  45. f.Flags = uint32(fi.Mode())
  46. f.Modified = fi.ModTime().Unix()
  47. testDataExpected[n] = f
  48. }
  49. }
  50. func TestRequest(t *testing.T) {
  51. db, _ := leveldb.Open(storage.NewMemStorage(), nil)
  52. m := NewModel("/tmp", &config.Configuration{}, "node", "syncthing", "dev", db)
  53. m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
  54. m.ScanRepo("default")
  55. bs, err := m.Request(node1, "default", "foo", 0, 6)
  56. if err != nil {
  57. t.Fatal(err)
  58. }
  59. if bytes.Compare(bs, []byte("foobar")) != 0 {
  60. t.Errorf("Incorrect data from request: %q", string(bs))
  61. }
  62. bs, err = m.Request(node1, "default", "../walk.go", 0, 6)
  63. if err == nil {
  64. t.Error("Unexpected nil error on insecure file read")
  65. }
  66. if bs != nil {
  67. t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
  68. }
  69. }
  70. func genFiles(n int) []protocol.FileInfo {
  71. files := make([]protocol.FileInfo, n)
  72. t := time.Now().Unix()
  73. for i := 0; i < n; i++ {
  74. files[i] = protocol.FileInfo{
  75. Name: fmt.Sprintf("file%d", i),
  76. Modified: t,
  77. Blocks: []protocol.BlockInfo{{0, 100, []byte("some hash bytes")}},
  78. }
  79. }
  80. return files
  81. }
  82. func BenchmarkIndex10000(b *testing.B) {
  83. db, _ := leveldb.Open(storage.NewMemStorage(), nil)
  84. m := NewModel("/tmp", nil, "node", "syncthing", "dev", db)
  85. m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
  86. m.ScanRepo("default")
  87. files := genFiles(10000)
  88. b.ResetTimer()
  89. for i := 0; i < b.N; i++ {
  90. m.Index(node1, "default", files)
  91. }
  92. }
  93. func BenchmarkIndex00100(b *testing.B) {
  94. db, _ := leveldb.Open(storage.NewMemStorage(), nil)
  95. m := NewModel("/tmp", nil, "node", "syncthing", "dev", db)
  96. m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
  97. m.ScanRepo("default")
  98. files := genFiles(100)
  99. b.ResetTimer()
  100. for i := 0; i < b.N; i++ {
  101. m.Index(node1, "default", files)
  102. }
  103. }
  104. func BenchmarkIndexUpdate10000f10000(b *testing.B) {
  105. db, _ := leveldb.Open(storage.NewMemStorage(), nil)
  106. m := NewModel("/tmp", nil, "node", "syncthing", "dev", db)
  107. m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
  108. m.ScanRepo("default")
  109. files := genFiles(10000)
  110. m.Index(node1, "default", files)
  111. b.ResetTimer()
  112. for i := 0; i < b.N; i++ {
  113. m.IndexUpdate(node1, "default", files)
  114. }
  115. }
  116. func BenchmarkIndexUpdate10000f00100(b *testing.B) {
  117. db, _ := leveldb.Open(storage.NewMemStorage(), nil)
  118. m := NewModel("/tmp", nil, "node", "syncthing", "dev", db)
  119. m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
  120. m.ScanRepo("default")
  121. files := genFiles(10000)
  122. m.Index(node1, "default", files)
  123. ufiles := genFiles(100)
  124. b.ResetTimer()
  125. for i := 0; i < b.N; i++ {
  126. m.IndexUpdate(node1, "default", ufiles)
  127. }
  128. }
  129. func BenchmarkIndexUpdate10000f00001(b *testing.B) {
  130. db, _ := leveldb.Open(storage.NewMemStorage(), nil)
  131. m := NewModel("/tmp", nil, "node", "syncthing", "dev", db)
  132. m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
  133. m.ScanRepo("default")
  134. files := genFiles(10000)
  135. m.Index(node1, "default", files)
  136. ufiles := genFiles(1)
  137. b.ResetTimer()
  138. for i := 0; i < b.N; i++ {
  139. m.IndexUpdate(node1, "default", ufiles)
  140. }
  141. }
  142. type FakeConnection struct {
  143. id protocol.NodeID
  144. requestData []byte
  145. }
  146. func (FakeConnection) Close() error {
  147. return nil
  148. }
  149. func (f FakeConnection) ID() protocol.NodeID {
  150. return f.id
  151. }
  152. func (f FakeConnection) Name() string {
  153. return ""
  154. }
  155. func (f FakeConnection) Option(string) string {
  156. return ""
  157. }
  158. func (FakeConnection) Index(string, []protocol.FileInfo) error {
  159. return nil
  160. }
  161. func (FakeConnection) IndexUpdate(string, []protocol.FileInfo) error {
  162. return nil
  163. }
  164. func (f FakeConnection) Request(repo, name string, offset int64, size int) ([]byte, error) {
  165. return f.requestData, nil
  166. }
  167. func (FakeConnection) ClusterConfig(protocol.ClusterConfigMessage) {}
  168. func (FakeConnection) Ping() bool {
  169. return true
  170. }
  171. func (FakeConnection) Statistics() protocol.Statistics {
  172. return protocol.Statistics{}
  173. }
  174. func BenchmarkRequest(b *testing.B) {
  175. db, _ := leveldb.Open(storage.NewMemStorage(), nil)
  176. m := NewModel("/tmp", nil, "node", "syncthing", "dev", db)
  177. m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
  178. m.ScanRepo("default")
  179. const n = 1000
  180. files := make([]protocol.FileInfo, n)
  181. t := time.Now().Unix()
  182. for i := 0; i < n; i++ {
  183. files[i] = protocol.FileInfo{
  184. Name: fmt.Sprintf("file%d", i),
  185. Modified: t,
  186. Blocks: []protocol.BlockInfo{{0, 100, []byte("some hash bytes")}},
  187. }
  188. }
  189. fc := FakeConnection{
  190. id: node1,
  191. requestData: []byte("some data to return"),
  192. }
  193. m.AddConnection(fc, fc)
  194. m.Index(node1, "default", files)
  195. b.ResetTimer()
  196. for i := 0; i < b.N; i++ {
  197. data, err := m.requestGlobal(node1, "default", files[i%n].Name, 0, 32, nil)
  198. if err != nil {
  199. b.Error(err)
  200. }
  201. if data == nil {
  202. b.Error("nil data")
  203. }
  204. }
  205. }
  206. func TestActivityMap(t *testing.T) {
  207. isValid := func(protocol.NodeID) bool {
  208. return true
  209. }
  210. m := make(activityMap)
  211. if node := m.leastBusyNode([]protocol.NodeID{node1}, isValid); node != node1 {
  212. t.Errorf("Incorrect least busy node %q", node)
  213. }
  214. if node := m.leastBusyNode([]protocol.NodeID{node2}, isValid); node != node2 {
  215. t.Errorf("Incorrect least busy node %q", node)
  216. }
  217. if node := m.leastBusyNode([]protocol.NodeID{node1, node2}, isValid); node != node1 {
  218. t.Errorf("Incorrect least busy node %q", node)
  219. }
  220. if node := m.leastBusyNode([]protocol.NodeID{node1, node2}, isValid); node != node2 {
  221. t.Errorf("Incorrect least busy node %q", node)
  222. }
  223. }
  224. func TestNodeRename(t *testing.T) {
  225. ccm := protocol.ClusterConfigMessage{
  226. ClientName: "syncthing",
  227. ClientVersion: "v0.9.4",
  228. }
  229. cfg, _ := config.Load(nil, node1)
  230. cfg.Nodes = []config.NodeConfiguration{
  231. {
  232. NodeID: node1,
  233. },
  234. }
  235. db, _ := leveldb.Open(storage.NewMemStorage(), nil)
  236. m := NewModel("/tmp", &cfg, "node", "syncthing", "dev", db)
  237. if cfg.Nodes[0].Name != "" {
  238. t.Errorf("Node already has a name")
  239. }
  240. m.ClusterConfig(node1, ccm)
  241. if cfg.Nodes[0].Name != "" {
  242. t.Errorf("Node already has a name")
  243. }
  244. ccm.Options = []protocol.Option{
  245. {
  246. Key: "name",
  247. Value: "tester",
  248. },
  249. }
  250. m.ClusterConfig(node1, ccm)
  251. if cfg.Nodes[0].Name != "tester" {
  252. t.Errorf("Node did not get a name")
  253. }
  254. ccm.Options[0].Value = "tester2"
  255. m.ClusterConfig(node1, ccm)
  256. if cfg.Nodes[0].Name != "tester" {
  257. t.Errorf("Node name got overwritten")
  258. }
  259. }