[release] prepare v0.24.1 release

ec040a9 .github/release_plan.md: add a template for the release plan
ce52d04 src/goTools: update dlv-dap latest version
18e3636 package.json: sync gopls settings to match v0.6.10
4948401 src/goDebugFactory.ts: send terminated event on server start error
6f9c0eb docs/dlv-dap.md: include go.delveConfig setting for debugAdapter
337ae93 src/testUtils: tighten test function detection regex
bded07b src/goDebugConfiguration.ts: clean up launch.json quickpick
c189ec0 src/goTest.ts: allow users to select default debug adapter
d5c8951 test/integration/goDebug: enable noDebug tests for dlv dap
44b7d36 src/goDebugConfiguration: clean up launch config snippets
d6e513e src/goDebugFactory.ts: fix output event destination
1d549a2 src/goInstallTools: linkify dlv-dap installation instruction
1cacf9d docs/dlv-dap: add the link to the list of dlv-dap only features
66b684a test/integration/goDebug.test.ts: add test for runtime error
25d2981 CHANGELOG.md: for v0.24.0
d7f3a5a package.json/package-lock.json: update dev version
505f363 src/goTools: update latest version of dlv-dap
8e70c58 src/goInstallTools.ts: update install instructions for dlv-dap
33339e6 test/integration/goDebug.test.ts: remove '.only' from test
d1ca321 test/integration/goDebug.test.ts: enable switch goroutine test dap
d9fca4d src/goInstallTools: remove dlv-dap from missing tools
f56b715 src/goDebugFactory: output dlv dap command as console output event
471ed7e test/integration: use DelveDAPOutputAdapter in dlv-dap mode testing
f8f5433 src/goDebugFactory: wait before killing the spawned dap server
e545b83 test/integration: disable broken tests
afbc36c .github/workflows: correct lint check condition
42de993 docs/dlv-dap: update installation instruction

