11import * as vscode from 'vscode' ;
2- import { loadedTestController } from './extension' ;
2+ import { allTestRuns , IServerSpec , loadedTestController , osAPI } from './extension' ;
33import { replaceRootItems , serverSpec } from './historyExplorer' ;
44import logger from './logger' ;
55import { makeRESTRequest } from './makeRESTRequest' ;
@@ -29,7 +29,7 @@ async function resolveItemChildren(item: vscode.TestItem) {
2929 `${ item . id } :${ fullClassName } ` ,
3030 fullClassName ,
3131 vscode . Uri . from ( {
32- scheme : "isfs-readonly" ,
32+ scheme : item . uri ?. scheme === "isfs" ? "isfs" : "isfs-readonly" ,
3333 authority : item . id . toLowerCase ( ) ,
3434 path : "/" + fullClassName . replace ( / \. / g, "/" ) + ".cls"
3535 } )
@@ -84,11 +84,15 @@ export async function runTestsHandler(request: vscode.TestRunRequest, cancellati
8484
8585 const run = loadedTestController . createTestRun (
8686 request ,
87- 'Fake Test Results' ,
87+ 'Test Results' ,
8888 true
8989 ) ;
90+
9091 run . appendOutput ( 'Fake output from fake run of fake server tests.\r\nTODO' ) ;
91- const mapAuthorities = new Map < string , Map < string , vscode . Uri > > ( ) ;
92+
93+ // For each authority (i.e. server:namespace) accumulate a map of the class-level Test nodes in the tree.
94+ // We don't yet support running only some TestXXX methods in a testclass
95+ const mapAuthorities = new Map < string , Map < string , vscode . TestItem > > ( ) ;
9296 const queue : vscode . TestItem [ ] = [ ] ;
9397
9498 // Loop through all included tests, or all known tests, and add them to our queue
@@ -111,16 +115,17 @@ export async function runTestsHandler(request: vscode.TestRunRequest, cancellati
111115
112116 // Resolve children if not already done
113117 if ( test . canResolveChildren && ! isResolvedMap . get ( test ) ) {
114- resolveItemChildren ( test ) ;
118+ await resolveItemChildren ( test ) ;
115119 }
116120
117- // Mark each leaf item as enqueued and note its .cls file for copying
118- if ( test . children . size === 0 && test . uri ) {
121+ // Mark each leaf item (a TestXXX method in a class) as enqueued and note its .cls file for copying.
122+ // Every leaf must have a uri.
123+ if ( test . children . size === 0 && test . uri && test . parent ) {
119124 run . enqueued ( test ) ;
120125 const authority = test . uri . authority ;
121- const mapUris = mapAuthorities . get ( authority ) || new Map < string , vscode . Uri > ( ) ;
122- mapUris . set ( test . uri . path , test . uri ) ;
123- mapAuthorities . set ( authority , mapUris ) ;
126+ const mapTestClasses = mapAuthorities . get ( authority ) || new Map < string , vscode . TestItem > ( ) ;
127+ mapTestClasses . set ( test . uri . path , test . parent ) ;
128+ mapAuthorities . set ( authority , mapTestClasses ) ;
124129 }
125130
126131 // Queue any children
@@ -131,31 +136,87 @@ export async function runTestsHandler(request: vscode.TestRunRequest, cancellati
131136 // TODO what?
132137 }
133138
134- for await ( const one of mapAuthorities ) {
135- const authority = one [ 0 ] ;
136- const mapUris = one [ 1 ] ;
137- const username = 'johnm' ; //TODO
138- const testRoot = vscode . Uri . from ( { scheme : 'isfs' , authority, path : `/.vscode/UnitTestRoot/${ username } ` } ) ;
139- try {
140- await vscode . workspace . fs . delete ( testRoot , { recursive : true } ) ;
141- } catch ( error ) {
142- console . log ( error ) ;
143- }
144- for await ( const one of mapUris ) {
145- const key = one [ 0 ] ;
146- const uri = one [ 1 ] ;
147- const keyParts = key . split ( '/' ) ;
148- const clsFile = keyParts . pop ( ) || '' ;
149- const directoryUri = testRoot . with ( { path : testRoot . path . concat ( keyParts . join ( '/' ) ) } ) ;
139+ for await ( const mapInstance of mapAuthorities ) {
140+ const authority = mapInstance [ 0 ] ;
141+ const mapTestClasses = mapInstance [ 1 ] ;
142+ const firstClassTestItem = Array . from ( mapTestClasses . values ( ) ) [ 0 ] ;
143+ const oneUri = firstClassTestItem . uri ;
144+
145+ // This will always be true since every test added to the map above required a uri
146+ if ( oneUri ) {
147+ const folder = vscode . workspace . getWorkspaceFolder ( oneUri ) ;
148+ const server = osAPI . serverForUri ( oneUri ) ;
149+ const username = server . username || 'UnknownUser' ;
150+ const testRoot = vscode . Uri . from ( { scheme : 'isfs' , authority, path : `/.vscode/UnitTestRoot/${ username } ` } ) ;
150151 try {
151- await vscode . workspace . fs . copy ( uri , directoryUri . with ( { path : directoryUri . path . concat ( clsFile ) } ) ) ;
152+ // Limitation of the Atelier API means this can only delete the files, not the folders
153+ // but zombie folders shouldn't cause problems.
154+ await vscode . workspace . fs . delete ( testRoot , { recursive : true } ) ;
152155 } catch ( error ) {
153156 console . log ( error ) ;
154157 }
158+ for await ( const mapInstance of mapTestClasses ) {
159+ const key = mapInstance [ 0 ] ;
160+ const uri = mapInstance [ 1 ] . uri ;
161+ const keyParts = key . split ( '/' ) ;
162+ const clsFile = keyParts . pop ( ) || '' ;
163+ const directoryUri = testRoot . with ( { path : testRoot . path . concat ( keyParts . join ( '/' ) ) } ) ;
164+ // This will always be true since every test added to the map above required a uri
165+ if ( uri ) {
166+ try {
167+ await vscode . workspace . fs . copy ( uri , directoryUri . with ( { path : directoryUri . path . concat ( clsFile ) } ) ) ;
168+ } catch ( error ) {
169+ console . log ( error ) ;
170+ }
171+ }
172+ }
173+
174+ // Find this user's most recent TestInstance
175+ const serverSpec : IServerSpec = {
176+ username : server . username ,
177+ name : server . serverName ,
178+ webServer : {
179+ host : server . host ,
180+ port : server . port ,
181+ pathPrefix : server . pathPrefix ,
182+ scheme : server . scheme
183+ }
184+ }
185+ const response = await makeRESTRequest (
186+ "POST" ,
187+ serverSpec ,
188+ { apiVersion : 1 , namespace : server . namespace , path : "/action/query" } ,
189+ {
190+ query : "SELECT TOP 1 ID, TestInstance, Name, Duration, Status, ErrorDescription FROM %UnitTest_Result.TestSuite WHERE Name %STARTSWITH ? ORDER BY TestInstance DESC" ,
191+ parameters : [ `${ server . username } \\` ]
192+ } ,
193+ ) ;
194+ if ( response ) {
195+ const latestInstanceId = response ?. data ?. result ?. content ?. [ 0 ] ?. ID ;
196+ console . log ( latestInstanceId ) ;
197+ }
198+
199+ // Run tests through the debugger but only stop at breakpoints etc if user chose "Debug Test" instead of "Run Test"
200+ const runIndex = allTestRuns . push ( run ) - 1 ;
201+ const configuration : vscode . DebugConfiguration = {
202+ "type" : "objectscript" ,
203+ "request" : "launch" ,
204+ "name" : `ServerTests:${ server . username } ` ,
205+ "program" : `##class(%UnitTest.Manager).RunTest("${ server . username } ","/noload/nodelete")` ,
206+ "testRunIndex" : runIndex ,
207+ "testIdBase" : firstClassTestItem . id . split ( ":" , 2 ) . join ( ":" )
208+ } ;
209+ const sessionOptions : vscode . DebugSessionOptions = {
210+ noDebug : request . profile ?. kind !== vscode . TestRunProfileKind . Debug
211+ }
212+ if ( ! await vscode . debug . startDebugging ( folder , configuration , sessionOptions ) ) {
213+ await vscode . window . showErrorMessage ( `Failed to launch testing` , { modal : true } ) ;
214+ run . end ( ) ;
215+ allTestRuns [ runIndex ] = undefined ;
216+ return ;
217+ }
155218 }
156219 }
157220
158- // TODO
159- await new Promise ( resolve => setTimeout ( resolve , 5000 ) ) ;
160- run . end ( ) ;
221+ //run.end();
161222}
0 commit comments