forked from holochain/holochain-proto
-
Notifications
You must be signed in to change notification settings - Fork 0
/
action_test.go
320 lines (267 loc) · 11.2 KB
/
action_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
package holochain
import (
// "fmt"
"fmt"
ic "github.com/libp2p/go-libp2p-crypto"
peer "github.com/libp2p/go-libp2p-peer"
. "github.com/metacurrency/holochain/hash"
. "github.com/smartystreets/goconvey/convey"
"testing"
)
func TestValidateAction(t *testing.T) {
d, _, h := PrepareTestChain("test")
defer CleanupTestChain(h, d)
var err error
// these test the generic properties of ValidateAction using a commit action as an example
Convey("it should fail if a validator doesn't exist for the entry type", t, func() {
entry := &GobEntry{C: "foo"}
a := NewCommitAction("bogusType", entry)
_, err = h.ValidateAction(a, a.entryType, nil, []peer.ID{h.nodeID})
So(err.Error(), ShouldEqual, "no definition for entry type: bogusType")
})
Convey("a valid entry returns the entry def", t, func() {
entry := &GobEntry{C: "2"}
a := NewCommitAction("evenNumbers", entry)
var d *EntryDef
d, err = h.ValidateAction(a, a.entryType, nil, []peer.ID{h.nodeID})
So(err, ShouldBeNil)
So(fmt.Sprintf("%v", d), ShouldEqual, "&{evenNumbers zygo public <nil>}")
})
Convey("an invalid action returns the ValidationFailedErr", t, func() {
entry := &GobEntry{C: "1"}
a := NewCommitAction("evenNumbers", entry)
_, err = h.ValidateAction(a, a.entryType, nil, []peer.ID{h.nodeID})
So(err, ShouldEqual, ValidationFailedErr)
})
// these test the sys type cases
Convey("adding or changing dna should fail", t, func() {
entry := &GobEntry{C: "fakeDNA"}
a := NewCommitAction(DNAEntryType, entry)
_, err = h.ValidateAction(a, a.entryType, nil, []peer.ID{h.nodeID})
So(err, ShouldEqual, ErrNotValidForDNAType)
ap := NewPutAction(DNAEntryType, entry, nil)
_, err = h.ValidateAction(ap, ap.entryType, nil, []peer.ID{h.nodeID})
So(err, ShouldEqual, ErrNotValidForDNAType)
am := NewModAction(DNAEntryType, entry, HashFromPeerID(h.nodeID))
_, err = h.ValidateAction(am, am.entryType, nil, []peer.ID{h.nodeID})
So(err, ShouldEqual, ErrNotValidForDNAType)
})
Convey("deleting all sys entry types should fail", t, func() {
a := NewDelAction(DNAEntryType, DelEntry{})
_, err = h.ValidateAction(a, a.entryType, nil, []peer.ID{h.nodeID})
So(err, ShouldEqual, ErrNotValidForDNAType)
a.entryType = KeyEntryType
_, err = h.ValidateAction(a, a.entryType, nil, []peer.ID{h.nodeID})
So(err, ShouldEqual, ErrNotValidForKeyType)
a.entryType = AgentEntryType
_, err = h.ValidateAction(a, a.entryType, nil, []peer.ID{h.nodeID})
So(err, ShouldEqual, ErrNotValidForAgentType)
})
}
func TestSysValidateEntry(t *testing.T) {
d, _, h := PrepareTestChain("test")
defer CleanupTestChain(h, d)
Convey("key entry should be a public key", t, func() {
e := &GobEntry{}
err := sysValidateEntry(h, KeyEntryDef, e, nil)
So(err, ShouldEqual, ValidationFailedErr)
e.C = []byte{1, 2, 3}
err = sysValidateEntry(h, KeyEntryDef, e, nil)
So(err, ShouldEqual, ValidationFailedErr)
e.C = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}
err = sysValidateEntry(h, KeyEntryDef, e, nil)
So(err, ShouldEqual, ValidationFailedErr)
pk, _ := ic.MarshalPublicKey(h.agent.PubKey())
e.C = pk
err = sysValidateEntry(h, KeyEntryDef, e, nil)
So(err, ShouldBeNil)
})
Convey("an agent entry should have the correct structure as defined", t, func() {
e := &GobEntry{}
err := sysValidateEntry(h, AgentEntryDef, e, nil)
So(err, ShouldEqual, ValidationFailedErr)
// bad agent entry (empty)
e.C = AgentEntry{}
err = sysValidateEntry(h, AgentEntryDef, e, nil)
So(err, ShouldEqual, ValidationFailedErr)
ae, _ := h.agent.AgentEntry(nil)
// bad public key
ae.PublicKey = nil
e.C = ae
err = sysValidateEntry(h, AgentEntryDef, e, nil)
So(err, ShouldEqual, ValidationFailedErr)
ae, _ = h.agent.AgentEntry(nil)
// bad public key
ae.PublicKey = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}
e.C = ae
err = sysValidateEntry(h, AgentEntryDef, e, nil)
So(err, ShouldEqual, ValidationFailedErr)
ae, _ = h.agent.AgentEntry(nil)
// bad revocation
ae.Revocation = []byte{1, 2, 3}
e.C = ae
err = sysValidateEntry(h, AgentEntryDef, e, nil)
So(err, ShouldEqual, ValidationFailedErr)
ae, _ = h.agent.AgentEntry(nil)
e.C = ae
err = sysValidateEntry(h, AgentEntryDef, e, nil)
So(err, ShouldBeNil)
})
_, def, _ := h.GetEntryDef("rating")
Convey("a nil entry is invalid", t, func() {
err := sysValidateEntry(h, def, nil, nil)
So(err.Error(), ShouldEqual, "nil entry invalid")
})
Convey("validate on a schema based entry should check entry against the schema", t, func() {
profile := `{"firstName":"Eric"}` // missing required lastName
_, def, _ := h.GetEntryDef("profile")
err := sysValidateEntry(h, def, &GobEntry{C: profile}, nil)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldEqual, "validator profile failed: object property 'lastName' is required")
})
Convey("validate on a links entry should fail if not formatted correctly", t, func() {
err := sysValidateEntry(h, def, &GobEntry{C: "badjson"}, nil)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldEqual, "invalid links entry, invalid json: invalid character 'b' looking for beginning of value")
err = sysValidateEntry(h, def, &GobEntry{C: `{}`}, nil)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldEqual, "invalid links entry: you must specify at least one link")
err = sysValidateEntry(h, def, &GobEntry{C: `{"Links":[{}]}`}, nil)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldEqual, "invalid links entry: missing Base")
err = sysValidateEntry(h, def, &GobEntry{C: `{"Links":[{"Base":"x","Link":"x","Tag":"sometag"}]}`}, nil)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldEqual, "invalid links entry: Base multihash too short. must be > 3 bytes")
err = sysValidateEntry(h, def, &GobEntry{C: `{"Links":[{"Base":"QmdRXz53TVT9qBYfbXctHyy2GpTNa6YrpAy6ZcDGG8Xhc5","Link":"x","Tag":"sometag"}]}`}, nil)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldEqual, "invalid links entry: Link multihash too short. must be > 3 bytes")
err = sysValidateEntry(h, def, &GobEntry{C: `{"Links":[{"Base":"QmdRXz53TVT9qBYfbXctHyy2GpTNa6YrpAy6ZcDGG8Xhc5","Link":"QmdRXz53TVT9qBYfbXctHyy2GpTNa6YrpAy6ZcDGG8Xhc5"}]}`}, nil)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldEqual, "invalid links entry: missing Tag")
})
}
func TestSysValidateMod(t *testing.T) {
d, _, h := PrepareTestChain("test")
defer CleanupTestChain(h, d)
hash := commit(h, "evenNumbers", "2")
_, def, _ := h.GetEntryDef("evenNumbers")
/* This is actually bogus because it assumes we have the entry type in our chain but
might be in a different chain.
Convey("it should check that entry types match on mod", t, func() {
a := NewModAction("oddNumbers", &GobEntry{}, hash)
err := a.SysValidation(h, def, nil, []peer.ID{h.nodeID})
So(err, ShouldEqual, ErrEntryTypeMismatch)
})
*/
Convey("it should check that entry isn't linking ", t, func() {
a := NewModAction("rating", &GobEntry{}, hash)
_, ratingsDef, _ := h.GetEntryDef("rating")
err := a.SysValidation(h, ratingsDef, nil, []peer.ID{h.nodeID})
So(err.Error(), ShouldEqual, "Can't mod Links entry")
})
Convey("it should check that entry validates", t, func() {
a := NewModAction("evenNumbers", nil, hash)
err := a.SysValidation(h, def, nil, []peer.ID{h.nodeID})
So(err, ShouldEqual, ErrNilEntryInvalid)
})
Convey("it should check that header isn't missing", t, func() {
a := NewModAction("evenNumbers", &GobEntry{}, hash)
err := a.SysValidation(h, def, nil, []peer.ID{h.nodeID})
So(err, ShouldBeError)
So(err.Error(), ShouldEqual, "mod: missing header")
})
Convey("it should check that replaces is doesn't make a loop", t, func() {
a := NewModAction("evenNumbers", &GobEntry{}, hash)
a.header = &Header{EntryLink: hash}
err := a.SysValidation(h, def, nil, []peer.ID{h.nodeID})
So(err, ShouldBeError)
So(err.Error(), ShouldEqual, "mod: replaces must be different from original hash")
})
}
func TestSysValidateDel(t *testing.T) {
d, _, h := PrepareTestChain("test")
defer CleanupTestChain(h, d)
hash := commit(h, "evenNumbers", "2")
_, def, _ := h.GetEntryDef("evenNumbers")
Convey("it should check that entry types match on del", t, func() {
a := NewDelAction("oddNumbers", DelEntry{Hash: hash})
err := a.SysValidation(h, def, nil, []peer.ID{h.nodeID})
So(err, ShouldEqual, ErrEntryTypeMismatch)
})
Convey("it should check that entry isn't linking ", t, func() {
a := NewDelAction("rating", DelEntry{Hash: hash})
_, ratingsDef, _ := h.GetEntryDef("rating")
err := a.SysValidation(h, ratingsDef, nil, []peer.ID{h.nodeID})
So(err.Error(), ShouldEqual, "Can't del Links entry")
})
}
func TestCheckArgCount(t *testing.T) {
Convey("it should check for wrong number of args", t, func() {
args := []Arg{{}}
err := checkArgCount(args, 2)
So(err, ShouldEqual, ErrWrongNargs)
// test with args that are optional: two that are required and one not
args = []Arg{{}, {}, {Optional: true}}
err = checkArgCount(args, 1)
So(err, ShouldEqual, ErrWrongNargs)
err = checkArgCount(args, 2)
So(err, ShouldBeNil)
err = checkArgCount(args, 3)
So(err, ShouldBeNil)
err = checkArgCount(args, 4)
So(err, ShouldEqual, ErrWrongNargs)
})
}
func TestActionGet(t *testing.T) {
nodesCount := 3
mt := setupMultiNodeTesting(nodesCount)
defer mt.cleanupMultiNodeTesting()
h := mt.nodes[0]
e := GobEntry{C: "3"}
hash, _ := e.Sum(h.hashSpec)
Convey("receive should return not found if it doesn't exist", t, func() {
m := h.node.NewMessage(GET_REQUEST, GetReq{H: hash})
_, err := ActionReceiver(h, m)
So(err, ShouldEqual, ErrHashNotFound)
})
commit(h, "oddNumbers", "3")
m := h.node.NewMessage(GET_REQUEST, GetReq{H: hash})
Convey("receive should return value if it exists", t, func() {
r, err := ActionReceiver(h, m)
So(err, ShouldBeNil)
resp := r.(GetResp)
So(fmt.Sprintf("%v", resp.Entry), ShouldEqual, fmt.Sprintf("%v", e))
})
ringConnect(t, mt.ctx, mt.nodes, nodesCount)
Convey("receive should return closer peers if it can", t, func() {
h2 := mt.nodes[2]
r, err := ActionReceiver(h2, m)
So(err, ShouldBeNil)
resp := r.(CloserPeersResp)
So(len(resp.CloserPeers), ShouldEqual, 1)
So(peer.ID(resp.CloserPeers[0].ID).Pretty(), ShouldEqual, "QmUfY4WeqD3UUfczjdkoFQGEgCAVNf7rgFfjdeTbr7JF1C")
})
}
func TestActionGetLocal(t *testing.T) {
d, _, h := PrepareTestChain("test")
defer CleanupTestChain(h, d)
hash := commit(h, "secret", "31415")
Convey("non local get should fail for private entries", t, func() {
req := GetReq{H: hash, GetMask: GetMaskEntry}
_, err := NewGetAction(req, &GetOptions{GetMask: req.GetMask}).Do(h)
So(err.Error(), ShouldEqual, "hash not found")
})
Convey("it should fail to get non-existent private local values", t, func() {
badHash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqh2")
req := GetReq{H: badHash, GetMask: GetMaskEntry}
_, err := NewGetAction(req, &GetOptions{GetMask: req.GetMask, Local: true}).Do(h)
So(err.Error(), ShouldEqual, "hash not found")
})
Convey("it should get private local values", t, func() {
req := GetReq{H: hash, GetMask: GetMaskEntry}
rsp, err := NewGetAction(req, &GetOptions{GetMask: req.GetMask, Local: true}).Do(h)
So(err, ShouldBeNil)
getResp := rsp.(GetResp)
So(getResp.Entry.Content().(string), ShouldEqual, "31415")
})
}