@helia/interop 7.1.3 → 8.0.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.
@@ -1,9 +1,14 @@
1
1
  /* eslint-env mocha */
2
2
  import { unixfs } from '@helia/unixfs';
3
+ import * as dagPb from '@ipld/dag-pb';
4
+ import { multiaddr } from '@multiformats/multiaddr';
3
5
  import { expect } from 'aegir/chai';
4
6
  import { fixedSize } from 'ipfs-unixfs-importer/chunker';
5
7
  import { balanced } from 'ipfs-unixfs-importer/layout';
8
+ import drain from 'it-drain';
9
+ import last from 'it-last';
6
10
  import { CID } from 'multiformats/cid';
11
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
7
12
  import { createHeliaNode } from './fixtures/create-helia.js';
8
13
  import { createKuboNode } from './fixtures/create-kubo.js';
9
14
  describe('@helia/unixfs - files', () => {
@@ -14,10 +19,24 @@ describe('@helia/unixfs - files', () => {
14
19
  const cid = await unixFs.addByteStream(data, opts);
15
20
  return cid;
16
21
  }
22
+ async function importDirectoryToHelia(data, opts) {
23
+ const result = await last(unixFs.addAll(data, opts));
24
+ if (result == null) {
25
+ throw new Error('Nothing imported');
26
+ }
27
+ return CID.parse(result.cid.toString());
28
+ }
17
29
  async function importToKubo(data, opts) {
18
30
  const result = await kubo.api.add(data, opts);
19
31
  return CID.parse(result.cid.toString());
20
32
  }
33
+ async function importDirectoryToKubo(data, opts) {
34
+ const result = await last(kubo.api.addAll(data, opts));
35
+ if (result == null) {
36
+ throw new Error('Nothing imported');
37
+ }
38
+ return CID.parse(result.cid.toString());
39
+ }
21
40
  async function expectSameCid(data, heliaOpts = {}, kuboOpts = {}) {
22
41
  const heliaCid = await importToHelia(data(), {
23
42
  // these are the default kubo options
@@ -63,5 +82,83 @@ describe('@helia/unixfs - files', () => {
63
82
  }());
64
83
  await expectSameCid(candidate);
65
84
  });
85
+ it('should return the same directory stats', async () => {
86
+ const candidates = [{
87
+ path: '/foo1.txt',
88
+ content: uint8ArrayFromString('Hello World!')
89
+ }, {
90
+ path: '/foo2.txt',
91
+ content: uint8ArrayFromString('Hello World!')
92
+ }];
93
+ const heliaCid = await importDirectoryToHelia(candidates, {
94
+ wrapWithDirectory: true
95
+ });
96
+ const kuboCid = await importDirectoryToKubo(candidates, {
97
+ cidVersion: 1,
98
+ chunker: `size-${1024 * 1024}`,
99
+ rawLeaves: true,
100
+ wrapWithDirectory: true
101
+ });
102
+ expect(heliaCid.toString()).to.equal(kuboCid.toString());
103
+ const heliaStat = await unixFs.stat(heliaCid, {
104
+ extended: true
105
+ });
106
+ const kuboStat = await kubo.api.files.stat(`/ipfs/${kuboCid}`, {
107
+ withLocal: true
108
+ });
109
+ expect(heliaStat.dagSize.toString()).to.equal(kuboStat.cumulativeSize.toString());
110
+ expect(heliaStat.dagSize.toString()).to.equal(kuboStat.sizeLocal?.toString());
111
+ // +1 because kubo doesn't count the root directory block
112
+ expect(heliaStat.blocks.toString()).to.equal((kuboStat.blocks + 1).toString());
113
+ });
114
+ it('fetches missing blocks during stat', async () => {
115
+ const chunkSize = 1024 * 1024;
116
+ const size = chunkSize * 10;
117
+ const candidate = () => (async function* () {
118
+ for (let i = 0; i < size; i += chunkSize) {
119
+ yield new Uint8Array(new Array(chunkSize).fill(0).map((val, index) => {
120
+ return Math.floor(Math.random() * 256);
121
+ }));
122
+ }
123
+ }());
124
+ const largeFileCid = await importToKubo(candidate());
125
+ const info = await kubo.info();
126
+ await helia.libp2p.dial(info.multiaddrs.map(ma => multiaddr(ma)));
127
+ // pull all blocks from kubo
128
+ await drain(unixFs.cat(largeFileCid));
129
+ // check the root block
130
+ const block = await helia.blockstore.get(largeFileCid);
131
+ const node = dagPb.decode(block);
132
+ expect(node.Links).to.have.lengthOf(40);
133
+ const stats = await unixFs.stat(largeFileCid, {
134
+ extended: true
135
+ });
136
+ expect(stats.unixfs?.fileSize()).to.equal(10485760n);
137
+ expect(stats.blocks).to.equal(41n);
138
+ expect(stats.dagSize).to.equal(10488250n);
139
+ expect(stats.localSize).to.equal(10485760n);
140
+ // remove one of the blocks so we now have an incomplete DAG
141
+ await helia.blockstore.delete(node.Links[0].Hash);
142
+ // block count and local file/dag sizes should be smaller
143
+ const updatedStats = await unixFs.stat(largeFileCid, {
144
+ extended: true,
145
+ offline: true
146
+ });
147
+ expect(updatedStats.unixfs?.fileSize()).to.equal(10485760n);
148
+ expect(updatedStats.blocks).to.equal(40n);
149
+ expect(updatedStats.dagSize).to.equal(10226092n);
150
+ expect(updatedStats.localSize).to.equal(10223616n);
151
+ await new Promise((resolve) => {
152
+ setTimeout(() => {
153
+ resolve();
154
+ }, 1_000);
155
+ });
156
+ // block count and local file/dag sizes should be smaller
157
+ const finalStats = await unixFs.stat(largeFileCid, {
158
+ extended: true
159
+ });
160
+ // should have fetched missing block from Kubo
161
+ expect(finalStats).to.deep.equal(stats, 'did not fetch missing block');
162
+ });
66
163
  });
67
164
  //# sourceMappingURL=unixfs-files.spec.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"unixfs-files.spec.js","sourceRoot":"","sources":["../../src/unixfs-files.spec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"unixfs-files.spec.js","sourceRoot":"","sources":["../../src/unixfs-files.spec.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helia/interop",
3
- "version": "7.1.3",
3
+ "version": "8.0.0",
4
4
  "description": "Interop tests for Helia",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "homepage": "https://github.com/ipfs/helia/tree/main/packages/interop#readme",
@@ -60,25 +60,27 @@
60
60
  "dependencies": {
61
61
  "@chainsafe/libp2p-gossipsub": "^14.1.0",
62
62
  "@helia/block-brokers": "^4.1.0",
63
- "@helia/car": "^4.0.3",
63
+ "@helia/car": "^4.0.4",
64
64
  "@helia/dag-cbor": "^4.0.3",
65
65
  "@helia/dag-json": "^4.0.3",
66
66
  "@helia/http": "^2.0.5",
67
67
  "@helia/interface": "^5.2.1",
68
68
  "@helia/ipns": "^8.2.0",
69
69
  "@helia/json": "^4.0.3",
70
- "@helia/mfs": "^4.0.3",
70
+ "@helia/mfs": "^5.0.0",
71
71
  "@helia/routers": "^3.0.1",
72
72
  "@helia/strings": "^4.0.3",
73
- "@helia/unixfs": "^4.0.3",
73
+ "@helia/unixfs": "^5.0.0",
74
74
  "@ipld/car": "^5.3.3",
75
75
  "@ipld/dag-cbor": "^9.2.2",
76
+ "@ipld/dag-pb": "^4.1.3",
76
77
  "@libp2p/crypto": "^5.0.7",
77
78
  "@libp2p/interface": "^2.2.1",
78
79
  "@libp2p/kad-dht": "^14.1.3",
79
80
  "@libp2p/keychain": "^5.0.10",
80
81
  "@libp2p/peer-id": "^5.0.8",
81
82
  "@libp2p/websockets": "^9.0.13",
83
+ "@multiformats/multiaddr": "^12.4.0",
82
84
  "@multiformats/sha3": "^3.0.2",
83
85
  "aegir": "^45.1.1",
84
86
  "helia": "^5.3.0",
@@ -1,15 +1,20 @@
1
1
  /* eslint-env mocha */
2
2
 
3
3
  import { unixfs } from '@helia/unixfs'
4
+ import * as dagPb from '@ipld/dag-pb'
5
+ import { multiaddr } from '@multiformats/multiaddr'
4
6
  import { expect } from 'aegir/chai'
5
7
  import { fixedSize } from 'ipfs-unixfs-importer/chunker'
6
8
  import { balanced } from 'ipfs-unixfs-importer/layout'
9
+ import drain from 'it-drain'
10
+ import last from 'it-last'
7
11
  import { CID } from 'multiformats/cid'
12
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
8
13
  import { createHeliaNode } from './fixtures/create-helia.js'
9
14
  import { createKuboNode } from './fixtures/create-kubo.js'
10
15
  import type { AddOptions, UnixFS } from '@helia/unixfs'
11
16
  import type { HeliaLibp2p } from 'helia'
12
- import type { ByteStream } from 'ipfs-unixfs-importer'
17
+ import type { ByteStream, ImportCandidateStream } from 'ipfs-unixfs-importer'
13
18
  import type { KuboNode } from 'ipfsd-ctl'
14
19
  import type { AddOptions as KuboAddOptions } from 'kubo-rpc-client'
15
20
 
@@ -24,12 +29,32 @@ describe('@helia/unixfs - files', () => {
24
29
  return cid
25
30
  }
26
31
 
32
+ async function importDirectoryToHelia (data: ImportCandidateStream, opts?: Partial<AddOptions>): Promise<CID> {
33
+ const result = await last(unixFs.addAll(data, opts))
34
+
35
+ if (result == null) {
36
+ throw new Error('Nothing imported')
37
+ }
38
+
39
+ return CID.parse(result.cid.toString())
40
+ }
41
+
27
42
  async function importToKubo (data: ByteStream, opts?: KuboAddOptions): Promise<CID> {
28
43
  const result = await kubo.api.add(data, opts)
29
44
 
30
45
  return CID.parse(result.cid.toString())
31
46
  }
32
47
 
48
+ async function importDirectoryToKubo (data: ImportCandidateStream, opts?: KuboAddOptions): Promise<CID> {
49
+ const result = await last(kubo.api.addAll(data, opts))
50
+
51
+ if (result == null) {
52
+ throw new Error('Nothing imported')
53
+ }
54
+
55
+ return CID.parse(result.cid.toString())
56
+ }
57
+
33
58
  async function expectSameCid (data: () => ByteStream, heliaOpts: Partial<AddOptions> = {}, kuboOpts: KuboAddOptions = {}): Promise<void> {
34
59
  const heliaCid = await importToHelia(data(), {
35
60
  // these are the default kubo options
@@ -85,4 +110,103 @@ describe('@helia/unixfs - files', () => {
85
110
 
86
111
  await expectSameCid(candidate)
87
112
  })
113
+
114
+ it('should return the same directory stats', async () => {
115
+ const candidates = [{
116
+ path: '/foo1.txt',
117
+ content: uint8ArrayFromString('Hello World!')
118
+ }, {
119
+ path: '/foo2.txt',
120
+ content: uint8ArrayFromString('Hello World!')
121
+ }]
122
+
123
+ const heliaCid = await importDirectoryToHelia(candidates, {
124
+ wrapWithDirectory: true
125
+ })
126
+ const kuboCid = await importDirectoryToKubo(candidates, {
127
+ cidVersion: 1,
128
+ chunker: `size-${1024 * 1024}`,
129
+ rawLeaves: true,
130
+ wrapWithDirectory: true
131
+ })
132
+
133
+ expect(heliaCid.toString()).to.equal(kuboCid.toString())
134
+
135
+ const heliaStat = await unixFs.stat(heliaCid, {
136
+ extended: true
137
+ })
138
+ const kuboStat = await kubo.api.files.stat(`/ipfs/${kuboCid}`, {
139
+ withLocal: true
140
+ })
141
+
142
+ expect(heliaStat.dagSize.toString()).to.equal(kuboStat.cumulativeSize.toString())
143
+ expect(heliaStat.dagSize.toString()).to.equal(kuboStat.sizeLocal?.toString())
144
+
145
+ // +1 because kubo doesn't count the root directory block
146
+ expect(heliaStat.blocks.toString()).to.equal((kuboStat.blocks + 1).toString())
147
+ })
148
+
149
+ it('fetches missing blocks during stat', async () => {
150
+ const chunkSize = 1024 * 1024
151
+ const size = chunkSize * 10
152
+
153
+ const candidate = (): ByteStream => (async function * () {
154
+ for (let i = 0; i < size; i += chunkSize) {
155
+ yield new Uint8Array(new Array(chunkSize).fill(0).map((val, index) => {
156
+ return Math.floor(Math.random() * 256)
157
+ }))
158
+ }
159
+ }())
160
+
161
+ const largeFileCid = await importToKubo(candidate())
162
+ const info = await kubo.info()
163
+
164
+ await helia.libp2p.dial(info.multiaddrs.map(ma => multiaddr(ma)))
165
+
166
+ // pull all blocks from kubo
167
+ await drain(unixFs.cat(largeFileCid))
168
+
169
+ // check the root block
170
+ const block = await helia.blockstore.get(largeFileCid)
171
+ const node = dagPb.decode(block)
172
+
173
+ expect(node.Links).to.have.lengthOf(40)
174
+
175
+ const stats = await unixFs.stat(largeFileCid, {
176
+ extended: true
177
+ })
178
+
179
+ expect(stats.unixfs?.fileSize()).to.equal(10485760n)
180
+ expect(stats.blocks).to.equal(41n)
181
+ expect(stats.dagSize).to.equal(10488250n)
182
+ expect(stats.localSize).to.equal(10485760n)
183
+
184
+ // remove one of the blocks so we now have an incomplete DAG
185
+ await helia.blockstore.delete(node.Links[0].Hash)
186
+
187
+ // block count and local file/dag sizes should be smaller
188
+ const updatedStats = await unixFs.stat(largeFileCid, {
189
+ extended: true,
190
+ offline: true
191
+ })
192
+
193
+ expect(updatedStats.unixfs?.fileSize()).to.equal(10485760n)
194
+ expect(updatedStats.blocks).to.equal(40n)
195
+ expect(updatedStats.dagSize).to.equal(10226092n)
196
+ expect(updatedStats.localSize).to.equal(10223616n)
197
+
198
+ await new Promise<void>((resolve) => {
199
+ setTimeout(() => {
200
+ resolve()
201
+ }, 1_000)
202
+ })
203
+
204
+ // block count and local file/dag sizes should be smaller
205
+ const finalStats = await unixFs.stat(largeFileCid, {
206
+ extended: true
207
+ })
208
+
209
+ // should have fetched missing block from Kubo
210
+ expect(finalStats).to.deep.equal(stats, 'did not fetch missing block')
211
+ })
88
212
  })