Kaynağa Gözat

[curiosity] Use haxeserver for display tests (#7951)

* [tests] run display tests through haxeserver

* [tests] use haxeserver for server tests
Simon Krajewski 6 yıl önce
ebeveyn
işleme
69b79b7ea0

+ 1 - 0
tests/display/build.hxml

@@ -1,5 +1,6 @@
 -p src
 --main Main
 -lib utest
+-lib haxeserver
 --interp
 -D use-rtti-doc

+ 4 - 38
tests/display/src/DisplayTestContext.hx

@@ -1,3 +1,4 @@
+import haxe.io.Bytes;
 import haxe.io.BytesBuffer;
 
 using StringTools;
@@ -23,7 +24,7 @@ class HaxeInvocationException {
 }
 
 class DisplayTestContext {
-	static var haxeServer = new sys.io.Process("haxe", ["--wait", "stdio"]);
+	static var haxeServer = haxeserver.HaxeServerSync.launch("haxe", []);
 
 	var markers:Map<Int, Int>;
 	var fieldName:String;
@@ -102,16 +103,7 @@ class DisplayTestContext {
 	}
 
 	function callHaxe(displayPart:String) {
-		var args = [
-			"-cp",
-			"src",
-			"-D",
-			"display-stdin",
-			"--display",
-			source.path + "@" + displayPart,
-			"-lib",
-			"utest"
-		];
+		var args = ["--display", source.path + "@" + displayPart];
 		var result = runHaxe(args, source.content);
 		if (result.hasError || result.stderr == "") {
 			throw new HaxeInvocationException(result.stderr, fieldName, args, source.content);
@@ -120,33 +112,7 @@ class DisplayTestContext {
 	}
 
 	static public function runHaxe(args:Array<String>, ?stdin:String) {
-		var bb = new BytesBuffer();
-		bb.addString(args.join("\n"));
-		if (stdin != null) {
-			bb.addByte(1);
-			bb.addString(stdin);
-		}
-		var b = bb.getBytes();
-		haxeServer.stdin.writeInt32(b.length);
-		haxeServer.stdin.write(b);
-		var data = haxeServer.stderr.readString(haxeServer.stderr.readInt32());
-		var buf = new StringBuf();
-		var hasError = false;
-		for (line in data.split("\n")) {
-			switch (line.fastCodeAt(0)) {
-				case 0x01: // print
-				case 0x02: // error
-					hasError = true;
-				default:
-					buf.add(line);
-					buf.addChar("\n".code);
-			}
-		}
-		var s = buf.toString().trim();
-		return {
-			hasError: hasError,
-			stderr: s
-		}
+		return haxeServer.rawRequest(args, stdin == null ? null : Bytes.ofString(stdin));
 	}
 
 	static function extractType(result:String) {

+ 5 - 1
tests/display/src/Main.hx

@@ -10,7 +10,11 @@ class Main {
 		var report = Report.create(runner);
 		report.displayHeader = AlwaysShowHeader;
 		report.displaySuccessResults = NeverShowSuccessResults;
-		DisplayTestContext.runHaxe(["-cp", "src", "--no-output", "-lib", "utest"]);
+
+		var haxeServer = @:privateAccess DisplayTestContext.haxeServer;
+		haxeServer.setDefaultRequestArguments(["-cp", "src", "--no-output", "-lib", "utest"]);
+		DisplayTestContext.runHaxe([]);
 		runner.run();
+		haxeServer.close();
 	}
 }

+ 2 - 1
tests/runci/targets/Js.hx

@@ -57,7 +57,7 @@ class Js {
 		changeDirectory(miscDir + "es6");
 		runCommand("haxe", ["run.hxml"]);
 
-		haxelibInstall("hxnodejs");
+		haxelibInstallGit("HaxeFoundation", "hxnodejs");
 		var env = Sys.environment();
 		if (
 			env.exists("SAUCE") &&
@@ -95,6 +95,7 @@ class Js {
 		runCommand("haxe", ["run.hxml"]);
 
 		runci.targets.Java.getJavaDependencies(); // this is awkward
+		haxelibInstallGit("Simn", "haxeserver");
 		changeDirectory(serverDir);
 		runCommand("haxe", ["build.hxml"]);
 		runCommand("node", ["test.js"]);

+ 1 - 0
tests/runci/targets/Macro.hx

@@ -11,6 +11,7 @@ class Macro {
 		runCommand("haxe", ["compile-macro.hxml"].concat(args));
 
 		changeDirectory(displayDir);
+		haxelibInstallGit("Simn", "haxeserver");
 		runCommand("haxe", ["build.hxml"]);
 
 		changeDirectory(sourcemapsDir);

+ 2 - 1
tests/server/build.hxml

@@ -2,4 +2,5 @@
 --main Main
 -js test.js
 -lib hxnodejs
--lib utest
+-lib utest
+-lib haxeserver

+ 0 - 266
tests/server/src/HaxeServer.hx

@@ -1,266 +0,0 @@
-import js.node.child_process.ChildProcess as ChildProcessObject;
-import js.node.child_process.ChildProcess.ChildProcessEvent;
-import js.node.Buffer;
-import js.node.ChildProcess;
-import js.node.stream.Readable;
-
-using StringTools;
-
-class ErrorUtils {
-	public static function errorToString(error:Dynamic, intro:String):String {
-		var result = intro + Std.string(error);
-		var stack = haxe.CallStack.exceptionStack();
-		if (stack != null && stack.length > 0)
-			result += "\n" + haxe.CallStack.toString(stack);
-		return result;
-	}
-}
-
-private class DisplayRequest {
-	// these are used for the queue
-	public var prev:DisplayRequest;
-	public var next:DisplayRequest;
-
-	var args:Array<String>;
-	var stdin:String;
-	var callback:String->Void;
-	var errback:String->Void;
-
-	static var stdinSepBuf = new Buffer([1]);
-
-	public function new(args:Array<String>, stdin:String, callback:String->Void, errback:String->Void) {
-		this.args = args;
-		this.stdin = stdin;
-		this.callback = callback;
-		this.errback = errback;
-	}
-
-	public function prepareBody():Buffer {
-		if (stdin != null) {
-			args.push("-D");
-			args.push("display-stdin");
-		}
-
-		var lenBuf = new Buffer(4);
-		var chunks = [lenBuf];
-		var length = 0;
-		for (arg in args) {
-			var buf = new Buffer(arg + "\n");
-			chunks.push(buf);
-			length += buf.length;
-		}
-
-		if (stdin != null) {
-			chunks.push(stdinSepBuf);
-			var buf = new Buffer(stdin);
-			chunks.push(buf);
-			length += buf.length + stdinSepBuf.length;
-		}
-
-		lenBuf.writeInt32LE(length, 0);
-
-		return Buffer.concat(chunks, length + 4);
-	}
-
-	public function processResult(context:Context, data:String) {
-		var buf = new StringBuf();
-		var hasError = false;
-		for (line in data.split("\n")) {
-			switch (line.fastCodeAt(0)) {
-				case 0x01: // print
-					var line = line.substring(1).replace("\x01", "\n");
-					context.sendLogMessage("Haxe print: " + line + "\n");
-				case 0x02: // error
-					hasError = true;
-				default:
-					buf.add(line);
-					buf.addChar("\n".code);
-			}
-		}
-
-		var data = buf.toString().trim();
-
-		if (hasError)
-			return errback(data);
-
-		try {
-			callback(data);
-		} catch (e:Any) {
-			errback(ErrorUtils.errorToString(e, "Exception while handling Haxe completion response: "));
-		}
-	}
-}
-
-typedef DisplayServerConfigBase = {
-	var haxePath:String;
-	var arguments:Array<String>;
-	var env:haxe.DynamicAccess<String>;
-}
-
-typedef Context = {
-	function sendErrorMessage(msg:String):Void;
-	function sendLogMessage(msg:String):Void;
-	var displayServerConfig:DisplayServerConfigBase;
-}
-
-private class MessageBuffer {
-	static inline var DEFAULT_SIZE = 8192;
-
-	var index:Int;
-	var buffer:Buffer;
-
-	public function new() {
-		index = 0;
-		buffer = new Buffer(DEFAULT_SIZE);
-	}
-
-	public function append(chunk:Buffer):Void {
-		if (buffer.length - index >= chunk.length) {
-			chunk.copy(buffer, index, 0, chunk.length);
-		} else {
-			var newSize = (Math.ceil((index + chunk.length) / DEFAULT_SIZE) + 1) * DEFAULT_SIZE;
-			if (index == 0) {
-				buffer = new Buffer(newSize);
-				chunk.copy(buffer, 0, 0, chunk.length);
-			} else {
-				buffer = Buffer.concat([buffer.slice(0, index), chunk], newSize);
-			}
-		}
-		index += chunk.length;
-	}
-
-	public function tryReadLength():Int {
-		if (index < 4)
-			return -1;
-		var length = buffer.readInt32LE(0);
-		buffer = buffer.slice(4);
-		index -= 4;
-		return length;
-	}
-
-	public function tryReadContent(length:Int):String {
-		if (index < length)
-			return null;
-		var result = buffer.toString("utf-8", 0, length);
-		var nextStart = length;
-		buffer.copy(buffer, 0, nextStart);
-		index -= nextStart;
-		return result;
-	}
-
-	public function getContent():String {
-		return buffer.toString("utf-8", 0, index);
-	}
-}
-
-class HaxeServer {
-	var proc:ChildProcessObject;
-	var context:Context;
-	var buffer:MessageBuffer;
-	var nextMessageLength:Int;
-	var requestsHead:DisplayRequest;
-	var requestsTail:DisplayRequest;
-	var currentRequest:DisplayRequest;
-
-	public function new(context:Context) {
-		this.context = context;
-	}
-
-	static var reTrailingNewline = ~/\r?\n$/;
-
-	public function start() {
-		stop();
-
-		inline function error(s)
-			context.sendErrorMessage(s);
-
-		var env = new haxe.DynamicAccess();
-		for (key in js.Node.process.env.keys())
-			env[key] = js.Node.process.env[key];
-
-		buffer = new MessageBuffer();
-		nextMessageLength = -1;
-
-		proc = ChildProcess.spawn(context.displayServerConfig.haxePath, context.displayServerConfig.arguments.concat(["--wait", "stdio"]), {env: env});
-
-		proc.stdout.on(ReadableEvent.Data, function(buf:Buffer) {
-			context.sendLogMessage(reTrailingNewline.replace(buf.toString(), ""));
-		});
-		proc.stderr.on(ReadableEvent.Data, onData);
-
-		proc.on(ChildProcessEvent.Exit, onExit);
-	}
-
-	public function stop() {
-		if (proc != null) {
-			proc.removeAllListeners();
-			proc.kill();
-			proc = null;
-		}
-
-		requestsHead = requestsTail = currentRequest = null;
-	}
-
-	public function restart(reason:String) {
-		context.sendLogMessage('Restarting Haxe completion server: $reason');
-		start();
-	}
-
-	function onExit(_, _) {
-		var haxeResponse = buffer.getContent();
-		trace("\nError message from the compiler:\n");
-		trace(haxeResponse);
-	}
-
-	function onData(data:Buffer) {
-		buffer.append(data);
-		while (true) {
-			if (nextMessageLength == -1) {
-				var length = buffer.tryReadLength();
-				if (length == -1)
-					return;
-				nextMessageLength = length;
-			}
-			var msg = buffer.tryReadContent(nextMessageLength);
-			if (msg == null)
-				return;
-			nextMessageLength = -1;
-			if (currentRequest != null) {
-				var request = currentRequest;
-				currentRequest = null;
-				request.processResult(context, msg);
-				checkQueue();
-			}
-		}
-	}
-
-	public function process(args:Array<String>, stdin:String, callback:String->Void, errback:String->Void) {
-		// create a request object
-		var request = new DisplayRequest(args, stdin, callback, errback);
-
-		// add to the queue
-		if (requestsHead == null) {
-			requestsHead = requestsTail = request;
-		} else {
-			requestsTail.next = request;
-			request.prev = requestsTail;
-			requestsTail = request;
-		}
-
-		// process the queue
-		checkQueue();
-	}
-
-	function checkQueue() {
-		// there's a currently processing request, wait and don't send another one to Haxe
-		if (currentRequest != null)
-			return;
-
-		// pop the first request still in queue, set it as current and send to Haxe
-		if (requestsHead != null) {
-			currentRequest = requestsHead;
-			requestsHead = currentRequest.next;
-			proc.stdin.write(currentRequest.prepareBody());
-		}
-	}
-}

+ 40 - 39
tests/server/src/HaxeServerTestCase.hx

@@ -1,52 +1,29 @@
 import haxe.display.JsonModuleTypes.JsonModuleType;
 import haxe.Json;
-import HaxeServer;
+import haxeserver.process.HaxeServerProcessNode;
+import haxeserver.HaxeServerAsync;
 import utest.Assert;
 import utest.ITest;
 
 using StringTools;
 using Lambda;
 
-class TestContext {
-	public var messages:Array<String> = []; // encapsulation is overrated
-	public var errorMessages = [];
-	public var displayServerConfig:DisplayServerConfigBase;
-
-	public function new(config:DisplayServerConfigBase) {
-		this.displayServerConfig = config;
-	}
-
-	public function sendErrorMessage(msg:String) {}
-
-	public function sendLogMessage(msg:String) {
-		var split = msg.split("\n");
-		for (message in split) {
-			messages.push(message.trim());
-		}
-	}
-}
-
 @:autoBuild(AsyncMacro.build())
 class HaxeServerTestCase implements ITest {
-	var context:TestContext;
-	var server:HaxeServer;
+	var server:HaxeServerAsync;
 	var vfs:Vfs;
 	var testDir:String;
 	var storedTypes:Array<JsonModuleType<Any>>;
+	var messages:Array<String> = [];
+	var errorMessages = [];
 	var i:Int = 0;
 
 	public function new() {}
 
 	public function setup() {
 		testDir = "test/cases/" + i++;
-		context = new TestContext({
-			haxePath: "haxe",
-			arguments: ["-v", "--cwd", testDir],
-			env: {}
-		});
 		vfs = new Vfs(testDir);
-		server = new HaxeServer(context);
-		server.start();
+		server = new HaxeServerAsync(() -> new HaxeServerProcessNode("haxe", ["-v", "--cwd", testDir]));
 	}
 
 	public function teardown() {
@@ -54,21 +31,45 @@ class HaxeServerTestCase implements ITest {
 	}
 
 	function runHaxe(args:Array<String>, storeTypes = false, done:Void->Void) {
-		context.messages = [];
-		context.errorMessages = [];
+		messages = [];
+		errorMessages = [];
 		storedTypes = [];
 		if (storeTypes) {
 			args = args.concat(['--display', '{ "method": "typer/compiledTypes", "id": 1 }']);
 		}
-		server.process(args, null, function(result) {
+		server.rawRequest(args, null, function(result) {
+			sendLogMessage(result.stdout);
+			for (print in result.prints) {
+				var line = print.trim();
+				messages.push('Haxe print: $line');
+			}
+			if (result.hasError) {
+				sendErrorMessage(result.stderr);
+			}
 			if (storeTypes) {
-				storedTypes = Json.parse(result).result.result;
+				storedTypes = try {
+					Json.parse(result.stderr).result.result;
+				} catch (e:Dynamic) {
+					trace(e);
+					[];
+				}
 			}
 			done();
-		}, function(message) {
-			context.errorMessages.push(message);
-			done();
-		});
+		}, sendErrorMessage);
+	}
+
+	function sendErrorMessage(msg:String) {
+		var split = msg.split("\n");
+		for (message in split) {
+			errorMessages.push(message.trim());
+		}
+	}
+
+	function sendLogMessage(msg:String) {
+		var split = msg.split("\n");
+		for (message in split) {
+			messages.push(message.trim());
+		}
 	}
 
 	function getTemplate(templateName:String) {
@@ -76,7 +77,7 @@ class HaxeServerTestCase implements ITest {
 	}
 
 	function hasMessage<T>(msg:String) {
-		for (message in context.messages) {
+		for (message in messages) {
 			if (message.endsWith(msg)) {
 				return true;
 			}
@@ -85,7 +86,7 @@ class HaxeServerTestCase implements ITest {
 	}
 
 	function hasErrorMessage<T>(msg:String) {
-		for (message in context.errorMessages) {
+		for (message in errorMessages) {
 			if (message.endsWith(msg)) {
 				return true;
 			}