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