@@ -7,6 +7,7 @@ use std::io::Write;
7
7
use std:: path:: Path ;
8
8
use std:: path:: PathBuf ;
9
9
use std:: sync:: Arc ;
10
+ use std:: sync:: atomic:: AtomicI32 ;
10
11
11
12
use deno_ast:: MediaType ;
12
13
use deno_ast:: ModuleKind ;
@@ -15,17 +16,15 @@ use deno_config::glob::FileCollector;
15
16
use deno_config:: glob:: FilePatterns ;
16
17
use deno_config:: glob:: PathOrPattern ;
17
18
use deno_config:: glob:: PathOrPatternSet ;
18
- use deno_core:: InspectorPostMessageError ;
19
- use deno_core:: InspectorPostMessageErrorKind ;
20
19
use deno_core:: LocalInspectorSession ;
21
20
use deno_core:: anyhow:: Context ;
22
21
use deno_core:: anyhow:: anyhow;
23
22
use deno_core:: error:: AnyError ;
24
23
use deno_core:: error:: CoreError ;
24
+ use deno_core:: parking_lot:: Mutex ;
25
25
use deno_core:: serde_json;
26
26
use deno_core:: sourcemap:: SourceMap ;
27
27
use deno_core:: url:: Url ;
28
- use deno_error:: JsErrorBox ;
29
28
use deno_resolver:: npm:: DenoInNpmPackageChecker ;
30
29
use node_resolver:: InNpmPackageChecker ;
31
30
use regex:: Regex ;
@@ -55,36 +54,47 @@ pub mod reporter;
55
54
mod util;
56
55
use merge:: ProcessCoverage ;
57
56
58
- pub struct CoverageCollector {
59
- pub dir : PathBuf ,
60
- session : LocalInspectorSession ,
57
+ static NEXT_MSG_ID : AtomicI32 = AtomicI32 :: new ( 0 ) ;
58
+
59
+ fn next_msg_id ( ) -> i32 {
60
+ NEXT_MSG_ID . fetch_add ( 1 , std:: sync:: atomic:: Ordering :: Relaxed )
61
61
}
62
62
63
- impl CoverageCollector {
64
- pub fn new ( dir : PathBuf , session : LocalInspectorSession ) -> Self {
65
- Self { dir, session }
66
- }
63
+ #[ derive( Debug ) ]
64
+ pub struct CoverageCollectorInner {
65
+ dir : PathBuf ,
66
+ coverage_msg_id : Option < i32 > ,
67
+ }
67
68
68
- pub async fn start_collecting (
69
- & mut self ,
70
- ) -> Result < ( ) , InspectorPostMessageError > {
71
- self . enable_debugger ( ) . await ?;
72
- self . enable_profiler ( ) . await ?;
73
- self
74
- . start_precise_coverage ( cdp:: StartPreciseCoverageArgs {
75
- call_count : true ,
76
- detailed : true ,
77
- allow_triggered_updates : false ,
78
- } )
79
- . await ?;
69
+ #[ derive( Clone , Debug ) ]
70
+ pub struct CoverageCollectorState ( Arc < Mutex < CoverageCollectorInner > > ) ;
80
71
81
- Ok ( ( ) )
72
+ impl CoverageCollectorState {
73
+ pub fn new ( dir : PathBuf ) -> Self {
74
+ Self ( Arc :: new ( Mutex :: new ( CoverageCollectorInner {
75
+ dir,
76
+ coverage_msg_id : None ,
77
+ } ) ) )
82
78
}
83
79
84
- pub async fn stop_collecting ( & mut self ) -> Result < ( ) , CoreError > {
85
- fs:: create_dir_all ( & self . dir ) ?;
80
+ pub fn callback ( & self , msg : deno_core:: InspectorMsg ) {
81
+ let deno_core:: InspectorMsgKind :: Message ( msg_id) = msg. kind else {
82
+ return ;
83
+ } ;
84
+ let maybe_coverage_msg_id = self . 0 . lock ( ) . coverage_msg_id . as_ref ( ) . cloned ( ) ;
85
+
86
+ if let Some ( coverage_msg_id) = maybe_coverage_msg_id
87
+ && coverage_msg_id == msg_id
88
+ {
89
+ let message: serde_json:: Value =
90
+ serde_json:: from_str ( & msg. content ) . unwrap ( ) ;
91
+ let coverages: cdp:: TakePreciseCoverageResponse =
92
+ serde_json:: from_value ( message[ "result" ] . clone ( ) ) . unwrap ( ) ;
93
+ self . write_coverages ( coverages. result ) ;
94
+ }
95
+ }
86
96
87
- let script_coverages = self . take_precise_coverage ( ) . await ? . result ;
97
+ fn write_coverages ( & self , script_coverages : Vec < cdp :: ScriptCoverage > ) {
88
98
for script_coverage in script_coverages {
89
99
// Filter out internal and http/https JS files, eval'd scripts,
90
100
// and scripts with invalid urls from being included in coverage reports
@@ -100,92 +110,86 @@ impl CoverageCollector {
100
110
}
101
111
102
112
let filename = format ! ( "{}.json" , Uuid :: new_v4( ) ) ;
103
- let filepath = self . dir . join ( filename) ;
104
-
105
- let mut out = BufWriter :: new ( File :: create ( & filepath) ?) ;
106
- let coverage = serde_json:: to_string ( & script_coverage)
107
- . map_err ( JsErrorBox :: from_err) ?;
113
+ let filepath = self . 0 . lock ( ) . dir . join ( filename) ;
114
+
115
+ let file = match File :: create ( & filepath) {
116
+ Ok ( f) => f,
117
+ Err ( err) => {
118
+ log:: error!(
119
+ "Failed to create coverage file at {:?}, reason: {:?}" ,
120
+ filepath,
121
+ err
122
+ ) ;
123
+ continue ;
124
+ }
125
+ } ;
126
+ let mut out = BufWriter :: new ( file) ;
127
+ let coverage = serde_json:: to_string ( & script_coverage) . unwrap ( ) ;
108
128
let formatted_coverage =
109
129
format_json ( & filepath, & coverage, & Default :: default ( ) )
110
130
. ok ( )
111
131
. flatten ( )
112
132
. unwrap_or ( coverage) ;
113
133
114
- out. write_all ( formatted_coverage. as_bytes ( ) ) ?;
115
- out. flush ( ) ?;
134
+ if let Err ( err) = out. write_all ( formatted_coverage. as_bytes ( ) ) {
135
+ log:: error!(
136
+ "Failed to write coverage file at {:?}, reason: {:?}" ,
137
+ filepath,
138
+ err
139
+ ) ;
140
+ continue ;
141
+ }
142
+ if let Err ( err) = out. flush ( ) {
143
+ log:: error!(
144
+ "Failed to flush coverage file at {:?}, reason: {:?}" ,
145
+ filepath,
146
+ err
147
+ ) ;
148
+ continue ;
149
+ }
116
150
}
117
-
118
- self . disable_debugger ( ) . await ?;
119
- self . disable_profiler ( ) . await ?;
120
-
121
- Ok ( ( ) )
122
- }
123
-
124
- async fn enable_debugger ( & mut self ) -> Result < ( ) , InspectorPostMessageError > {
125
- self
126
- . session
127
- . post_message :: < ( ) > ( "Debugger.enable" , None )
128
- . await ?;
129
- Ok ( ( ) )
130
151
}
152
+ }
131
153
132
- async fn enable_profiler ( & mut self ) -> Result < ( ) , InspectorPostMessageError > {
133
- self
134
- . session
135
- . post_message :: < ( ) > ( "Profiler.enable" , None )
136
- . await ?;
137
- Ok ( ( ) )
138
- }
154
+ pub struct CoverageCollector {
155
+ pub state : CoverageCollectorState ,
156
+ session : LocalInspectorSession ,
157
+ }
139
158
140
- async fn disable_debugger (
141
- & mut self ,
142
- ) -> Result < ( ) , InspectorPostMessageError > {
143
- self
144
- . session
145
- . post_message :: < ( ) > ( "Debugger.disable" , None )
146
- . await ?;
147
- Ok ( ( ) )
159
+ impl CoverageCollector {
160
+ pub fn new (
161
+ state : CoverageCollectorState ,
162
+ session : LocalInspectorSession ,
163
+ ) -> Self {
164
+ Self { state, session }
148
165
}
149
166
150
- async fn disable_profiler (
151
- & mut self ,
152
- ) -> Result < ( ) , InspectorPostMessageError > {
167
+ pub fn start_collecting ( & mut self ) {
153
168
self
154
169
. session
155
- . post_message :: < ( ) > ( "Profiler.disable" , None )
156
- . await ?;
157
- Ok ( ( ) )
158
- }
159
-
160
- async fn start_precise_coverage (
161
- & mut self ,
162
- parameters : cdp:: StartPreciseCoverageArgs ,
163
- ) -> Result < cdp:: StartPreciseCoverageResponse , InspectorPostMessageError > {
164
- let return_value = self
165
- . session
166
- . post_message ( "Profiler.startPreciseCoverage" , Some ( parameters) )
167
- . await ?;
168
-
169
- let return_object = serde_json:: from_value ( return_value) . map_err ( |e| {
170
- InspectorPostMessageErrorKind :: JsBox ( JsErrorBox :: from_err ( e) ) . into_box ( )
171
- } ) ?;
172
-
173
- Ok ( return_object)
170
+ . post_message :: < ( ) > ( next_msg_id ( ) , "Profiler.enable" , None ) ;
171
+ self . session . post_message (
172
+ next_msg_id ( ) ,
173
+ "Profiler.startPreciseCoverage" ,
174
+ Some ( cdp:: StartPreciseCoverageArgs {
175
+ call_count : true ,
176
+ detailed : true ,
177
+ allow_triggered_updates : false ,
178
+ } ) ,
179
+ ) ;
174
180
}
175
181
176
- async fn take_precise_coverage (
177
- & mut self ,
178
- ) -> Result < cdp:: TakePreciseCoverageResponse , InspectorPostMessageError > {
179
- let return_value = self
180
- . session
181
- . post_message :: < ( ) > ( "Profiler.takePreciseCoverage" , None )
182
- . await ?;
182
+ pub fn stop_collecting ( & mut self ) -> Result < ( ) , CoreError > {
183
+ fs:: create_dir_all ( & self . state . 0 . lock ( ) . dir ) ?;
184
+ let msg_id = next_msg_id ( ) ;
185
+ self . state . 0 . lock ( ) . coverage_msg_id . replace ( msg_id) ;
183
186
184
- let return_object = serde_json:: from_value ( return_value) . map_err ( |e| {
185
- InspectorPostMessageErrorKind :: JsBox ( JsErrorBox :: from_err ( e) ) . into_box ( )
186
- } ) ?;
187
-
188
- Ok ( return_object)
187
+ self . session . post_message :: < ( ) > (
188
+ msg_id,
189
+ "Profiler.takePreciseCoverage" ,
190
+ None ,
191
+ ) ;
192
+ Ok ( ( ) )
189
193
}
190
194
}
191
195
0 commit comments