github.com/metacurrency/holochain@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/validate_test.go (about)

     1  package holochain
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	. "github.com/holochain/holochain-proto/hash"
     7  	. "github.com/smartystreets/goconvey/convey"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  )
    12  
    13  func TestValidateReceiver(t *testing.T) {
    14  	d, _, h := PrepareTestChain("test")
    15  	defer CleanupTestChain(h, d)
    16  
    17  	Convey("VALIDATE_PUT_REQUEST should fail if  body isn't a ValidateQuery", t, func() {
    18  		m := h.node.NewMessage(VALIDATE_PUT_REQUEST, "fish")
    19  		_, err := ValidateReceiver(h, m)
    20  		So(err.Error(), ShouldEqual, "expected ValidateQuery got string")
    21  	})
    22  	Convey("VALIDATE_PUT_REQUEST should fail if hash doesn't exist", t, func() {
    23  		hash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2")
    24  		m := h.node.NewMessage(VALIDATE_PUT_REQUEST, ValidateQuery{H: hash})
    25  		_, err := ValidateReceiver(h, m)
    26  		So(err, ShouldNotBeNil)
    27  		So(err.Error(), ShouldEqual, "hash not found")
    28  	})
    29  	Convey("VALIDATE_PUT_REQUEST should return entry by hash", t, func() {
    30  		entry := GobEntry{C: "bogus entry data"}
    31  		_, hd, err := h.NewEntry(time.Now(), "evenNumbers", &entry)
    32  
    33  		m := h.node.NewMessage(VALIDATE_PUT_REQUEST, ValidateQuery{H: hd.EntryLink})
    34  		r, err := ValidateReceiver(h, m)
    35  		So(err, ShouldBeNil)
    36  		vr := r.(ValidateResponse)
    37  		So(vr.Type, ShouldEqual, "evenNumbers")
    38  		So(fmt.Sprintf("%v", vr.Entry), ShouldEqual, fmt.Sprintf("%v", entry))
    39  		So(fmt.Sprintf("%v", vr.Header), ShouldEqual, fmt.Sprintf("%v", *hd))
    40  	})
    41  	Convey("VALIDATE_LINK_REQUEST should fail if  body isn't a ValidateQuery", t, func() {
    42  		m := h.node.NewMessage(VALIDATE_LINK_REQUEST, "fish")
    43  		_, err := ValidateReceiver(h, m)
    44  		So(err.Error(), ShouldEqual, "expected ValidateQuery got string")
    45  	})
    46  	Convey("VALIDATE_LINK_REQUEST should fail if hash doesn't exist", t, func() {
    47  		hash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2")
    48  		m := h.node.NewMessage(VALIDATE_LINK_REQUEST, ValidateQuery{H: hash})
    49  		_, err := ValidateReceiver(h, m)
    50  		So(err, ShouldNotBeNil)
    51  		So(err.Error(), ShouldEqual, "hash not found")
    52  	})
    53  
    54  	entry := GobEntry{C: "bogus entry data"}
    55  	_, hd, _ := h.NewEntry(time.Now(), "evenNumbers", &entry)
    56  	hash := hd.EntryLink
    57  
    58  	Convey("VALIDATE_LINK_REQUEST should return error if hash isn't a linking entry", t, func() {
    59  		m := h.node.NewMessage(VALIDATE_LINK_REQUEST, ValidateQuery{H: hash})
    60  		_, err := ValidateReceiver(h, m)
    61  		So(err.Error(), ShouldEqual, "hash not of a linking entry")
    62  	})
    63  
    64  	Convey("VALIDATE_LINK_REQUEST should return entry by linking entry hash", t, func() {
    65  		someData := `{"firstName":"Zippy","lastName":"Pinhead"}`
    66  		e := GobEntry{C: someData}
    67  		_, phd, _ := h.NewEntry(time.Now(), "profile", &e)
    68  		profileHash := phd.EntryLink
    69  		e = GobEntry{C: fmt.Sprintf(`{"Links":[{"Base":"%s","Link":"%s","Tag":"4stars"}]}`, hash.String(), profileHash.String())}
    70  		_, le, _ := h.NewEntry(time.Now(), "rating", &e)
    71  
    72  		m := h.node.NewMessage(VALIDATE_LINK_REQUEST, ValidateQuery{H: le.EntryLink})
    73  		r, err := ValidateReceiver(h, m)
    74  		So(err, ShouldBeNil)
    75  		vr := r.(ValidateResponse)
    76  		So(vr.Type, ShouldEqual, "rating")
    77  		So(fmt.Sprintf("%v", vr.Entry), ShouldEqual, fmt.Sprintf("%v", e))
    78  		So(fmt.Sprintf("%v", vr.Header), ShouldEqual, fmt.Sprintf("%v", *le))
    79  	})
    80  }
    81  
    82  func TestValidateMakePackage(t *testing.T) {
    83  	d, _, h := PrepareTestChain("test")
    84  	defer CleanupTestChain(h, d)
    85  	var emptyStringList []string
    86  
    87  	Convey("it should be able to make a full chain package", t, func() {
    88  		req := PackagingReq{PkgReqChain: int64(PkgReqChainOptFull)}
    89  		pkg, err := MakePackage(h, req)
    90  		So(err, ShouldBeNil)
    91  
    92  		var b bytes.Buffer
    93  		h.chain.MarshalChain(&b, ChainMarshalFlagsOmitDNA, emptyStringList, emptyStringList)
    94  		So(string(pkg.Chain), ShouldEqual, string(b.Bytes()))
    95  	})
    96  	Convey("it should be able to make a headers only chain package", t, func() {
    97  		req := PackagingReq{PkgReqChain: int64(PkgReqChainOptHeaders)}
    98  		pkg, err := MakePackage(h, req)
    99  		So(err, ShouldBeNil)
   100  
   101  		var b bytes.Buffer
   102  		h.chain.MarshalChain(&b, ChainMarshalFlagsNoEntries+ChainMarshalFlagsOmitDNA, emptyStringList, emptyStringList)
   103  		So(string(pkg.Chain), ShouldEqual, string(b.Bytes()))
   104  	})
   105  	Convey("it should be able to make an entries only chain package", t, func() {
   106  		req := PackagingReq{PkgReqChain: int64(PkgReqChainOptEntries)}
   107  		pkg, err := MakePackage(h, req)
   108  		So(err, ShouldBeNil)
   109  
   110  		var b bytes.Buffer
   111  		h.chain.MarshalChain(&b, ChainMarshalFlagsNoHeaders+ChainMarshalFlagsOmitDNA, emptyStringList, emptyStringList)
   112  		So(string(pkg.Chain), ShouldEqual, string(b.Bytes()))
   113  	})
   114  
   115  	Convey("it should be able to make package of a chain of just a few types", t, func() {
   116  		entry := GobEntry{C: "2"}
   117  		h.NewEntry(time.Now(), "evenNumbers", &entry)
   118  		entry = GobEntry{C: "3"}
   119  		h.NewEntry(time.Now(), "oddNumbers", &entry)
   120  
   121  		req := PackagingReq{PkgReqChain: int64(PkgReqChainOptFull), PkgReqEntryTypes: []string{"oddNumbers"}}
   122  		pkg, err := MakePackage(h, req)
   123  		So(err, ShouldBeNil)
   124  
   125  		var b bytes.Buffer
   126  		h.chain.MarshalChain(&b, ChainMarshalFlagsOmitDNA, []string{"oddNumbers"}, emptyStringList)
   127  		So(string(pkg.Chain), ShouldEqual, string(b.Bytes()))
   128  	})
   129  
   130  	Convey("it should not contain the real contents of private entries", t, func() {
   131  		entry := GobEntry{C: "secret message"}
   132  		h.NewEntry(time.Now(), "privateData", &entry)
   133  
   134  		req := PackagingReq{PkgReqChain: int64(PkgReqChainOptFull)}
   135  		pkg, err := MakePackage(h, req)
   136  		So(err, ShouldBeNil)
   137  
   138  		_, c1, err := UnmarshalChain(h.hashSpec, bytes.NewBuffer(pkg.Chain))
   139  		So(err, ShouldBeNil)
   140  		So(c1.Entries[2].Content(), ShouldEqual, "2") //from previous test cases
   141  		So(c1.Entries[3].Content(), ShouldEqual, "3") //from previous test cases
   142  		So(c1.Entries[4].Content(), ShouldNotEqual, "secret message")
   143  		So(c1.Entries[4].Content(), ShouldEqual, ChainMarshalPrivateEntryRedacted)
   144  	})
   145  
   146  }
   147  
   148  func TestGetValidationResponse(t *testing.T) {
   149  	d, _, h := PrepareTestChain("test")
   150  	defer CleanupTestChain(h, d)
   151  	var emptyStringList []string
   152  
   153  	hash := commit(h, "oddNumbers", "3")
   154  
   155  	Convey("entry types should return packages based on definition", t, func() {
   156  		entry, _, err := h.chain.GetEntry(hash)
   157  		if err != nil {
   158  			panic(err)
   159  		}
   160  		a := NewPutAction("oddNumbers", entry, &Header{})
   161  		resp, err := h.GetValidationResponse(a, hash)
   162  		So(err, ShouldBeNil)
   163  		So(resp.Type, ShouldEqual, "oddNumbers")
   164  		So(fmt.Sprintf("%v", &resp.Entry), ShouldEqual, fmt.Sprintf("%v", entry))
   165  		var b bytes.Buffer
   166  		h.chain.MarshalChain(&b, ChainMarshalFlagsOmitDNA, emptyStringList, emptyStringList)
   167  		So(fmt.Sprintf("%v", string(resp.Package.Chain)), ShouldEqual, fmt.Sprintf("%v", string(b.Bytes())))
   168  	})
   169  
   170  	Convey("it should fail on the DNA (can't validate DNA as it's what determines what's valid)", t, func() {
   171  		entry, _, err := h.chain.GetEntry(h.dnaHash)
   172  		a := NewPutAction(AgentEntryType, entry, &Header{})
   173  		_, err = h.GetValidationResponse(a, h.dnaHash)
   174  		So(err, ShouldEqual, ErrNotValidForDNAType)
   175  
   176  	})
   177  
   178  	Convey("agent entry type should return the type chain in the package", t, func() {
   179  		entry, _, err := h.chain.GetEntry(h.agentHash)
   180  		a := NewPutAction(AgentEntryType, entry, &Header{})
   181  		resp, err := h.GetValidationResponse(a, h.agentHash)
   182  		So(err, ShouldBeNil)
   183  		So(resp.Type, ShouldEqual, AgentEntryType)
   184  		So(fmt.Sprintf("%v", &resp.Entry), ShouldEqual, fmt.Sprintf("%v", entry))
   185  
   186  		types := []string{AgentEntryType}
   187  		var b bytes.Buffer
   188  		h.chain.MarshalChain(&b, ChainMarshalFlagsOmitDNA, types, emptyStringList)
   189  		So(fmt.Sprintf("%v", string(resp.Package.Chain)), ShouldEqual, fmt.Sprintf("%v", string(b.Bytes())))
   190  	})
   191  
   192  	Convey("key entry type should return empty package with pubkey as entry", t, func() {
   193  		hash := HashFromPeerID(h.nodeID)
   194  		a := NewPutAction(KeyEntryType, nil, &Header{})
   195  		resp, err := h.GetValidationResponse(a, hash)
   196  		So(err, ShouldBeNil)
   197  		So(resp.Type, ShouldEqual, KeyEntryType)
   198  
   199  		pk, err := h.agent.EncodePubKey()
   200  		if err != nil {
   201  			panic(err)
   202  		}
   203  
   204  		So(string(resp.Entry.Content().(string)), ShouldEqual, pk)
   205  		So(fmt.Sprintf("%v", resp.Package), ShouldEqual, fmt.Sprintf("%v", Package{}))
   206  	})
   207  
   208  	Convey("headers entry type should return empty package with the entry", t, func() {
   209  		hd := h.Chain().Top()
   210  		j, _ := hd.ToJSON()
   211  		entryStr := fmt.Sprintf(`[{"Header":%s,"Role":"someRole","Source":"%s"}]`, j, h.nodeID.Pretty())
   212  		hash := commit(h, HeadersEntryType, entryStr)
   213  		hd = h.Chain().Top()
   214  		e := &GobEntry{C: entryStr}
   215  		a := NewPutAction(HeadersEntryType, e, hd)
   216  		resp, err := h.GetValidationResponse(a, hash)
   217  		So(err, ShouldBeNil)
   218  		So(resp.Type, ShouldEqual, HeadersEntryType)
   219  		So(fmt.Sprintf("%v", resp.Entry.Content()), ShouldEqual, entryStr)
   220  		So(fmt.Sprintf("%v", resp.Package), ShouldEqual, fmt.Sprintf("%v", Package{}))
   221  	})
   222  }
   223  
   224  func TestMakeValidatePackage(t *testing.T) {
   225  	d, _, h := PrepareTestChain("test")
   226  	defer CleanupTestChain(h, d)
   227  
   228  	entry := GobEntry{C: `{"firstName":"Zippy","lastName":"Pinhead"}`}
   229  	h.NewEntry(time.Now().Round(0), "evenNumbers", &entry)
   230  
   231  	pkg, _ := MakePackage(h, PackagingReq{PkgReqChain: int64(PkgReqChainOptFull)})
   232  	Convey("it should be able to make a validate package", t, func() {
   233  		vpkg, err := MakeValidationPackage(h, &pkg)
   234  		So(err, ShouldBeNil)
   235  		So(fmt.Sprintf("%v", vpkg.Chain), ShouldEqual, fmt.Sprintf("%v", h.chain))
   236  	})
   237  
   238  	Convey("it should return an error if the package data was tweaked", t, func() {
   239  		// tweak the agent header
   240  		pkg.Chain = []byte(strings.Replace(string(pkg.Chain), "%agent", "!agent", -1))
   241  		vpkg, err := MakeValidationPackage(h, &pkg)
   242  		So(err, ShouldNotBeNil)
   243  		So(vpkg, ShouldBeNil)
   244  
   245  		// restore
   246  		pkg.Chain = []byte(strings.Replace(string(pkg.Chain), "!agent", "%agent", -1))
   247  
   248  		// tweak
   249  		pkg.Chain = []byte(strings.Replace(string(pkg.Chain), "Zippy", "Zappy", -1))
   250  
   251  		vpkg, err = MakeValidationPackage(h, &pkg)
   252  		So(err, ShouldNotBeNil)
   253  
   254  	})
   255  }