@webex/plugin-meetings 3.9.0-webinar5k.1 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +16 -0
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +40 -328
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +6 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +196 -160
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +5 -2
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/type.js +7 -0
- package/dist/meeting/type.js.map +1 -0
- package/dist/meeting/util.js +79 -10
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +37 -39
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/members/collection.js +0 -13
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +21 -40
- package/dist/members/index.js.map +1 -1
- package/dist/members/util.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +1 -1
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js +34 -5
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +42 -2
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/types/constants.d.ts +16 -0
- package/dist/types/locus-info/index.d.ts +3 -102
- package/dist/types/meeting/in-meeting-actions.d.ts +6 -0
- package/dist/types/meeting/index.d.ts +23 -28
- package/dist/types/meeting/type.d.ts +9 -0
- package/dist/types/meeting/util.d.ts +6 -3
- package/dist/types/member/types.d.ts +0 -1
- package/dist/types/members/collection.d.ts +0 -6
- package/dist/types/members/index.d.ts +7 -16
- package/dist/types/members/util.d.ts +2 -1
- package/dist/types/multistream/remoteMedia.d.ts +20 -1
- package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -24
- package/src/constants.ts +16 -2
- package/src/locus-info/index.ts +39 -409
- package/src/meeting/in-meeting-actions.ts +13 -0
- package/src/meeting/index.ts +92 -63
- package/src/meeting/muteState.ts +6 -2
- package/src/meeting/type.ts +9 -0
- package/src/meeting/util.ts +93 -19
- package/src/meetings/index.ts +6 -19
- package/src/member/types.ts +0 -1
- package/src/members/collection.ts +0 -11
- package/src/members/index.ts +10 -33
- package/src/members/util.ts +2 -1
- package/src/multistream/mediaRequestManager.ts +7 -7
- package/src/multistream/remoteMedia.ts +34 -4
- package/src/multistream/remoteMediaGroup.ts +37 -2
- package/test/unit/spec/locus-info/index.js +8 -365
- package/test/unit/spec/meeting/in-meeting-actions.ts +6 -0
- package/test/unit/spec/meeting/index.js +254 -38
- package/test/unit/spec/meeting/utils.js +122 -1
- package/test/unit/spec/meetings/index.js +2 -0
- package/test/unit/spec/members/index.js +37 -1
- package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
- package/test/unit/spec/multistream/remoteMedia.ts +66 -2
- package/dist/hashTree/constants.js +0 -23
- package/dist/hashTree/constants.js.map +0 -1
- package/dist/hashTree/hashTree.js +0 -516
- package/dist/hashTree/hashTree.js.map +0 -1
- package/dist/hashTree/hashTreeParser.js +0 -521
- package/dist/hashTree/hashTreeParser.js.map +0 -1
- package/dist/types/hashTree/constants.d.ts +0 -8
- package/dist/types/hashTree/hashTree.d.ts +0 -128
- package/dist/types/hashTree/hashTreeParser.d.ts +0 -152
- package/src/hashTree/constants.ts +0 -12
- package/src/hashTree/hashTree.ts +0 -460
- package/src/hashTree/hashTreeParser.ts +0 -556
- package/test/unit/spec/hashTree/hashTree.ts +0 -394
- package/test/unit/spec/hashTree/hashTreeParser.ts +0 -156
@@ -1,394 +0,0 @@
|
|
1
|
-
import HashTree from '@webex/plugin-meetings/src/hashTree/hashTree';
|
2
|
-
import {EMPTY_HASH} from '@webex/plugin-meetings/src/hashTree/constants';
|
3
|
-
|
4
|
-
import { expect } from "@webex/test-helper-chai";
|
5
|
-
|
6
|
-
// Define a type for the leaf data items used in tests
|
7
|
-
type LeafDataItem = {
|
8
|
-
type: string;
|
9
|
-
id: number;
|
10
|
-
version: number;
|
11
|
-
};
|
12
|
-
|
13
|
-
describe('HashTree', () => {
|
14
|
-
it('should initialize with empty leaves and hashes', () => {
|
15
|
-
const leafData: LeafDataItem[] = [];
|
16
|
-
const numLeaves = 4;
|
17
|
-
const hashTree = new HashTree(leafData, numLeaves);
|
18
|
-
|
19
|
-
expect(hashTree.leaves).to.deep.equal(new Array(numLeaves).fill(null).map(() => ({})));
|
20
|
-
expect(hashTree.leafHashes).to.deep.equal(new Array(numLeaves).fill(EMPTY_HASH));
|
21
|
-
expect(hashTree.getLeafCount()).to.equal(numLeaves);
|
22
|
-
expect(hashTree.getTotalItemCount()).to.equal(0);
|
23
|
-
});
|
24
|
-
|
25
|
-
it('constructor should allow 0 leaves', () => {
|
26
|
-
const leafData: LeafDataItem[] = [];
|
27
|
-
const numLeaves = 0;
|
28
|
-
const hashTree = new HashTree(leafData, numLeaves);
|
29
|
-
expect(hashTree.getLeafCount()).to.equal(0);
|
30
|
-
expect(hashTree.getRootHash()).to.equal(EMPTY_HASH);
|
31
|
-
expect(hashTree.getHashes()).to.deep.equal([EMPTY_HASH]);
|
32
|
-
});
|
33
|
-
|
34
|
-
it('number of leaves must be 0 or a power of 2', () => {
|
35
|
-
const leafData: LeafDataItem[] = [];
|
36
|
-
const numLeaves = 3; // Not a power of 2
|
37
|
-
expect(() => new HashTree(leafData, numLeaves)).to.throw('Number of leaves must be a power of 2, saw 3');
|
38
|
-
const numLeavesNegative = -1;
|
39
|
-
expect(() => new HashTree(leafData, numLeavesNegative)).to.throw('Number of leaves must be a power of 2, saw -1');
|
40
|
-
});
|
41
|
-
|
42
|
-
it('should have the correct hashes after putting ObjectIds using constructor', () => {
|
43
|
-
const oids: LeafDataItem[] = [
|
44
|
-
{type: 'participant', id: 1, version: 3} // Hashes to bucket 1 % 4 = 1
|
45
|
-
];
|
46
|
-
// numLeaves is 4. Item id 1 % 4 = 1. So, leafHashes[1] will be updated.
|
47
|
-
// leafHashes[0], leafHashes[2], leafHashes[3] remain EMPTY_HASH.
|
48
|
-
const tree = new HashTree(oids, 4);
|
49
|
-
|
50
|
-
// These are the expected hash values from the Java reference for a similar structure.
|
51
|
-
// The actual values depend on the specific XXHash128 implementation and input serialization.
|
52
|
-
// For this test, we'll use the previously provided values, assuming they are correct for the TS implementation.
|
53
|
-
expect(tree.getHashes()).to.deep.equal([
|
54
|
-
"24a75d115a0a90ddb376a02b435c780f", // Root hash
|
55
|
-
"457eeb22808eadfcff92ee47d67acbbf", // Internal node (children: leaf 0, leaf 1)
|
56
|
-
"b113a76304e3a7121afecfe1606ee1c1", // Internal node (children: leaf 2, leaf 3)
|
57
|
-
EMPTY_HASH, // Leaf 0 hash (empty)
|
58
|
-
"42df811f5a902c5b6bfcf50c7004e275", // Leaf 1 hash (for item {type: 'participant', id: 1, version: 3})
|
59
|
-
EMPTY_HASH, // Leaf 2 hash (empty)
|
60
|
-
EMPTY_HASH // Leaf 3 hash (empty)
|
61
|
-
]);
|
62
|
-
expect(tree.getRootHash()).to.equal("24a75d115a0a90ddb376a02b435c780f");
|
63
|
-
});
|
64
|
-
|
65
|
-
it('should have the correct hashes after putting multiple ObjectIds using constructor', () => {
|
66
|
-
const oids: LeafDataItem[] = [
|
67
|
-
{type: "typeA", id: 1, version: 3}, // Leaf 1 (1 % 4 = 1)
|
68
|
-
{type: "typeA", id: 6, version: 2}, // Leaf 2 (6 % 4 = 2)
|
69
|
-
{type: "typeA", id: 7, version: 1}, // Leaf 3 (7 % 4 = 3)
|
70
|
-
{type: "typeB", id: 11, version: 4},// Leaf 3 (11 % 4 = 3)
|
71
|
-
];
|
72
|
-
const tree = new HashTree(oids, 4);
|
73
|
-
|
74
|
-
// Corrected expected hashes based on the test failure output
|
75
|
-
expect(tree.getHashes()).to.deep.equal([
|
76
|
-
"c8415198d4abca6f885fe974e9b3729d", // Root
|
77
|
-
"457eeb22808eadfcff92ee47d67acbbf", // Internal node (L0, L1)
|
78
|
-
"5c9ba182a069c16a77a1928fce52dad8", // Internal node (L2, L3)
|
79
|
-
EMPTY_HASH, // Leaf 0 (empty)
|
80
|
-
"42df811f5a902c5b6bfcf50c7004e275", // Leaf 1 (item id 1)
|
81
|
-
"feb384d8ac6374ffdbee92a9f48f2b40", // Leaf 2 (item id 6)
|
82
|
-
"ebfa4f7e104e1e30fbb6b8857ccb685d" // Leaf 3 (items id 7, 11)
|
83
|
-
]);
|
84
|
-
expect(tree.getRootHash()).to.equal("c8415198d4abca6f885fe974e9b3729d");
|
85
|
-
});
|
86
|
-
|
87
|
-
it('should putItems and compute hashes correctly', () => {
|
88
|
-
const initialLeafData: LeafDataItem[] = [];
|
89
|
-
const numLeaves = 4;
|
90
|
-
const hashTree = new HashTree(initialLeafData, numLeaves);
|
91
|
-
|
92
|
-
const itemsToPut: LeafDataItem[] = [
|
93
|
-
{ type: 'participant', id: 1, version: 1 }, // bucket 1
|
94
|
-
{ type: 'participant', id: 2, version: 1 }, // bucket 2
|
95
|
-
];
|
96
|
-
const results = hashTree.putItems(itemsToPut);
|
97
|
-
|
98
|
-
expect(results).to.deep.equal([true, true]);
|
99
|
-
expect(hashTree.leaves[1]['participant'][1]).to.deep.equal({ type: 'participant', id: 1, version: 1 });
|
100
|
-
expect(hashTree.leaves[2]['participant'][2]).to.deep.equal({ type: 'participant', id: 2, version: 1 });
|
101
|
-
expect(hashTree.leafHashes[0]).to.equal(EMPTY_HASH);
|
102
|
-
expect(hashTree.leafHashes[1]).to.not.equal(EMPTY_HASH);
|
103
|
-
expect(hashTree.leafHashes[2]).to.not.equal(EMPTY_HASH);
|
104
|
-
expect(hashTree.leafHashes[3]).to.equal(EMPTY_HASH);
|
105
|
-
expect(hashTree.getTotalItemCount()).to.equal(2);
|
106
|
-
});
|
107
|
-
|
108
|
-
it('putItem should add a single item and update hash', () => {
|
109
|
-
const hashTree = new HashTree([], 2);
|
110
|
-
const item: LeafDataItem = {type: 'data', id: 3, version: 1}; // bucket 1
|
111
|
-
|
112
|
-
const result = hashTree.putItem(item);
|
113
|
-
expect(result).to.be.true;
|
114
|
-
expect(hashTree.leaves[1]['data'][3]).to.deep.equal(item);
|
115
|
-
expect(hashTree.leafHashes[1]).to.not.equal(EMPTY_HASH);
|
116
|
-
expect(hashTree.getTotalItemCount()).to.equal(1);
|
117
|
-
|
118
|
-
const itemSameVersion = {type: 'data', id: 3, version: 1};
|
119
|
-
const resultSame = hashTree.putItem(itemSameVersion);
|
120
|
-
expect(resultSame).to.be.false; // Not updated as version is not newer
|
121
|
-
|
122
|
-
const itemNewerVersion = {type: 'data', id: 3, version: 2};
|
123
|
-
const resultNewer = hashTree.putItem(itemNewerVersion);
|
124
|
-
expect(resultNewer).to.be.true;
|
125
|
-
expect(hashTree.leaves[1]['data'][3].version).to.equal(2);
|
126
|
-
});
|
127
|
-
|
128
|
-
it('putItem should return false for tree with 0 leaves', () => {
|
129
|
-
const hashTree = new HashTree([], 0);
|
130
|
-
const item: LeafDataItem = {type: 'data', id: 1, version: 1};
|
131
|
-
expect(hashTree.putItem(item)).to.be.false;
|
132
|
-
});
|
133
|
-
|
134
|
-
it('putItems should return array of false for tree with 0 leaves if items are provided', () => {
|
135
|
-
const hashTree = new HashTree([], 0);
|
136
|
-
const items: LeafDataItem[] = [{type: 'data', id: 1, version: 1}];
|
137
|
-
expect(hashTree.putItems(items)).to.deep.equal([false]);
|
138
|
-
});
|
139
|
-
|
140
|
-
|
141
|
-
it('should have correct root hash after putting one item', () => {
|
142
|
-
const leafData: LeafDataItem[] = [{type: 'participant', id: 1, version: 10}]; // bucket 1 (1 % 2 = 1)
|
143
|
-
const numLeaves = 2;
|
144
|
-
const hashTree = new HashTree(leafData, numLeaves);
|
145
|
-
|
146
|
-
expect(hashTree.leaves[1]['participant'][1]).to.deep.equal({
|
147
|
-
type: 'participant',
|
148
|
-
id: 1,
|
149
|
-
version: 10,
|
150
|
-
});
|
151
|
-
// This hash is from the original test.
|
152
|
-
expect(hashTree.getRootHash()).to.equal('e1cb70c75b488d87cbc8f74934a4290b');
|
153
|
-
});
|
154
|
-
|
155
|
-
it('removeItem should remove an item and update hash', () => {
|
156
|
-
const items: LeafDataItem[] = [{type: 'p', id: 1, version: 1}];
|
157
|
-
const hashTree = new HashTree(items, 2); // item in bucket 1
|
158
|
-
expect(hashTree.getTotalItemCount()).to.equal(1);
|
159
|
-
const oldRootHash = hashTree.getRootHash();
|
160
|
-
|
161
|
-
const result = hashTree.removeItem({type: 'p', id: 1, version: 1});
|
162
|
-
expect(result).to.be.true;
|
163
|
-
expect(hashTree.getTotalItemCount()).to.equal(0);
|
164
|
-
expect(hashTree.leaves[1]['p']).to.be.undefined;
|
165
|
-
expect(hashTree.leafHashes[1]).to.equal(EMPTY_HASH);
|
166
|
-
expect(hashTree.getRootHash()).to.not.equal(oldRootHash);
|
167
|
-
// After removing the only item, it should be like an empty tree with 2 leaves
|
168
|
-
const emptyTree = new HashTree([], 2);
|
169
|
-
expect(hashTree.getRootHash()).to.equal(emptyTree.getRootHash());
|
170
|
-
|
171
|
-
const resultNotFound = hashTree.removeItem({type: 'p', id: 1, version: 1});
|
172
|
-
expect(resultNotFound).to.be.false;
|
173
|
-
});
|
174
|
-
|
175
|
-
it('removeItem should only remove if version is <= existing (as per new logic)', () => {
|
176
|
-
const itemV1 = {type: 'test', id: 5, version: 1}; // bucket 1 (5%2=1)
|
177
|
-
const hashTree = new HashTree([itemV1], 2);
|
178
|
-
|
179
|
-
// Try to remove with older version - should fail if strict "version must be >=" is used for removal item
|
180
|
-
// The current removeItem logic: existingItem.version <= item.version for removal
|
181
|
-
let removed = hashTree.removeItem({type: 'test', id: 5, version: 0});
|
182
|
-
expect(removed).to.be.false;
|
183
|
-
|
184
|
-
removed = hashTree.removeItem({type: 'test', id: 5, version: 1}); // same version
|
185
|
-
expect(removed).to.be.true;
|
186
|
-
expect(hashTree.getTotalItemCount()).to.equal(0);
|
187
|
-
|
188
|
-
hashTree.putItem(itemV1); // re-add
|
189
|
-
expect(hashTree.getTotalItemCount()).to.equal(1);
|
190
|
-
removed = hashTree.removeItem({type: 'test', id: 5, version: 2}); // newer version in request
|
191
|
-
expect(removed).to.be.true;
|
192
|
-
expect(hashTree.getTotalItemCount()).to.equal(0);
|
193
|
-
});
|
194
|
-
|
195
|
-
it('removeItem should return false for tree with 0 leaves', () => {
|
196
|
-
const hashTree = new HashTree([], 0);
|
197
|
-
const item: LeafDataItem = {type: 'data', id: 1, version: 1};
|
198
|
-
expect(hashTree.removeItem(item)).to.be.false;
|
199
|
-
});
|
200
|
-
|
201
|
-
it('removeItems should process multiple items', () => {
|
202
|
-
const items: LeafDataItem[] = [
|
203
|
-
{type: 'a', id: 1, version: 2}, // bucket 1
|
204
|
-
{type: 'b', id: 2, version: 2} // bucket 0
|
205
|
-
];
|
206
|
-
const hashTree = new HashTree(items, 2);
|
207
|
-
expect(hashTree.getTotalItemCount()).to.equal(2);
|
208
|
-
|
209
|
-
const itemsToRemove: LeafDataItem[] = [
|
210
|
-
{type: 'a', id: 1, version: 3}, // remove with newer version (original logic)
|
211
|
-
{type: 'b', id: 2, version: 1}, // attempt remove with older version (should fail by original logic)
|
212
|
-
{type: 'c', id: 3, version: 1} // item not present
|
213
|
-
];
|
214
|
-
const results = hashTree.removeItems(itemsToRemove);
|
215
|
-
expect(results).to.deep.equal([true, false, false]);
|
216
|
-
expect(hashTree.getTotalItemCount()).to.equal(1); // item 'b' should remain
|
217
|
-
expect(hashTree.leaves[1]['a']).to.be.undefined;
|
218
|
-
expect(hashTree.leaves[0]['b'][2]).to.deep.equal({type: 'b', id: 2, version: 2});
|
219
|
-
});
|
220
|
-
|
221
|
-
it('removeItems should return array of false for tree with 0 leaves if items are provided', () => {
|
222
|
-
const hashTree = new HashTree([], 0);
|
223
|
-
const items: LeafDataItem[] = [{type: 'data', id: 1, version: 1}];
|
224
|
-
expect(hashTree.removeItems(items)).to.deep.equal([false]);
|
225
|
-
});
|
226
|
-
|
227
|
-
it('returns the correct root hash for an empty tree (0 leaves)', () => {
|
228
|
-
const hashTree = new HashTree([], 0);
|
229
|
-
expect(hashTree.getRootHash()).to.equal(EMPTY_HASH);
|
230
|
-
});
|
231
|
-
|
232
|
-
it('returns the correct root hash for an empty tree with 2 leaves', () => {
|
233
|
-
const hashTree = new HashTree([], 2);
|
234
|
-
// This hash is from the original test.
|
235
|
-
expect(hashTree.getRootHash()).to.equal('b113a76304e3a7121afecfe1606ee1c1');
|
236
|
-
});
|
237
|
-
|
238
|
-
it('returns the correct root hash for an empty tree with 4 leaves', () => {
|
239
|
-
const hashTree = new HashTree([], 4);
|
240
|
-
// This hash is from the original test.
|
241
|
-
expect(hashTree.getRootHash()).to.equal('b5df9b92242752424d87053a14e6222d');
|
242
|
-
});
|
243
|
-
|
244
|
-
describe('getLeafData', () => {
|
245
|
-
it('should return items from a specific leaf', () => {
|
246
|
-
const items: LeafDataItem[] = [
|
247
|
-
{type: 't1', id: 0, version: 1}, // leaf 0
|
248
|
-
{type: 't2', id: 1, version: 1}, // leaf 1
|
249
|
-
{type: 't1', id: 2, version: 1}, // leaf 0
|
250
|
-
];
|
251
|
-
const tree = new HashTree(items, 2);
|
252
|
-
const leaf0Data = tree.getLeafData(0);
|
253
|
-
expect(leaf0Data).to.have.deep.members([
|
254
|
-
{type: 't1', id: 0, version: 1},
|
255
|
-
{type: 't1', id: 2, version: 1}
|
256
|
-
]);
|
257
|
-
expect(leaf0Data.length).to.equal(2);
|
258
|
-
|
259
|
-
const leaf1Data = tree.getLeafData(1);
|
260
|
-
expect(leaf1Data).to.have.deep.members([{type: 't2', id: 1, version: 1}]);
|
261
|
-
expect(leaf1Data.length).to.equal(1);
|
262
|
-
});
|
263
|
-
|
264
|
-
it('should return empty array for invalid leaf index or empty leaf', () => {
|
265
|
-
const tree = new HashTree([{type: 't', id: 0, version: 1}], 2); // item in leaf 0
|
266
|
-
expect(tree.getLeafData(1)).to.deep.equal([]); // leaf 1 is empty
|
267
|
-
expect(tree.getLeafData(2)).to.deep.equal([]); // invalid index
|
268
|
-
expect(tree.getLeafData(-1)).to.deep.equal([]); // invalid index
|
269
|
-
});
|
270
|
-
|
271
|
-
it('should return empty array for tree with 0 leaves', () => {
|
272
|
-
const tree = new HashTree([], 0);
|
273
|
-
expect(tree.getLeafData(0)).to.deep.equal([]);
|
274
|
-
});
|
275
|
-
});
|
276
|
-
|
277
|
-
describe('resize', () => {
|
278
|
-
it('should resize the tree and redistribute items', () => {
|
279
|
-
const items: LeafDataItem[] = [
|
280
|
-
{type: 'a', id: 0, version: 1}, // old leaf 0 (0%2=0)
|
281
|
-
{type: 'b', id: 1, version: 1}, // old leaf 1 (1%2=1)
|
282
|
-
{type: 'c', id: 2, version: 1}, // old leaf 0 (2%2=0)
|
283
|
-
{type: 'd', id: 3, version: 1}, // old leaf 1 (3%2=1)
|
284
|
-
];
|
285
|
-
const tree = new HashTree(items, 2);
|
286
|
-
expect(tree.getLeafCount()).to.equal(2);
|
287
|
-
expect(tree.getTotalItemCount()).to.equal(4);
|
288
|
-
const originalRootHash = tree.getRootHash();
|
289
|
-
|
290
|
-
const resized = tree.resize(4);
|
291
|
-
expect(resized).to.be.true;
|
292
|
-
expect(tree.getLeafCount()).to.equal(4);
|
293
|
-
expect(tree.getTotalItemCount()).to.equal(4); // count should remain same
|
294
|
-
|
295
|
-
// Check redistribution
|
296
|
-
// id:0 -> 0%4 = 0
|
297
|
-
// id:1 -> 1%4 = 1
|
298
|
-
// id:2 -> 2%4 = 2
|
299
|
-
// id:3 -> 3%4 = 3
|
300
|
-
expect(tree.getLeafData(0)).to.deep.include({type: 'a', id: 0, version: 1});
|
301
|
-
expect(tree.getLeafData(1)).to.deep.include({type: 'b', id: 1, version: 1});
|
302
|
-
expect(tree.getLeafData(2)).to.deep.include({type: 'c', id: 2, version: 1});
|
303
|
-
expect(tree.getLeafData(3)).to.deep.include({type: 'd', id: 3, version: 1});
|
304
|
-
expect(tree.getRootHash()).to.not.equal(originalRootHash); // Hash should change
|
305
|
-
});
|
306
|
-
|
307
|
-
it('should return false if size does not change', () => {
|
308
|
-
const tree = new HashTree([], 4);
|
309
|
-
expect(tree.resize(4)).to.be.false;
|
310
|
-
});
|
311
|
-
|
312
|
-
it('should throw error for invalid new number of leaves', () => {
|
313
|
-
const tree = new HashTree([], 4);
|
314
|
-
expect(() => tree.resize(3)).to.throw('New number of leaves must be 0 or a power of 2');
|
315
|
-
});
|
316
|
-
|
317
|
-
it('should handle resize to 0 leaves', () => {
|
318
|
-
const items: LeafDataItem[] = [{type: 'a', id: 0, version: 1}];
|
319
|
-
const tree = new HashTree(items, 2);
|
320
|
-
expect(tree.getTotalItemCount()).to.equal(1);
|
321
|
-
tree.resize(0);
|
322
|
-
expect(tree.getLeafCount()).to.equal(0);
|
323
|
-
expect(tree.getTotalItemCount()).to.equal(0);
|
324
|
-
expect(tree.getRootHash()).to.equal(EMPTY_HASH);
|
325
|
-
expect(tree.leaves.length).to.equal(0);
|
326
|
-
expect(tree.leafHashes.length).to.equal(0);
|
327
|
-
});
|
328
|
-
|
329
|
-
it('should handle resize from 0 leaves', () => {
|
330
|
-
const tree = new HashTree([], 0);
|
331
|
-
tree.resize(2);
|
332
|
-
expect(tree.getLeafCount()).to.equal(2);
|
333
|
-
expect(tree.getTotalItemCount()).to.equal(0);
|
334
|
-
const emptyTree = new HashTree([], 2);
|
335
|
-
expect(tree.getRootHash()).to.equal(emptyTree.getRootHash());
|
336
|
-
});
|
337
|
-
});
|
338
|
-
|
339
|
-
describe('diffHashes', () => {
|
340
|
-
it('should return empty array if hashes are identical', () => {
|
341
|
-
const items: LeafDataItem[] = [{type: 'x', id: 1, version: 1}];
|
342
|
-
const tree1 = new HashTree(items, 2);
|
343
|
-
const tree2 = new HashTree(items, 2);
|
344
|
-
expect(tree1.diffHashes(tree2.getHashes())).to.deep.equal([]);
|
345
|
-
});
|
346
|
-
|
347
|
-
it('should return differing leaf indices', () => {
|
348
|
-
const tree1 = new HashTree([{type: 'x', id: 0, version: 1}], 4); // item in leaf 0
|
349
|
-
const tree2 = new HashTree([{type: 'y', id: 1, version: 1}], 4); // item in leaf 1
|
350
|
-
// tree1: leaf 0 has item, leaves 1,2,3 empty
|
351
|
-
// tree2: leaf 1 has item, leaves 0,2,3 empty
|
352
|
-
// Expected diffs: leaf 0 (present in 1, not in 2), leaf 1 (present in 2, not in 1)
|
353
|
-
const diff = tree1.diffHashes(tree2.getHashes());
|
354
|
-
expect(diff).to.include.members([0, 1]);
|
355
|
-
// If one leaf's hash is EMPTY_HASH and the other's is a computed hash, they are different.
|
356
|
-
});
|
357
|
-
|
358
|
-
it('should return all leaf indices if externalHashes is for a different structure (e.g. too short)', () => {
|
359
|
-
const tree = new HashTree([{type: 'x', id: 0, version: 1}], 4);
|
360
|
-
const externalHashesShort = [EMPTY_HASH, EMPTY_HASH]; // Too short for 4 leaves + internal nodes
|
361
|
-
expect(tree.diffHashes(externalHashesShort)).to.deep.equal([0,1,2,3]);
|
362
|
-
});
|
363
|
-
|
364
|
-
it('should handle diff for 0-leaf trees', () => {
|
365
|
-
const tree0 = new HashTree([], 0);
|
366
|
-
expect(tree0.diffHashes([EMPTY_HASH])).to.deep.equal([]);
|
367
|
-
expect(tree0.diffHashes(["some_other_hash"])).to.deep.equal([]); // No leaves to differ
|
368
|
-
const tree2 = new HashTree([],2);
|
369
|
-
// Comparing a 0-leaf tree with a 2-leaf tree's hashes
|
370
|
-
expect(tree0.diffHashes(tree2.getHashes())).to.deep.equal([]);
|
371
|
-
});
|
372
|
-
|
373
|
-
it('should correctly identify differences when one leaf changes', () => {
|
374
|
-
const initialItems: LeafDataItem[] = [
|
375
|
-
{ type: 'a', id: 0, version: 1 }, // leaf 0
|
376
|
-
{ type: 'b', id: 1, version: 1 } // leaf 1
|
377
|
-
];
|
378
|
-
const tree1 = new HashTree(initialItems, 2);
|
379
|
-
const tree1Hashes = tree1.getHashes();
|
380
|
-
|
381
|
-
const modifiedItems: LeafDataItem[] = [
|
382
|
-
{ type: 'a', id: 0, version: 1 }, // leaf 0 (same)
|
383
|
-
{ type: 'b', id: 1, version: 2 } // leaf 1 (changed version)
|
384
|
-
];
|
385
|
-
const tree2 = new HashTree(modifiedItems, 2);
|
386
|
-
|
387
|
-
const diff1_2 = tree1.diffHashes(tree2.getHashes());
|
388
|
-
expect(diff1_2).to.deep.equal([1]); // Leaf 1 should differ
|
389
|
-
|
390
|
-
const diff2_1 = tree2.diffHashes(tree1Hashes);
|
391
|
-
expect(diff2_1).to.deep.equal([1]);
|
392
|
-
});
|
393
|
-
});
|
394
|
-
});
|
@@ -1,156 +0,0 @@
|
|
1
|
-
import HashTreeParser from '@webex/plugin-meetings/src/hashTree/hashTreeParser';
|
2
|
-
import HashTree from '@webex/plugin-meetings/src/hashTree/hashTree';
|
3
|
-
import { expect } from "@webex/test-helper-chai";
|
4
|
-
|
5
|
-
const exampleInitialLocus = {
|
6
|
-
dataSets: [
|
7
|
-
{
|
8
|
-
url: 'https://locus-a.wbx2.com/locus/api/v1/loci/97d64a5f/datasets/main',
|
9
|
-
root: '9bb9d5a911a74d53a915b4dfbec7329f',
|
10
|
-
version: 51118,
|
11
|
-
leafCount: 16,
|
12
|
-
name: 'main',
|
13
|
-
idleMs: 1000,
|
14
|
-
backoff: {maxMs: 1000, exponent: 2}
|
15
|
-
},
|
16
|
-
{
|
17
|
-
url: 'https://locus-a.wbx2.com/locus/api/v1/loci/97d64a5f/participant/713e9f99/datasets/self',
|
18
|
-
root: '5b8cc7ffda1346d2bfb1c0b60b8ab601',
|
19
|
-
version: 89891,
|
20
|
-
leafCount: 1,
|
21
|
-
name: 'self',
|
22
|
-
idleMs: 1000,
|
23
|
-
backoff: {maxMs: 1000, exponent: 2}
|
24
|
-
},
|
25
|
-
{
|
26
|
-
url: 'https://locus-a.wbx2.com/locus/api/v1/loci/97d64a5f/datasets/atd-unmuted',
|
27
|
-
root: '9279d2e149da43a1b8e2cd7cbf77f9f0',
|
28
|
-
version: 91277,
|
29
|
-
leafCount: 16,
|
30
|
-
name: 'atd-unmuted',
|
31
|
-
idleMs: 1000,
|
32
|
-
backoff: {maxMs: 1000, exponent: 2}
|
33
|
-
},
|
34
|
-
],
|
35
|
-
locus: {
|
36
|
-
url: 'https://locus-a.wbx2.com/locus/api/v1/loci/97d64a5f',
|
37
|
-
htMeta: {
|
38
|
-
elementId: {
|
39
|
-
type: 'LOCUS',
|
40
|
-
id: 0,
|
41
|
-
version: 5678,
|
42
|
-
},
|
43
|
-
dataSetNames: ['main'],
|
44
|
-
},
|
45
|
-
participants: [
|
46
|
-
{
|
47
|
-
url: 'https://locus-a.wbx2.com/locus/api/v1/loci/97d64a5f/participant/11941033',
|
48
|
-
person: {},
|
49
|
-
htMeta: {
|
50
|
-
elementId: {
|
51
|
-
type: 'PARTICIPANT',
|
52
|
-
id: 14,
|
53
|
-
version: 5678,
|
54
|
-
},
|
55
|
-
dataSetNames: ['atd-active', 'attendees', 'atd-unmuted'],
|
56
|
-
},
|
57
|
-
},
|
58
|
-
],
|
59
|
-
self: {
|
60
|
-
url: 'https://locus-a.wbx2.com/locus/api/v1/loci/97d64a5f/participant/11941033',
|
61
|
-
visibleDataSets: ['main', 'self', 'atd-unmuted'],
|
62
|
-
person: {},
|
63
|
-
htMeta: {
|
64
|
-
elementId: {
|
65
|
-
type: 'SELF',
|
66
|
-
id: 4,
|
67
|
-
version: 5678,
|
68
|
-
},
|
69
|
-
dataSetNames: ['self'],
|
70
|
-
},
|
71
|
-
},
|
72
|
-
},
|
73
|
-
};
|
74
|
-
|
75
|
-
describe('HashTreeParser', () => {
|
76
|
-
it('should correctly initialize trees from initialLocus data', () => {
|
77
|
-
const parser = new HashTreeParser({initialLocus: exampleInitialLocus, webexRequest: () => Promise.resolve(), locusInfoUpdateCallback : () => {}});
|
78
|
-
|
79
|
-
// Check that the correct number of trees are created
|
80
|
-
expect(Object.keys(parser.dataSets).length).to.equal(3);
|
81
|
-
|
82
|
-
// Verify the 'main' tree
|
83
|
-
const mainTree = parser.dataSets.main.hashTree;
|
84
|
-
expect(mainTree).to.be.instanceOf(HashTree);
|
85
|
-
const expectedMainLeaves = new Array(16).fill(null).map(() => ({}));
|
86
|
-
expectedMainLeaves[0 % 16] = { LOCUS: { 0: { type: 'LOCUS', id: 0, version: 5678 } } };
|
87
|
-
expect(mainTree.leaves).to.deep.equal(expectedMainLeaves);
|
88
|
-
expect(mainTree.numLeaves).to.equal(16);
|
89
|
-
|
90
|
-
// Verify the 'self' tree
|
91
|
-
const selfTree = parser.dataSets.self.hashTree;
|
92
|
-
expect(selfTree).to.be.instanceOf(HashTree);
|
93
|
-
const expectedSelfLeaves = new Array(1).fill(null).map(() => ({}));
|
94
|
-
expectedSelfLeaves[4 % 1] = { SELF: { 4: { type: 'SELF', id: 4, version: 5678 } } };
|
95
|
-
expect(selfTree.leaves).to.deep.equal(expectedSelfLeaves);
|
96
|
-
expect(selfTree.numLeaves).to.equal(1);
|
97
|
-
|
98
|
-
// Verify the 'atd-unmuted' tree
|
99
|
-
const atdUnmutedTree = parser.dataSets['atd-unmuted'].hashTree;
|
100
|
-
expect(atdUnmutedTree).to.be.instanceOf(HashTree);
|
101
|
-
const expectedAtdUnmutedLeaves = new Array(16).fill(null).map(() => ({}));
|
102
|
-
expectedAtdUnmutedLeaves[14 % 16] = { PARTICIPANT: { 14: { type: 'PARTICIPANT', id: 14, version: 5678 } } };
|
103
|
-
expect(atdUnmutedTree.leaves).to.deep.equal(expectedAtdUnmutedLeaves);
|
104
|
-
expect(atdUnmutedTree.numLeaves).to.equal(16);
|
105
|
-
|
106
|
-
// Ensure no other trees were created
|
107
|
-
expect(parser.dataSets['atd-active']).to.be.undefined;
|
108
|
-
expect(parser.dataSets.attendees).to.be.undefined;
|
109
|
-
});
|
110
|
-
|
111
|
-
it('should handle datasets with no corresponding metadata found', () => {
|
112
|
-
const modifiedLocus = JSON.parse(JSON.stringify(exampleInitialLocus));
|
113
|
-
// Remove a participant meta to simulate missing data for 'atd-unmuted'
|
114
|
-
modifiedLocus.locus.participants = [];
|
115
|
-
// Add a new dataset that won't have corresponding metadata
|
116
|
-
modifiedLocus.dataSets.push({
|
117
|
-
url: 'https://locus-a.wbx2.com/locus/api/v1/loci/97d64a5f/datasets/empty-set',
|
118
|
-
root: 'f00f00f00f00f00f00f00f00f00f00f0',
|
119
|
-
version: 1,
|
120
|
-
leafCount: 4,
|
121
|
-
name: 'empty-set',
|
122
|
-
});
|
123
|
-
|
124
|
-
|
125
|
-
const parser = new HashTreeParser({initialLocus: modifiedLocus, webexRequest: () => Promise.resolve(), locusInfoUpdateCallback : () => {}});
|
126
|
-
|
127
|
-
expect(Object.keys(parser.dataSets).length).to.equal(4); // main, self, atd-unmuted (now empty), empty-set
|
128
|
-
|
129
|
-
// 'main' and 'self' should be populated as before
|
130
|
-
const mainTree = parser.dataSets.main.hashTree;
|
131
|
-
const expectedMainLeaves = new Array(16).fill(null).map(() => ({}));
|
132
|
-
expectedMainLeaves[0 % 16] = { LOCUS: { 0: { type: 'LOCUS', id: 0, version: 5678 } } };
|
133
|
-
expect(mainTree.leaves).to.deep.equal(expectedMainLeaves);
|
134
|
-
expect(mainTree.numLeaves).to.equal(16);
|
135
|
-
|
136
|
-
const selfTree = parser.dataSets.self.hashTree;
|
137
|
-
const expectedSelfLeaves = new Array(1).fill(null).map(() => ({}));
|
138
|
-
expectedSelfLeaves[4 % 1] = { SELF: { 4: { type: 'SELF', id: 4, version: 5678 } } };
|
139
|
-
expect(selfTree.leaves).to.deep.equal(expectedSelfLeaves);
|
140
|
-
expect(selfTree.numLeaves).to.equal(1);
|
141
|
-
|
142
|
-
// 'atd-unmuted' metadata was removed from locus, so leaves should be empty
|
143
|
-
const atdUnmutedTree = parser.dataSets['atd-unmuted'].hashTree;
|
144
|
-
expect(atdUnmutedTree).to.be.instanceOf(HashTree);
|
145
|
-
const expectedAtdUnmutedEmptyLeaves = new Array(16).fill(null).map(() => ({}));
|
146
|
-
expect(atdUnmutedTree.leaves).to.deep.equal(expectedAtdUnmutedEmptyLeaves);
|
147
|
-
expect(atdUnmutedTree.numLeaves).to.equal(16); // leafCount from dataSet definition
|
148
|
-
|
149
|
-
// 'empty-set' was added to dataSets but has no metadata in locus
|
150
|
-
const emptySetTree = parser.dataSets['empty-set'].hashTree;
|
151
|
-
expect(emptySetTree).to.be.instanceOf(HashTree);
|
152
|
-
const expectedEmptySetLeaves = new Array(4).fill(null).map(() => ({})); // leafCount is 4
|
153
|
-
expect(emptySetTree.leaves).to.deep.equal(expectedEmptySetLeaves);
|
154
|
-
expect(emptySetTree.numLeaves).to.equal(4);
|
155
|
-
});
|
156
|
-
});
|