Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
6b666279
V
vscode
项目概览
掘金者说
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
6b666279
编写于
4月 09, 2021
作者:
C
Connor Peet
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
wip
上级
6229e7a5
变更
18
隐藏空白更改
内联
并排
Showing
18 changed file
with
514 addition
and
60 deletion
+514
-60
src/vs/platform/terminal/common/terminal.ts
src/vs/platform/terminal/common/terminal.ts
+6
-0
src/vs/vscode.proposed.d.ts
src/vs/vscode.proposed.d.ts
+3
-0
src/vs/workbench/api/browser/mainThreadTesting.ts
src/vs/workbench/api/browser/mainThreadTesting.ts
+14
-1
src/vs/workbench/api/common/extHost.protocol.ts
src/vs/workbench/api/common/extHost.protocol.ts
+1
-0
src/vs/workbench/api/common/extHostTesting.ts
src/vs/workbench/api/common/extHostTesting.ts
+3
-2
src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts
...kbench/contrib/terminal/browser/terminalProcessManager.ts
+5
-5
src/vs/workbench/contrib/testing/browser/testExplorerActions.ts
.../workbench/contrib/testing/browser/testExplorerActions.ts
+24
-0
src/vs/workbench/contrib/testing/browser/testing.contribution.ts
...workbench/contrib/testing/browser/testing.contribution.ts
+19
-16
src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts
...orkbench/contrib/testing/browser/testingExplorerFilter.ts
+11
-11
src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts
...h/contrib/testing/browser/testingOutputTerminalService.ts
+159
-0
src/vs/workbench/contrib/testing/common/observableValue.ts
src/vs/workbench/contrib/testing/common/observableValue.ts
+13
-3
src/vs/workbench/contrib/testing/common/testResult.ts
src/vs/workbench/contrib/testing/common/testResult.ts
+113
-8
src/vs/workbench/contrib/testing/common/testResultService.ts
src/vs/workbench/contrib/testing/common/testResultService.ts
+16
-1
src/vs/workbench/contrib/testing/common/testResultStorage.ts
src/vs/workbench/contrib/testing/common/testResultStorage.ts
+102
-4
src/vs/workbench/contrib/testing/common/testService.ts
src/vs/workbench/contrib/testing/common/testService.ts
+2
-2
src/vs/workbench/contrib/testing/common/testServiceImpl.ts
src/vs/workbench/contrib/testing/common/testServiceImpl.ts
+3
-3
src/vs/workbench/contrib/testing/test/common/testResultService.test.ts
...nch/contrib/testing/test/common/testResultService.test.ts
+17
-4
src/vs/workbench/contrib/testing/test/common/testResultStorage.test.ts
...nch/contrib/testing/test/common/testResultStorage.test.ts
+3
-0
未找到文件。
src/vs/platform/terminal/common/terminal.ts
浏览文件 @
6b666279
...
...
@@ -243,6 +243,12 @@ export interface IShellLaunchConfig {
*/
isExtensionCustomPtyTerminal
?:
boolean
;
/**
* Custom PTY/pseudoterminal process to use.
* @todo should `TerminalProcessExtHostProxy` be passed to here and remove `isExtensionCustomPtyTerminal`?
*/
customPtyImplementation
?:
ITerminalChildProcess
;
/**
* A UUID generated by the extension host process for terminals created on the extension host process.
*/
...
...
src/vs/vscode.proposed.d.ts
浏览文件 @
6b666279
...
...
@@ -2323,6 +2323,9 @@ declare module 'vscode' {
* Appends raw output from the test runner. On the user's request, the
* output will be displayed in a terminal. ANSI escape sequences,
* such as colors and text styles, are supported.
*
* @param output Output text to append
* @param associateTo Optionally, associate the given segment of output
*/
appendOutput
(
output
:
string
):
void
;
}
...
...
src/vs/workbench/api/browser/mainThreadTesting.ts
浏览文件 @
6b666279
...
...
@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
bufferToStream
,
VSBuffer
}
from
'
vs/base/common/buffer
'
;
import
{
CancellationToken
}
from
'
vs/base/common/cancellation
'
;
import
{
Disposable
,
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
isDefined
}
from
'
vs/base/common/types
'
;
...
...
@@ -71,7 +72,8 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
* @inheritdoc
*/
public
$publishExtensionProvidedResults
(
results
:
ISerializedTestResults
,
persist
:
boolean
):
void
{
this
.
resultService
.
push
(
new
HydratedTestResult
(
results
,
persist
));
// todo
this
.
resultService
.
push
(
new
HydratedTestResult
(
results
,
()
=>
Promise
.
resolve
(
bufferToStream
(
VSBuffer
.
alloc
(
0
))),
persist
));
}
/**
...
...
@@ -84,6 +86,17 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
}
}
/**
* @inheritdoc
*/
public
$appendOutputToRun
(
runId
:
string
,
output
:
VSBuffer
):
void
{
const
r
=
this
.
resultService
.
getResult
(
runId
);
if
(
r
&&
r
instanceof
LiveTestResult
)
{
r
.
output
.
append
(
output
);
}
}
/**
* @inheritdoc
*/
...
...
src/vs/workbench/api/common/extHost.protocol.ts
浏览文件 @
6b666279
...
...
@@ -1977,6 +1977,7 @@ export interface MainThreadTestingShape {
$publishDiff
(
resource
:
ExtHostTestingResource
,
uri
:
UriComponents
,
diff
:
TestsDiff
):
void
;
$updateTestStateInRun
(
runId
:
string
,
testId
:
string
,
state
:
TestResultState
,
duration
?:
number
):
void
;
$appendTestMessageInRun
(
runId
:
string
,
testId
:
string
,
message
:
ITestMessage
):
void
;
$appendOutputToRun
(
runId
:
string
,
output
:
VSBuffer
):
void
;
$runTests
(
req
:
RunTestsRequest
,
token
:
CancellationToken
):
Promise
<
string
>
;
$publishExtensionProvidedResults
(
results
:
ISerializedTestResults
,
persist
:
boolean
):
void
;
}
...
...
src/vs/workbench/api/common/extHostTesting.ts
浏览文件 @
6b666279
...
...
@@ -5,6 +5,7 @@
import
{
mapFind
}
from
'
vs/base/common/arrays
'
;
import
{
disposableTimeout
}
from
'
vs/base/common/async
'
;
import
{
VSBuffer
}
from
'
vs/base/common/buffer
'
;
import
{
CancellationToken
,
CancellationTokenSource
}
from
'
vs/base/common/cancellation
'
;
import
{
Emitter
}
from
'
vs/base/common/event
'
;
import
{
once
}
from
'
vs/base/common/functional
'
;
...
...
@@ -274,8 +275,8 @@ export class ExtHostTesting implements ExtHostTestingShape {
try
{
await
provider
.
runTests
({
appendOutput
()
{
// todo
appendOutput
:
message
=>
{
this
.
proxy
.
$appendOutputToRun
(
req
.
runId
,
VSBuffer
.
fromString
(
message
));
},
appendMessage
:
(
test
,
message
)
=>
{
if
(
!
isExcluded
(
test
))
{
...
...
src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts
浏览文件 @
6b666279
...
...
@@ -42,7 +42,7 @@ const LATENCY_MEASURING_INTERVAL = 1000;
enum
ProcessType
{
Process
,
Extension
Terminal
Psuedo
Terminal
}
/**
...
...
@@ -191,9 +191,9 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
let
newProcess
:
ITerminalChildProcess
;
if
(
shellLaunchConfig
.
isExtensionCustomPtyTerminal
)
{
this
.
_processType
=
ProcessType
.
Extension
Terminal
;
newProcess
=
this
.
_instantiationService
.
createInstance
(
TerminalProcessExtHostProxy
,
this
.
_instanceId
,
shellLaunchConfig
,
cols
,
rows
);
if
(
shellLaunchConfig
.
isExtensionCustomPtyTerminal
||
shellLaunchConfig
.
customPtyImplementation
)
{
this
.
_processType
=
ProcessType
.
Psuedo
Terminal
;
newProcess
=
shellLaunchConfig
.
customPtyImplementation
||
this
.
_instantiationService
.
createInstance
(
TerminalProcessExtHostProxy
,
this
.
_instanceId
,
shellLaunchConfig
,
cols
,
rows
);
}
else
{
const
forceExtHostProcess
=
(
this
.
_configHelper
.
config
as
any
).
extHostProcess
;
if
(
shellLaunchConfig
.
cwd
&&
typeof
shellLaunchConfig
.
cwd
===
'
object
'
)
{
...
...
@@ -488,7 +488,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
await
this
.
ptyProcessReady
;
this
.
_dataFilter
.
triggerSwap
();
this
.
_hasWrittenData
=
true
;
if
(
this
.
shellProcessId
||
this
.
_processType
===
ProcessType
.
Extension
Terminal
)
{
if
(
this
.
shellProcessId
||
this
.
_processType
===
ProcessType
.
Psuedo
Terminal
)
{
if
(
this
.
_process
)
{
// Send data if the pty is ready
this
.
_process
.
input
(
data
);
...
...
src/vs/workbench/contrib/testing/browser/testExplorerActions.ts
浏览文件 @
6b666279
...
...
@@ -31,6 +31,7 @@ import * as icons from 'vs/workbench/contrib/testing/browser/icons';
import
{
ITestExplorerFilterState
}
from
'
vs/workbench/contrib/testing/browser/testingExplorerFilter
'
;
import
{
TestingExplorerView
,
TestingExplorerViewModel
}
from
'
vs/workbench/contrib/testing/browser/testingExplorerView
'
;
import
{
TestingOutputPeekController
}
from
'
vs/workbench/contrib/testing/browser/testingOutputPeek
'
;
import
{
ITestingOutputTerminalService
}
from
'
vs/workbench/contrib/testing/browser/testingOutputTerminalService
'
;
import
{
TestExplorerViewMode
,
TestExplorerViewSorting
,
Testing
}
from
'
vs/workbench/contrib/testing/common/constants
'
;
import
{
InternalTestItem
,
ITestItem
,
TestIdPath
,
TestIdWithSrc
,
TestResultItem
}
from
'
vs/workbench/contrib/testing/common/testCollection
'
;
import
{
ITestingAutoRun
}
from
'
vs/workbench/contrib/testing/common/testingAutoRun
'
;
...
...
@@ -435,6 +436,29 @@ export class TestingSortByLocationAction extends ViewAction<TestingExplorerView>
}
}
export
class
ShowMostRecentOutputAction
extends
Action2
{
constructor
()
{
super
({
id
:
'
testing.showMostRecentOutput
'
,
title
:
localize
(
'
testing.showMostRecentOutput
'
,
"
Collapse All Tests
"
),
f1
:
false
,
icon
:
Codicon
.
terminal
,
menu
:
{
id
:
MenuId
.
ViewTitle
,
order
:
ActionOrder
.
Collapse
,
group
:
'
navigation
'
,
when
:
ContextKeyEqualsExpr
.
create
(
'
view
'
,
Testing
.
ExplorerViewId
)
}
});
}
public
run
(
accessor
:
ServicesAccessor
)
{
const
result
=
accessor
.
get
(
ITestResultService
).
results
[
0
];
accessor
.
get
(
ITestingOutputTerminalService
).
open
(
result
);
}
}
export
class
CollapseAllAction
extends
ViewAction
<
TestingExplorerView
>
{
constructor
()
{
super
({
...
...
src/vs/workbench/contrib/testing/browser/testing.contribution.ts
浏览文件 @
6b666279
...
...
@@ -20,6 +20,7 @@ import { TestingDecorations } from 'vs/workbench/contrib/testing/browser/testing
import
{
ITestExplorerFilterState
,
TestExplorerFilterState
}
from
'
vs/workbench/contrib/testing/browser/testingExplorerFilter
'
;
import
{
TestingExplorerView
}
from
'
vs/workbench/contrib/testing/browser/testingExplorerView
'
;
import
{
CloseTestPeek
,
ITestingPeekOpener
,
TestingOutputPeekController
,
TestingPeekOpener
}
from
'
vs/workbench/contrib/testing/browser/testingOutputPeek
'
;
import
{
ITestingOutputTerminalService
,
TestingOutputTerminalService
}
from
'
vs/workbench/contrib/testing/browser/testingOutputTerminalService
'
;
import
{
ITestingProgressUiService
,
TestingProgressUiService
}
from
'
vs/workbench/contrib/testing/browser/testingProgressUiService
'
;
import
{
TestingViewPaneContainer
}
from
'
vs/workbench/contrib/testing/browser/testingViewPaneContainer
'
;
import
{
testingConfiguation
}
from
'
vs/workbench/contrib/testing/common/configuration
'
;
...
...
@@ -41,6 +42,7 @@ registerSingleton(ITestResultStorage, TestResultStorage);
registerSingleton
(
ITestResultService
,
TestResultService
);
registerSingleton
(
ITestExplorerFilterState
,
TestExplorerFilterState
);
registerSingleton
(
ITestingAutoRun
,
TestingAutoRun
,
true
);
registerSingleton
(
ITestingOutputTerminalService
,
TestingOutputTerminalService
,
true
);
registerSingleton
(
ITestingPeekOpener
,
TestingPeekOpener
);
registerSingleton
(
ITestingProgressUiService
,
TestingProgressUiService
);
registerSingleton
(
IWorkspaceTestCollectionService
,
WorkspaceTestCollectionService
);
...
...
@@ -86,30 +88,31 @@ viewsRegistry.registerViews([{
when
:
ContextKeyExpr
.
greater
(
TestingContextKeys
.
providerCount
.
key
,
0
),
}],
viewContainer
);
registerAction2
(
Action
.
TestingViewAsList
Action
);
registerAction2
(
Action
.
TestingViewAsTree
Action
);
registerAction2
(
Action
.
AutoRunOff
Action
);
registerAction2
(
Action
.
AutoRunOn
Action
);
registerAction2
(
Action
.
CancelTestRunAction
);
registerAction2
(
Action
.
RunSelectedAction
);
registerAction2
(
Action
.
DebugSelectedAction
);
registerAction2
(
Action
.
TestingSortByNameAction
);
registerAction2
(
Action
.
TestingSortByLocationAction
);
registerAction2
(
Action
.
RefreshTestsAction
);
registerAction2
(
Action
.
ClearTestResultsAction
);
registerAction2
(
Action
.
CollapseAllAction
);
registerAction2
(
Action
.
RunAllAction
);
registerAction2
(
Action
.
DebugAllAction
);
registerAction2
(
Action
.
EditFocusedTest
);
registerAction2
(
Action
.
ClearTestResultsAction
);
registerAction2
(
Action
.
AutoRunOffAction
);
registerAction2
(
Action
.
AutoRunOnAction
);
registerAction2
(
Action
.
DebugAtCursor
);
registerAction2
(
Action
.
RunAtCursor
);
registerAction2
(
Action
.
DebugCurrentFile
);
registerAction2
(
Action
.
RunCurrentFile
);
registerAction2
(
Action
.
ReRunFailedTests
);
registerAction2
(
Action
.
DebugFailedTests
);
registerAction2
(
Action
.
ReRunLastRun
);
registerAction2
(
Action
.
DebugLastRun
);
registerAction2
(
Action
.
DebugSelectedAction
);
registerAction2
(
Action
.
EditFocusedTest
);
registerAction2
(
Action
.
RefreshTestsAction
);
registerAction2
(
Action
.
ReRunFailedTests
);
registerAction2
(
Action
.
ReRunLastRun
);
registerAction2
(
Action
.
RunAllAction
);
registerAction2
(
Action
.
RunAtCursor
);
registerAction2
(
Action
.
RunCurrentFile
);
registerAction2
(
Action
.
RunSelectedAction
);
registerAction2
(
Action
.
SearchForTestExtension
);
registerAction2
(
Action
.
ShowMostRecentOutputAction
);
registerAction2
(
Action
.
TestingSortByLocationAction
);
registerAction2
(
Action
.
TestingSortByNameAction
);
registerAction2
(
Action
.
TestingViewAsListAction
);
registerAction2
(
Action
.
TestingViewAsTreeAction
);
registerAction2
(
CloseTestPeek
);
Registry
.
as
<
IWorkbenchContributionsRegistry
>
(
WorkbenchExtensions
.
Workbench
).
registerWorkbenchContribution
(
TestingContentProvider
,
LifecyclePhase
.
Restored
);
...
...
src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts
浏览文件 @
6b666279
...
...
@@ -25,7 +25,7 @@ import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'
import
{
ViewContainerLocation
}
from
'
vs/workbench/common/views
'
;
import
{
testingFilterIcon
}
from
'
vs/workbench/contrib/testing/browser/icons
'
;
import
{
TestExplorerStateFilter
,
Testing
}
from
'
vs/workbench/contrib/testing/common/constants
'
;
import
{
ObservableValue
}
from
'
vs/workbench/contrib/testing/common/observableValue
'
;
import
{
Mutable
ObservableValue
}
from
'
vs/workbench/contrib/testing/common/observableValue
'
;
import
{
StoredValue
}
from
'
vs/workbench/contrib/testing/common/storedValue
'
;
import
{
TestIdPath
}
from
'
vs/workbench/contrib/testing/common/testCollection
'
;
import
{
TestingContextKeys
}
from
'
vs/workbench/contrib/testing/common/testingContextKeys
'
;
...
...
@@ -33,17 +33,17 @@ import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
export
interface
ITestExplorerFilterState
{
_serviceBrand
:
undefined
;
readonly
text
:
ObservableValue
<
string
>
;
readonly
text
:
Mutable
ObservableValue
<
string
>
;
/**
* Reveal request: the path to the test to reveal. The last element of the
* array is the test the user wanted to reveal, and the previous
* items are its parents.
*/
readonly
reveal
:
ObservableValue
<
TestIdPath
|
undefined
>
;
readonly
stateFilter
:
ObservableValue
<
TestExplorerStateFilter
>
;
readonly
currentDocumentOnly
:
ObservableValue
<
boolean
>
;
readonly
reveal
:
Mutable
ObservableValue
<
TestIdPath
|
undefined
>
;
readonly
stateFilter
:
Mutable
ObservableValue
<
TestExplorerStateFilter
>
;
readonly
currentDocumentOnly
:
Mutable
ObservableValue
<
boolean
>
;
/** Whether excluded test should be shown in the view */
readonly
showExcludedTests
:
ObservableValue
<
boolean
>
;
readonly
showExcludedTests
:
Mutable
ObservableValue
<
boolean
>
;
readonly
onDidRequestInputFocus
:
Event
<
void
>
;
focusInput
():
void
;
...
...
@@ -54,20 +54,20 @@ export const ITestExplorerFilterState = createDecorator<ITestExplorerFilterState
export
class
TestExplorerFilterState
implements
ITestExplorerFilterState
{
declare
_serviceBrand
:
undefined
;
private
readonly
focusEmitter
=
new
Emitter
<
void
>
();
public
readonly
text
=
new
ObservableValue
(
''
);
public
readonly
stateFilter
=
ObservableValue
.
stored
(
new
StoredValue
<
TestExplorerStateFilter
>
({
public
readonly
text
=
new
Mutable
ObservableValue
(
''
);
public
readonly
stateFilter
=
Mutable
ObservableValue
.
stored
(
new
StoredValue
<
TestExplorerStateFilter
>
({
key
:
'
testStateFilter
'
,
scope
:
StorageScope
.
WORKSPACE
,
target
:
StorageTarget
.
USER
},
this
.
storage
),
TestExplorerStateFilter
.
All
);
public
readonly
currentDocumentOnly
=
ObservableValue
.
stored
(
new
StoredValue
<
boolean
>
({
public
readonly
currentDocumentOnly
=
Mutable
ObservableValue
.
stored
(
new
StoredValue
<
boolean
>
({
key
:
'
testsByCurrentDocumentOnly
'
,
scope
:
StorageScope
.
WORKSPACE
,
target
:
StorageTarget
.
USER
},
this
.
storage
),
false
);
public
readonly
showExcludedTests
=
new
ObservableValue
(
false
);
public
readonly
reveal
=
new
ObservableValue
<
TestIdPath
|
undefined
>
(
undefined
);
public
readonly
showExcludedTests
=
new
Mutable
ObservableValue
(
false
);
public
readonly
reveal
=
new
Mutable
ObservableValue
<
TestIdPath
|
undefined
>
(
undefined
);
public
readonly
onDidRequestInputFocus
=
this
.
focusEmitter
.
event
;
...
...
src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts
0 → 100644
浏览文件 @
6b666279
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
Emitter
}
from
'
vs/base/common/event
'
;
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
listenStream
}
from
'
vs/base/common/stream
'
;
import
{
localize
}
from
'
vs/nls
'
;
import
{
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IProcessDataEvent
,
ITerminalChildProcess
,
ITerminalLaunchError
,
TerminalShellType
}
from
'
vs/platform/terminal/common/terminal
'
;
import
{
ITerminalInstance
,
ITerminalService
}
from
'
vs/workbench/contrib/terminal/browser/terminal
'
;
import
{
ITestResult
}
from
'
vs/workbench/contrib/testing/common/testResult
'
;
export
interface
ITestingOutputTerminalService
{
_serviceBrand
:
undefined
;
/**
* Opens a terminal for the given test's output.
*/
open
(
result
:
ITestResult
):
Promise
<
void
>
;
}
const
friendlyDate
=
(
date
:
number
)
=>
{
const
d
=
new
Date
(
date
);
return
d
.
getHours
()
+
'
:
'
+
String
(
d
.
getMinutes
()).
padStart
(
2
,
'
0
'
)
+
'
:
'
+
String
(
d
.
getSeconds
()).
padStart
(
2
,
'
0
'
);
};
const
genericTitle
=
localize
(
'
testOutputTerminalTitle
'
,
'
Test Output
'
);
type
TestOutputTerminalInstance
=
ITerminalInstance
&
{
shellLaunchConfig
:
{
customPtyImplementation
:
TestOutputProcess
}
};
export
const
ITestingOutputTerminalService
=
createDecorator
<
ITestingOutputTerminalService
>
(
'
ITestingOutputTerminalService
'
);
export
class
TestingOutputTerminalService
implements
ITestingOutputTerminalService
{
_serviceBrand
:
undefined
;
constructor
(@
ITerminalService
private
readonly
terminalService
:
ITerminalService
)
{
}
/**
* @inheritdoc
*/
public
async
open
(
result
:
ITestResult
|
undefined
):
Promise
<
void
>
{
const
title
=
result
?
localize
(
'
testOutputTerminalTitleWithDate
'
,
'
Test Output at {0}
'
,
friendlyDate
(
result
.
completedAt
??
Date
.
now
()))
:
genericTitle
;
const
testOutputPtys
=
this
.
terminalService
.
terminalInstances
.
filter
(
(
i
):
i
is
TestOutputTerminalInstance
=>
i
.
shellLaunchConfig
.
customPtyImplementation
instanceof
TestOutputProcess
);
// If there's an existing terminal for the attempted reveal, show that instead.
const
existing
=
testOutputPtys
.
find
(
i
=>
i
.
shellLaunchConfig
.
customPtyImplementation
.
resultId
===
result
?.
id
);
if
(
existing
)
{
this
.
terminalService
.
setActiveInstance
(
existing
);
this
.
terminalService
.
showPanel
();
return
;
}
// Try to reuse ended terminals, otherwise make a new one
let
output
:
TestOutputProcess
;
let
terminal
=
testOutputPtys
.
find
(
i
=>
i
.
shellLaunchConfig
.
customPtyImplementation
.
ended
);
if
(
terminal
)
{
output
=
terminal
.
shellLaunchConfig
.
customPtyImplementation
;
}
else
{
output
=
new
TestOutputProcess
();
terminal
=
this
.
terminalService
.
createTerminal
({
isFeatureTerminal
:
true
,
customPtyImplementation
:
output
,
name
:
title
,
})
as
TestOutputTerminalInstance
;
}
output
.
resetFor
(
result
?.
id
,
title
);
this
.
terminalService
.
setActiveInstance
(
terminal
);
this
.
terminalService
.
showPanel
();
if
(
!
result
)
{
// seems like it takes a tick for listeners to be registered
output
.
ended
=
true
;
setTimeout
(()
=>
output
.
pushData
(
localize
(
'
testNoRunYet
'
,
'
\r\n
No tests have been run, yet.
\r\n
'
)));
return
;
}
listenStream
(
await
result
.
getOutput
(),
{
onData
:
d
=>
output
.
pushData
(
d
.
toString
()),
onError
:
err
=>
output
.
pushData
(
`\r\n\r\n
${
err
.
stack
||
err
.
message
}
`
),
onEnd
:
()
=>
{
const
completedAt
=
result
.
completedAt
?
new
Date
(
result
.
completedAt
)
:
new
Date
();
const
text
=
localize
(
'
runFinished
'
,
'
Test run finished at {0}
'
,
completedAt
.
toLocaleString
());
output
.
pushData
(
`\r\n\r\n\x1b[1m>
${
text
}
<\x1b[0m\r\n`
);
output
.
ended
=
true
;
},
});
}
}
class
TestOutputProcess
extends
Disposable
implements
ITerminalChildProcess
{
private
processDataEmitter
=
this
.
_register
(
new
Emitter
<
string
|
IProcessDataEvent
>
());
private
titleEmitter
=
this
.
_register
(
new
Emitter
<
string
>
());
/** Whether the associated test has ended (indicating the terminal can be reused) */
public
ended
=
true
;
/** Result currently being displayed */
public
resultId
:
string
|
undefined
;
public
pushData
(
data
:
string
|
IProcessDataEvent
)
{
this
.
processDataEmitter
.
fire
(
data
);
}
public
resetFor
(
resultId
:
string
|
undefined
,
title
:
string
)
{
this
.
ended
=
false
;
this
.
resultId
=
resultId
;
this
.
processDataEmitter
.
fire
(
'
\
x1bc
'
);
this
.
titleEmitter
.
fire
(
title
);
}
//#region implementation
public
readonly
id
=
0
;
public
readonly
shouldPersist
=
false
;
public
readonly
onProcessData
=
this
.
processDataEmitter
.
event
;
public
readonly
onProcessExit
=
this
.
_register
(
new
Emitter
<
number
|
undefined
>
()).
event
;
public
readonly
onProcessReady
=
this
.
_register
(
new
Emitter
<
{
pid
:
number
;
cwd
:
string
;
}
>
()).
event
;
public
readonly
onProcessTitleChanged
=
this
.
titleEmitter
.
event
;
public
readonly
onProcessShellTypeChanged
=
this
.
_register
(
new
Emitter
<
TerminalShellType
>
()).
event
;
public
start
():
Promise
<
ITerminalLaunchError
|
undefined
>
{
return
Promise
.
resolve
(
undefined
);
}
public
shutdown
():
void
{
// no-op
}
public
input
():
void
{
// not supported
}
public
processBinary
():
Promise
<
void
>
{
return
Promise
.
resolve
();
}
public
resize
():
void
{
// no-op
}
public
acknowledgeDataEvent
():
void
{
// no-op, flow control not currently implemented
}
public
getInitialCwd
():
Promise
<
string
>
{
return
Promise
.
resolve
(
''
);
}
public
getCwd
():
Promise
<
string
>
{
return
Promise
.
resolve
(
''
);
}
public
getLatency
():
Promise
<
number
>
{
return
Promise
.
resolve
(
0
);
}
//#endregion
}
src/vs/workbench/contrib/testing/common/observableValue.ts
浏览文件 @
6b666279
...
...
@@ -3,10 +3,20 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
Emitter
}
from
'
vs/base/common/event
'
;
import
{
Emitter
,
Event
}
from
'
vs/base/common/event
'
;
import
{
StoredValue
}
from
'
vs/workbench/contrib/testing/common/storedValue
'
;
export
class
ObservableValue
<
T
>
{
export
interface
IObservableValue
<
T
>
{
onDidChange
:
Event
<
T
>
;
readonly
value
:
T
;
}
export
const
staticObservableValue
=
<
T
>
(
value
:
T
):
IObservableValue
<
T
>
=>
({
onDidChange
:
Event
.
None
,
value
,
});
export
class
MutableObservableValue
<
T
>
implements
IObservableValue
<
T
>
{
private
readonly
changeEmitter
=
new
Emitter
<
T
>
();
public
readonly
onDidChange
=
this
.
changeEmitter
.
event
;
...
...
@@ -23,7 +33,7 @@ export class ObservableValue<T> {
}
public
static
stored
<
T
>
(
stored
:
StoredValue
<
T
>
,
defaultValue
:
T
)
{
const
o
=
new
ObservableValue
(
stored
.
get
(
defaultValue
));
const
o
=
new
Mutable
ObservableValue
(
stored
.
get
(
defaultValue
));
o
.
onDidChange
(
value
=>
stored
.
store
(
value
));
return
o
;
}
...
...
src/vs/workbench/contrib/testing/common/testResult.ts
浏览文件 @
6b666279
...
...
@@ -3,10 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
newWriteableBufferStream
,
VSBuffer
,
VSBufferReadableStream
,
VSBufferWriteableStream
}
from
'
vs/base/common/buffer
'
;
import
{
Emitter
}
from
'
vs/base/common/event
'
;
import
{
Lazy
}
from
'
vs/base/common/lazy
'
;
import
{
DisposableStore
}
from
'
vs/base/common/lifecycle
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
generateUuid
}
from
'
vs/base/common/uuid
'
;
import
{
Range
}
from
'
vs/editor/common/core/range
'
;
import
{
TestResultState
}
from
'
vs/workbench/api/common/extHostTypes
'
;
import
{
IComputedStateAccessor
,
refreshComputedState
}
from
'
vs/workbench/contrib/testing/common/getComputedState
'
;
...
...
@@ -46,6 +47,11 @@ export interface ITestResult {
*/
getStateById
(
testExtId
:
string
):
TestResultItem
|
undefined
;
/**
* Loads the output of the result as a stream.
*/
getOutput
():
Promise
<
VSBufferReadableStream
>
;
/**
* Serializes the test result. Used to save and restore results
* in the workspace.
...
...
@@ -78,6 +84,88 @@ export const sumCounts = (counts: Iterable<TestStateCount>) => {
return
total
;
};
/**
* Deals with output of a {@link LiveTestResult}. By default we pass-through
* data into the underlying write stream, but if a client requests to read it
* we splice in the written data and then continue streaming incoming data.
*/
export
class
LiveOutputController
{
/** Set on close() to a promise that is resolved once closing is complete */
private
closed
?:
Promise
<
void
>
;
/** Data written so far. This is available until the file closes. */
private
previouslyWritten
:
VSBuffer
[]
|
undefined
=
[];
private
readonly
dataEmitter
=
new
Emitter
<
VSBuffer
>
();
private
readonly
endEmitter
=
new
Emitter
<
void
>
();
constructor
(
private
readonly
writer
:
Lazy
<
[
VSBufferWriteableStream
,
Promise
<
void
>
]
>
,
private
readonly
reader
:
()
=>
Promise
<
VSBufferReadableStream
>
,
)
{
}
/**
* Appends data to the output.
*/
public
append
(
data
:
VSBuffer
):
Promise
<
void
>
|
void
{
if
(
this
.
closed
)
{
return
this
.
closed
;
}
this
.
previouslyWritten
?.
push
(
data
);
this
.
dataEmitter
.
fire
(
data
);
return
this
.
writer
.
getValue
()[
0
].
write
(
data
);
}
/**
* Reads the value of the stream.
*/
public
read
()
{
if
(
!
this
.
previouslyWritten
)
{
return
this
.
reader
();
}
const
stream
=
newWriteableBufferStream
();
for
(
const
chunk
of
this
.
previouslyWritten
)
{
stream
.
write
(
chunk
);
}
const
disposable
=
new
DisposableStore
();
disposable
.
add
(
this
.
dataEmitter
.
event
(
d
=>
stream
.
write
(
d
)));
disposable
.
add
(
this
.
endEmitter
.
event
(()
=>
stream
.
end
()));
stream
.
on
(
'
end
'
,
()
=>
disposable
.
dispose
());
return
Promise
.
resolve
(
stream
);
}
/**
* Closes the output, signalling no more writes will be made.
* @returns a promise that resolves when the output is written
*/
public
close
():
Promise
<
void
>
{
if
(
this
.
closed
)
{
return
this
.
closed
;
}
if
(
!
this
.
writer
.
hasValue
())
{
this
.
closed
=
Promise
.
resolve
();
}
else
{
const
[
stream
,
ended
]
=
this
.
writer
.
getValue
();
stream
.
end
();
this
.
closed
=
ended
;
}
this
.
endEmitter
.
fire
();
this
.
closed
.
then
(()
=>
{
this
.
previouslyWritten
=
undefined
;
this
.
dataEmitter
.
dispose
();
this
.
endEmitter
.
dispose
();
});
return
this
.
closed
;
}
}
const
itemToNode
=
(
item
:
IncrementalTestCollectionItem
,
...
...
@@ -172,7 +260,9 @@ export class LiveTestResult implements ITestResult {
* of collections.
*/
public
static
from
(
resultId
:
string
,
collections
:
ReadonlyArray
<
IMainThreadTestCollection
>
,
output
:
LiveOutputController
,
req
:
RunTestsRequest
,
)
{
const
testByExtId
=
new
Map
<
string
,
TestResultItem
>
();
...
...
@@ -189,7 +279,7 @@ export class LiveTestResult implements ITestResult {
}
}
return
new
LiveTestResult
(
collections
,
testByExtId
,
excludeSe
t
,
!!
req
.
isAutoRun
);
return
new
LiveTestResult
(
resultId
,
collections
,
testByExtId
,
excludeSet
,
outpu
t
,
!!
req
.
isAutoRun
);
}
private
readonly
completeEmitter
=
new
Emitter
<
void
>
();
...
...
@@ -199,11 +289,6 @@ export class LiveTestResult implements ITestResult {
public
readonly
onChange
=
this
.
changeEmitter
.
event
;
public
readonly
onComplete
=
this
.
completeEmitter
.
event
;
/**
* Unique ID for referring to this set of test results.
*/
public
readonly
id
=
generateUuid
();
/**
* @inheritdoc
*/
...
...
@@ -255,9 +340,11 @@ export class LiveTestResult implements ITestResult {
};
constructor
(
public
readonly
id
:
string
,
private
readonly
collections
:
ReadonlyArray
<
IMainThreadTestCollection
>
,
private
readonly
testById
:
Map
<
string
,
TestResultItem
>
,
private
readonly
excluded
:
ReadonlySet
<
string
>
,
public
readonly
output
:
LiveOutputController
,
public
readonly
isAutoRun
:
boolean
,
)
{
this
.
counts
[
TestResultState
.
Unset
]
=
testById
.
size
;
...
...
@@ -315,6 +402,13 @@ export class LiveTestResult implements ITestResult {
});
}
/**
* @inheritdoc
*/
public
getOutput
()
{
return
this
.
output
.
read
();
}
private
fireUpdateAndRefresh
(
entry
:
TestResultItem
,
newState
:
TestResultState
)
{
const
previous
=
entry
.
state
.
state
;
if
(
newState
===
previous
)
{
...
...
@@ -445,7 +539,11 @@ export class HydratedTestResult implements ITestResult {
private
readonly
testById
=
new
Map
<
string
,
TestResultItem
>
();
constructor
(
private
readonly
serialized
:
ISerializedTestResults
,
private
readonly
persist
=
true
)
{
constructor
(
private
readonly
serialized
:
ISerializedTestResults
,
private
readonly
outputLoader
:
()
=>
Promise
<
VSBufferReadableStream
>
,
private
readonly
persist
=
true
,
)
{
this
.
id
=
serialized
.
id
;
this
.
completedAt
=
serialized
.
completedAt
;
...
...
@@ -472,6 +570,13 @@ export class HydratedTestResult implements ITestResult {
return
this
.
testById
.
get
(
extTestId
);
}
/**
* @inheritdoc
*/
public
getOutput
()
{
return
this
.
outputLoader
();
}
/**
* @inheritdoc
*/
...
...
src/vs/workbench/contrib/testing/common/testResultService.ts
浏览文件 @
6b666279
...
...
@@ -9,13 +9,15 @@ import { Emitter, Event } from 'vs/base/common/event';
import
{
once
}
from
'
vs/base/common/functional
'
;
import
{
Iterable
}
from
'
vs/base/common/iterator
'
;
import
{
equals
}
from
'
vs/base/common/objects
'
;
import
{
generateUuid
}
from
'
vs/base/common/uuid
'
;
import
{
IContextKey
,
IContextKeyService
}
from
'
vs/platform/contextkey/common/contextkey
'
;
import
{
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
TestResultState
}
from
'
vs/workbench/api/common/extHostTypes
'
;
import
{
TestResultItem
}
from
'
vs/workbench/contrib/testing/common/testCollection
'
;
import
{
RunTestsRequest
,
TestResultItem
}
from
'
vs/workbench/contrib/testing/common/testCollection
'
;
import
{
TestingContextKeys
}
from
'
vs/workbench/contrib/testing/common/testingContextKeys
'
;
import
{
ITestResult
,
LiveTestResult
,
TestResultItemChange
,
TestResultItemChangeReason
}
from
'
vs/workbench/contrib/testing/common/testResult
'
;
import
{
ITestResultStorage
,
RETAIN_MAX_RESULTS
}
from
'
vs/workbench/contrib/testing/common/testResultStorage
'
;
import
{
IMainThreadTestCollection
}
from
'
vs/workbench/contrib/testing/common/testService
'
;
export
type
ResultChangeEvent
=
|
{
completed
:
LiveTestResult
}
...
...
@@ -45,6 +47,11 @@ export interface ITestResultService {
*/
clear
():
void
;
/**
* Creates a new, live test result.
*/
createLiveResult
(
collections
:
ReadonlyArray
<
IMainThreadTestCollection
>
,
req
:
RunTestsRequest
):
LiveTestResult
;
/**
* Adds a new test result to the collection.
*/
...
...
@@ -125,6 +132,14 @@ export class TestResultService implements ITestResultService {
return
undefined
;
}
/**
* @inheritdoc
*/
public
createLiveResult
(
collections
:
ReadonlyArray
<
IMainThreadTestCollection
>
,
req
:
RunTestsRequest
)
{
const
id
=
generateUuid
();
return
this
.
push
(
LiveTestResult
.
from
(
id
,
collections
,
this
.
storage
.
getOutputController
(
id
),
req
));
}
/**
* @inheritdoc
*/
...
...
src/vs/workbench/contrib/testing/common/testResultStorage.ts
浏览文件 @
6b666279
...
...
@@ -3,7 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
VSBuffer
}
from
'
vs/base/common/buffer
'
;
import
{
bufferToStream
,
newWriteableBufferStream
,
VSBuffer
,
VSBufferReadableStream
,
VSBufferWriteableStream
}
from
'
vs/base/common/buffer
'
;
import
{
Lazy
}
from
'
vs/base/common/lazy
'
;
import
{
isDefined
}
from
'
vs/base/common/types
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
IEnvironmentService
}
from
'
vs/platform/environment/common/environment
'
;
...
...
@@ -14,11 +15,12 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag
import
{
IWorkspaceContextService
}
from
'
vs/platform/workspace/common/workspace
'
;
import
{
StoredValue
}
from
'
vs/workbench/contrib/testing/common/storedValue
'
;
import
{
ISerializedTestResults
}
from
'
vs/workbench/contrib/testing/common/testCollection
'
;
import
{
HydratedTestResult
,
ITestResult
}
from
'
vs/workbench/contrib/testing/common/testResult
'
;
import
{
HydratedTestResult
,
ITestResult
,
LiveOutputController
,
LiveTestResult
}
from
'
vs/workbench/contrib/testing/common/testResult
'
;
export
const
RETAIN_MAX_RESULTS
=
128
;
const
RETAIN_MIN_RESULTS
=
16
;
const
RETAIN_MAX_BYTES
=
1024
*
128
;
const
CLEANUP_PROBABILITY
=
0.2
;
export
interface
ITestResultStorage
{
_serviceBrand
:
undefined
;
...
...
@@ -32,6 +34,11 @@ export interface ITestResultStorage {
* Persists the list of test results.
*/
persist
(
results
:
ReadonlyArray
<
ITestResult
>
):
Promise
<
void
>
;
/**
* Gets the output controller for a new or existing test result.
*/
getOutputController
(
resultId
:
string
):
LiveOutputController
;
}
export
const
ITestResultStorage
=
createDecorator
(
'
ITestResultStorage
'
);
...
...
@@ -39,7 +46,7 @@ export const ITestResultStorage = createDecorator('ITestResultStorage');
export
abstract
class
BaseTestResultStorage
implements
ITestResultStorage
{
declare
readonly
_serviceBrand
:
undefined
;
pr
ivate
readonly
stored
=
new
StoredValue
<
ReadonlyArray
<
{
id
:
string
,
bytes
:
number
}
>>
({
pr
otected
readonly
stored
=
new
StoredValue
<
ReadonlyArray
<
{
id
:
string
,
bytes
:
number
}
>>
({
key
:
'
storedTestResults
'
,
scope
:
StorageScope
.
WORKSPACE
,
target
:
StorageTarget
.
MACHINE
...
...
@@ -62,7 +69,7 @@ export abstract class BaseTestResultStorage implements ITestResultStorage {
return
undefined
;
}
return
new
HydratedTestResult
(
contents
);
return
new
HydratedTestResult
(
contents
,
()
=>
this
.
readOutputForResultId
(
id
)
);
}
catch
(
e
)
{
this
.
logService
.
warn
(
`Error deserializing stored test result
${
id
}
`
,
e
);
return
undefined
;
...
...
@@ -72,6 +79,29 @@ export abstract class BaseTestResultStorage implements ITestResultStorage {
return
results
.
filter
(
isDefined
);
}
/**
* @override
*/
public
getOutputController
(
resultId
:
string
)
{
return
new
LiveOutputController
(
new
Lazy
(()
=>
{
const
stream
=
newWriteableBufferStream
();
const
promise
=
this
.
storeOutputForResultId
(
resultId
,
stream
);
return
[
stream
,
promise
];
}),
()
=>
this
.
readOutputForResultId
(
resultId
),
);
}
/**
* @override
*/
public
getResultOutputWriter
(
resultId
:
string
)
{
const
stream
=
newWriteableBufferStream
();
this
.
storeOutputForResultId
(
resultId
,
stream
);
return
stream
;
}
/**
* @override
*/
...
...
@@ -108,6 +138,10 @@ export abstract class BaseTestResultStorage implements ITestResultStorage {
todo
.
push
(
this
.
storeForResultId
(
result
.
id
,
obj
));
toStore
.
push
({
id
:
result
.
id
,
bytes
:
contents
.
byteLength
});
budget
-=
contents
.
byteLength
;
if
(
result
instanceof
LiveTestResult
&&
result
.
completedAt
!==
undefined
)
{
todo
.
push
(
result
.
output
.
close
());
}
}
for
(
const
id
of
toDelete
.
keys
())
{
...
...
@@ -123,6 +157,11 @@ export abstract class BaseTestResultStorage implements ITestResultStorage {
*/
protected
abstract
readForResultId
(
id
:
string
):
Promise
<
ISerializedTestResults
|
undefined
>
;
/**
* Reads serialized results for the test. Is allowed to throw.
*/
protected
abstract
readOutputForResultId
(
id
:
string
):
Promise
<
VSBufferReadableStream
>
;
/**
* Deletes serialized results for the test.
*/
...
...
@@ -132,6 +171,11 @@ export abstract class BaseTestResultStorage implements ITestResultStorage {
* Stores test results by ID.
*/
protected
abstract
storeForResultId
(
id
:
string
,
data
:
ISerializedTestResults
):
Promise
<
unknown
>
;
/**
* Reads serialized results for the test. Is allowed to throw.
*/
protected
abstract
storeOutputForResultId
(
id
:
string
,
input
:
VSBufferWriteableStream
):
Promise
<
void
>
;
}
export
class
InMemoryResultStorage
extends
BaseTestResultStorage
{
...
...
@@ -150,6 +194,14 @@ export class InMemoryResultStorage extends BaseTestResultStorage {
this
.
cache
.
delete
(
id
);
return
Promise
.
resolve
();
}
protected
readOutputForResultId
(
id
:
string
):
Promise
<
VSBufferReadableStream
>
{
throw
new
Error
(
'
Method not implemented.
'
);
}
protected
storeOutputForResultId
(
id
:
string
,
input
:
VSBufferWriteableStream
):
Promise
<
void
>
{
throw
new
Error
(
'
Method not implemented.
'
);
}
}
export
class
TestResultStorage
extends
BaseTestResultStorage
{
...
...
@@ -179,7 +231,53 @@ export class TestResultStorage extends BaseTestResultStorage {
return
this
.
fileService
.
del
(
this
.
getResultJsonPath
(
id
)).
catch
(()
=>
undefined
);
}
protected
async
readOutputForResultId
(
id
:
string
):
Promise
<
VSBufferReadableStream
>
{
try
{
const
{
value
}
=
await
this
.
fileService
.
readFileStream
(
this
.
getResultOutputPath
(
id
));
return
value
;
}
catch
{
return
bufferToStream
(
VSBuffer
.
alloc
(
0
));
}
}
protected
async
storeOutputForResultId
(
id
:
string
,
input
:
VSBufferWriteableStream
)
{
await
this
.
fileService
.
createFile
(
this
.
getResultOutputPath
(
id
),
input
);
}
/**
* @inheritdoc
*/
public
override
async
persist
(
results
:
ReadonlyArray
<
ITestResult
>
)
{
await
super
.
persist
(
results
);
if
(
Math
.
random
()
<
CLEANUP_PROBABILITY
)
{
await
this
.
cleanupDereferenced
();
}
}
/**
* Cleans up orphaned files. For instance, output can get orphaned if it's
* written but the editor is closed before the test run is complete.
*/
private
async
cleanupDereferenced
()
{
const
{
children
}
=
await
this
.
fileService
.
resolve
(
this
.
directory
);
if
(
!
children
)
{
return
;
}
const
stored
=
new
Set
(
this
.
stored
.
get
()?.
map
(({
id
})
=>
id
));
await
Promise
.
all
(
children
.
filter
(
child
=>
!
stored
.
has
(
child
.
name
.
replace
(
/
\.[
a-z
]
+$/
,
''
)))
.
map
(
child
=>
this
.
fileService
.
del
(
child
.
resource
))
);
}
private
getResultJsonPath
(
id
:
string
)
{
return
URI
.
joinPath
(
this
.
directory
,
`
${
id
}
.json`
);
}
private
getResultOutputPath
(
id
:
string
)
{
return
URI
.
joinPath
(
this
.
directory
,
`
${
id
}
.output`
);
}
}
src/vs/workbench/contrib/testing/common/testService.ts
浏览文件 @
6b666279
...
...
@@ -9,7 +9,7 @@ import { DisposableStore, IDisposable, IReference } from 'vs/base/common/lifecyc
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
createDecorator
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
ExtHostTestingResource
}
from
'
vs/workbench/api/common/extHost.protocol
'
;
import
{
ObservableValue
}
from
'
vs/workbench/contrib/testing/common/observableValue
'
;
import
{
Mutable
ObservableValue
}
from
'
vs/workbench/contrib/testing/common/observableValue
'
;
import
{
AbstractIncrementalTestCollection
,
IncrementalTestCollectionItem
,
InternalTestItem
,
RunTestForProviderRequest
,
RunTestsRequest
,
TestIdPath
,
TestIdWithSrc
,
TestsDiff
}
from
'
vs/workbench/contrib/testing/common/testCollection
'
;
import
{
ITestResult
}
from
'
vs/workbench/contrib/testing/common/testResult
'
;
...
...
@@ -157,7 +157,7 @@ export interface ITestService {
/**
* Set of test IDs the user asked to exclude.
*/
readonly
excludeTests
:
ObservableValue
<
ReadonlySet
<
string
>>
;
readonly
excludeTests
:
Mutable
ObservableValue
<
ReadonlySet
<
string
>>
;
/**
* Sets whether a test is excluded.
...
...
src/vs/workbench/contrib/testing/common/testServiceImpl.ts
浏览文件 @
6b666279
...
...
@@ -14,7 +14,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c
import
{
INotificationService
}
from
'
vs/platform/notification/common/notification
'
;
import
{
IStorageService
,
StorageScope
,
StorageTarget
}
from
'
vs/platform/storage/common/storage
'
;
import
{
ExtHostTestingResource
}
from
'
vs/workbench/api/common/extHost.protocol
'
;
import
{
ObservableValue
}
from
'
vs/workbench/contrib/testing/common/observableValue
'
;
import
{
Mutable
ObservableValue
}
from
'
vs/workbench/contrib/testing/common/observableValue
'
;
import
{
StoredValue
}
from
'
vs/workbench/contrib/testing/common/storedValue
'
;
import
{
AbstractIncrementalTestCollection
,
getTestSubscriptionKey
,
IncrementalTestCollectionItem
,
InternalTestItem
,
RunTestsRequest
,
TestDiffOpType
,
TestIdWithSrc
,
TestsDiff
}
from
'
vs/workbench/contrib/testing/common/testCollection
'
;
import
{
TestingContextKeys
}
from
'
vs/workbench/contrib/testing/common/testingContextKeys
'
;
...
...
@@ -48,7 +48,7 @@ export class TestService extends Disposable implements ITestService {
private
readonly
runningTests
=
new
Map
<
RunTestsRequest
,
CancellationTokenSource
>
();
private
readonly
rootProviders
=
new
Set
<
ITestRootProvider
>
();
public
readonly
excludeTests
=
ObservableValue
.
stored
(
new
StoredValue
<
ReadonlySet
<
string
>>
({
public
readonly
excludeTests
=
Mutable
ObservableValue
.
stored
(
new
StoredValue
<
ReadonlySet
<
string
>>
({
key
:
'
excludedTestItems
'
,
scope
:
StorageScope
.
WORKSPACE
,
target
:
StorageTarget
.
USER
,
...
...
@@ -196,7 +196,7 @@ export class TestService extends Disposable implements ITestService {
const
subscriptions
=
[...
this
.
testSubscriptions
.
values
()]
.
filter
(
v
=>
req
.
tests
.
some
(
t
=>
v
.
collection
.
getNodeById
(
t
.
testId
)))
.
map
(
s
=>
this
.
subscribeToDiffs
(
s
.
ident
.
resource
,
s
.
ident
.
uri
));
const
result
=
this
.
testResults
.
push
(
LiveTestResult
.
from
(
subscriptions
.
map
(
s
=>
s
.
object
),
req
)
);
const
result
=
this
.
testResults
.
createLiveResult
(
subscriptions
.
map
(
s
=>
s
.
object
),
req
);
try
{
const
tests
=
groupBy
(
req
.
tests
,
(
a
,
b
)
=>
a
.
src
.
provider
===
b
.
src
.
provider
?
0
:
1
);
...
...
src/vs/workbench/contrib/testing/test/common/testResultService.test.ts
浏览文件 @
6b666279
...
...
@@ -5,16 +5,23 @@
import
*
as
assert
from
'
assert
'
;
import
{
timeout
}
from
'
vs/base/common/async
'
;
import
{
bufferToStream
,
newWriteableBufferStream
,
VSBuffer
}
from
'
vs/base/common/buffer
'
;
import
{
Lazy
}
from
'
vs/base/common/lazy
'
;
import
{
MockContextKeyService
}
from
'
vs/platform/keybinding/test/common/mockKeybindingService
'
;
import
{
NullLogService
}
from
'
vs/platform/log/common/log
'
;
import
{
InternalTestItem
}
from
'
vs/workbench/contrib/testing/common/testCollection
'
;
import
{
HydratedTestResult
,
LiveTestResult
,
makeEmptyCounts
,
TestResultItemChange
,
TestResultItemChangeReason
}
from
'
vs/workbench/contrib/testing/common/testResult
'
;
import
{
HydratedTestResult
,
Live
OutputController
,
Live
TestResult
,
makeEmptyCounts
,
TestResultItemChange
,
TestResultItemChangeReason
}
from
'
vs/workbench/contrib/testing/common/testResult
'
;
import
{
TestResultService
}
from
'
vs/workbench/contrib/testing/common/testResultService
'
;
import
{
InMemoryResultStorage
,
ITestResultStorage
}
from
'
vs/workbench/contrib/testing/common/testResultStorage
'
;
import
{
ReExportedTestRunState
as
TestRunState
}
from
'
vs/workbench/contrib/testing/common/testStubs
'
;
import
{
getInitializedMainTestCollection
}
from
'
vs/workbench/contrib/testing/test/common/ownedTestCollection
'
;
import
{
TestStorageService
}
from
'
vs/workbench/test/common/workbenchTestServices
'
;
export
const
emptyOutputController
=
()
=>
new
LiveOutputController
(
new
Lazy
(()
=>
[
newWriteableBufferStream
(),
Promise
.
resolve
()]),
()
=>
Promise
.
resolve
(
bufferToStream
(
VSBuffer
.
alloc
(
0
))),
);
suite
(
'
Workbench - Test Results Service
'
,
()
=>
{
const
getLabelsIn
=
(
it
:
Iterable
<
InternalTestItem
>
)
=>
[...
it
].
map
(
t
=>
t
.
item
.
label
).
sort
();
const
getChangeSummary
=
()
=>
[...
changed
]
...
...
@@ -27,8 +34,10 @@ suite('Workbench - Test Results Service', () => {
setup
(
async
()
=>
{
changed
=
new
Set
();
r
=
LiveTestResult
.
from
(
'
foo
'
,
[
await
getInitializedMainTestCollection
()],
{
tests
:
[{
src
:
{
provider
:
'
provider
'
,
tree
:
0
},
testId
:
'
id-a
'
}],
debug
:
false
}
emptyOutputController
(),
{
tests
:
[{
src
:
{
provider
:
'
provider
'
,
tree
:
0
},
testId
:
'
id-a
'
}],
debug
:
false
},
);
r
.
onChange
(
e
=>
changed
.
add
(
e
));
...
...
@@ -36,7 +45,7 @@ suite('Workbench - Test Results Service', () => {
suite
(
'
LiveTestResult
'
,
()
=>
{
test
(
'
is empty if no tests are requesteed
'
,
async
()
=>
{
const
r
=
LiveTestResult
.
from
(
[
await
getInitializedMainTestCollection
()]
,
{
tests
:
[],
debug
:
false
});
const
r
=
LiveTestResult
.
from
(
''
,
[
await
getInitializedMainTestCollection
()],
emptyOutputController
()
,
{
tests
:
[],
debug
:
false
});
assert
.
deepStrictEqual
(
getLabelsIn
(
r
.
tests
),
[]);
});
...
...
@@ -181,7 +190,9 @@ suite('Workbench - Test Results Service', () => {
r
.
markComplete
();
const
r2
=
results
.
push
(
LiveTestResult
.
from
(
''
,
[
await
getInitializedMainTestCollection
()],
emptyOutputController
(),
{
tests
:
[{
src
:
{
provider
:
'
provider
'
,
tree
:
0
},
testId
:
'
1
'
}],
debug
:
false
}
));
results
.
clear
();
...
...
@@ -192,7 +203,9 @@ suite('Workbench - Test Results Service', () => {
test
(
'
keeps ongoing tests on top
'
,
async
()
=>
{
results
.
push
(
r
);
const
r2
=
results
.
push
(
LiveTestResult
.
from
(
''
,
[
await
getInitializedMainTestCollection
()],
emptyOutputController
(),
{
tests
:
[{
src
:
{
provider
:
'
provider
'
,
tree
:
0
},
testId
:
'
1
'
}],
debug
:
false
}
));
...
...
@@ -213,7 +226,7 @@ suite('Workbench - Test Results Service', () => {
retired
:
undefined
,
children
:
[],
}]
});
}
,
()
=>
Promise
.
resolve
(
bufferToStream
(
VSBuffer
.
alloc
(
0
)))
);
test
(
'
pushes hydrated results
'
,
async
()
=>
{
results
.
push
(
r
);
...
...
src/vs/workbench/contrib/testing/test/common/testResultStorage.test.ts
浏览文件 @
6b666279
...
...
@@ -10,6 +10,7 @@ import { ITestResult, LiveTestResult } from 'vs/workbench/contrib/testing/common
import
{
InMemoryResultStorage
,
RETAIN_MAX_RESULTS
}
from
'
vs/workbench/contrib/testing/common/testResultStorage
'
;
import
{
MainThreadTestCollection
}
from
'
vs/workbench/contrib/testing/common/testServiceImpl
'
;
import
{
getInitializedMainTestCollection
}
from
'
vs/workbench/contrib/testing/test/common/ownedTestCollection
'
;
import
{
emptyOutputController
}
from
'
vs/workbench/contrib/testing/test/common/testResultService.test
'
;
import
{
TestStorageService
}
from
'
vs/workbench/test/common/workbenchTestServices
'
;
suite
(
'
Workbench - Test Result Storage
'
,
()
=>
{
...
...
@@ -18,7 +19,9 @@ suite('Workbench - Test Result Storage', () => {
const
makeResult
=
(
addMessage
?:
string
)
=>
{
const
t
=
LiveTestResult
.
from
(
''
,
[
collection
],
emptyOutputController
(),
{
tests
:
[{
src
:
{
provider
:
'
provider
'
,
tree
:
0
},
testId
:
'
id-a
'
}],
debug
:
false
}
);
if
(
addMessage
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录