]> Cypherpunks.ru repositories - nncp.git/blob - src/cypherpunks.ru/nncp/toss_test.go
47a4ba48a0e5b18ada946cbb250c35520e4bbe73
[nncp.git] / src / cypherpunks.ru / nncp / toss_test.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2017 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package nncp
20
21 import (
22         "bytes"
23         "crypto/rand"
24         "fmt"
25         "io"
26         "io/ioutil"
27         "os"
28         "path/filepath"
29         "strconv"
30         "testing"
31         "testing/quick"
32
33         "github.com/davecgh/go-xdr/xdr2"
34         "golang.org/x/crypto/blake2b"
35 )
36
37 var (
38         TDebug bool = false
39 )
40
41 func dirFiles(path string) []string {
42         dir, err := os.Open(path)
43         if err != nil {
44                 panic(err)
45         }
46         defer dir.Close()
47         names, err := dir.Readdirnames(0)
48         if err != nil {
49                 panic(err)
50         }
51         return names
52 }
53
54 func TestTossEmail(t *testing.T) {
55         f := func(recipients [16]uint8) bool {
56                 for i, recipient := range recipients {
57                         recipients[i] = recipient % 8
58                 }
59                 spool, err := ioutil.TempDir("", "testtoss")
60                 if err != nil {
61                         panic(err)
62                 }
63                 defer os.RemoveAll(spool)
64                 nodeOur, err := NewNodeGenerate()
65                 if err != nil {
66                         panic(err)
67                 }
68                 ctx := Ctx{
69                         Spool:   spool,
70                         Self:    nodeOur,
71                         SelfId:  nodeOur.Id,
72                         Neigh:   make(map[NodeId]*Node),
73                         Alias:   make(map[string]*NodeId),
74                         LogPath: filepath.Join(spool, "log.log"),
75                         Debug:   TDebug,
76                 }
77                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
78                 privates := make(map[uint8]*NodeOur)
79                 for _, recipient := range recipients {
80                         if _, exists := privates[recipient]; exists {
81                                 continue
82                         }
83                         our, err := NewNodeGenerate()
84                         if err != nil {
85                                 panic(err)
86                         }
87                         privates[recipient] = our
88                         ctx.Neigh[*our.Id] = our.Their()
89                 }
90                 for _, recipient := range recipients {
91                         if err := ctx.TxMail(
92                                 ctx.Neigh[*privates[recipient].Id],
93                                 DefaultNiceMail,
94                                 "recipient",
95                                 []byte{123},
96                                 1<<15,
97                         ); err != nil {
98                                 panic(err)
99                         }
100                 }
101                 for _, recipient := range recipients {
102                         ctx.Self = privates[recipient]
103                         rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
104                         os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
105                         if len(dirFiles(rxPath)) == 0 {
106                                 continue
107                         }
108                         ctx.Toss(ctx.Self.Id, DefaultNiceMail-1, false, false)
109                         if len(dirFiles(rxPath)) == 0 {
110                                 return false
111                         }
112                         ctx.Neigh[*nodeOur.Id].Sendmail = []string{"/bin/sh", "-c", "false"}
113                         ctx.Toss(ctx.Self.Id, DefaultNiceMail, false, false)
114                         if len(dirFiles(rxPath)) == 0 {
115                                 return false
116                         }
117                         ctx.Neigh[*nodeOur.Id].Sendmail = []string{
118                                 "/bin/sh", "-c",
119                                 fmt.Sprintf("cat >> %s", filepath.Join(spool, "mbox")),
120                         }
121                         ctx.Toss(ctx.Self.Id, DefaultNiceMail, false, false)
122                         if len(dirFiles(rxPath)) != 0 {
123                                 return false
124                         }
125                 }
126                 mbox, err := ioutil.ReadFile(filepath.Join(spool, "mbox"))
127                 if err != nil {
128                         return false
129                 }
130                 expected := make([]byte, 0, 16)
131                 for i := 0; i < 16; i++ {
132                         expected = append(expected, 123)
133                 }
134                 return bytes.Compare(mbox, expected) == 0
135         }
136         if err := quick.Check(f, nil); err != nil {
137                 t.Error(err)
138         }
139 }
140
141 func TestTossFile(t *testing.T) {
142         f := func(fileSizes []uint8) bool {
143                 if len(fileSizes) == 0 {
144                         return true
145                 }
146                 files := make(map[string][]byte)
147                 for i, fileSize := range fileSizes {
148                         data := make([]byte, fileSize)
149                         if _, err := io.ReadFull(rand.Reader, data); err != nil {
150                                 panic(err)
151                         }
152                         files[strconv.Itoa(i)] = data
153                 }
154                 spool, err := ioutil.TempDir("", "testtoss")
155                 if err != nil {
156                         panic(err)
157                 }
158                 defer os.RemoveAll(spool)
159                 nodeOur, err := NewNodeGenerate()
160                 if err != nil {
161                         panic(err)
162                 }
163                 ctx := Ctx{
164                         Spool:   spool,
165                         Self:    nodeOur,
166                         SelfId:  nodeOur.Id,
167                         Neigh:   make(map[NodeId]*Node),
168                         Alias:   make(map[string]*NodeId),
169                         LogPath: filepath.Join(spool, "log.log"),
170                         Debug:   TDebug,
171                 }
172                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
173                 incomingPath := filepath.Join(spool, "incoming")
174                 for _, fileData := range files {
175                         checksum := blake2b.Sum256(fileData)
176                         fileName := ToBase32(checksum[:])
177                         src := filepath.Join(spool, fileName)
178                         if err := ioutil.WriteFile(src, fileData, os.FileMode(0600)); err != nil {
179                                 panic(err)
180                         }
181                         if err := ctx.TxFile(
182                                 ctx.Neigh[*nodeOur.Id],
183                                 DefaultNiceFile,
184                                 src,
185                                 fileName,
186                                 1<<15,
187                         ); err != nil {
188                                 panic(err)
189                         }
190                 }
191                 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
192                 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
193                 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false)
194                 if len(dirFiles(rxPath)) == 0 {
195                         return false
196                 }
197                 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
198                 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false)
199                 if len(dirFiles(rxPath)) != 0 {
200                         return false
201                 }
202                 for _, fileData := range files {
203                         checksum := blake2b.Sum256(fileData)
204                         fileName := ToBase32(checksum[:])
205                         data, err := ioutil.ReadFile(filepath.Join(incomingPath, fileName))
206                         if err != nil {
207                                 panic(err)
208                         }
209                         if bytes.Compare(data, fileData) != 0 {
210                                 return false
211                         }
212                 }
213                 return true
214         }
215         if err := quick.Check(f, nil); err != nil {
216                 t.Error(err)
217         }
218 }
219
220 func TestTossFileSameName(t *testing.T) {
221         f := func(filesRaw uint8) bool {
222                 files := int(filesRaw)%8 + 1
223                 spool, err := ioutil.TempDir("", "testtoss")
224                 if err != nil {
225                         panic(err)
226                 }
227                 defer os.RemoveAll(spool)
228                 nodeOur, err := NewNodeGenerate()
229                 if err != nil {
230                         panic(err)
231                 }
232                 ctx := Ctx{
233                         Spool:   spool,
234                         Self:    nodeOur,
235                         SelfId:  nodeOur.Id,
236                         Neigh:   make(map[NodeId]*Node),
237                         Alias:   make(map[string]*NodeId),
238                         LogPath: filepath.Join(spool, "log.log"),
239                         Debug:   TDebug,
240                 }
241                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
242                 srcPath := filepath.Join(spool, "junk")
243                 if err = ioutil.WriteFile(
244                         srcPath,
245                         []byte("doesnotmatter"),
246                         os.FileMode(0600),
247                 ); err != nil {
248                         panic(err)
249                 }
250                 incomingPath := filepath.Join(spool, "incoming")
251                 for i := 0; i < files; i++ {
252                         if err := ctx.TxFile(
253                                 ctx.Neigh[*nodeOur.Id],
254                                 DefaultNiceFile,
255                                 srcPath,
256                                 "samefile",
257                                 1<<15,
258                         ); err != nil {
259                                 panic(err)
260                         }
261                 }
262                 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
263                 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
264                 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
265                 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false)
266                 expected := make(map[string]struct{})
267                 expected["samefile"] = struct{}{}
268                 for i := 0; i < files-1; i++ {
269                         expected["samefile"+strconv.Itoa(i)] = struct{}{}
270                 }
271                 for _, filename := range dirFiles(incomingPath) {
272                         if _, exists := expected[filename]; !exists {
273                                 return false
274                         }
275                         delete(expected, filename)
276                 }
277                 if len(expected) != 0 {
278                         return false
279                 }
280                 return true
281         }
282         if err := quick.Check(f, nil); err != nil {
283                 t.Error(err)
284         }
285 }
286
287 func TestTossFreq(t *testing.T) {
288         f := func(fileSizes []uint8) bool {
289                 if len(fileSizes) == 0 {
290                         return true
291                 }
292                 spool, err := ioutil.TempDir("", "testtoss")
293                 if err != nil {
294                         panic(err)
295                 }
296                 defer os.RemoveAll(spool)
297                 nodeOur, err := NewNodeGenerate()
298                 if err != nil {
299                         panic(err)
300                 }
301                 ctx := Ctx{
302                         Spool:   spool,
303                         Self:    nodeOur,
304                         SelfId:  nodeOur.Id,
305                         Neigh:   make(map[NodeId]*Node),
306                         Alias:   make(map[string]*NodeId),
307                         LogPath: filepath.Join(spool, "log.log"),
308                         Debug:   TDebug,
309                 }
310                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
311                 files := make(map[string][]byte)
312                 for i, fileSize := range fileSizes {
313                         fileData := make([]byte, fileSize)
314                         if _, err := io.ReadFull(rand.Reader, fileData); err != nil {
315                                 panic(err)
316                         }
317                         fileName := strconv.Itoa(i)
318                         files[fileName] = fileData
319                         if err := ctx.TxFreq(
320                                 ctx.Neigh[*nodeOur.Id],
321                                 DefaultNiceFreq,
322                                 fileName,
323                                 fileName,
324                                 1<<15,
325                         ); err != nil {
326                                 panic(err)
327                         }
328                 }
329                 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
330                 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
331                 os.Rename(txPath, rxPath)
332                 os.MkdirAll(txPath, os.FileMode(0700))
333                 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false)
334                 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
335                         return false
336                 }
337                 ctx.Neigh[*nodeOur.Id].Freq = &spool
338                 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false)
339                 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
340                         return false
341                 }
342                 for fileName, fileData := range files {
343                         if err := ioutil.WriteFile(
344                                 filepath.Join(spool, fileName),
345                                 fileData,
346                                 os.FileMode(0600),
347                         ); err != nil {
348                                 panic(err)
349                         }
350                 }
351                 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false)
352                 if len(dirFiles(txPath)) == 0 || len(dirFiles(rxPath)) != 0 {
353                         return false
354                 }
355                 for job := range ctx.Jobs(ctx.Self.Id, TTx) {
356                         var buf bytes.Buffer
357                         _, _, err := PktEncRead(ctx.Self, ctx.Neigh, job.Fd, &buf)
358                         if err != nil {
359                                 panic(err)
360                         }
361                         var pkt Pkt
362                         if _, err = xdr.Unmarshal(&buf, &pkt); err != nil {
363                                 panic(err)
364                         }
365                         dst := string(pkt.Path[:int(pkt.PathLen)])
366                         if bytes.Compare(buf.Bytes(), files[dst]) != 0 {
367                                 return false
368                         }
369                 }
370                 return true
371         }
372         if err := quick.Check(f, nil); err != nil {
373                 t.Error(err)
374         }
375 }
376
377 func TestTossTrns(t *testing.T) {
378         f := func(datumLens []uint8) bool {
379                 if len(datumLens) == 0 {
380                         return true
381                 }
382                 datum := make(map[int][]byte)
383                 for i, datumLen := range datumLens {
384                         datumLen += 64
385                         data := make([]byte, datumLen)
386                         if _, err := io.ReadFull(rand.Reader, data); err != nil {
387                                 panic(err)
388                         }
389                         datum[i] = data
390                 }
391                 spool, err := ioutil.TempDir("", "testtoss")
392                 if err != nil {
393                         panic(err)
394                 }
395                 defer os.RemoveAll(spool)
396                 nodeOur, err := NewNodeGenerate()
397                 if err != nil {
398                         panic(err)
399                 }
400                 ctx := Ctx{
401                         Spool:   spool,
402                         Self:    nodeOur,
403                         SelfId:  nodeOur.Id,
404                         Neigh:   make(map[NodeId]*Node),
405                         Alias:   make(map[string]*NodeId),
406                         LogPath: filepath.Join(spool, "log.log"),
407                         Debug:   TDebug,
408                 }
409                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
410                 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
411                 os.MkdirAll(rxPath, os.FileMode(0700))
412                 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
413                 os.MkdirAll(txPath, os.FileMode(0700))
414                 for _, data := range datum {
415                         pktTrans := Pkt{
416                                 Magic:   MagicNNCPPv1,
417                                 Type:    PktTypeTrns,
418                                 PathLen: blake2b.Size256,
419                                 Path:    new([MaxPathSize]byte),
420                         }
421                         copy(pktTrans.Path[:], nodeOur.Id[:])
422                         var dst bytes.Buffer
423                         if err := PktEncWrite(
424                                 ctx.Self,
425                                 ctx.Neigh[*nodeOur.Id],
426                                 &pktTrans,
427                                 123,
428                                 int64(len(data)),
429                                 0,
430                                 bytes.NewReader(data),
431                                 &dst,
432                         ); err != nil {
433                                 panic(err)
434                         }
435                         checksum := blake2b.Sum256(dst.Bytes())
436                         if err := ioutil.WriteFile(
437                                 filepath.Join(rxPath, ToBase32(checksum[:])),
438                                 dst.Bytes(),
439                                 os.FileMode(0600),
440                         ); err != nil {
441                                 panic(err)
442                         }
443                 }
444                 ctx.Toss(ctx.Self.Id, 123, false, false)
445                 if len(dirFiles(rxPath)) != 0 {
446                         return false
447                 }
448                 for _, filename := range dirFiles(txPath) {
449                         dataRead, err := ioutil.ReadFile(filepath.Join(txPath, filename))
450                         if err != nil {
451                                 panic(err)
452                         }
453                         for k, data := range datum {
454                                 if bytes.Compare(dataRead, data) == 0 {
455                                         delete(datum, k)
456                                         break
457                                 }
458                         }
459                 }
460                 if len(datum) > 0 {
461                         return false
462                 }
463                 return true
464         }
465         if err := quick.Check(f, nil); err != nil {
466                 t.Error(err)
467         }
468 }