Change-Id: I0ad0961a4980471cd2d20cb1c5d959a06f612ef8
diff --git a/.github/release_plan.md b/.github/release_plan.md
new file mode 100644
index 0000000..571894e
--- /dev/null
+++ b/.github/release_plan.md
@@ -0,0 +1,39 @@
+# Release candidate (DATE)
+
+-   [ ] Announce the release, leave enough time for teams to surface any last minute issues that need to get in before freeze. Make sure debugger and gopls teams are looped in as well.
+-   [ ] Create a milestone with the issues that are fixed by this release
+-	[ ] Update `master` for the release
+	-	[ ] Update hardcoded latest version for `dlv-dap` and `gopls`
+-   [ ] Update `release` for the release
+    -   [ ] Create a branch against `release` for a pull request
+    -   [ ] Merge changes from `master` to prepare for the release
+    -   [ ] Change the version in [`package.json`](https://github.com/golang/vscode-go/blob/master/package.json) from a `-dev` suffix
+    -   [ ] Run `npm install` to make sure [`package-lock.json`](https://github.com/golang/vscode-go/blob/master/package.json) is up-to-date
+    -   [ ] Update the license file (`$ tools/license.sh; mv LICENSE.prod LICENSE`)
+	-   [ ] Update [`CHANGELOG.md`](https://github.com/golang/vscode-go/blob/master/CHANGELOG.md)
+        -   [ ] Make sure the "Thanks" section is up-to-date
+        -   [ ] Check the Markdown rendering to make sure everything looks good
+-   [ ] Check the [Long Tests status](https://github.com/golang/vscode-go/actions?query=workflow%3A%22Long+Tests%22)  is green. Otherwise, fix the tests, send cls for review, submit them, and repeat. 
+-   [ ] Perform manual [smoke tests]( https://github.com/golang/vscode-go/blob/master/docs/smoke-test.md)
+-   [ ] Create new version tag for X.XX.X-rc.1 at gerrit’s vscode-go [repo management page](https://go-review.googlesource.com/admin/repos/vscode-go,tags)
+-   [ ] Go to the release page https://github.com/golang/vscode-go/releases and check if the new release candidate is up. If necessary, you can manually edit the comment by clicking the “Edit” button. Don’t mutate uploaded vsix.
+-   [ ] Ask editor team and contributors to this release to test the release candidate
+
+# Release Candidate >1 (if necessary)
+- 	 ] Fix any bugs on `master` and cherry pick changes to `release
+-   [ ] Create new version tag for X.XX.X-rc.1 at gerrit’s vscode-go [repo management page](https://go-review.googlesource.com/admin/repos/vscode-go,tags)
+-   [ ] Go to the release page https://github.com/golang/vscode-go/releases and check if the new release candidate is up. If necessary, you can manually edit the comment by clicking the “Edit” button. Don’t mutate uploaded vsix.
+-   [ ] Ask editor team and contributors to this release to test the release candidate
+
+
+# Final (DATE)
+-	[ ] Tag the new release
+-	[ ] Update the release description with CHANGELOG contents
+-	[ ] Close the milestone
+
+# Prepare for the Next Release
+-   [ ] Update `master` post-release
+    -   [ ] Bump the version number to the next monthly ("X.XX.X-dev") release in the `master` branch
+        -   [ ] `package.json`
+        -   [ ] `package-lock.json`
+    -   [ ] Cherry pick CHANGELOG.md back to master
diff --git a/.github/workflows/test-long-all.yml b/.github/workflows/test-long-all.yml
index d6f8d08..20ea53c 100644
--- a/.github/workflows/test-long-all.yml
+++ b/.github/workflows/test-long-all.yml
@@ -79,4 +79,4 @@
 
       - name: Lint check
         run: npm run lint
-        if: ${{ matrix.os }} == 'ubuntu-latest' && ${{ matrix.version }} == 'stable' && !contains(${{ matrix.go }}, "beta") && !contains(${{ matrix.go }}, "rc")
+        if: ${{ matrix.os == 'ubuntu-latest' && matrix.version == 'stable' }}
diff --git a/.github/workflows/test-long.yml b/.github/workflows/test-long.yml
index 3d04297..fa77e01 100644
--- a/.github/workflows/test-long.yml
+++ b/.github/workflows/test-long.yml
@@ -76,4 +76,4 @@
       
       - name: Lint check
         run: npm run lint
-        if: ${{ matrix.os }} == 'ubuntu-latest'
+        if: ${{ matrix.os == 'ubuntu-latest' && matrix.version == 'stable' }}
diff --git a/.github/workflows/test-smoke.yml b/.github/workflows/test-smoke.yml
index e8e5276..523d40a 100644
--- a/.github/workflows/test-smoke.yml
+++ b/.github/workflows/test-smoke.yml
@@ -74,4 +74,4 @@
 
       - name: Lint check
         run: npm run lint
-        if: ${{ matrix.os }} == 'ubuntu-latest'
+        if: ${{ matrix.os == 'ubuntu-latest' && matrix.version == 'stable' }}
diff --git a/docs/debugging.md b/docs/debugging.md
index 561660f..a66ae0d 100644
--- a/docs/debugging.md
+++ b/docs/debugging.md
@@ -2,6 +2,8 @@
 
 This document explains how to debug your Go programs in VS Code. The Go debugger is [Delve]. You can read more about it in the [Delve documentation](https://github.com/go-delve/delve/tree/master/Documentation).
 
+📣 Integration with the [Delve's native DAP implementation](https://github.com/golang/vscode-go/tree/master/docs/dlv-dap.md) is available for preview. Please give it a try and provide feedback!
+
 ## Overview
 
 * [Set up](#set-up)
@@ -172,7 +174,7 @@
 
 #### Debug the current file (`Go: Launch file`)
 
-Recall that `${file}` refers to the currently opened file (see [Using VS Code Variables](#using-vs-code-variables)).
+Recall that `${file}` refers to the currently opened file (see [Using VS Code Variables](#using-vs-code-variables)). For debugging a package that consists with multiple files, use `${fileDirname}` instead.
 
 ```json5
 {
@@ -204,7 +206,8 @@
 
 #### Debug all tests in the given package (`Go: Launch test package`)
 
-Recall that `${workspaceFolder}` refers to the current workspace (see [Using VS Code Variables](#using-vs-code-variables)).
+A package is a collection of source files in the same directory that are compiled together.
+Recall that `${fileDirname}` refers to the directory of the open file (see [Using VS Code Variables](#using-vs-code-variables)).
 
 ```json5
 {
diff --git a/docs/dlv-dap.md b/docs/dlv-dap.md
index b840cc4..7a4d91f 100644
--- a/docs/dlv-dap.md
+++ b/docs/dlv-dap.md
@@ -1,26 +1,23 @@
-# Dlv DAP - Delve's native DAP implementationa
+# Dlv DAP - Delve's native DAP implementation
 
 [`Delve`'s native DAP implementation](https://github.com/go-delve/delve/tree/master/service/dap) is now available to be used to debug Go programs.
 
-This debug adapter runs in a separate `go` process, which is spawned by VS Code when you debug Go code. Since `dlv dap` is under active development, we recommend that `dlv` be installed at master to get all recent updates.
+_________________
+**🔥 This new adapter is still in active development, so to take advantage of the most recent features and bug fixes, you need to use Delve built from the dev branch. When the extension asks to install/update `dlv-dap`, please follow the instruction and rebuild the tool.**
+_________________
 
-```
-$ GO111MODULES=on go get github.com/go-delve/delve@master
-```
+The Go extension currently maintains this development version of Delve separately from the stable version of `dlv`. This version is installed with the name `dlv-dap`. Please follow the instruction in [Getting Started](#getting-started) to configure the extension and install `dlv-dap`.
 
-Please see the [Debug Adapter Protocol (DAP)](https://microsoft.github.io/debug-adapter-protocol/) to understand how the Debug Adapter acts as an intermediary between VS Code and the debugger ([Delve](https://github.com/go-delve/delve)).
+This new debug adapter runs in a separate `go` process, which is spawned by VS Code when you debug Go code.
+Please see the [Debug Adapter Protocol (DAP)](https://microsoft.github.io/debug-adapter-protocol/) to learn about how the Debug Adapter acts as an intermediary between VS Code and the debugger ([Delve](https://github.com/go-delve/delve)).
 
-Follow along with [golang/vscode-go#23](https://github.com/golang/vscode-go/issues/23) and the [project dashboard](https://github.com/golang/vscode-go/projects/3) for updates on the implementation.
 
-## Overview
+## Getting Started
 
-* [How to use dlv dap](#how-to-use-dlv-dap)
+You can select the default debug adapter to use in all launch configurations and codelenses through the `"debugAdapter"` field in the [`"go.delveConfig"`](settings.md#go.delveConfig) setting. You can choose which debug adapter to use for individual launch configurations with the `"debugAdapter"` field in [your `launch.json` configuration](https://github.com/golang/vscode-go/blob/master/docs/debugging.md#snippets). Most settings will continue to work with in this new `"dlv-dap"` mode except [a few caveats](#features-and-caveats).
+If you do not already have a `launch.json`, select `create a launch.json file` from the debug pane and choose an initial Go debug configuration.
 
-## How to use dlv dap
-
-You can choose which debug adapter to use with the `"debugAdapter"` field in your launch configuration. If you do not already have a `launch.json`, select `create a launch.json file` from the debug pane and choose an initial Go debug configuration.
-
-<div style="text-align: center;"><img src="images/createlaunchjson.png" alt="The debug pane with the option to create launch.json"> </div>
+<div style="text-align: center;"><img src="images/createlaunchjson.png" width=200 alt="The debug pane with the option to create launch.json"> </div>
 
 In your launch configuration, set the `"debugAdapter"` field to be `"dlv-dap"`. For example, a launch configuration for a file would look like:
 
@@ -30,9 +27,110 @@
     "type": "go",
     "request": "launch",
     "mode": "auto",
-    "program": "${file}",
+    "program": "${fileDirname}",
     "debugAdapter": "dlv-dap"
 }
 ```
 
-To switch back to the legacy adapter, set `"debugAdapter"` to `"legacy"`.
\ No newline at end of file
+To switch back to the legacy adapter, set `"debugAdapter"` to `"legacy"`.
+
+When you start debugging using the configuration for the first time, the extension will ask you to install `dlv-dap`.
+
+<div style="text-align: center;"><img src="images/dlv-dap-install-prompt.gif" width=350 alt="missing tool notification"> </div>
+
+Once `dlv-dap` is installed, the extension will prompt you for update whenever installing a newer version is necessary (usually after the Go extension update).
+
+### Updating dlv dap
+The easiest way is to use the `"Go: Install/Update Tools"` command from the command palette (⇧+⌘+P or Ctrl+Shift+P). The command will show `dlv-dap` in the tool list. Select it, and the extension will build the tool at master.
+
+If you want to install it manually, `go get` with the following command and rename it to `dlv-dap`.
+
+```
+$ GO111MODULE=on GOBIN=/tmp/ go get github.com/go-delve/delve/cmd/dlv@master
+$ mv /tmp/dlv $GOPATH/bin/dlv-dap
+```
+
+## Features and Caveats
+<!-- TODO: update the debugging section of features.md using dlv-dap mode -->
+
+🎉  The new debug adapter offers many improvements and fixes bugs that existed in the old adapter. [Here](https://github.com/golang/vscode-go/issues?q=is%3Aissue+label%3Afixedindlvdaponly) is a partial list of enhancement/fixes available only in the new adapter.
+
+* User-friendly inlined presentation of variables of all complex types (map, struct, pointer, array, slice, ...)
+* Fixed handling of maps with compound keys
+* Improved CALL STACK presentation
+* Fixed automated "Add to Watch" / "Copy as Expression" expressions.
+* Support to switch goroutines while stepping.
+* Robust `call` evaluation.
+* Good test coverage.
+
+
+Most of all, the new adapter is written in Go and integrated in `dlv`. That will make it easier for the Go community to contribute. </br>
+Because it is native, we hope for improvement in speed and reliability.
+
+⚒️ The following features are still under development. 
+
+* Stop/pause/restart while the debugged program is running does not work yet.
+* Cannot be used with `debug test` codelens.
+* Support for `"dlvFlags"` attributes in launch configuration is not available.
+* `dlvLoadConfig` to configure max string/bytes length in [`"go.delveConfig"`](https://github.com/golang/vscode-go/blob/master/docs/debugging.md#configuration) does not work.
+* [Remote debugging](https://github.com/golang/vscode-go/blob/master/docs/debugging.md#remote-debugging) is not supported.
+
+Follow along with [golang/vscode-go#23](https://github.com/golang/vscode-go/issues/23) and the [project dashboard](https://github.com/golang/vscode-go/projects/3) for updates on the implementation.
+
+## Reporting issues
+
+The VS Code Go maintainers are reachable via the issue tracker and the #vscode-dev channel in the Gophers Slack. </br>
+Please reach out on Slack with questions, suggestions, or ideas. If you have trouble getting started on an issue, we'd be happy to give pointers and advice.
+
+When you are having issues in `dlv-dap` mode, first check if the problems are reproducible after updating `dlv-dap`. It's possible that the issues are already fixed. Follow the instruction for [updating dlv-dap](#updating-dlv-dap)) and [updating extension](https://code.visualstudio.com/docs/editor/extension-gallery#_extension-autoupdate).
+
+Please report issues in [our issue tracker](https://github.com/golang/vscode-go/issues) with the following information.
+
+* `go version`
+* `go version -m dlv-dap`
+* VS Code and VS Code Go version.
+* Instruction to reproduce the issue (code snippets, your `launch.json`, screenshot)
+
+## Developing
+
+### Code location
+The core part of Delve DAP implementation is in the [`service/dap`](https://github.com/go-delve/delve/tree/master/service/dap) package. Follow Delve project's [contribution guideline](https://github.com/go-delve/delve/blob/master/CONTRIBUTING.md#contributing-code) to send PRs.
+Code for integration with the Go extension is mostly in [`src/goDebugFactory.ts`](https://github.com/golang/vscode-go/blob/master/src/goDebugFactory.ts) and tests are in [`test/integration/goDebug.test.ts`](https://github.com/golang/vscode-go/blob/master/test/integration/goDebug.test.ts). Please take a look at VS Code Go project's [contribution guideline](https://github.com/golang/vscode-go/blob/master/docs/contributing.md) to learn about how to prepare a change and send it for review.
+
+### Testing
+For simple launch cases, build the delve binary, and configure `"go.alternateTools"` setting.
+
+```json5
+"go.alternateTools": {
+    "dlv-dap": <path_to_your_delve>
+}
+```
+
+Set `logOutput` and `showLog` attributes in `launch.json` to enable logging and DAP message tracing.
+```json5
+{
+    "name": "Launch file",
+    "type": "go",
+    "debugAdapter": "dlv-dap",
+    "showLog": true,
+    "logOutput": "dap",
+    ...
+}
+```
+
+If you are having issues with seeing logs and or suspect problems in extension's integration, you can start Delve DAP server from a separate terminal and configure the extension to directly connect to it.
+
+```
+$ dlv-dap dap --listen=:12345 --log-output=dap
+```
+
+```json5
+{
+    "name": "Launch file",
+    "type": "go",
+    "request": "launch",
+    "debugAdapter": "dlv-dap",
+    ...
+    "port": 12345
+}
+```
diff --git a/docs/images/dlv-dap-install-prompt.gif b/docs/images/dlv-dap-install-prompt.gif
new file mode 100644
index 0000000..03c9c9e
--- /dev/null
+++ b/docs/images/dlv-dap-install-prompt.gif
Binary files differ
diff --git a/docs/settings.md b/docs/settings.md
index e255a96..cd432d2 100644
--- a/docs/settings.md
+++ b/docs/settings.md
@@ -143,6 +143,7 @@
 | Properties | Description |
 | --- | --- |
 | `apiVersion` | Delve Api Version to use. Default value is 2. <br/> Allowed Options: `1`, `2` <br/> Default: `2` |
+| `debugAdapter` | Select which debug adapter to use by default. This is also used for choosing which debug adapter to use when no launch.json is present and with codelenses. <br/> Allowed Options: `legacy`, `dlv-dap` <br/> Default: `"legacy"` |
 | `dlvLoadConfig` | LoadConfig describes to delve, how to load values from target's memory <br/> Default: ``` { <pre>"followPointers" :	true,<br/>"maxArrayValues" :	64,<br/>"maxStringLen" :	64,<br/>"maxStructFields" :	-1,<br/>"maxVariableRecurse" :	1,</pre>} ``` |
 | `showGlobalVariables` | Boolean value to indicate whether global package variables should be shown in the variables pane or not. <br/> Default: `false` |
 
@@ -150,6 +151,7 @@
 ```
 {
 	"apiVersion" :	2,
+	"debugAdapter" :	"legacy",
 	"dlvLoadConfig" :		{
 		"followPointers" :	true,
 		"maxArrayValues" :	64,
@@ -598,6 +600,13 @@
 
 
 Default: `"100ms"`
+### `ui.completion.experimentalPostfixCompletions`
+
+(Experimental) experimentalPostfixCompletions enables artifical method snippets
+such as "someSlice.sort!".
+
+
+Default: `false`
 ### `ui.completion.matcher`
 
 (Advanced) matcher sets the algorithm that is used when calculating completion
diff --git a/docs/tools.md b/docs/tools.md
index 49137e5..90d391b 100644
--- a/docs/tools.md
+++ b/docs/tools.md
@@ -35,6 +35,8 @@
 
 For a comprehensive overview of how to debug your Go programs, please see the [debugging guide](./debugging.md).
 
+### [`dlv-dap`](https://github.com/go-delve/delve)
+This extension requires an unstable version of [`dlv`](#dlv) when users opt in to use Delve's native DAP implementation. `dlv-dap` is a `dlv` built from the master, which includes unreleased features. Please see the documentation about [Dlv DAP - Delve's Native DAP implementation](./dlv-dap.md) for details.
 
 ### [`gopkgs`](https://pkg.go.dev/github.com/uudashr/gopkgs?tab=overview)
 
diff --git a/package-lock.json b/package-lock.json
index dd07020..f00776f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "go",
-  "version": "0.24.0",
+  "version": "0.24.1",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "go",
-      "version": "0.24.0",
+      "version": "0.24.1",
       "license": "MIT",
       "dependencies": {
         "deep-equal": "^2.0.2",
diff --git a/package.json b/package.json
index 7a2a17c..986d1da 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "go",
   "displayName": "Go",
-  "version": "0.24.0",
+  "version": "0.24.1",
   "publisher": "golang",
   "description": "Rich Go language support for Visual Studio Code",
   "author": {
@@ -428,12 +428,12 @@
         "configurationSnippets": [
           {
             "label": "Go: Launch package",
-            "description": "Debug the package in the program attribute",
+            "description": "Debug/test the package in the program attribute",
             "body": {
               "name": "${2:Launch Package}",
               "type": "go",
               "request": "launch",
-              "mode": "debug",
+              "mode": "auto",
               "program": "^\"\\${workspaceFolder}${1:}\""
             }
           },
@@ -449,17 +449,6 @@
             }
           },
           {
-            "label": "Go: Launch test package",
-            "description": "Debug the test package in the program attribute",
-            "body": {
-              "name": "${2:Launch test package}",
-              "type": "go",
-              "request": "launch",
-              "mode": "test",
-              "program": "^\"\\${workspaceFolder}${1:}\""
-            }
-          },
-          {
             "label": "Go: Launch test function",
             "description": "Debug the test function in the args, ensure program attributes points to right package",
             "body": {
@@ -1701,6 +1690,15 @@
               "type": "boolean",
               "description": "Boolean value to indicate whether global package variables should be shown in the variables pane or not.",
               "default": false
+            },
+            "debugAdapter": {
+              "type": "string",
+              "enum": [
+                "legacy",
+                "dlv-dap"
+              ],
+              "description": "Select which debug adapter to use by default. This is also used for choosing which debug adapter to use when no launch.json is present and with codelenses.",
+              "default": "legacy"
             }
           },
           "default": {
@@ -1712,7 +1710,8 @@
               "maxStructFields": -1
             },
             "apiVersion": 2,
-            "showGlobalVariables": false
+            "showGlobalVariables": false,
+            "debugAdapter": "legacy"
           },
           "description": "Delve settings that applies to all debugging sessions. Debug configuration in the launch.json file will override these values.",
           "scope": "resource"
@@ -1861,6 +1860,12 @@
               "default": "100ms",
               "scope": "resource"
             },
+            "ui.completion.experimentalPostfixCompletions": {
+              "type": "boolean",
+              "markdownDescription": "(Experimental) experimentalPostfixCompletions enables artifical method snippets\nsuch as \"someSlice.sort!\".\n",
+              "default": false,
+              "scope": "resource"
+            },
             "ui.completion.matcher": {
               "type": "string",
               "markdownDescription": "(Advanced) matcher sets the algorithm that is used when calculating completion\ncandidates.\n",
diff --git a/src/goDebugConfiguration.ts b/src/goDebugConfiguration.ts
index 5894790..0dcef51 100644
--- a/src/goDebugConfiguration.ts
+++ b/src/goDebugConfiguration.ts
@@ -34,57 +34,14 @@
 	public async pickConfiguration(): Promise<vscode.DebugConfiguration[]> {
 		const debugConfigurations = [
 			{
-				label: 'Go: Launch package',
-				description: 'Debug the package in the program attribute',
+				label: 'Go: Launch Package',
+				description: 'Debug/test the package of the open file',
 				config: {
 					name: 'Launch Package',
 					type: this.defaultDebugAdapterType,
 					request: 'launch',
-					mode: 'debug',
-					program: '${workspaceFolder}'
-				}
-			},
-			{
-				label: 'Go: Launch file',
-				description: 'Debug the file in the program attribute',
-				config: {
-					name: 'Launch file',
-					type: 'go',
-					request: 'launch',
-					mode: 'debug',
-					program: '${file}'
-				}
-			},
-			{
-				label: 'Go: Launch test package',
-				description: 'Debug the test package in the program attribute',
-				config: {
-					name: 'Launch test package',
-					type: 'go',
-					request: 'launch',
-					mode: 'test',
-					program: '${workspaceFolder}'
-				}
-			},
-			{
-				label: 'Go: Launch test function',
-				description: 'Debug the test function in the args, ensure program attributes points to right package',
-				config: {
-					name: 'Launch test function',
-					type: 'go',
-					request: 'launch',
-					mode: 'test',
-					program: '${workspaceFolder}',
-					args: ['-test.run', 'MyTestFunction']
-				},
-				fill: async (config: vscode.DebugConfiguration) => {
-					const testFunc = await vscode.window.showInputBox({
-						placeHolder: 'MyTestFunction',
-						prompt: 'Name of the function to test'
-					});
-					if (testFunc) {
-						config.args = ['-test.run', testFunc];
-					}
+					mode: 'auto',
+					program: '${fileDirname}'
 				}
 			},
 			{
@@ -207,6 +164,9 @@
 			// expand 'cwd' folder path containing '~', which would cause dlv to fail
 			debugConfiguration['cwd'] = resolvePath(debugConfiguration['cwd']);
 		}
+		if (!debugConfiguration.hasOwnProperty('debugAdapter') && dlvConfig.hasOwnProperty('debugAdapter')) {
+			debugConfiguration['debugAdapter'] = dlvConfig['debugAdapter'];
+		}
 
 		// Remove any '--gcflags' entries and show a warning
 		if (debugConfiguration['buildFlags']) {
diff --git a/src/goDebugFactory.ts b/src/goDebugFactory.ts
index 9ad0e25..47c79be 100644
--- a/src/goDebugFactory.ts
+++ b/src/goDebugFactory.ts
@@ -51,8 +51,9 @@
 // start method is called.
 export class ProxyDebugAdapter implements vscode.DebugAdapter {
 	private messageEmitter = new vscode.EventEmitter<vscode.DebugProtocolMessage>();
-	// connection to server.
-	private conn?: stream.Duplex;
+	// connection from/to server (= dlv dap)
+	private readable?: stream.Readable;
+	private writable?: stream.Writable;
 
 	constructor() {
 		this.onDidSendMessage = this.messageEmitter.event;
@@ -63,13 +64,6 @@
 	// listen on onDidSendMessage to receive messages.
 	onDidSendMessage: vscode.Event<vscode.DebugProtocolMessage>;
 	async handleMessage(message: vscode.DebugProtocolMessage): Promise<void> {
-		// TODO(hyangah): dlv dap often terminates before us
-		// receiving the disconnect response, which causes
-		// vscode to hang forever. Either generate a disconnect
-		// respond after timeout so vscode completes the normal
-		// debug session teardown including the call to this
-		// thin adapter's dispose() or change dlv dap not to
-		// kill itself until the client connection is closed.
 		await this.sendMessageToServer(message);
 	}
 
@@ -79,34 +73,37 @@
 	}
 	protected sendMessageToServer(message: vscode.DebugProtocolMessage): void {
 		const json = JSON.stringify(message) ?? '';
-		if (this.conn) {
-			this.conn.write(`Content-Length: ${Buffer.byteLength(json, 'utf8')}${TWO_CRLF}${json}`, 'utf8', (err) => {
-				if (err) {
-					console.log(`error sending message: ${err}`);
-					this.sendMessageToClient(new TerminatedEvent());
+		if (this.writable) {
+			this.writable.write(
+				`Content-Length: ${Buffer.byteLength(json, 'utf8')}${TWO_CRLF}${json}`,
+				'utf8',
+				(err) => {
+					if (err) {
+						console.log(`error sending message: ${err}`);
+						this.sendMessageToClient(new TerminatedEvent());
+					}
 				}
-			});
+			);
 		} else {
 			console.log(`stream is closed; dropping ${json}`);
 		}
 	}
 
-	public async start(server: stream.Duplex) {
-		if (this.conn) {
+	public async start(readable: stream.Readable, writable: stream.Writable) {
+		if (this.readable || this.writable) {
 			throw new Error('start was called more than once');
 		}
-		this.conn = server;
-		this.conn.on('data', (data: Buffer) => {
+		this.readable = readable;
+		this.writable = writable;
+		this.readable.on('data', (data: Buffer) => {
 			this.handleDataFromServer(data);
 		});
-		this.conn.once('close', () => {
-			console.log('stream closed');
-			this.conn.destroy();
-			this.conn = undefined;
+		this.readable.once('close', () => {
+			this.readable = undefined;
 		});
-		this.conn.on('error', (err) => {
-			console.log(`stream error: ${err}`);
+		this.readable.on('error', (err) => {
 			if (err) {
+				console.log(`stream error: ${err}`);
 				this.sendMessageToClient(new OutputEvent(`socket to network closed: ${err}`, 'console'));
 			}
 			this.sendMessageToClient(new TerminatedEvent());
@@ -114,11 +111,7 @@
 	}
 
 	async dispose() {
-		if (this.conn) {
-			// TODO(hyangah): not sure if sleep is necessary.
-			await sleep(500);
-			this.conn?.destroy();
-		}
+		this.writable?.end(); // no more write.
 	}
 
 	private rawData = Buffer.alloc(0);
@@ -163,10 +156,6 @@
 	}
 }
 
-function sleep(ms: number) {
-	return new Promise((resolve) => setTimeout(resolve, ms));
-}
-
 // DelveDAPOutputAdapter is a ProxyDebugAdapter that proxies between
 // VSCode and a dlv dap process spawned and managed by this adapter.
 // It turns the process's stdout/stderrr into OutputEvent.
@@ -184,24 +173,56 @@
 		if (!this.connected) {
 			this.connected = this.startAndConnectToServer();
 		}
-		await this.connected;
-		super.sendMessageToServer(message);
+		try {
+			await this.connected;
+			super.sendMessageToServer(message);
+		} catch (err) {
+			// If there was an error connecting, show an error message
+			// and send a terminated event, since we cannot start.
+			if (err) {
+				const errMsg = `connect to server error: ${err}`;
+				this.sendMessageToClient(new OutputEvent(errMsg));
+				vscode.window.showErrorMessage(errMsg);
+			}
+			this.sendMessageToClient(new TerminatedEvent());
+		}
 	}
 
 	async dispose() {
-		console.log(`DelveDAPOutputAdapter.dispose ${this.dlvDapServer?.pid}`);
-		super.dispose();
-		if (this.connected) {
-			killProcessTree(this.dlvDapServer);
-			this.connected = undefined;
+		await super.dispose();
+
+		if (this.connected === undefined) {
+			return;
 		}
+		this.connected = undefined;
+		const dlvDapServer = this.dlvDapServer;
+		if (!dlvDapServer) {
+			return;
+		}
+		if (dlvDapServer.exitCode !== null) {
+			console.log(`dlv dap process(${dlvDapServer.pid}) exited ${dlvDapServer.exitCode}`);
+			return;
+		}
+		await new Promise<void>((resolve) => {
+			const exitTimeoutToken = setTimeout(() => {
+				console.log(`killing dlv dap process(${dlvDapServer.pid}) after 1sec`);
+				killProcessTree(dlvDapServer);
+				resolve();
+			}, 1_000);
+			dlvDapServer.on('exit', () => {
+				console.log(`dlv dap process(${dlvDapServer.pid}) exited`);
+				clearTimeout(exitTimeoutToken);
+				resolve();
+			});
+		});
 	}
 
 	private async startAndConnectToServer() {
 		const { port, host, dlvDapServer } = await startDapServer(
 			this.config,
-			(msg) => this.stdoutEvent(msg),
-			(msg) => this.stderrEvent(msg)
+			(msg) => this.outputEvent('stdout', msg),
+			(msg) => this.outputEvent('stderr', msg),
+			(msg) => this.outputEvent('console', msg)
 		);
 		const socket = await new Promise<net.Socket>((resolve, reject) => {
 			// eslint-disable-next-line prefer-const
@@ -212,37 +233,29 @@
 			});
 			timer = setTimeout(() => {
 				reject('connection timeout');
-				console.log('failed to connect within 1s');
 				s?.destroy();
-				killProcessTree(dlvDapServer);
 			}, 1000);
 		});
 
 		this.dlvDapServer = dlvDapServer;
 		this.port = port;
 		this.socket = socket;
-		this.start(this.socket);
+		this.start(this.socket, this.socket);
 	}
 
-	stdoutEvent(output: string, data?: any) {
-		this.sendMessageToClient(new OutputEvent(output, 'stdout', data));
+	private outputEvent(dest: string, output: string, data?: any) {
+		this.sendMessageToClient(new OutputEvent(output, dest, data));
 		if (this.outputToConsole) {
 			console.log(output);
 		}
 	}
-
-	stderrEvent(output: string, data?: any) {
-		this.sendMessageToClient(new OutputEvent(output, 'stderr', data));
-		if (this.outputToConsole) {
-			console.error(output);
-		}
-	}
 }
 
 export async function startDapServer(
 	configuration: vscode.DebugConfiguration,
 	log?: (msg: string) => void,
-	logErr?: (msg: string) => void
+	logErr?: (msg: string) => void,
+	logConsole?: (msg: string) => void
 ): Promise<{ port: number; host: string; dlvDapServer?: ChildProcessWithoutNullStreams }> {
 	const host = configuration.host || '127.0.0.1';
 
@@ -258,7 +271,10 @@
 	if (!logErr) {
 		logErr = appendToDebugConsole;
 	}
-	const dlvDapServer = await spawnDlvDapServerProcess(configuration, host, port, log, logErr);
+	if (!logConsole) {
+		logConsole = appendToDebugConsole;
+	}
+	const dlvDapServer = await spawnDlvDapServerProcess(configuration, host, port, log, logErr, logConsole);
 	return { dlvDapServer, port, host };
 }
 
@@ -267,17 +283,18 @@
 	host: string,
 	port: number,
 	log: (msg: string) => void,
-	logErr: (msg: string) => void
+	logErr: (msg: string) => void,
+	logConsole: (msg: string) => void
 ): Promise<ChildProcess> {
 	const launchArgsEnv = launchArgs.env || {};
 	const env = Object.assign({}, process.env, launchArgsEnv);
 
-	const dlvPath = launchArgs.dlvToolPath ?? getTool('dlv');
+	const dlvPath = launchArgs.dlvToolPath ?? getTool('dlv-dap');
 
 	if (!fs.existsSync(dlvPath)) {
 		const envPath = process.env['PATH'] || (process.platform === 'win32' ? process.env['Path'] : null);
 		logErr(
-			`Couldn't find dlv at the Go tools path, ${process.env['GOPATH']}${
+			`Couldn't find dlv-dap at the Go tools path, ${process.env['GOPATH']}${
 				env['GOPATH'] ? ', ' + env['GOPATH'] : ''
 			} or ${envPath}`
 		);
@@ -299,7 +316,7 @@
 	if (launchArgs.logOutput) {
 		dlvArgs.push('--log-output=' + launchArgs.logOutput);
 	}
-	log(`Running: ${dlvPath} ${dlvArgs.join(' ')}`);
+	logConsole(`Running: ${dlvPath} ${dlvArgs.join(' ')}\n`);
 
 	const dir = parseProgramArgSync(launchArgs).dirname;
 	// TODO(hyangah): determine the directories:
@@ -330,6 +347,12 @@
 
 		p.stdout.on('data', (chunk) => {
 			if (!started) {
+				// TODO(hyangah): when --log-dest is specified, the following message
+				// will be written to the log dest file, not stdout/stderr.
+				// Either disable --log-dest, or take advantage of it, i.e.,
+				// always pass a file descriptor to --log-dest, watch the file
+				// descriptor to process the log output, and also swap os.Stdout/os.Stderr
+				// in dlv dap for launch requests to generate proper OutputEvents.
 				if (chunk.toString().startsWith('DAP server listening at:')) {
 					stopWaitingForServerToStart();
 				} else {
@@ -347,13 +370,12 @@
 			logErr(chunk.toString());
 		});
 		p.on('close', (code) => {
+			// TODO: should we watch 'exit' instead?
 			if (!started) {
 				stopWaitingForServerToStart(`dlv dap closed with code: '${code}' signal: ${p.killed}`);
 			}
 			if (code) {
 				logErr(`Process exiting with code: ${code} signal: ${p.killed}`);
-			} else {
-				log(`Process exited normally: ${p.killed}`);
 			}
 		});
 		p.on('error', (err) => {
diff --git a/src/goInstallTools.ts b/src/goInstallTools.ts
index 542eac6..ebf9be2 100644
--- a/src/goInstallTools.ts
+++ b/src/goInstallTools.ts
@@ -355,8 +355,12 @@
 		// Offer the option to install all tools.
 		installOptions.push('Install All');
 	}
-	const msg = `The "${tool.name}" command is not available.
+	let msg = `The "${tool.name}" command is not available.
 Run "go get -v ${getImportPath(tool, goVersion)}" to install.`;
+	if (tool.name === 'dlv-dap') {
+		msg = `The ["${tool.name}"](https://github.com/golang/vscode-go/blob/master/docs/dlv-dap.md) command is not available.
+Please select "Install", or follow the installation instructions [here](https://github.com/golang/vscode-go/blob/master/docs/dlv-dap.md#updating-dlv-dap).`;
+	}
 	const selected = await vscode.window.showErrorMessage(msg, ...installOptions);
 	switch (selected) {
 		case 'Install':
diff --git a/src/goTest.ts b/src/goTest.ts
index e103391..d1cb29f 100644
--- a/src/goTest.ts
+++ b/src/goTest.ts
@@ -196,8 +196,8 @@
 		name: 'Debug Test',
 		type: 'go',
 		request: 'launch',
-		mode: 'auto',
-		program: editor.document.fileName,
+		mode: 'test',
+		program: path.dirname(editor.document.fileName),
 		env: goConfig.get('testEnvVars', {}),
 		envFile: goConfig.get('testEnvFile'),
 		args,
diff --git a/src/goTools.ts b/src/goTools.ts
index 8a61b7b..9cf93fb 100644
--- a/src/goTools.ts
+++ b/src/goTools.ts
@@ -450,8 +450,8 @@
 		description: 'Go debugger (Delve built for DAP experiment)',
 		defaultVersion: 'master', // Always build from the master.
 		minimumGoVersion: semver.coerce('1.14'), // last 3 versions per delve policy
-		latestVersion: semver.parse('v1.6.1-0.20210325164530-b120b11cc383'),
-		latestVersionTimestamp: moment('2021-03-25', 'YYYY-MM-DD')
+		latestVersion: semver.parse('1.6.1-0.20210414072240-747f03788315'),
+		latestVersionTimestamp: moment('2021-04-14', 'YYYY-MM-DD')
 	},
 	'fillstruct': {
 		name: 'fillstruct',
diff --git a/src/testUtils.ts b/src/testUtils.ts
index 2433a4b..77e812d 100644
--- a/src/testUtils.ts
+++ b/src/testUtils.ts
@@ -32,9 +32,14 @@
  */
 const runningTestProcesses: cp.ChildProcess[] = [];
 
-const testFuncRegex = /^Test.*|^Example.*/;
-const testMethodRegex = /^\(([^)]+)\)\.(Test.*)$/;
-const benchmarkRegex = /^Benchmark.*/;
+// https://github.com/golang/go/blob/117b1c84d3678a586c168a5f7f2f0a750c27f0c2/src/cmd/go/internal/load/test.go#L487
+// uses !unicode.isLower to find test/example/benchmark functions.
+// There could be slight difference between \P{Ll} (not lowercase letter)
+// & go unicode package's uppercase detection. But hopefully
+// these will be replaced by gopls's codelens computation soon.
+const testFuncRegex = /^Test\P{Ll}.*|^Example\P{Ll}.*/u;
+const testMethodRegex = /^\(([^)]+)\)\.(Test\P{Ll}.*)$/u;
+const benchmarkRegex = /^Benchmark\P{Ll}.*/u;
 
 /**
  * Input to goTest.
diff --git a/test/integration/codelens.test.ts b/test/integration/codelens.test.ts
index bee6b27..bbe2f61 100644
--- a/test/integration/codelens.test.ts
+++ b/test/integration/codelens.test.ts
@@ -129,4 +129,21 @@
 			assert.equal(codeLenses[i].command.command, wantCommands[i]);
 		}
 	});
+
+	test('Test codelenses include only valid test function names', async () => {
+		const uri = vscode.Uri.file(path.join(fixturePath, 'codelens2_test.go'));
+		const benchmarkDocument = await vscode.workspace.openTextDocument(uri);
+		const codeLenses = await codeLensProvider.provideCodeLenses(benchmarkDocument, cancellationTokenSource.token);
+		assert.equal(codeLenses.length, 12, JSON.stringify(codeLenses, null, 2));
+		const found = [] as string[];
+		for (let i = 0; i < codeLenses.length; i++) {
+			const lens = codeLenses[i];
+			if (lens.command.command === 'go.test.cursor') {
+				found.push(lens.command.arguments[0].functionName);
+			}
+		}
+		found.sort();
+		// Results should match `go test -list`.
+		assert.deepStrictEqual(found, ['Test1Function', 'TestFunction', 'Test_foobar', 'TestΣυνάρτηση', 'Test함수']);
+	});
 });
diff --git a/test/integration/goDebug.test.ts b/test/integration/goDebug.test.ts
index 473fa11..382d865 100644
--- a/test/integration/goDebug.test.ts
+++ b/test/integration/goDebug.test.ts
@@ -8,10 +8,11 @@
 import * as fs from 'fs';
 import * as http from 'http';
 import { tmpdir } from 'os';
+import * as net from 'net';
 import * as path from 'path';
 import * as sinon from 'sinon';
 import * as proxy from '../../src/goDebugFactory';
-import { DebugConfiguration } from 'vscode';
+import { DebugConfiguration, DebugProtocolMessage } from 'vscode';
 import { DebugClient } from 'vscode-debugadapter-testsupport';
 import { ILocation } from 'vscode-debugadapter-testsupport/lib/debugClient';
 import { DebugProtocol } from 'vscode-debugprotocol';
@@ -289,12 +290,11 @@
 
 // Test suite adapted from:
 // https://github.com/microsoft/vscode-mock-debug/blob/master/src/tests/adapter.test.ts
-const testAll = (isDlvDap: boolean) => {
+const testAll = (ctx: Mocha.Context, isDlvDap: boolean) => {
 	// To disable skipping of dlvDapTests, set dlvDapSkipsEnabled = false.
 	const dlvDapSkipsEnabled = true;
 	const debugConfigProvider = new GoDebugConfigurationProvider();
 	const DEBUG_ADAPTER = path.join('.', 'out', 'src', 'debugAdapter', 'goDebug.js');
-	let dlvDapProcess: cp.ChildProcess;
 
 	const PROJECT_ROOT = path.normalize(path.join(__dirname, '..', '..', '..'));
 	const DATA_ROOT = path.join(PROJECT_ROOT, 'test', 'testdata');
@@ -309,18 +309,17 @@
 	};
 
 	let dc: DebugClient;
+	let dlvDapAdapter: DelveDAPDebugAdapterOnSocket;
 
 	setup(async () => {
 		if (isDlvDap) {
 			dc = new DebugClient('dlv', 'dap', 'go');
+			// dc.start will be called in initializeDebugConfig call,
+			// which creates a thin adapter for delve dap mode,
+			// runs it on a network port, and gets wired with this dc.
 
 			// Launching delve may take longer than the default timeout of 5000.
 			dc.defaultTimeout = 20_000;
-
-			// Change the output to be printed to the console.
-			sinon.stub(proxy, 'appendToDebugConsole').callsFake((msg: string) => {
-				console.log(msg);
-			});
 			return;
 		}
 
@@ -333,9 +332,14 @@
 
 	teardown(async () => {
 		await dc.stop();
-		if (dlvDapProcess) {
-			await killProcessTree(dlvDapProcess);
-			dlvDapProcess = null;
+		if (dlvDapAdapter) {
+			const d = dlvDapAdapter;
+			dlvDapAdapter = null;
+			if (ctx.currentTest?.state === 'failed') {
+				console.log(`${ctx.currentTest?.title} FAILED: DAP Trace`);
+				d.printLog();
+			}
+			await d.dispose();
 		}
 		sinon.restore();
 	});
@@ -771,11 +775,7 @@
 			await assertLocalVariableValue('strdat', '"Goodbye, World."');
 		});
 
-		test('should run program with cwd set (noDebug)', async function () {
-			if (isDlvDap && dlvDapSkipsEnabled) {
-				this.skip(); // OutputEvents not implemented
-			}
-
+		test('should run program with cwd set (noDebug)', async () => {
 			const WD = path.join(DATA_ROOT, 'cwdTest');
 			const PROGRAM = path.join(WD, 'cwdTest');
 
@@ -789,19 +789,15 @@
 				noDebug: true
 			};
 			const debugConfig = await initializeDebugConfig(config);
-			await Promise.all([
-				dc.launch(debugConfig),
-				dc.waitForEvent('output').then((event) => {
-					assert.strictEqual(event.body.output, 'Hello, World!\n');
-				})
-			]);
+			dc.launch(debugConfig);
+			let found = false;
+			while (!found) {
+				const event = await dc.waitForEvent('output');
+				found = event.body.output === 'Hello, World!\n';
+			}
 		});
 
-		test('should run program without cwd set (noDebug)', async function () {
-			if (isDlvDap && dlvDapSkipsEnabled) {
-				this.skip(); // OutputEvents not implemented
-			}
-
+		test('should run program without cwd set (noDebug)', async () => {
 			const WD = path.join(DATA_ROOT, 'cwdTest');
 			const PROGRAM = path.join(WD, 'cwdTest');
 
@@ -814,19 +810,15 @@
 				noDebug: true
 			};
 			const debugConfig = await initializeDebugConfig(config);
-			await Promise.all([
-				dc.launch(debugConfig),
-				dc.waitForEvent('output').then((event) => {
-					assert.strictEqual(event.body.output, 'Goodbye, World.\n');
-				})
-			]);
+			dc.launch(debugConfig);
+			let found = false;
+			while (!found) {
+				const event = await dc.waitForEvent('output');
+				found = event.body.output === 'Goodbye, World.\n';
+			}
 		});
 
-		test('should run file program with cwd set (noDebug)', async function () {
-			if (isDlvDap && dlvDapSkipsEnabled) {
-				this.skip(); // OutputEvents not implemented
-			}
-
+		test('should run file program with cwd set (noDebug)', async () => {
 			const WD = path.join(DATA_ROOT, 'cwdTest');
 			const PROGRAM = path.join(WD, 'cwdTest', 'main.go');
 
@@ -840,19 +832,15 @@
 				noDebug: true
 			};
 			const debugConfig = await initializeDebugConfig(config);
-			await Promise.all([
-				dc.launch(debugConfig),
-				dc.waitForEvent('output').then((event) => {
-					assert.strictEqual(event.body.output, 'Hello, World!\n');
-				})
-			]);
+			dc.launch(debugConfig);
+			let found = false;
+			while (!found) {
+				const event = await dc.waitForEvent('output');
+				found = event.body.output === 'Hello, World!\n';
+			}
 		});
 
-		test('should run file program without cwd set (noDebug)', async function () {
-			if (isDlvDap && dlvDapSkipsEnabled) {
-				this.skip(); // OutputEvents not implemented
-			}
-
+		test('should run file program without cwd set (noDebug)', async () => {
 			const WD = path.join(DATA_ROOT, 'cwdTest');
 			const PROGRAM = path.join(WD, 'cwdTest', 'main.go');
 
@@ -865,12 +853,12 @@
 				noDebug: true
 			};
 			const debugConfig = await initializeDebugConfig(config);
-			await Promise.all([
-				dc.launch(debugConfig),
-				dc.waitForEvent('output').then((event) => {
-					assert.strictEqual(event.body.output, 'Goodbye, World.\n');
-				})
-			]);
+			dc.launch(debugConfig);
+			let found = false;
+			while (!found) {
+				const event = await dc.waitForEvent('output');
+				found = event.body.output === 'Goodbye, World.\n';
+			}
 		});
 	});
 
@@ -1104,15 +1092,22 @@
 			]);
 		}
 
-		test('should set breakpoints during next', async () => {
-			setBreakpointsDuringStep(async () => {
+		test('should set breakpoints during next', async function () {
+			if (isDlvDap && dlvDapSkipsEnabled) {
+				this.skip(); // Skipped due to github.com/golang/vscode-go/issues/1390
+			}
+			await setBreakpointsDuringStep(async () => {
 				const nextResponse = await dc.nextRequest({ threadId: 1 });
 				assert.ok(nextResponse.success);
 			});
 		});
 
-		test('should set breakpoints during step out', async () => {
-			setBreakpointsDuringStep(async () => {
+		test('should set breakpoints during step out', async function () {
+			if (isDlvDap && dlvDapSkipsEnabled) {
+				this.skip(); // Skipped due to github.com/golang/vscode-go/issues/1390
+			}
+
+			await setBreakpointsDuringStep(async () => {
 				const stepOutResponse = await dc.stepOutRequest({ threadId: 1 });
 				assert.ok(stepOutResponse.success);
 			});
@@ -1282,6 +1277,59 @@
 				dc.assertStoppedLocation('panic', {})
 			]);
 		});
+
+		test('should stop on runtime error during continue', async function () {
+			if (!isDlvDap) {
+				// Not implemented in the legacy adapter.
+				this.skip();
+			}
+
+			const PROGRAM_WITH_EXCEPTION = path.join(DATA_ROOT, 'runtimeError');
+
+			const config = {
+				name: 'Launch',
+				type: 'go',
+				request: 'launch',
+				mode: 'auto',
+				program: PROGRAM_WITH_EXCEPTION
+			};
+			const debugConfig = await initializeDebugConfig(config);
+			await Promise.all([
+				dc.configurationSequence(),
+				dc.launch(debugConfig),
+				dc.waitForEvent('stopped').then((event) => {
+					assert(event.body.reason === 'runtime error' || event.body.reason === 'panic');
+				})
+			]);
+		});
+
+		test('should stop on runtime error during next', async function () {
+			if (!isDlvDap) {
+				// Not implemented in the legacy adapter.
+				this.skip();
+			}
+
+			const PROGRAM_WITH_EXCEPTION = path.join(DATA_ROOT, 'runtimeError');
+			const FILE = path.join(PROGRAM_WITH_EXCEPTION, 'oops.go');
+			const BREAKPOINT_LINE = 5;
+
+			const config = {
+				name: 'Launch',
+				type: 'go',
+				request: 'launch',
+				mode: 'auto',
+				program: PROGRAM_WITH_EXCEPTION
+			};
+			const debugConfig = await initializeDebugConfig(config);
+
+			await dc.hitBreakpoint(debugConfig, getBreakpointLocation(FILE, BREAKPOINT_LINE));
+			await Promise.all([
+				dc.nextRequest({ threadId: 1 }),
+				dc.waitForEvent('stopped').then((event) => {
+					assert(event.body.reason === 'runtime error' || event.body.reason === 'panic');
+				})
+			]);
+		});
 	});
 
 	suite('disconnect', () => {
@@ -1626,12 +1674,19 @@
 			]);
 		}
 
-		test.skip('next', async () => {
-			// neither debug adapter implements this behavior
+		test('next', async function () {
+			if (!isDlvDap) {
+				// Not implemented in the legacy adapter.
+				this.skip();
+			}
 			await runSwitchGoroutineTest('next');
 		});
 
-		test.skip('step in', async () => {
+		test('step in', async function () {
+			if (!isDlvDap) {
+				// Not implemented in the legacy adapter.
+				this.skip();
+			}
 			// neither debug adapter implements this behavior
 			await runSwitchGoroutineTest('step in');
 		});
@@ -1805,10 +1860,9 @@
 
 		const debugConfig = await debugConfigProvider.resolveDebugConfiguration(undefined, config);
 		if (isDlvDap) {
-			const { port, dlvDapServer } = await proxy.startDapServer(debugConfig);
-			dlvDapProcess = dlvDapServer;
-			debugConfig.port = port; // let the debug test client connect to our dap server.
-			await dc.start(port);
+			dlvDapAdapter = new DelveDAPDebugAdapterOnSocket(debugConfig);
+			const port = await dlvDapAdapter.serve();
+			await dc.start(port); // This will connect to the adapter's port.
 		}
 		return debugConfig;
 	}
@@ -1816,10 +1870,134 @@
 
 suite('Go Debug Adapter Tests (legacy)', function () {
 	this.timeout(60_000);
-	testAll(false);
+	testAll(this.ctx, false);
 });
 
 suite('Go Debug Adapter Tests (dlv-dap)', function () {
 	this.timeout(60_000);
-	testAll(true);
+	testAll(this.ctx, true);
 });
+
+// DelveDAPDebugAdapterOnSocket runs a DelveDAPOutputAdapter
+// over a network socket. This allows tests to instantiate
+// the thin adapter for Delve DAP and the debug test support's
+// DebugClient to communicate with the adapter over a network socket.
+class DelveDAPDebugAdapterOnSocket extends proxy.DelveDAPOutputAdapter {
+	constructor(config: DebugConfiguration) {
+		super(config, false);
+	}
+
+	private static TWO_CRLF = '\r\n\r\n';
+	private _rawData: Buffer;
+	private _contentLength: number;
+	private _writableStream: NodeJS.WritableStream;
+	private _server: net.Server;
+	private _port: number; // port for the thin adapter.
+
+	public serve(): Promise<number> {
+		return new Promise(async (resolve, reject) => {
+			this._port = await getPort();
+			this._server = net.createServer((c) => {
+				this.log('>> accepted connection from client');
+				c.on('end', () => {
+					this.log('>> client disconnected');
+					this.dispose();
+				});
+				this.run(c, c);
+			});
+			this._server.on('error', (err) => reject(err));
+			this._server.listen(this._port, () => resolve(this._port));
+		});
+	}
+
+	private run(inStream: NodeJS.ReadableStream, outStream: NodeJS.WritableStream): void {
+		this._writableStream = outStream;
+		this._rawData = Buffer.alloc(0);
+
+		// forward to DelveDAPDebugAdapter, which will forward to dlv dap.
+		inStream.on('data', (data: Buffer) => this._handleData(data));
+		// handle data from DelveDAPDebugAdapter, that's from dlv dap.
+		this.onDidSendMessage((m) => this._send(m));
+
+		inStream.resume();
+	}
+
+	private _disposed = false;
+	public async dispose() {
+		if (this._disposed) {
+			return;
+		}
+		this._disposed = true;
+		this.log('adapter disposed');
+		await this._server.close();
+		await super.dispose();
+	}
+
+	// Code from
+	// https://github.com/microsoft/vscode-debugadapter-node/blob/2235a2227d1a439372be578cd3f55e15211851b7/testSupport/src/protocolClient.ts#L96-L97
+	private _send(message: DebugProtocolMessage): void {
+		if (this._writableStream) {
+			const json = JSON.stringify(message);
+			this.log(`<- server: ${json}`);
+			if (!this._writableStream.writable) {
+				this.log('socket closed already');
+				return;
+			}
+			this._writableStream.write(
+				`Content-Length: ${Buffer.byteLength(json, 'utf8')}${DelveDAPDebugAdapterOnSocket.TWO_CRLF}${json}`,
+				'utf8'
+			);
+		}
+	}
+
+	// Code from
+	// https://github.com/microsoft/vscode-debugadapter-node/blob/2235a2227d1a439372be578cd3f55e15211851b7/testSupport/src/protocolClient.ts#L100-L132
+	private _handleData(data: Buffer): void {
+		this._rawData = Buffer.concat([this._rawData, data]);
+
+		// eslint-disable-next-line no-constant-condition
+		while (true) {
+			if (this._contentLength >= 0) {
+				if (this._rawData.length >= this._contentLength) {
+					const message = this._rawData.toString('utf8', 0, this._contentLength);
+					this._rawData = this._rawData.slice(this._contentLength);
+					this._contentLength = -1;
+					if (message.length > 0) {
+						try {
+							this.log(`-> server: ${message}`);
+							const msg: DebugProtocol.ProtocolMessage = JSON.parse(message);
+							this.handleMessage(msg);
+						} catch (e) {
+							throw new Error('Error handling data: ' + (e && e.message));
+						}
+					}
+					continue; // there may be more complete messages to process
+				}
+			} else {
+				const idx = this._rawData.indexOf(DelveDAPDebugAdapterOnSocket.TWO_CRLF);
+				if (idx !== -1) {
+					const header = this._rawData.toString('utf8', 0, idx);
+					const lines = header.split('\r\n');
+					for (let i = 0; i < lines.length; i++) {
+						const pair = lines[i].split(/: +/);
+						if (pair[0] === 'Content-Length') {
+							this._contentLength = +pair[1];
+						}
+					}
+					this._rawData = this._rawData.slice(idx + DelveDAPDebugAdapterOnSocket.TWO_CRLF.length);
+					continue;
+				}
+			}
+			break;
+		}
+	}
+
+	/* --- accumulate log messages so we can output when the test fails --- */
+	private _log = [] as string[];
+	private log(msg: string) {
+		this._log.push(msg);
+	}
+	public printLog() {
+		this._log.forEach((msg) => console.log(msg));
+	}
+}
diff --git a/test/testdata/codelens/codelens2_test.go b/test/testdata/codelens/codelens2_test.go
new file mode 100644
index 0000000..405f4ef
--- /dev/null
+++ b/test/testdata/codelens/codelens2_test.go
@@ -0,0 +1,39 @@
+package main
+
+import (
+	"testing"
+)
+
+// As of Go1.16, `go test -list` returns
+//   TestFunction
+//   Test1Function
+//   TestΣυνάρτηση
+//   Test함수
+//   Test_foobar
+func TestFunction(t *testing.T) {
+	t.Log("this is a valid test function")
+}
+
+func Testfunction(t *testing.T) {
+	t.Fatal("this is not a valid test function")
+}
+
+func Test1Function(t *testing.T) {
+	t.Log("this is an acceptable test function")
+}
+
+func TestΣυνάρτηση(t *testing.T) {
+	t.Log("this is a valid test function")
+}
+
+func Testσυνάρτηση(t *testing.T) {
+	t.Fatal("this is not a valid test function")
+}
+
+func Test함수(t *testing.T) {
+	t.Log("this is a valid test function")
+}
+
+func Test_foobar(t *testing.T) {
+	t.Log("this is an acceptable test function")
+}
\ No newline at end of file
diff --git a/test/testdata/runtimeError/go.mod b/test/testdata/runtimeError/go.mod
new file mode 100644
index 0000000..f03fa68
--- /dev/null
+++ b/test/testdata/runtimeError/go.mod
@@ -0,0 +1,3 @@
+module github.com/golang/vscode-go/gofixtures/runtimeError
+
+go 1.16
diff --git a/test/testdata/runtimeError/oops.go b/test/testdata/runtimeError/oops.go
new file mode 100644
index 0000000..c3be2a5
--- /dev/null
+++ b/test/testdata/runtimeError/oops.go
@@ -0,0 +1,10 @@
+package main
+
+func oops() {
+	var a *int
+	*a++
+}
+
+func main() {
+	oops()
+}