Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit e3ec402

Browse files
committed
[FAB-6812] Peer Group Resolver
Change-Id: I2c4f3986cf86bc4299b0f523bcb6ab20bc267454 Signed-off-by: Sandra Vrtikapa <sandra.vrtikapa@securekey.com>
1 parent 2b9159f commit e3ec402

File tree

8 files changed

+1507
-0
lines changed

8 files changed

+1507
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
Copyright SecureKey Technologies Inc. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package pgresolver
8+
9+
import (
10+
sdkApi "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
11+
)
12+
13+
// Item represents any item
14+
type Item interface {
15+
}
16+
17+
// Group contains a group of Items
18+
type Group interface {
19+
// Items returns all of the items
20+
Items() []Item
21+
22+
// Equals returns true if this Group contains the same items as the given Group
23+
Equals(other Group) bool
24+
25+
// Reduce reduces the group (which may be a hierarchy of groups) into a simple, non-hierarchical set of groups.
26+
// For example, given the group, G=(A and (B or C or D))
27+
// then G.Reduce() = [(A and B) or (A and C) or (A and D)]
28+
Reduce() []Group
29+
}
30+
31+
// GroupOfGroups contains a set of groups.
32+
type GroupOfGroups interface {
33+
// GroupOfGroups is also a Group
34+
Group
35+
36+
// Groups returns all of the groups in this container
37+
Groups() []Group
38+
39+
// Nof returns a set of groups that includes all possible combinations for the given threshold.
40+
// For example, given the group-of-groups, G=(G1, G2, G3), where G1=(A or B), G2=(C or D), G3=(E or F),
41+
// then:
42+
// - G.Nof(1) = (G1 or G2 or G3)
43+
// - G.Nof(2) = ((G1 and G2) or (G1 and G3) or (G2 and G3)
44+
// - G.Nof(3) = (G1 and G2 and G3)
45+
Nof(threshold int32) (GroupOfGroups, error)
46+
}
47+
48+
// PeerGroup contains a group of Peers
49+
type PeerGroup interface {
50+
Group
51+
Peers() []sdkApi.Peer
52+
}
53+
54+
// Collapsable is implemented by any group that can collapse into a simple (non-hierarchical) Group
55+
type Collapsable interface {
56+
// Collapse converts a hierarchical group into a single-level group (if possible).
57+
// For example, say G = (A and (B and C) and (D and E) and (F or G))
58+
// then G.Collapse() = (A and B and C and D and E and (F or G))
59+
Collapse() Group
60+
}
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/*
2+
Copyright SecureKey Technologies Inc. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
package pgresolver
7+
8+
import (
9+
"testing"
10+
)
11+
12+
const (
13+
a = "A"
14+
b = "B"
15+
c = "C"
16+
d = "D"
17+
e = "E"
18+
f = "F"
19+
h = "H"
20+
i = "I"
21+
j = "J"
22+
k = "K"
23+
l = "L"
24+
m = "M"
25+
)
26+
27+
func TestGroupItems(t *testing.T) {
28+
g := g(a, b)
29+
30+
items := g.Items()
31+
if len(items) != 2 {
32+
t.Fatalf("expecting %d items in group but got %d", 2, len(items))
33+
}
34+
item0 := items[0]
35+
if s, ok := item0.(string); ok {
36+
if s != a {
37+
t.Fatalf("expecting item[%d] to be %s but got %s", 0, a, items[0])
38+
}
39+
} else {
40+
t.Fatalf("expecting item[%d] to be %s but got %s", 0, a, items[0])
41+
}
42+
}
43+
44+
func TestGroupEquals(t *testing.T) {
45+
g1 := g(a, b)
46+
g2 := g(a, b)
47+
g3 := g(a, b, c)
48+
g4 := g(a, c)
49+
50+
if !g1.Equals(g1) {
51+
t.Fatalf("expecting Equals to return true")
52+
}
53+
if !g1.Equals(g2) {
54+
t.Fatalf("expecting Equals to return true")
55+
}
56+
if g1.Equals(g3) {
57+
t.Fatalf("expecting Equals to return false")
58+
}
59+
if g3.Equals(g4) {
60+
t.Fatalf("expecting Equals to return false")
61+
}
62+
if !g3.Equals(g3) {
63+
t.Fatalf("expecting Equals to return true")
64+
}
65+
}
66+
67+
func TestGroupReduce(t *testing.T) {
68+
g1 := mg(a, b)
69+
g2 := mg(c, d)
70+
71+
r1 := g(g1).Reduce()
72+
logger.Debugf("%v\n", r1)
73+
verifyGroups(t, []Group{g1}, r1)
74+
75+
r2 := g(g1, g2).Reduce()
76+
logger.Debugf("%v\n", r2)
77+
verifyGroups(t, []Group{g(g1, g2)}, r2)
78+
}
79+
80+
func TestGroupCollapse(t *testing.T) {
81+
g1 := g(g(a, b), g(c), g(d, e, f))
82+
logger.Debugf("%v\n", g1)
83+
84+
r1 := g1.(Collapsable).Collapse()
85+
logger.Debugf("%v\n", r1)
86+
expected := g(a, b, c, d, e, f)
87+
if !expected.Equals(r1) {
88+
t.Fatalf("group %s is not in the set of expected groups: %v", g1, expected)
89+
}
90+
91+
}
92+
93+
func TestGOGGroups(t *testing.T) {
94+
g1 := mg(a, b)
95+
g2 := mg(c, d)
96+
97+
gog1 := gog(g1, g2)
98+
99+
groups := gog1.Groups()
100+
if len(groups) != 2 {
101+
t.Fatalf("expecting %d groups in the group-of-groups but got %d", 2, len(groups))
102+
}
103+
group0 := groups[0]
104+
if g, ok := group0.(Group); ok {
105+
if g != g1 {
106+
t.Fatalf("expecting item[%d] to be %s but got %s", 0, g1, groups[0])
107+
}
108+
} else {
109+
t.Fatalf("expecting item[%d] to be %s but got %s", 0, g1, groups[0])
110+
}
111+
}
112+
113+
func TestGOGEquals(t *testing.T) {
114+
g1 := g(a, b)
115+
g2 := g(a, b)
116+
g3 := g(a, b, c)
117+
g4 := g(a, c)
118+
119+
gog1 := gog(g1, g2)
120+
gog2 := gog(g1, g2)
121+
gog3 := gog(g3, g4)
122+
gog4 := gog(g3, g4)
123+
124+
if !gog1.Equals(gog1) {
125+
t.Fatalf("expecting Equals to return true")
126+
}
127+
if !gog1.Equals(gog2) {
128+
t.Fatalf("expecting Equals to return true")
129+
}
130+
if gog1.Equals(gog3) {
131+
t.Fatalf("expecting Equals to return false")
132+
}
133+
if !gog3.Equals(gog4) {
134+
t.Fatalf("expecting Equals to return true")
135+
}
136+
}
137+
138+
func TestGroupOfGroupsReduce(t *testing.T) {
139+
g1 := mg(a, b)
140+
g2 := mg(c, d)
141+
142+
r1 := gog(g1).Reduce()
143+
logger.Debugf("%v\n", r1)
144+
verifyGroups(t, []Group{g1}, r1)
145+
146+
r2 := gog(g1, g2).Reduce()
147+
logger.Debugf("%v\n", r2)
148+
verifyGroups(t, []Group{g1, g2}, r2)
149+
}
150+
151+
func TestGOGCollapse(t *testing.T) {
152+
g1 := gog(g(a, b), g(c), g(d, e, f))
153+
logger.Debugf("%v\n", g1)
154+
155+
r1 := g1.(Collapsable).Collapse()
156+
logger.Debugf("%v\n", r1)
157+
expected := g1
158+
if !expected.Equals(r1) {
159+
t.Fatalf("group %s is not in the set of expected groups: %v", g1, expected)
160+
}
161+
}
162+
163+
func TestCompositeReduce(t *testing.T) {
164+
g1 := mg(a, b)
165+
g2 := mg(c, d)
166+
g3 := mg(e, f)
167+
g4 := mg(h, i, j)
168+
g5 := mg(k, l, m)
169+
170+
r := g(gog(g1, g2), gog(g3, g4, g5)).Reduce()
171+
logger.Debugf("%v\n", r)
172+
verifyGroups(t, []Group{g(g1, g3), g(g1, g4), g(g1, g5), g(g2, g3), g(g2, g4), g(g2, g5)}, r)
173+
}
174+
175+
func TestAndOperation(t *testing.T) {
176+
g1 := g(a, b)
177+
g2 := g(c, d, e)
178+
179+
expected := []Group{
180+
g(a, c), g(a, d), g(a, e),
181+
g(b, c), g(b, d), g(b, e),
182+
}
183+
184+
r := and([]Group{g1, g2})
185+
logger.Debugf("%v\n", r)
186+
187+
verifyGroups(t, expected, r)
188+
}
189+
190+
func g(items ...Item) Group {
191+
return NewGroup(items)
192+
}
193+
194+
func gog(groups ...Group) GroupOfGroups {
195+
return NewGroupOfGroups(groups)
196+
}
197+
198+
func verifyGroups(t *testing.T, expected []Group, actual []Group) {
199+
if len(expected) != len(actual) {
200+
t.Fatalf("expecting %d groups but got %d", len(expected), len(actual))
201+
}
202+
203+
for _, g := range actual {
204+
if !containsGroup(expected, g) {
205+
t.Fatalf("group %s is not in the set of expected groups: %v", g, expected)
206+
}
207+
}
208+
}
209+
210+
type mockGroup struct {
211+
groupImpl
212+
}
213+
214+
func (g *mockGroup) Reduce() []Group {
215+
return []Group{g}
216+
}
217+
218+
func (g *mockGroup) Collapse() Group {
219+
return NewGroup([]Item{g})
220+
}
221+
222+
func mg(items ...Item) Group {
223+
itms := make([]Item, len(items))
224+
for i := 0; i < len(items); i++ {
225+
itms[i] = items[i]
226+
}
227+
return &mockGroup{groupImpl{Itms: itms}}
228+
}

0 commit comments

Comments
 (0)