Skip to content

Commit a79553f

Browse files
authored
fix(dart_frog_cli): report daemon missing parameters (#1050)
1 parent 31515b4 commit a79553f

File tree

7 files changed

+339
-46
lines changed

7 files changed

+339
-46
lines changed

packages/dart_frog_cli/lib/src/daemon/domain/dev_server_domain.dart

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,11 @@ class DevServerDomain extends DomainBase {
3636

3737
/// Starts a [DevServerRunner] for the given [request].
3838
Future<DaemonResponse> _start(DaemonRequest request) async {
39-
final workingDirectory = request.params?['workingDirectory'];
40-
if (workingDirectory is! String) {
41-
throw const DartFrogDaemonMalformedMessageException(
42-
'invalid workingDirectory',
43-
);
44-
}
39+
final workingDirectory = request.getParam<String>('workingDirectory');
4540

46-
final port = request.params?['port'];
47-
if (port is! int) {
48-
throw const DartFrogDaemonMalformedMessageException('invalid port');
49-
}
41+
final port = request.getParam<int>('port');
5042

51-
final dartVmServicePort = request.params?['dartVmServicePort'];
52-
if (dartVmServicePort is! int) {
53-
throw const DartFrogDaemonMalformedMessageException(
54-
'invalid dartVmServicePort',
55-
);
56-
}
43+
final dartVmServicePort = request.getParam<int>('dartVmServicePort');
5744

5845
final applicationId = getId();
5946

@@ -127,12 +114,7 @@ class DevServerDomain extends DomainBase {
127114
}
128115

129116
Future<DaemonResponse> _reload(DaemonRequest request) async {
130-
final applicationId = request.params?['applicationId'];
131-
if (applicationId is! String) {
132-
throw const DartFrogDaemonMalformedMessageException(
133-
'invalid applicationId',
134-
);
135-
}
117+
final applicationId = request.getParam<String>('applicationId');
136118

137119
final runner = _devServerRunners[applicationId];
138120
if (runner == null) {
@@ -166,12 +148,7 @@ class DevServerDomain extends DomainBase {
166148
}
167149

168150
Future<DaemonResponse> _stop(DaemonRequest request) async {
169-
final applicationId = request.params?['applicationId'];
170-
if (applicationId is! String) {
171-
throw const DartFrogDaemonMalformedMessageException(
172-
'invalid applicationId',
173-
);
174-
}
151+
final applicationId = request.getParam<String>('applicationId');
175152

176153
final runner = _devServerRunners.remove(applicationId);
177154
if (runner == null) {

packages/dart_frog_cli/lib/src/daemon/domain/route_configuration_domain.dart

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,7 @@ class RouteConfigurationDomain extends DomainBase {
3434
final RouteConfigurationWatcherBuilder _routeConfigWatcherBuilder;
3535

3636
Future<DaemonResponse> _watcherStart(DaemonRequest request) async {
37-
final workingDirectory = request.params?['workingDirectory'];
38-
if (workingDirectory is! String) {
39-
throw const DartFrogDaemonMalformedMessageException(
40-
'invalid workingDirectory',
41-
);
42-
}
37+
final workingDirectory = request.getParam<String>('workingDirectory');
4338

4439
final watcherId = getId();
4540

@@ -128,12 +123,7 @@ class RouteConfigurationDomain extends DomainBase {
128123
Future<DaemonResponse> _watcherGenerateRouteConfiguration(
129124
DaemonRequest request,
130125
) async {
131-
final watcherId = request.params?['watcherId'];
132-
if (watcherId is! String) {
133-
throw const DartFrogDaemonMalformedMessageException(
134-
'invalid watcherId',
135-
);
136-
}
126+
final watcherId = request.getParam<String>('watcherId');
137127

138128
final watcher = _routeConfigurationWatchers[watcherId];
139129
if (watcher == null) {
@@ -168,12 +158,7 @@ class RouteConfigurationDomain extends DomainBase {
168158
}
169159

170160
Future<DaemonResponse> _watcherStop(DaemonRequest request) async {
171-
final watcherId = request.params?['watcherId'];
172-
if (watcherId is! String) {
173-
throw const DartFrogDaemonMalformedMessageException(
174-
'invalid watcherId',
175-
);
176-
}
161+
final watcherId = request.getParam<String>('watcherId');
177162

178163
final watcher = _routeConfigurationWatchers.remove(watcherId);
179164
if (watcher == null) {

packages/dart_frog_cli/lib/src/daemon/exceptions.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,14 @@ class DartFrogDaemonMalformedMessageException
2727
const DartFrogDaemonMalformedMessageException(String message)
2828
: super('Malformed message, $message');
2929
}
30+
31+
/// {@template dart_frog_daemon_missing_parameter_exception}
32+
/// An exception thrown when the daemon reports a missing parameter of a
33+
/// message.
34+
/// {@endtemplate}
35+
class DartFrogDaemonMissingParameterException
36+
extends DartFrogDaemonMessageException {
37+
/// {@macro dart_frog_daemon_malformed_message_exception}
38+
const DartFrogDaemonMissingParameterException(String message)
39+
: super('Missing parameter, $message');
40+
}

packages/dart_frog_cli/lib/src/daemon/protocol.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,46 @@ class DaemonRequest extends DaemonMessage {
118118

119119
@override
120120
List<Object?> get props => [id, method, params, domain];
121+
122+
///
123+
/// Gets a parameter of this request.
124+
///
125+
/// Throws a [DartFrogDaemonMissingParameterException] if the parameter
126+
/// is not found and type [T] is not nullable.
127+
///
128+
/// Throws a [DartFrogDaemonMalformedMessageException] if the parameter
129+
/// is not of type [T].
130+
///
131+
/// Required parameters should be typed as not nullable
132+
/// `final paramValue = getParam<String>('requiredValue')`.
133+
///
134+
/// Optional parameters should be typed as nullable
135+
/// `final paramValue = getParam<String?>('optionalValue')`.
136+
///
137+
T getParam<T>(String name) {
138+
final params = this.params;
139+
140+
if (params == null) {
141+
throw const DartFrogDaemonMalformedMessageException(
142+
'Missing params object',
143+
);
144+
}
145+
146+
final param = params[name];
147+
if (param is! T) {
148+
// Check if param type is optional or not
149+
if (param == null && null is! T) {
150+
throw DartFrogDaemonMissingParameterException(
151+
'$name not found',
152+
);
153+
}
154+
throw DartFrogDaemonMalformedMessageException(
155+
'invalid $name',
156+
);
157+
}
158+
159+
return param;
160+
}
121161
}
122162

123163
/// {@template daemon_response}

packages/dart_frog_cli/test/src/daemon/domain/dev_server_domain_test.dart

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,77 @@ void main() {
122122
).called(1);
123123
});
124124

125+
group('missing parameters', () {
126+
test('workingDirectory', () async {
127+
expect(
128+
await domain.handleRequest(
129+
const DaemonRequest(
130+
id: '12',
131+
domain: 'dev_server',
132+
method: 'start',
133+
params: {'port': 3000, 'dartVmServicePort': 3001},
134+
),
135+
),
136+
equals(
137+
const DaemonResponse.error(
138+
id: '12',
139+
error: {
140+
'message': 'Missing parameter, workingDirectory not found',
141+
},
142+
),
143+
),
144+
);
145+
});
146+
147+
test('port', () async {
148+
expect(
149+
await domain.handleRequest(
150+
const DaemonRequest(
151+
id: '12',
152+
domain: 'dev_server',
153+
method: 'start',
154+
params: {
155+
'workingDirectory': '/',
156+
'dartVmServicePort': 3001,
157+
},
158+
),
159+
),
160+
equals(
161+
const DaemonResponse.error(
162+
id: '12',
163+
error: {
164+
'message': 'Missing parameter, port not found',
165+
},
166+
),
167+
),
168+
);
169+
});
170+
171+
test('dartVmServicePort', () async {
172+
expect(
173+
await domain.handleRequest(
174+
const DaemonRequest(
175+
id: '12',
176+
domain: 'dev_server',
177+
method: 'start',
178+
params: {
179+
'workingDirectory': '/',
180+
'port': 3000,
181+
},
182+
),
183+
),
184+
equals(
185+
const DaemonResponse.error(
186+
id: '12',
187+
error: {
188+
'message': 'Missing parameter, dartVmServicePort not found',
189+
},
190+
),
191+
),
192+
);
193+
});
194+
});
195+
125196
group('malformed messages', () {
126197
test('workingDirectory', () async {
127198
expect(
@@ -277,6 +348,29 @@ void main() {
277348
);
278349
});
279350

351+
group('missing parameters', () {
352+
test('applicationId', () async {
353+
expect(
354+
await domain.handleRequest(
355+
const DaemonRequest(
356+
id: '12',
357+
domain: 'dev_server',
358+
method: 'reload',
359+
params: {},
360+
),
361+
),
362+
equals(
363+
const DaemonResponse.error(
364+
id: '12',
365+
error: {
366+
'message': 'Missing parameter, applicationId not found',
367+
},
368+
),
369+
),
370+
);
371+
});
372+
});
373+
280374
test('application not found', () async {
281375
expect(
282376
await domain.handleRequest(
@@ -387,6 +481,29 @@ void main() {
387481
);
388482
});
389483

484+
group('missing parameters', () {
485+
test('applicationId', () async {
486+
expect(
487+
await domain.handleRequest(
488+
const DaemonRequest(
489+
id: '12',
490+
domain: 'dev_server',
491+
method: 'stop',
492+
params: {},
493+
),
494+
),
495+
equals(
496+
const DaemonResponse.error(
497+
id: '12',
498+
error: {
499+
'message': 'Missing parameter, applicationId not found',
500+
},
501+
),
502+
),
503+
);
504+
});
505+
});
506+
390507
test('application not found', () async {
391508
expect(
392509
await domain.handleRequest(

packages/dart_frog_cli/test/src/daemon/domain/route_configuration_domain_test.dart

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,29 @@ void main() {
166166
});
167167
});
168168

169+
group('missing parameters', () {
170+
test('workingDirectory', () async {
171+
expect(
172+
await domain.handleRequest(
173+
const DaemonRequest(
174+
id: '12',
175+
domain: 'route_configuration',
176+
method: 'watcherStart',
177+
params: {},
178+
),
179+
),
180+
equals(
181+
const DaemonResponse.error(
182+
id: '12',
183+
error: {
184+
'message': 'Missing parameter, workingDirectory not found',
185+
},
186+
),
187+
),
188+
);
189+
});
190+
});
191+
169192
test('on dev server throw', () async {
170193
when(() => watcher.start()).thenThrow('error');
171194

@@ -276,6 +299,29 @@ void main() {
276299
});
277300
});
278301

302+
group('missing parameters', () {
303+
test('watcherId', () async {
304+
expect(
305+
await domain.handleRequest(
306+
const DaemonRequest(
307+
id: '12',
308+
domain: 'route_configuration',
309+
method: 'watcherStop',
310+
params: {},
311+
),
312+
),
313+
equals(
314+
const DaemonResponse.error(
315+
id: '12',
316+
error: {
317+
'message': 'Missing parameter, watcherId not found',
318+
},
319+
),
320+
),
321+
);
322+
});
323+
});
324+
279325
test('on dev server throw', () async {
280326
when(() => watcher.stop()).thenThrow('error');
281327

@@ -421,6 +467,29 @@ void main() {
421467
});
422468
});
423469

470+
group('missing parameters', () {
471+
test('watcherId', () async {
472+
expect(
473+
await domain.handleRequest(
474+
const DaemonRequest(
475+
id: '12',
476+
domain: 'route_configuration',
477+
method: 'watcherGenerateRouteConfiguration',
478+
params: {},
479+
),
480+
),
481+
equals(
482+
const DaemonResponse.error(
483+
id: '12',
484+
error: {
485+
'message': 'Missing parameter, watcherId not found',
486+
},
487+
),
488+
),
489+
);
490+
});
491+
});
492+
424493
test('when cannot generate route config', () async {
425494
when(() => watcher.forceRouteConfigurationRegeneration())
426495
.thenReturn(null);

0 commit comments

Comments
 (0)