protocol_test.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. // Copyright (C) 2014 The Protocol Authors.
  2. package protocol
  3. import (
  4. "bytes"
  5. "encoding/json"
  6. "errors"
  7. "io"
  8. "io/ioutil"
  9. "strings"
  10. "testing"
  11. "testing/quick"
  12. "time"
  13. "encoding/hex"
  14. "github.com/syncthing/syncthing/lib/rand"
  15. )
  16. var (
  17. c0ID = NewDeviceID([]byte{1})
  18. c1ID = NewDeviceID([]byte{2})
  19. quickCfg = &quick.Config{}
  20. )
  21. func TestPing(t *testing.T) {
  22. ar, aw := io.Pipe()
  23. br, bw := io.Pipe()
  24. c0 := NewConnection(c0ID, ar, bw, newTestModel(), "name", CompressAlways).(wireFormatConnection).Connection.(*rawConnection)
  25. c0.Start()
  26. c1 := NewConnection(c1ID, br, aw, newTestModel(), "name", CompressAlways).(wireFormatConnection).Connection.(*rawConnection)
  27. c1.Start()
  28. c0.ClusterConfig(ClusterConfig{})
  29. c1.ClusterConfig(ClusterConfig{})
  30. if ok := c0.ping(); !ok {
  31. t.Error("c0 ping failed")
  32. }
  33. if ok := c1.ping(); !ok {
  34. t.Error("c1 ping failed")
  35. }
  36. }
  37. func TestClose(t *testing.T) {
  38. m0 := newTestModel()
  39. m1 := newTestModel()
  40. ar, aw := io.Pipe()
  41. br, bw := io.Pipe()
  42. c0 := NewConnection(c0ID, ar, bw, m0, "name", CompressAlways).(wireFormatConnection).Connection.(*rawConnection)
  43. c0.Start()
  44. c1 := NewConnection(c1ID, br, aw, m1, "name", CompressAlways)
  45. c1.Start()
  46. c0.ClusterConfig(ClusterConfig{})
  47. c1.ClusterConfig(ClusterConfig{})
  48. c0.close(errors.New("manual close"))
  49. <-c0.closed
  50. if err := m0.closedError(); err == nil || !strings.Contains(err.Error(), "manual close") {
  51. t.Fatal("Connection should be closed")
  52. }
  53. // None of these should panic, some should return an error
  54. if c0.ping() {
  55. t.Error("Ping should not return true")
  56. }
  57. c0.Index("default", nil)
  58. c0.Index("default", nil)
  59. if _, err := c0.Request("default", "foo", 0, 0, nil, false); err == nil {
  60. t.Error("Request should return an error")
  61. }
  62. }
  63. func TestMarshalIndexMessage(t *testing.T) {
  64. if testing.Short() {
  65. quickCfg.MaxCount = 10
  66. }
  67. f := func(m1 Index) bool {
  68. if len(m1.Files) == 0 {
  69. m1.Files = nil
  70. }
  71. for i, f := range m1.Files {
  72. if len(f.Blocks) == 0 {
  73. m1.Files[i].Blocks = nil
  74. } else {
  75. for j := range f.Blocks {
  76. f.Blocks[j].Offset = 0
  77. if len(f.Blocks[j].Hash) == 0 {
  78. f.Blocks[j].Hash = nil
  79. }
  80. }
  81. }
  82. if len(f.Version.Counters) == 0 {
  83. m1.Files[i].Version.Counters = nil
  84. }
  85. }
  86. return testMarshal(t, "index", &m1, &Index{})
  87. }
  88. if err := quick.Check(f, quickCfg); err != nil {
  89. t.Error(err)
  90. }
  91. }
  92. func TestMarshalRequestMessage(t *testing.T) {
  93. if testing.Short() {
  94. quickCfg.MaxCount = 10
  95. }
  96. f := func(m1 Request) bool {
  97. if len(m1.Hash) == 0 {
  98. m1.Hash = nil
  99. }
  100. return testMarshal(t, "request", &m1, &Request{})
  101. }
  102. if err := quick.Check(f, quickCfg); err != nil {
  103. t.Error(err)
  104. }
  105. }
  106. func TestMarshalResponseMessage(t *testing.T) {
  107. if testing.Short() {
  108. quickCfg.MaxCount = 10
  109. }
  110. f := func(m1 Response) bool {
  111. if len(m1.Data) == 0 {
  112. m1.Data = nil
  113. }
  114. return testMarshal(t, "response", &m1, &Response{})
  115. }
  116. if err := quick.Check(f, quickCfg); err != nil {
  117. t.Error(err)
  118. }
  119. }
  120. func TestMarshalClusterConfigMessage(t *testing.T) {
  121. if testing.Short() {
  122. quickCfg.MaxCount = 10
  123. }
  124. f := func(m1 ClusterConfig) bool {
  125. if len(m1.Folders) == 0 {
  126. m1.Folders = nil
  127. }
  128. for i := range m1.Folders {
  129. if len(m1.Folders[i].Devices) == 0 {
  130. m1.Folders[i].Devices = nil
  131. }
  132. }
  133. return testMarshal(t, "clusterconfig", &m1, &ClusterConfig{})
  134. }
  135. if err := quick.Check(f, quickCfg); err != nil {
  136. t.Error(err)
  137. }
  138. }
  139. func TestMarshalCloseMessage(t *testing.T) {
  140. if testing.Short() {
  141. quickCfg.MaxCount = 10
  142. }
  143. f := func(m1 Close) bool {
  144. return testMarshal(t, "close", &m1, &Close{})
  145. }
  146. if err := quick.Check(f, quickCfg); err != nil {
  147. t.Error(err)
  148. }
  149. }
  150. func TestMarshalFDPU(t *testing.T) {
  151. if testing.Short() {
  152. quickCfg.MaxCount = 10
  153. }
  154. f := func(m1 FileDownloadProgressUpdate) bool {
  155. if len(m1.Version.Counters) == 0 {
  156. m1.Version.Counters = nil
  157. }
  158. return testMarshal(t, "close", &m1, &FileDownloadProgressUpdate{})
  159. }
  160. if err := quick.Check(f, quickCfg); err != nil {
  161. t.Error(err)
  162. }
  163. }
  164. func TestUnmarshalFDPUv16v17(t *testing.T) {
  165. var fdpu FileDownloadProgressUpdate
  166. m0, _ := hex.DecodeString("08cda1e2e3011278f3918787f3b89b8af2958887f0aa9389f3a08588f3aa8f96f39aa8a5f48b9188f19286a0f3848da4f3aba799f3beb489f0a285b9f487b684f2a3bda2f48598b4f2938a89f2a28badf187a0a2f2aebdbdf4849494f4808fbbf2b3a2adf2bb95bff0a6ada4f198ab9af29a9c8bf1abb793f3baabb2f188a6ba1a0020bb9390f60220f6d9e42220b0c7e2b2fdffffffff0120fdb2dfcdfbffffffff0120cedab1d50120bd8784c0feffffffff0120ace99591fdffffffff0120eed7d09af9ffffffff01")
  167. if err := fdpu.Unmarshal(m0); err != nil {
  168. t.Fatal("Unmarshalling message from v0.14.16:", err)
  169. }
  170. m1, _ := hex.DecodeString("0880f1969905128401f099b192f0abb1b9f3b280aff19e9aa2f3b89e84f484b39df1a7a6b0f1aea4b1f0adac94f3b39caaf1939281f1928a8af0abb1b0f0a8b3b3f3a88e94f2bd85acf29c97a9f2969da6f0b7a188f1908ea2f09a9c9bf19d86a6f29aada8f389bb95f0bf9d88f1a09d89f1b1a4b5f29b9eabf298a59df1b2a589f2979ebdf0b69880f18986b21a440a1508c7d8fb8897ca93d90910e8c4d8e8f2f8f0ccee010a1508afa8ffd8c085b393c50110e5bdedc3bddefe9b0b0a1408a1bedddba4cac5da3c10b8e5d9958ca7e3ec19225ae2f88cb2f8ffffffff018ceda99cfbffffffff01b9c298a407e295e8e9fcffffffff01f3b9ade5fcffffffff01c08bfea9fdffffffff01a2c2e5e1ffffffffff0186dcc5dafdffffffff01e9ffc7e507c9d89db8fdffffffff01")
  171. if err := fdpu.Unmarshal(m1); err != nil {
  172. t.Fatal("Unmarshalling message from v0.14.16:", err)
  173. }
  174. }
  175. func testMarshal(t *testing.T, prefix string, m1, m2 message) bool {
  176. buf, err := m1.Marshal()
  177. if err != nil {
  178. t.Fatal(err)
  179. }
  180. err = m2.Unmarshal(buf)
  181. if err != nil {
  182. t.Fatal(err)
  183. }
  184. bs1, _ := json.MarshalIndent(m1, "", " ")
  185. bs2, _ := json.MarshalIndent(m2, "", " ")
  186. if !bytes.Equal(bs1, bs2) {
  187. ioutil.WriteFile(prefix+"-1.txt", bs1, 0644)
  188. ioutil.WriteFile(prefix+"-2.txt", bs2, 0644)
  189. return false
  190. }
  191. return true
  192. }
  193. func TestMarshalledIndexMessageSize(t *testing.T) {
  194. // We should be able to handle a 1 TiB file without
  195. // blowing the default max message size.
  196. if testing.Short() {
  197. t.Skip("this test requires a lot of memory")
  198. return
  199. }
  200. const (
  201. maxMessageSize = MaxMessageLen
  202. fileSize = 1 << 40
  203. blockSize = BlockSize
  204. )
  205. f := FileInfo{
  206. Name: "a normal length file name withoout any weird stuff.txt",
  207. Type: FileInfoTypeFile,
  208. Size: fileSize,
  209. Permissions: 0666,
  210. ModifiedS: time.Now().Unix(),
  211. Version: Vector{Counters: []Counter{{ID: 1 << 60, Value: 1}, {ID: 2 << 60, Value: 1}}},
  212. Blocks: make([]BlockInfo, fileSize/blockSize),
  213. }
  214. for i := 0; i < fileSize/blockSize; i++ {
  215. f.Blocks[i].Offset = int64(i) * blockSize
  216. f.Blocks[i].Size = blockSize
  217. f.Blocks[i].Hash = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 30, 1, 2}
  218. }
  219. idx := Index{
  220. Folder: "some folder ID",
  221. Files: []FileInfo{f},
  222. }
  223. msgSize := idx.ProtoSize()
  224. if msgSize > maxMessageSize {
  225. t.Errorf("Message size %d bytes is larger than max %d", msgSize, maxMessageSize)
  226. }
  227. }
  228. func TestLZ4Compression(t *testing.T) {
  229. c := new(rawConnection)
  230. for i := 0; i < 10; i++ {
  231. dataLen := 150 + rand.Intn(150)
  232. data := make([]byte, dataLen)
  233. _, err := io.ReadFull(rand.Reader, data[100:])
  234. if err != nil {
  235. t.Fatal(err)
  236. }
  237. comp, err := c.lz4Compress(data)
  238. if err != nil {
  239. t.Errorf("compressing %d bytes: %v", dataLen, err)
  240. continue
  241. }
  242. res, err := c.lz4Decompress(comp)
  243. if err != nil {
  244. t.Errorf("decompressing %d bytes to %d: %v", len(comp), dataLen, err)
  245. continue
  246. }
  247. if len(res) != len(data) {
  248. t.Errorf("Incorrect len %d != expected %d", len(res), len(data))
  249. }
  250. if !bytes.Equal(data, res) {
  251. t.Error("Incorrect decompressed data")
  252. }
  253. t.Logf("OK #%d, %d -> %d -> %d", i, dataLen, len(comp), dataLen)
  254. }
  255. }
  256. func TestCheckFilename(t *testing.T) {
  257. cases := []struct {
  258. name string
  259. ok bool
  260. }{
  261. // Valid filenames
  262. {"foo", true},
  263. {"foo/bar/baz", true},
  264. {"foo/bar:baz", true}, // colon is ok in general, will be filtered on windows
  265. {`\`, true}, // path separator on the wire is forward slash, so as above
  266. {`\.`, true},
  267. {`\..`, true},
  268. {".foo", true},
  269. {"foo..", true},
  270. // Invalid filenames
  271. {"foo/..", false},
  272. {"foo/../bar", false},
  273. {"../foo/../bar", false},
  274. {"", false},
  275. {".", false},
  276. {"..", false},
  277. {"/", false},
  278. {"/.", false},
  279. {"/..", false},
  280. {"/foo", false},
  281. {"./foo", false},
  282. {"foo./", false},
  283. {"foo/.", false},
  284. {"foo/", false},
  285. }
  286. for _, tc := range cases {
  287. err := checkFilename(tc.name)
  288. if (err == nil) != tc.ok {
  289. t.Errorf("Unexpected result for checkFilename(%q): %v", tc.name, err)
  290. }
  291. }
  292. }