Files
Multi-Hoster-Upload/tests/doodstream-api-upload.test.js
T
Sucukdeluxe d7c9f287e4
CI / verify (push) Has been cancelled
release: restore v2.1.19 baseline for v2.1.24
Restore the v2.1.19 application baseline and retain only the focused import preflight summary with duplicate, unavailable, destination, job, and size-limit visibility.
2026-08-17 04:25:22 +02:00

106 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const { test, before, after } = require('node:test');
const assert = require('node:assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
// Mock the undici transport BEFORE requiring hosters so the destructured
// `request` picks up our stub. apiGet (getUploadServer) uses global fetch, which
// we override per-test. This exercises the FULL doodstream API upload + recovery
// orchestration against the doc-verified response shapes — the gap between the
// already-tested parseDoodstreamResult helper and the real uploadFile path.
// (mock.module needs an experimental flag npm test doesn't pass, so we reassign
// undici.request on the module object and refresh the hosters cache instead.)
let requestRouter = async () => ({ statusCode: 200, headers: {}, body: { text: async () => '{}' } });
const undici = require('undici');
const _origUndiciRequest = undici.request;
undici.request = (...a) => requestRouter(...a);
delete require.cache[require.resolve('../lib/hosters')];
const hostersMod = require('../lib/hosters');
const { uploadFile } = hostersMod;
let tmpFile;
let origFetch;
before(() => {
tmpFile = path.join(os.tmpdir(), `dood-itest-${process.pid}.mkv`);
fs.writeFileSync(tmpFile, Buffer.alloc(2048, 7));
origFetch = global.fetch;
// Keep the "never appears" recovery test fast (real default is 12 × 2.5 s).
hostersMod.__test.DOODSTREAM_POLL.attempts = 3;
hostersMod.__test.DOODSTREAM_POLL.delayMs = 5;
});
after(() => {
global.fetch = origFetch;
undici.request = _origUndiciRequest; // restore real transport for other test files
delete require.cache[require.resolve('../lib/hosters')];
try { fs.unlinkSync(tmpFile); } catch {}
});
// getUploadServer hits /api/upload/server via global fetch.
function stubUploadServer() {
global.fetch = async (url) => {
if (/upload\/server/.test(String(url))) {
return { status: 200, text: async () => JSON.stringify({ status: 200, result: 'https://node1.cloudatacdn.com/upload/01' }) };
}
return { status: 200, text: async () => '{"status":200}' };
};
}
// Build an undici-style router. uploadBody is the POST result; listBodies is a
// queue consumed by successive /api/file/list calls (baseline, then polls).
function routeWith(uploadBody, listBodies = []) {
return async (url, opts) => {
const u = String(url);
if (/\/api\/file\/list/.test(u)) {
const body = listBodies.length ? listBodies.shift() : '{"status":200,"result":{"files":[]}}';
return { statusCode: 200, headers: {}, body: { text: async () => body } };
}
// Upload POST: drain the streamed body so the file handle closes.
if (opts && opts.body && typeof opts.body[Symbol.asyncIterator] === 'function') {
for await (const chunk of opts.body) { if (chunk && chunk.length === -1) break; }
}
return { statusCode: uploadBody.status, headers: { 'content-type': 'application/json' }, body: { text: async () => uploadBody.body } };
};
}
test('doodstream API upload: filecode returned directly is used', async () => {
stubUploadServer();
requestRouter = routeWith({
status: 200,
body: JSON.stringify({ status: 200, result: [{ filecode: 'DOODCODE1234', download_url: 'https://doodstream.com/d/DOODCODE1234', protected_embed: 'https://doodstream.com/e/DOODCODE1234' }] })
});
const res = await uploadFile('doodstream.com', tmpFile, 'VALIDKEY', null, null, null);
assert.equal(res.file_code, 'DOODCODE1234');
assert.equal(res.download_url, 'https://doodstream.com/d/DOODCODE1234');
});
test('doodstream API upload: codeless result recovered via file-list name match', async () => {
stubUploadServer();
const fileName = path.basename(tmpFile).replace(/\.[^.]+$/, ''); // title doodstream stores
requestRouter = routeWith(
{ status: 200, body: JSON.stringify({ status: 200, msg: 'OK' }) }, // codeless upload
[
'{"status":200,"result":{"files":[]}}', // baseline (pre-upload)
`{"status":200,"result":{"files":[{"file_code":"RECOVER9999","title":"${fileName}"}]}}` // poll finds it
]
);
const res = await uploadFile('doodstream.com', tmpFile, 'VALIDKEY', null, null, null);
assert.equal(res.file_code, 'RECOVER9999');
assert.equal(res.download_url, 'https://doodstream.com/d/RECOVER9999');
});
test('doodstream API upload: codeless + file never appears → throws hosterTransient (no account poison)', async () => {
stubUploadServer();
requestRouter = routeWith(
{ status: 200, body: JSON.stringify({ status: 200, msg: 'OK' }) },
[] // every file/list returns empty
);
await assert.rejects(
() => uploadFile('doodstream.com', tmpFile, 'VALIDKEY', null, null, null),
(err) => {
assert.equal(err.hosterTransient, true, 'codeless result must be tagged hosterTransient');
return true;
}
);
});