/* NNCP -- Node to Node copy, utilities for store-and-forward data exchange Copyright (C) 2016-2023 Sergey Matveev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package nncp import ( "bytes" "crypto/rand" "io" "os" "path/filepath" "testing" "testing/quick" xdr "github.com/davecgh/go-xdr/xdr2" ) func TestTx(t *testing.T) { f := func( hops uint8, pathSrc string, dataSize uint32, nice, replyNice uint8, minSize uint32, ) bool { dataSize %= 1 << 20 data := make([]byte, dataSize) if _, err := io.ReadFull(rand.Reader, data); err != nil { panic(err) } minSize %= 1 << 20 if len(pathSrc) > int(MaxPathSize) { pathSrc = pathSrc[:MaxPathSize] } hops = hops % 4 spool, err := os.MkdirTemp("", "testtx") if err != nil { panic(err) } defer os.RemoveAll(spool) nodeOur, err := NewNodeGenerate() if err != nil { panic(err) } nodeTgtOur, err := NewNodeGenerate() if err != nil { panic(err) } nodeTgt := nodeTgtOur.Their() ctx := Ctx{ Spool: spool, LogPath: filepath.Join(spool, "log.log"), Debug: true, Self: nodeOur, SelfId: nodeOur.Id, Neigh: make(map[NodeId]*Node, hops), Alias: make(map[string]*NodeId), } ctx.Neigh[*nodeOur.Id] = nodeOur.Their() ctx.Neigh[*nodeTgt.Id] = nodeTgt privates := make(map[NodeId]*NodeOur, int(hops)+1) privates[*nodeTgt.Id] = nodeTgtOur privates[*nodeOur.Id] = nodeOur for i := uint8(0); i < hops; i++ { node, err := NewNodeGenerate() if err != nil { panic(err) } ctx.Neigh[*node.Id] = node.Their() privates[*node.Id] = node nodeTgt.Via = append(nodeTgt.Via, node.Id) } pkt, err := NewPkt(PktTypeExec, replyNice, []byte(pathSrc)) if err != nil { panic(err) } src := bytes.NewReader(data) dstNode, _, _, err := ctx.Tx( nodeTgt, pkt, 123, int64(src.Len()), int64(minSize), MaxFileSize, src, "pktName", nil, ) if err != nil { return false } sentJobs := make([]Job, 0, 1) for txJob := range ctx.Jobs(dstNode.Id, TTx) { sentJobs = append(sentJobs, txJob) } if len(sentJobs) != 1 { return false } txJob := sentJobs[0] fd, err := os.Open(txJob.Path) if err != nil { panic(err) } defer fd.Close() var bufR bytes.Buffer if _, err = io.Copy(&bufR, fd); err != nil { panic(err) } var bufW bytes.Buffer vias := append(nodeTgt.Via, nodeTgt.Id) for i, hopId := range vias { hopOur := privates[*hopId] _, foundNode, _, err := PktEncRead( hopOur, ctx.Neigh, &bufR, &bufW, true, nil, ) if err != nil { return false } if *foundNode.Id != *nodeOur.Id { return false } bufR, bufW = bufW, bufR bufW.Reset() var pkt Pkt if _, err = xdr.Unmarshal(&bufR, &pkt); err != nil { return false } if *hopId == *nodeTgt.Id { if pkt.Type != PktTypeExec { return false } if pkt.Nice != replyNice { return false } if !bytes.HasPrefix(pkt.Path[:], []byte(pathSrc)) { return false } if !bytes.Equal(bufR.Bytes(), []byte(data)) { return false } } else { if pkt.Type != PktTypeTrns { return false } if !bytes.Equal(pkt.Path[:MTHSize], vias[i+1][:]) { return false } } } return true } if err := quick.Check(f, nil); err != nil { t.Error(err) } }