mirror of
https://github.com/webrecorder/browsertrix-crawler.git
synced 2025-10-19 14:33:17 +00:00

Fixes #674 This PR supersedes #505, and instead of using js-wacz for optimized WACZ creation: - generates an 'in-place' or 'streaming' WACZ in the crawler, without having to copy the data again. - WACZ contents are streamed to remote upload (or to disk) from existing files on disk - CDXJ indices per-WARC are first written to 'warc-cdx' directory, then merged using the linux 'sort' command, and compressed to ZipNum if >50K (or always if using --generateCDX) - All data in the WARCs is written and read only once - Should result in significant speed / disk usage improvements: previously WARC was written once, then read again (for CDXJ indexing), read again (for adding to new WACZ ZIP), written to disk (into new WACZ ZIP), read again (if upload to remote endpoint). Now, WARCs are written once, along with the per-WARC CDXJ, the CDXJ only is reread, sorted and merged on-disk, and all data is read once to either generate WACZ on disk or upload to remote. --------- Co-authored-by: Tessa Walsh <tessa@bitarchivist.net>
196 lines
6.3 KiB
JavaScript
196 lines
6.3 KiB
JavaScript
import child_process from "child_process";
|
|
import fs from "fs";
|
|
import path from "path";
|
|
import { WARCParser } from "warcio";
|
|
|
|
test("run warc and ensure pageinfo records contain the correct resources", async () => {
|
|
child_process.execSync(
|
|
"docker run -v $PWD/test-crawls:/crawls webrecorder/browsertrix-crawler crawl --url https://webrecorder.net/ --url https://webrecorder.net/about --url https://invalid.invalid/ --scopeType page --collection page-info-test --combineWARC",
|
|
);
|
|
|
|
const filename = path.join(
|
|
"test-crawls",
|
|
"collections",
|
|
"page-info-test",
|
|
"page-info-test_0.warc.gz",
|
|
);
|
|
|
|
const nodeStream = fs.createReadStream(filename);
|
|
|
|
const parser = new WARCParser(nodeStream);
|
|
|
|
let foundIndex = false;
|
|
let foundAbout = false;
|
|
let foundInvalid = false;
|
|
|
|
for await (const record of parser) {
|
|
if (
|
|
!foundIndex &&
|
|
record.warcTargetURI === "urn:pageinfo:https://webrecorder.net/"
|
|
) {
|
|
foundIndex = true;
|
|
const text = await record.contentText();
|
|
validateResourcesIndex(JSON.parse(text));
|
|
}
|
|
|
|
if (
|
|
!foundAbout &&
|
|
record.warcTargetURI === "urn:pageinfo:https://webrecorder.net/about"
|
|
) {
|
|
foundAbout = true;
|
|
const text = await record.contentText();
|
|
validateResourcesAbout(JSON.parse(text));
|
|
}
|
|
|
|
if (
|
|
!foundInvalid &&
|
|
record.warcTargetURI === "urn:pageinfo:https://invalid.invalid/"
|
|
) {
|
|
foundInvalid = true;
|
|
const text = await record.contentText();
|
|
validateResourcesInvalid(JSON.parse(text));
|
|
}
|
|
}
|
|
|
|
expect(foundIndex).toBe(true);
|
|
expect(foundAbout).toBe(true);
|
|
expect(foundInvalid).toBe(true);
|
|
});
|
|
|
|
function validateResourcesIndex(json) {
|
|
expect(json).toHaveProperty("pageid");
|
|
expect(json).toHaveProperty("url");
|
|
expect(json).toHaveProperty("ts");
|
|
expect(json).toHaveProperty("urls");
|
|
expect(json.counts).toEqual({ jsErrors: 0 });
|
|
expect(json.urls).toEqual({
|
|
"https://webrecorder.net/": {
|
|
status: 200,
|
|
mime: "text/html",
|
|
type: "document",
|
|
},
|
|
"https://webrecorder.net/assets/tools/logo-pywb.png": {
|
|
mime: "image/png",
|
|
status: 200,
|
|
type: "image",
|
|
},
|
|
"https://webrecorder.net/assets/brand/archivewebpage-icon-color.svg": {
|
|
mime: "image/svg+xml",
|
|
status: 200,
|
|
type: "image",
|
|
},
|
|
"https://webrecorder.net/assets/brand/browsertrix-icon-color.svg": {
|
|
mime: "image/svg+xml",
|
|
status: 200,
|
|
type: "image",
|
|
},
|
|
"https://webrecorder.net/assets/brand/browsertrixcrawler-icon-color.svg": {
|
|
mime: "image/svg+xml",
|
|
status: 200,
|
|
type: "image",
|
|
},
|
|
"https://webrecorder.net/assets/brand/replaywebpage-icon-color.svg": {
|
|
mime: "image/svg+xml",
|
|
status: 200,
|
|
type: "image",
|
|
},
|
|
"https://webrecorder.net/assets/fontawesome/all.css": {
|
|
status: 200,
|
|
mime: "text/css",
|
|
type: "stylesheet",
|
|
},
|
|
"https://webrecorder.net/assets/wr-logo.svg": {
|
|
status: 200,
|
|
mime: "image/svg+xml",
|
|
type: "image",
|
|
},
|
|
"https://webrecorder.net/assets/main.css": {
|
|
status: 200,
|
|
mime: "text/css",
|
|
type: "stylesheet",
|
|
},
|
|
"https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@700;900&display=swap":
|
|
{ status: 200, mime: "text/css", type: "stylesheet" },
|
|
"https://fonts.googleapis.com/css?family=Source+Code+Pro|Source+Sans+Pro&display=swap":
|
|
{ status: 200, mime: "text/css", type: "stylesheet" },
|
|
"https://stats.browsertrix.com/js/script.tagged-events.js": {
|
|
status: 200,
|
|
mime: "application/javascript",
|
|
type: "script",
|
|
},
|
|
"https://fonts.gstatic.com/s/sourcesanspro/v22/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7l.woff2":
|
|
{ status: 200, mime: "font/woff2", type: "font" },
|
|
"https://fonts.gstatic.com/s/sourcesanspro/v22/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2":
|
|
{ status: 200, mime: "font/woff2", type: "font" },
|
|
"https://webrecorder.net/assets/favicon.ico": {
|
|
status: 200,
|
|
mime: "image/vnd.microsoft.icon",
|
|
type: "other",
|
|
},
|
|
"https://stats.browsertrix.com/api/event?__wb_method=POST&n=pageview&u=https%3A%2F%2Fwebrecorder.net%2F&d=webrecorder.net&r=null":
|
|
{ status: 202, mime: "text/plain", type: "xhr" },
|
|
});
|
|
}
|
|
|
|
function validateResourcesAbout(json) {
|
|
expect(json).toHaveProperty("pageid");
|
|
expect(json).toHaveProperty("url");
|
|
expect(json).toHaveProperty("ts");
|
|
expect(json).toHaveProperty("urls");
|
|
expect(json.counts).toEqual({ jsErrors: 0 });
|
|
expect(json.urls).toEqual({
|
|
"https://webrecorder.net/about": {
|
|
status: 200,
|
|
mime: "text/html",
|
|
type: "document",
|
|
},
|
|
"https://webrecorder.net/assets/main.css": {
|
|
status: 200,
|
|
mime: "text/css",
|
|
type: "stylesheet",
|
|
},
|
|
"https://webrecorder.net/assets/fontawesome/all.css": {
|
|
status: 200,
|
|
mime: "text/css",
|
|
type: "stylesheet",
|
|
},
|
|
"https://fonts.googleapis.com/css?family=Source+Code+Pro|Source+Sans+Pro&display=swap":
|
|
{ status: 200, mime: "text/css", type: "stylesheet" },
|
|
"https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@700;900&display=swap":
|
|
{ status: 200, mime: "text/css", type: "stylesheet" },
|
|
"https://stats.browsertrix.com/js/script.tagged-events.js": {
|
|
status: 200,
|
|
mime: "application/javascript",
|
|
type: "script",
|
|
},
|
|
"https://webrecorder.net/assets/wr-logo.svg": {
|
|
status: 200,
|
|
mime: "image/svg+xml",
|
|
type: "image",
|
|
},
|
|
"https://fonts.gstatic.com/s/sourcesanspro/v22/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7l.woff2":
|
|
{ status: 200, mime: "font/woff2", type: "font" },
|
|
"https://fonts.gstatic.com/s/sourcesanspro/v22/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2":
|
|
{ status: 200, mime: "font/woff2", type: "font" },
|
|
"https://stats.browsertrix.com/api/event?__wb_method=POST&n=pageview&u=https%3A%2F%2Fwebrecorder.net%2Fabout&d=webrecorder.net&r=null":
|
|
{
|
|
status: 0,
|
|
type: "xhr",
|
|
error: "net::ERR_BLOCKED_BY_CLIENT",
|
|
},
|
|
});
|
|
}
|
|
|
|
function validateResourcesInvalid(json) {
|
|
expect(json).toHaveProperty("pageid");
|
|
expect(json).toHaveProperty("url");
|
|
expect(json).toHaveProperty("urls");
|
|
expect(json.counts).toEqual({ jsErrors: 0 });
|
|
expect(json.urls).toEqual({
|
|
"https://invalid.invalid/": {
|
|
status: 0,
|
|
type: "document",
|
|
error: "net::ERR_NAME_NOT_RESOLVED",
|
|
},
|
|
});
|
|
}
|