v86/tests/full/run.js

450 lines
11 KiB
JavaScript
Raw Normal View History

2015-11-11 04:28:59 +01:00
#!/usr/bin/env node
2015-09-15 19:30:53 +02:00
"use strict";
var TIMEOUT_EXTRA_FACTOR = +process.env.TIMEOUT_EXTRA_FACTOR || 1;
var MAX_PARALLEL_TESTS = +process.env.MAX_PARALLEL_TESTS || 4;
2016-09-07 10:02:46 +02:00
var TEST_NAME = process.env.TEST_NAME;
2016-01-03 19:10:13 +01:00
2015-09-15 19:30:53 +02:00
try
{
var V86 = require("../../build/libv86.js").V86Starter;
}
catch(e)
{
console.error("Failed to import build/libv86.js. Run `make build/libv86.js first.");
process.exit(1);
}
2015-12-30 22:36:44 +01:00
var cluster = require("cluster");
var os = require("os");
2015-09-15 19:30:53 +02:00
var fs = require("fs");
var root_path = __dirname + "/../..";
var SCREEN_WIDTH = 80;
2016-08-02 05:13:23 +02:00
function get_line(screen, y)
{
return screen.subarray(y * SCREEN_WIDTH, (y + 1) * SCREEN_WIDTH);
}
2015-09-15 19:30:53 +02:00
function line_to_text(screen, y)
{
2016-08-02 05:13:23 +02:00
return bytearray_to_string(get_line(screen, y));
}
function string_to_bytearray(str)
{
return new Uint8Array(str.split("").map(chr => chr.charCodeAt(0)));
}
function bytearray_to_string(arr)
{
return String.fromCharCode.apply(String, arr);
2015-09-15 19:30:53 +02:00
}
function screen_to_text(s)
{
var result = [];
2016-01-01 23:23:17 +01:00
result.push("+==================================== SCREEN ====================================+");
2015-09-15 19:30:53 +02:00
for(var i = 0; i < 25; i++)
{
var line = line_to_text(s, i);
2016-01-01 23:23:17 +01:00
result.push("|" + line + "|");
2015-09-15 19:30:53 +02:00
}
2016-01-01 23:23:17 +01:00
result.push("+================================================================================+");
2015-09-15 19:30:53 +02:00
return result.join("\n");
}
function send_work_to_worker(worker, message)
{
if(current_test < tests.length)
{
worker.send(tests[current_test]);
current_test++;
}
else
{
worker.disconnect();
}
}
2015-12-30 22:36:44 +01:00
if(cluster.isMaster)
2015-09-15 19:30:53 +02:00
{
2015-12-30 22:36:44 +01:00
var tests = [
{
name: "FreeDOS boot",
fda: root_path + "/images/freedos722.img",
timeout: 10,
expected_texts: [
"Welcome to FreeDOS",
],
},
2016-02-05 14:40:46 +01:00
{
name: "FreeDOS boot with Bochs BIOS",
fda: root_path + "/images/freedos722.img",
timeout: 10,
alternative_bios: true,
expected_texts: [
"Welcome to FreeDOS",
],
},
2015-12-30 22:36:44 +01:00
{
name: "Windows 1.01 boot",
fda: root_path + "/images/windows101.img",
timeout: 10,
expect_graphical_mode: true,
expect_mouse_registered: true,
},
{
name: "Sol OS",
fda: root_path + "/images/os8.dsk",
2016-02-05 14:40:46 +01:00
timeout: 20,
2015-12-30 22:36:44 +01:00
expect_graphical_mode: true,
expect_mouse_registered: true,
actions: [
{
2016-08-02 05:13:23 +02:00
on_text: " or press",
2015-12-30 22:36:44 +01:00
run: "\n"
},
],
},
{
name: "Linux",
cdrom: root_path + "/images/linux.iso",
2016-08-02 05:13:23 +02:00
timeout: 90,
2016-02-05 14:40:46 +01:00
expected_texts: [
"/root%",
"test passed",
],
actions: [
{
on_text: "/root%",
run: "cd tests; ./test-i386 > emu.test; diff emu.test reference.test > /dev/null && echo test pas''sed || echo failed\n",
},
],
},
{
2016-08-04 19:47:19 +02:00
name: "Windows 98",
hda: root_path + "/images/windows98.img",
2016-09-07 10:02:46 +02:00
timeout: 60,
2016-08-04 19:47:19 +02:00
expect_graphical_mode: true,
expect_graphical_size: [800, 600],
expect_mouse_registered: true,
skip_if_disk_image_missing: true,
},
2017-06-07 16:48:06 +02:00
//{
// name: "Oberon",
// hda: root_path + "/images/oberon.dsk",
// fda: root_path + "/images/oberon-boot.dsk",
// timeout: 30,
// expect_graphical_mode: true,
// expect_mouse_registered: true,
//},
2015-12-30 22:36:44 +01:00
{
name: "Linux 3",
cdrom: root_path + "/images/linux3.iso",
timeout: 200,
expected_texts: [
"test passed",
],
actions: [
{
on_text: "~%",
run: "echo test pas''sed\n"
},
],
},
{
name: "KolibriOS",
fda: root_path + "/images/kolibri.img",
timeout: 120,
expect_graphical_mode: true,
expect_mouse_registered: true,
},
2016-08-04 19:47:19 +02:00
{
name: "Linux with Bochs BIOS",
cdrom: root_path + "/images/linux.iso",
timeout: 90,
expected_texts: [
"/root%",
"test passed",
],
alternative_bios: true,
actions: [
{
on_text: "/root%",
run: "cd tests; ./test-i386 > emu.test; diff emu.test reference.test > /dev/null && echo test pas''sed || echo failed\n",
},
],
},
2016-01-03 19:15:46 +01:00
{
name: "OpenBSD",
fda: root_path + "/images/openbsd.img",
2016-02-05 14:40:46 +01:00
timeout: 180,
2016-01-03 19:15:46 +01:00
expected_texts: ["(I)nstall, (U)pgrade or (S)hell"],
},
2015-12-30 22:36:44 +01:00
];
2016-09-07 10:02:46 +02:00
if(TEST_NAME)
{
tests = tests.filter(test => test.name === TEST_NAME);
}
2016-07-28 00:29:32 +02:00
var nr_of_cpus = Math.min(Math.round(os.cpus().length / 2) || 1, tests.length, MAX_PARALLEL_TESTS);
2015-12-30 22:36:44 +01:00
console.log("Using %d cpus", nr_of_cpus);
var current_test = 0;
for(var i = 0; i < nr_of_cpus; i++)
2015-09-15 19:30:53 +02:00
{
2015-12-30 22:36:44 +01:00
var worker = cluster.fork();
2017-03-07 01:03:28 +01:00
worker.on("message", send_work_to_worker.bind(null, worker));
worker.on("online", send_work_to_worker.bind(null, worker));
2015-12-30 22:36:44 +01:00
worker.on("exit", function(code, signal)
{
if(code !== 0)
{
process.exit(code);
}
2016-01-03 19:10:13 +01:00
});
2015-12-30 22:36:44 +01:00
2016-01-03 19:10:13 +01:00
worker.on("error", function(error)
{
console.error("Worker error: ", error.toString(), error);
process.exit(1);
});
2015-09-15 19:30:53 +02:00
}
2015-12-30 22:36:44 +01:00
}
else
{
cluster.worker.on("message", function(test_case)
{
run_test(test_case, function()
{
process.send("I'm done");
});
});
}
2016-08-02 05:13:23 +02:00
function bytearray_starts_with(arr, search)
{
for(var i = 0; i < search.length; i++)
{
if(arr[i] !== search[i])
{
2017-03-07 01:03:28 +01:00
return false;
2016-08-02 05:13:23 +02:00
}
}
return true;
}
2015-12-30 22:36:44 +01:00
function run_test(test, done)
{
console.log("Starting test: %s", test.name);
2015-09-15 19:30:53 +02:00
let image = test.fda || test.hda || test.cdrom;
console.assert(image, "Bootable drive expected");
if(!fs.existsSync(image))
{
if(test.skip_if_disk_image_missing)
{
console.warn("Missing disk image: " + image + ", test skipped");
console.warn();
done();
return;
}
else
{
console.warn("Missing disk image: " + image);
process.exit(1);
}
}
2016-02-05 14:40:46 +01:00
if(test.alternative_bios)
{
var bios = root_path + "/bios/bochs-bios.bin";
var vga_bios = root_path + "/bios/bochs-vgabios.bin";
2016-02-05 14:40:46 +01:00
}
else
{
var bios = root_path + "/bios/seabios.bin";
var vga_bios = root_path + "/bios/vgabios.bin";
2016-02-05 14:40:46 +01:00
}
2015-09-15 19:30:53 +02:00
var settings = {
bios: { url: bios },
vga_bios: { url: vga_bios },
2015-09-15 19:30:53 +02:00
autostart: true,
};
if(test.cdrom)
2015-09-15 19:30:53 +02:00
{
settings.cdrom = { url: test.cdrom };
2015-09-15 19:30:53 +02:00
}
if(test.fda)
2015-09-15 19:30:53 +02:00
{
settings.fda = { url: test.fda };
}
if(test.hda)
{
settings.hda = { url: test.hda };
2015-09-15 19:30:53 +02:00
}
2016-08-02 05:13:23 +02:00
if(test.expected_texts)
{
test.expected_texts = test.expected_texts.map(string_to_bytearray);
}
else
2015-12-30 21:25:42 +01:00
{
test.expected_texts = [];
}
2015-09-15 19:30:53 +02:00
var emulator = new V86(settings);
2015-12-30 22:36:44 +01:00
var screen = new Uint8Array(SCREEN_WIDTH * 25);
2015-09-15 19:30:53 +02:00
2015-12-30 21:25:42 +01:00
function check_text_test_done()
2015-09-15 19:30:53 +02:00
{
2015-12-30 21:25:42 +01:00
return test.expected_texts.length === 0;
2015-09-15 19:30:53 +02:00
}
2015-12-30 21:25:42 +01:00
var mouse_test_done = false;
function check_mouse_test_done()
2015-09-15 19:30:53 +02:00
{
2015-12-30 21:25:42 +01:00
return !test.expect_mouse_registered || mouse_test_done;
2015-09-15 19:30:53 +02:00
}
2015-12-30 21:25:42 +01:00
var graphical_test_done = false;
2016-08-04 19:47:19 +02:00
var size_test_done = false;
2020-10-04 19:46:41 +02:00
function check_graphical_test_done()
2015-09-15 19:30:53 +02:00
{
2016-08-04 19:47:19 +02:00
return !test.expect_graphical_mode || (graphical_test_done && (!test.expect_graphical_size || size_test_done));
2015-09-15 19:30:53 +02:00
}
var test_start = Date.now();
2016-01-03 19:10:13 +01:00
var timeout_seconds = test.timeout * TIMEOUT_EXTRA_FACTOR;
var timeout = setTimeout(check_test_done, (timeout_seconds + 1) * 1000);
2015-12-30 21:25:42 +01:00
2015-09-15 19:30:53 +02:00
var on_text = [];
2015-12-30 21:25:42 +01:00
var stopped = false;
2015-09-15 19:30:53 +02:00
function check_test_done()
{
2015-12-30 21:25:42 +01:00
if(stopped)
{
return;
}
2020-10-04 19:46:41 +02:00
if(check_text_test_done() && check_mouse_test_done() && check_graphical_test_done())
2015-09-15 19:30:53 +02:00
{
2016-08-02 05:13:23 +02:00
var end = Date.now();
2015-12-30 22:36:44 +01:00
clearTimeout(timeout);
2015-12-30 21:25:42 +01:00
stopped = true;
2016-01-03 19:10:13 +01:00
2015-09-15 19:30:53 +02:00
emulator.stop();
2016-08-02 05:13:23 +02:00
console.warn("Passed test: %s (took %ds)", test.name, (end - test_start) / 1000);
2015-09-15 19:30:53 +02:00
console.warn();
2015-12-30 22:36:44 +01:00
done();
2015-09-15 19:30:53 +02:00
}
2016-01-03 19:10:13 +01:00
else if(Date.now() >= test_start + timeout_seconds * 1000)
2015-09-15 19:30:53 +02:00
{
2016-01-03 19:10:13 +01:00
clearTimeout(timeout);
2015-12-30 22:36:44 +01:00
stopped = true;
2016-01-03 19:10:13 +01:00
2015-09-15 19:30:53 +02:00
emulator.stop();
emulator.destroy();
2015-12-30 22:36:44 +01:00
2015-09-15 19:30:53 +02:00
console.warn(screen_to_text(screen));
console.warn("Test failed: %s\n", test.name);
2015-12-30 21:25:42 +01:00
if(!check_text_test_done())
2015-09-15 19:30:53 +02:00
{
2016-09-07 10:02:46 +02:00
console.warn('Expected text "%s" after %d seconds.', bytearray_to_string(test.expected_texts[0]), timeout_seconds);
2015-09-15 19:30:53 +02:00
}
2020-10-04 19:46:41 +02:00
if(!check_graphical_test_done())
2015-09-15 19:30:53 +02:00
{
2016-01-03 19:10:13 +01:00
console.warn("Expected graphical mode after %d seconds.", timeout_seconds);
2015-09-15 19:30:53 +02:00
}
2015-12-30 21:25:42 +01:00
if(!check_mouse_test_done())
2015-09-15 19:30:53 +02:00
{
2016-01-03 19:10:13 +01:00
console.warn("Expected mouse activation after %d seconds.", timeout_seconds);
2015-09-15 19:30:53 +02:00
}
2015-12-30 22:36:44 +01:00
process.exit(1);
2015-09-15 19:30:53 +02:00
}
}
2015-12-30 21:25:42 +01:00
emulator.add_listener("mouse-enable", function()
{
mouse_test_done = true;
check_test_done();
});
emulator.add_listener("screen-set-mode", function(is_graphical)
{
graphical_test_done = is_graphical;
check_test_done();
});
2016-08-04 19:47:19 +02:00
emulator.add_listener("screen-set-size-graphical", function(size)
{
if(test.expect_graphical_size)
{
size_test_done = size[0] === test.expect_graphical_size[0] &&
size[1] === test.expect_graphical_size[1];
check_test_done();
}
});
2015-09-15 19:30:53 +02:00
emulator.add_listener("screen-put-char", function(chr)
{
var y = chr[0];
var x = chr[1];
var code = chr[2];
screen[x + SCREEN_WIDTH * y] = code;
2016-08-02 05:13:23 +02:00
var line = get_line(screen, y);
2015-09-15 19:30:53 +02:00
2015-12-30 21:25:42 +01:00
if(!check_text_test_done())
2015-09-15 19:30:53 +02:00
{
2016-08-02 05:13:23 +02:00
let expected = test.expected_texts[0];
if(x < expected.length && bytearray_starts_with(line, expected))
2015-09-15 19:30:53 +02:00
{
test.expected_texts.shift();
check_test_done();
}
}
if(on_text.length)
{
2016-08-02 05:13:23 +02:00
let expected = on_text[0].text;
if(x < expected.length && bytearray_starts_with(line, expected))
2015-09-15 19:30:53 +02:00
{
var action = on_text.shift();
emulator.keyboard_send_text(action.run);
}
}
});
test.actions && test.actions.forEach(function(action)
{
if(action.on_text)
{
2016-08-02 05:13:23 +02:00
on_text.push({ text: string_to_bytearray(action.on_text), run: action.run, });
2015-09-15 19:30:53 +02:00
}
});
}