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