|
1 |
| -import tape from 'tape'; |
2 |
| -import * as semver from 'semver'; |
3 | 1 | import * as tmp from 'tmp';
|
4 |
| -import wrapper from '../wrapper'; |
| 2 | +import tape from 'tape'; |
| 3 | +import nock from 'nock'; |
| 4 | +import fs from 'fs'; |
| 5 | +import path from 'path'; |
| 6 | +import { keccak256 } from 'js-sha3'; |
| 7 | +import { https } from 'follow-redirects'; |
5 | 8 | import downloader from '../downloader';
|
6 | 9 |
|
7 |
| -const pkg = require('../package.json'); |
| 10 | +const assets = path.resolve(__dirname, 'resources/assets'); |
| 11 | + |
| 12 | +tape.onFinish(() => { |
| 13 | + if (!nock.isDone()) { |
| 14 | + throw Error('expected requests were not performed'); |
| 15 | + } |
| 16 | +}); |
| 17 | + |
| 18 | +function hash (filePath: string): string { |
| 19 | + return '0x' + keccak256(fs.readFileSync(filePath, { encoding: 'binary' })); |
| 20 | +} |
| 21 | + |
| 22 | +function generateTestFile (t: tape.Test, content: string): tmp.FileResult { |
| 23 | + // As the `keep` option is set to true the removeCallback must be called by the caller |
| 24 | + // to cleanup the files after the test. |
| 25 | + const file = tmp.fileSync({ template: 'soljson-XXXXXX.js', keep: true }); |
| 26 | + try { |
| 27 | + fs.writeFileSync(file.name, content); |
| 28 | + } catch (err) { |
| 29 | + t.fail('error writing test file'); |
| 30 | + } |
| 31 | + |
| 32 | + return file; |
| 33 | +} |
| 34 | + |
| 35 | +function versionListMock (url: string): nock.Interceptor { |
| 36 | + return nock(url).get('/bin/list.json'); |
| 37 | +} |
| 38 | + |
| 39 | +function downloadBinaryMock (url: string, filename: string): nock.Interceptor { |
| 40 | + return nock(url).get(`/bin/${path.basename(filename)}`); |
| 41 | +} |
| 42 | + |
| 43 | +function defaultListener (req, res) { |
| 44 | + res.writeHead(200); |
| 45 | + res.end('OK'); |
| 46 | +}; |
| 47 | + |
| 48 | +async function startMockServer (listener = defaultListener) { |
| 49 | + const server = https.createServer({ |
| 50 | + key: fs.readFileSync(path.resolve(assets, 'key.pem')), |
| 51 | + cert: fs.readFileSync(path.resolve(assets, 'cert.pem')) |
| 52 | + }, listener); |
| 53 | + |
| 54 | + await new Promise(resolve => server.listen(resolve)); |
| 55 | + server.port = server.address().port; |
| 56 | + server.origin = `https://localhost:${server.port}`; |
| 57 | + return server; |
| 58 | +} |
| 59 | + |
| 60 | +tape('Download version list', async function (t) { |
| 61 | + const server = await startMockServer(); |
| 62 | + |
| 63 | + t.teardown(function () { |
| 64 | + server.close(); |
| 65 | + nock.cleanAll(); |
| 66 | + }); |
| 67 | + |
| 68 | + t.test('successfully get version list', async function (st) { |
| 69 | + const dummyListPath = path.resolve(assets, 'dummy-list.json'); |
| 70 | + versionListMock(server.origin).replyWithFile(200, dummyListPath, { |
| 71 | + 'Content-Type': 'application/json' |
| 72 | + }); |
8 | 73 |
|
9 |
| -tape('Download latest binary', function (t) { |
10 |
| - t.test('checking whether the current version is the latest available for download', async function (st) { |
11 | 74 | try {
|
12 |
| - const list = JSON.parse(await downloader.getVersionList()); |
13 |
| - const wanted = pkg.version.match(/^(\d+\.\d+\.\d+)$/)[1]; |
14 |
| - if (semver.neq(wanted, list.latestRelease)) { |
15 |
| - st.fail(`Version ${wanted} is not the latest release ${list.latestRelease}`); |
16 |
| - } |
| 75 | + const list = JSON.parse( |
| 76 | + await downloader.getVersionList(`${server.origin}/bin/list.json`) |
| 77 | + ); |
| 78 | + const expected = require(dummyListPath); |
| 79 | + st.deepEqual(list, expected, 'list should match'); |
| 80 | + st.equal(list.latestRelease, expected.latestRelease, 'latest release should be equal'); |
| 81 | + } catch (err) { |
| 82 | + st.fail(err.message); |
| 83 | + } |
| 84 | + st.end(); |
| 85 | + }); |
17 | 86 |
|
18 |
| - const releaseFileName = list.releases[wanted]; |
19 |
| - const expectedFile = list.builds.filter(function (entry) { return entry.path === releaseFileName; })[0]; |
20 |
| - if (!expectedFile) { |
21 |
| - st.fail(`Version ${wanted} not found. Version list is invalid or corrupted?`); |
22 |
| - } |
| 87 | + t.test('should throw an exception when version list not found', async function (st) { |
| 88 | + versionListMock(server.origin).reply(404); |
| 89 | + |
| 90 | + try { |
| 91 | + await downloader.getVersionList(`${server.origin}/bin/list.json`); |
| 92 | + st.fail('should throw file not found error'); |
| 93 | + } catch (err) { |
| 94 | + st.equal(err.message, 'Error downloading file: 404', 'should throw file not found error'); |
| 95 | + } |
| 96 | + st.end(); |
| 97 | + }); |
| 98 | +}); |
| 99 | + |
| 100 | +tape('Download latest binary', async function (t) { |
| 101 | + const server = await startMockServer(); |
| 102 | + const content = '() => {}'; |
| 103 | + const tmpDir = tmp.dirSync({ unsafeCleanup: true, prefix: 'solcjs-download-test-' }).name; |
| 104 | + |
| 105 | + t.teardown(function () { |
| 106 | + server.close(); |
| 107 | + nock.cleanAll(); |
| 108 | + }); |
| 109 | + |
| 110 | + t.test('successfully download binary', async function (st) { |
| 111 | + const targetFilename = `${tmpDir}/target-success.js`; |
| 112 | + const file = generateTestFile(st, content); |
23 | 113 |
|
24 |
| - const tempDir = tmp.dirSync({ unsafeCleanup: true, prefix: 'solc-js-compiler-test-' }).name; |
25 |
| - const solcjsBin = `${tempDir}/${expectedFile.path}`; |
26 |
| - await downloader.downloadBinary(solcjsBin, releaseFileName, expectedFile.keccak256); |
| 114 | + st.teardown(function () { |
| 115 | + file.removeCallback(); |
| 116 | + }); |
27 | 117 |
|
28 |
| - const solc = wrapper(require(solcjsBin)); |
29 |
| - if (semver.neq(solc.version(), wanted)) { |
30 |
| - st.fail('Downloaded version differs from package version'); |
| 118 | + downloadBinaryMock(server.origin, file.name) |
| 119 | + .replyWithFile(200, file.name, { |
| 120 | + 'content-type': 'application/javascript', |
| 121 | + 'content-length': content.length.toString() |
| 122 | + }); |
| 123 | + |
| 124 | + try { |
| 125 | + await downloader.downloadBinary( |
| 126 | + `${server.origin}/bin`, |
| 127 | + targetFilename, |
| 128 | + file.name, |
| 129 | + hash(file.name) |
| 130 | + ); |
| 131 | + |
| 132 | + if (!fs.existsSync(targetFilename)) { |
| 133 | + st.fail('download failed'); |
31 | 134 | }
|
32 |
| - st.pass(`Version ${wanted} successfully downloaded`); |
| 135 | + |
| 136 | + const got = fs.readFileSync(targetFilename, { encoding: 'binary' }); |
| 137 | + const expected = fs.readFileSync(file.name, { encoding: 'binary' }); |
| 138 | + st.equal(got.length, expected.length, 'should download the correct file'); |
33 | 139 | } catch (err) {
|
34 | 140 | st.fail(err.message);
|
35 | 141 | }
|
36 | 142 | st.end();
|
37 | 143 | });
|
| 144 | + |
| 145 | + t.test('should throw an exception when file not found', async function (st) { |
| 146 | + const targetFilename = `${tmpDir}/target-fail404.js`; |
| 147 | + downloadBinaryMock(server.origin, 'test.js').reply(404); |
| 148 | + |
| 149 | + try { |
| 150 | + await downloader.downloadBinary( |
| 151 | + `${server.origin}/bin`, |
| 152 | + targetFilename, |
| 153 | + 'test.js', |
| 154 | + `0x${keccak256('something')}` |
| 155 | + ); |
| 156 | + st.fail('should throw file not found error'); |
| 157 | + } catch (err) { |
| 158 | + st.equal(err.message, 'Error downloading file: 404', 'should throw file not found error'); |
| 159 | + } |
| 160 | + st.end(); |
| 161 | + }); |
| 162 | + |
| 163 | + t.test('should throw an exception if hashes do not match', async function (st) { |
| 164 | + const targetFilename = `${tmpDir}/target-fail-hash.js`; |
| 165 | + const file = generateTestFile(st, content); |
| 166 | + |
| 167 | + st.teardown(function () { |
| 168 | + file.removeCallback(); |
| 169 | + }); |
| 170 | + |
| 171 | + downloadBinaryMock(server.origin, file.name) |
| 172 | + .replyWithFile(200, file.name, { |
| 173 | + 'content-type': 'application/javascript', |
| 174 | + 'content-length': content.length.toString() |
| 175 | + }); |
| 176 | + |
| 177 | + try { |
| 178 | + await downloader.downloadBinary( |
| 179 | + `${server.origin}/bin`, |
| 180 | + targetFilename, |
| 181 | + file.name, |
| 182 | + `0x${keccak256('something')}` |
| 183 | + ); |
| 184 | + st.fail('should throw hash mismatch error'); |
| 185 | + } catch (err) { |
| 186 | + st.match(err.message, /Hash mismatch/, 'should detect hash mismatch'); |
| 187 | + } |
| 188 | + st.end(); |
| 189 | + }); |
38 | 190 | });
|
0 commit comments