src/goDebugFactory: connect after createDebugAdapterDescriptor

This is a partial revert of https://go-review.googlesource.com/c/vscode-go/+/313049

CL/313049 attempted to complete the launch + connect before returning
from createDebugAdapterDescriptor call. The intention was to detect
the problems early enough and simplify the code path. But it turned out
VSCode does not fully initialize the debug session and its associated
resources such as a Debug Console before createDebugAdapterDescriptor
is complete. As a result, any log messages before the return are dropped
from Debug Console, which hurts usability/discoverability.

Revert the cl, but instead of lazily calling startAndConnectToServer
upon the very first sendMessageToServer call, call it from the
constructor.  We will need it anyway even when we disconnect
without sending any message before.

logDest test suite is temporarily disabled because the test
depends on createDebugAdapterDescriptor's failure when invalid
logDest is specified.

Change-Id: I980dd27e265133274b8f98bbfddc3a40160e115e
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/320432
Trust: Hyang-Ah Hana Kim <hyangah@gmail.com>
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Suzy Mueller <suzmue@golang.org>
diff --git a/src/goDebugFactory.ts b/src/goDebugFactory.ts
index 4bce258..41613a5 100644
--- a/src/goDebugFactory.ts
+++ b/src/goDebugFactory.ts
@@ -41,7 +41,6 @@
 		}
 		const logger = new TimestampedLogger(configuration.trace, this.outputChannel);
 		const d = new DelveDAPOutputAdapter(configuration, logger);
-		await d.startAndConnectToServer();
 		return new vscode.DebugAdapterInlineImplementation(d);
 	}
 }
@@ -196,14 +195,33 @@
 export class DelveDAPOutputAdapter extends ProxyDebugAdapter {
 	constructor(private config: vscode.DebugConfiguration, logger?: Logger) {
 		super(logger);
+		this.connected = this.startAndConnectToServer();
 	}
 
+	private connected: Promise<void>;
 	private dlvDapServer: ChildProcess;
 	private port: number;
 	private socket: net.Socket;
+	private terminatedOnError = false;
 
 	protected async sendMessageToServer(message: vscode.DebugProtocolMessage): Promise<void> {
-		super.sendMessageToServer(message);
+		try {
+			await this.connected;
+			super.sendMessageToServer(message);
+		} catch (err) {
+			if (this.terminatedOnError) {
+				return;
+			}
+			this.terminatedOnError = true;
+			// If there was an error connecting, show an error message and send a terminated event
+			// since we cannot start.
+			if (err) {
+				const errMsg = `Debug Error: ${err}`;
+				this.outputEvent('stderr', errMsg);
+				vscode.window.showErrorMessage(errMsg);
+			}
+			this.sendMessageToClient(new TerminatedEvent());
+		}
 	}
 
 	async dispose(timeoutMS?: number) {
@@ -213,6 +231,10 @@
 		if (!this.dlvDapServer) {
 			return;
 		}
+		if (this.connected === undefined) {
+			return;
+		}
+		this.connected = undefined;
 
 		if (timeoutMS === undefined || timeoutMS < 0) {
 			timeoutMS = 1_000;
@@ -245,7 +267,7 @@
 		});
 	}
 
-	public async startAndConnectToServer() {
+	private async startAndConnectToServer() {
 		const { port, host, dlvDapServer } = await startDapServer(
 			this.config,
 			(msg) => this.outputEvent('stdout', msg),
diff --git a/test/integration/goDebug.test.ts b/test/integration/goDebug.test.ts
index b9c81d5..d2db3dc 100644
--- a/test/integration/goDebug.test.ts
+++ b/test/integration/goDebug.test.ts
@@ -1760,7 +1760,7 @@
 		});
 	});
 
-	suite('logDest attribute tests', () => {
+	suite.skip('logDest attribute tests', () => {
 		const PROGRAM = path.join(DATA_ROOT, 'baseTest');
 
 		let tmpDir: string;
@@ -2033,7 +2033,6 @@
 class DelveDAPDebugAdapterOnSocket extends proxy.DelveDAPOutputAdapter {
 	static async create(config: DebugConfiguration) {
 		const d = new DelveDAPDebugAdapterOnSocket(config);
-		await d.startAndConnectToServer();
 		return d;
 	}