]> Cypherpunks.ru repositories - nncp.git/blob - src/cypherpunks.ru/nncp/toss_test.go
037c777321a62752541cd3d46b2bfc3eb31efd5c
[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-2018 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                         t.Error(err)
67                         return false
68                 }
69                 ctx := Ctx{
70                         Spool:   spool,
71                         Self:    nodeOur,
72                         SelfId:  nodeOur.Id,
73                         Neigh:   make(map[NodeId]*Node),
74                         Alias:   make(map[string]*NodeId),
75                         LogPath: filepath.Join(spool, "log.log"),
76                         Debug:   TDebug,
77                 }
78                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
79                 privates := make(map[uint8]*NodeOur)
80                 for _, recipient := range recipients {
81                         if _, exists := privates[recipient]; exists {
82                                 continue
83                         }
84                         our, err := NewNodeGenerate()
85                         if err != nil {
86                                 t.Error(err)
87                                 return false
88                         }
89                         privates[recipient] = our
90                         ctx.Neigh[*our.Id] = our.Their()
91                 }
92                 for _, recipient := range recipients {
93                         if err := ctx.TxMail(
94                                 ctx.Neigh[*privates[recipient].Id],
95                                 DefaultNiceMail,
96                                 "recipient",
97                                 []byte{123},
98                                 1<<15,
99                         ); err != nil {
100                                 t.Error(err)
101                                 return false
102                         }
103                 }
104                 for _, recipient := range recipients {
105                         ctx.Self = privates[recipient]
106                         rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
107                         os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
108                         if len(dirFiles(rxPath)) == 0 {
109                                 continue
110                         }
111                         ctx.Toss(ctx.Self.Id, DefaultNiceMail-1, false, false, false, false, false, false)
112                         if len(dirFiles(rxPath)) == 0 {
113                                 return false
114                         }
115                         ctx.Neigh[*nodeOur.Id].Sendmail = []string{"/bin/sh", "-c", "false"}
116                         ctx.Toss(ctx.Self.Id, DefaultNiceMail, false, false, false, false, false, false)
117                         if len(dirFiles(rxPath)) == 0 {
118                                 return false
119                         }
120                         ctx.Neigh[*nodeOur.Id].Sendmail = []string{
121                                 "/bin/sh", "-c",
122                                 fmt.Sprintf("cat >> %s", filepath.Join(spool, "mbox")),
123                         }
124                         ctx.Toss(ctx.Self.Id, DefaultNiceMail, false, false, false, false, false, false)
125                         if len(dirFiles(rxPath)) != 0 {
126                                 return false
127                         }
128                 }
129                 mbox, err := ioutil.ReadFile(filepath.Join(spool, "mbox"))
130                 if err != nil {
131                         return false
132                 }
133                 expected := make([]byte, 0, 16)
134                 for i := 0; i < 16; i++ {
135                         expected = append(expected, 123)
136                 }
137                 return bytes.Compare(mbox, expected) == 0
138         }
139         if err := quick.Check(f, nil); err != nil {
140                 t.Error(err)
141         }
142 }
143
144 func TestTossFile(t *testing.T) {
145         f := func(fileSizes []uint8) bool {
146                 if len(fileSizes) == 0 {
147                         return true
148                 }
149                 files := make(map[string][]byte)
150                 for i, fileSize := range fileSizes {
151                         data := make([]byte, fileSize)
152                         if _, err := io.ReadFull(rand.Reader, data); err != nil {
153                                 panic(err)
154                         }
155                         files[strconv.Itoa(i)] = data
156                 }
157                 spool, err := ioutil.TempDir("", "testtoss")
158                 if err != nil {
159                         panic(err)
160                 }
161                 defer os.RemoveAll(spool)
162                 nodeOur, err := NewNodeGenerate()
163                 if err != nil {
164                         t.Error(err)
165                         return false
166                 }
167                 ctx := Ctx{
168                         Spool:   spool,
169                         Self:    nodeOur,
170                         SelfId:  nodeOur.Id,
171                         Neigh:   make(map[NodeId]*Node),
172                         Alias:   make(map[string]*NodeId),
173                         LogPath: filepath.Join(spool, "log.log"),
174                         Debug:   TDebug,
175                 }
176                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
177                 incomingPath := filepath.Join(spool, "incoming")
178                 for _, fileData := range files {
179                         checksum := blake2b.Sum256(fileData)
180                         fileName := ToBase32(checksum[:])
181                         src := filepath.Join(spool, fileName)
182                         if err := ioutil.WriteFile(src, fileData, os.FileMode(0600)); err != nil {
183                                 panic(err)
184                         }
185                         if err := ctx.TxFile(
186                                 ctx.Neigh[*nodeOur.Id],
187                                 DefaultNiceFile,
188                                 src,
189                                 fileName,
190                                 1<<15,
191                         ); err != nil {
192                                 t.Error(err)
193                                 return false
194                         }
195                 }
196                 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
197                 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
198                 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
199                 if len(dirFiles(rxPath)) == 0 {
200                         return false
201                 }
202                 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
203                 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
204                 if len(dirFiles(rxPath)) != 0 {
205                         return false
206                 }
207                 for _, fileData := range files {
208                         checksum := blake2b.Sum256(fileData)
209                         fileName := ToBase32(checksum[:])
210                         data, err := ioutil.ReadFile(filepath.Join(incomingPath, fileName))
211                         if err != nil {
212                                 panic(err)
213                         }
214                         if bytes.Compare(data, fileData) != 0 {
215                                 return false
216                         }
217                 }
218                 return true
219         }
220         if err := quick.Check(f, nil); err != nil {
221                 t.Error(err)
222         }
223 }
224
225 func TestTossFileSameName(t *testing.T) {
226         f := func(filesRaw uint8) bool {
227                 files := int(filesRaw)%8 + 1
228                 spool, err := ioutil.TempDir("", "testtoss")
229                 if err != nil {
230                         panic(err)
231                 }
232                 defer os.RemoveAll(spool)
233                 nodeOur, err := NewNodeGenerate()
234                 if err != nil {
235                         t.Error(err)
236                         return false
237                 }
238                 ctx := Ctx{
239                         Spool:   spool,
240                         Self:    nodeOur,
241                         SelfId:  nodeOur.Id,
242                         Neigh:   make(map[NodeId]*Node),
243                         Alias:   make(map[string]*NodeId),
244                         LogPath: filepath.Join(spool, "log.log"),
245                         Debug:   TDebug,
246                 }
247                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
248                 srcPath := filepath.Join(spool, "junk")
249                 if err = ioutil.WriteFile(
250                         srcPath,
251                         []byte("doesnotmatter"),
252                         os.FileMode(0600),
253                 ); err != nil {
254                         t.Error(err)
255                         return false
256                 }
257                 incomingPath := filepath.Join(spool, "incoming")
258                 for i := 0; i < files; i++ {
259                         if err := ctx.TxFile(
260                                 ctx.Neigh[*nodeOur.Id],
261                                 DefaultNiceFile,
262                                 srcPath,
263                                 "samefile",
264                                 1<<15,
265                         ); err != nil {
266                                 t.Error(err)
267                                 return false
268                         }
269                 }
270                 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
271                 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
272                 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
273                 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false, false, false, false, false)
274                 expected := make(map[string]struct{})
275                 expected["samefile"] = struct{}{}
276                 for i := 0; i < files-1; i++ {
277                         expected["samefile"+strconv.Itoa(i)] = struct{}{}
278                 }
279                 for _, filename := range dirFiles(incomingPath) {
280                         if _, exists := expected[filename]; !exists {
281                                 return false
282                         }
283                         delete(expected, filename)
284                 }
285                 if len(expected) != 0 {
286                         return false
287                 }
288                 return true
289         }
290         if err := quick.Check(f, nil); err != nil {
291                 t.Error(err)
292         }
293 }
294
295 func TestTossFreq(t *testing.T) {
296         f := func(fileSizes []uint8, replyNice uint8) bool {
297                 if len(fileSizes) == 0 {
298                         return true
299                 }
300                 spool, err := ioutil.TempDir("", "testtoss")
301                 if err != nil {
302                         panic(err)
303                 }
304                 defer os.RemoveAll(spool)
305                 nodeOur, err := NewNodeGenerate()
306                 if err != nil {
307                         t.Error(err)
308                         return false
309                 }
310                 ctx := Ctx{
311                         Spool:   spool,
312                         Self:    nodeOur,
313                         SelfId:  nodeOur.Id,
314                         Neigh:   make(map[NodeId]*Node),
315                         Alias:   make(map[string]*NodeId),
316                         LogPath: filepath.Join(spool, "log.log"),
317                         Debug:   TDebug,
318                 }
319                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
320                 files := make(map[string][]byte)
321                 for i, fileSize := range fileSizes {
322                         fileData := make([]byte, fileSize)
323                         if _, err := io.ReadFull(rand.Reader, fileData); err != nil {
324                                 panic(err)
325                         }
326                         fileName := strconv.Itoa(i)
327                         files[fileName] = fileData
328                         if err := ctx.TxFreq(
329                                 ctx.Neigh[*nodeOur.Id],
330                                 DefaultNiceFreq,
331                                 replyNice,
332                                 fileName,
333                                 fileName,
334                                 1<<15,
335                         ); err != nil {
336                                 t.Error(err)
337                                 return false
338                         }
339                 }
340                 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
341                 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
342                 os.Rename(txPath, rxPath)
343                 os.MkdirAll(txPath, os.FileMode(0700))
344                 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
345                 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
346                         return false
347                 }
348                 ctx.Neigh[*nodeOur.Id].Freq = &spool
349                 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
350                 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
351                         return false
352                 }
353                 for fileName, fileData := range files {
354                         if err := ioutil.WriteFile(
355                                 filepath.Join(spool, fileName),
356                                 fileData,
357                                 os.FileMode(0600),
358                         ); err != nil {
359                                 panic(err)
360                         }
361                 }
362                 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false, false, false, false, false)
363                 if len(dirFiles(txPath)) == 0 || len(dirFiles(rxPath)) != 0 {
364                         return false
365                 }
366                 for job := range ctx.Jobs(ctx.Self.Id, TTx) {
367                         var buf bytes.Buffer
368                         _, _, err := PktEncRead(ctx.Self, ctx.Neigh, job.Fd, &buf)
369                         if err != nil {
370                                 t.Error(err)
371                                 return false
372                         }
373                         var pkt Pkt
374                         if _, err = xdr.Unmarshal(&buf, &pkt); err != nil {
375                                 t.Error(err)
376                                 return false
377                         }
378                         if pkt.Nice != replyNice {
379                                 return false
380                         }
381                         dst := string(pkt.Path[:int(pkt.PathLen)])
382                         if bytes.Compare(buf.Bytes(), files[dst]) != 0 {
383                                 return false
384                         }
385                 }
386                 return true
387         }
388         if err := quick.Check(f, nil); err != nil {
389                 t.Error(err)
390         }
391 }
392
393 func TestTossTrns(t *testing.T) {
394         f := func(datumLens []uint8) bool {
395                 if len(datumLens) == 0 {
396                         return true
397                 }
398                 datum := make(map[int][]byte)
399                 for i, datumLen := range datumLens {
400                         datumLen += 64
401                         data := make([]byte, datumLen)
402                         if _, err := io.ReadFull(rand.Reader, data); err != nil {
403                                 panic(err)
404                         }
405                         datum[i] = data
406                 }
407                 spool, err := ioutil.TempDir("", "testtoss")
408                 if err != nil {
409                         panic(err)
410                 }
411                 defer os.RemoveAll(spool)
412                 nodeOur, err := NewNodeGenerate()
413                 if err != nil {
414                         t.Error(err)
415                         return false
416                 }
417                 ctx := Ctx{
418                         Spool:   spool,
419                         Self:    nodeOur,
420                         SelfId:  nodeOur.Id,
421                         Neigh:   make(map[NodeId]*Node),
422                         Alias:   make(map[string]*NodeId),
423                         LogPath: filepath.Join(spool, "log.log"),
424                         Debug:   TDebug,
425                 }
426                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
427                 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
428                 os.MkdirAll(rxPath, os.FileMode(0700))
429                 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
430                 os.MkdirAll(txPath, os.FileMode(0700))
431                 for _, data := range datum {
432                         pktTrans := Pkt{
433                                 Magic:   MagicNNCPPv2,
434                                 Type:    PktTypeTrns,
435                                 PathLen: blake2b.Size256,
436                                 Path:    new([MaxPathSize]byte),
437                         }
438                         copy(pktTrans.Path[:], nodeOur.Id[:])
439                         var dst bytes.Buffer
440                         if err := PktEncWrite(
441                                 ctx.Self,
442                                 ctx.Neigh[*nodeOur.Id],
443                                 &pktTrans,
444                                 123,
445                                 int64(len(data)),
446                                 0,
447                                 bytes.NewReader(data),
448                                 &dst,
449                         ); err != nil {
450                                 t.Error(err)
451                                 return false
452                         }
453                         checksum := blake2b.Sum256(dst.Bytes())
454                         if err := ioutil.WriteFile(
455                                 filepath.Join(rxPath, ToBase32(checksum[:])),
456                                 dst.Bytes(),
457                                 os.FileMode(0600),
458                         ); err != nil {
459                                 panic(err)
460                         }
461                 }
462                 ctx.Toss(ctx.Self.Id, 123, false, false, false, false, false, false)
463                 if len(dirFiles(rxPath)) != 0 {
464                         return false
465                 }
466                 for _, filename := range dirFiles(txPath) {
467                         dataRead, err := ioutil.ReadFile(filepath.Join(txPath, filename))
468                         if err != nil {
469                                 panic(err)
470                         }
471                         for k, data := range datum {
472                                 if bytes.Compare(dataRead, data) == 0 {
473                                         delete(datum, k)
474                                         break
475                                 }
476                         }
477                 }
478                 if len(datum) > 0 {
479                         return false
480                 }
481                 return true
482         }
483         if err := quick.Check(f, nil); err != nil {
484                 t.Error(err)
485         }
486 }