Skip to content

Commit 8009533

Browse files
authored
feat: move dashboard's dev_cocoon to integration tests (#4961)
Updates the dashboard code to use a "real" server in the browser. Currently, `DevelopmentCocoonService` in `dashboard/lib/service/dev_cocoon.dart` generates fake data manually. While effective, it doesn't test end-to-end with the backend logic or API surface, leading to a false sense of security (and having caused multiple 'push to prod to fix'). By using `IntegrationServer`, we can run the real `app_dart` logic against in-memory fakes (Firestore, BigQuery, etc.), ensuring the frontend is tested against the same logic the production server uses. 1. defangs app_dart/lib/** by removing app_engine and dart:io. * gae_server.dart passes in the needed "dart:io" handlers * server.dart now handles an abstract Request, which can be real (app engine, local server) or fake (tests / dashboard local). * "dynamic config" no longer looks up the config.yaml from the read only filesystem and instead we build dynamic config with build hooks - `generated_config.dart`. 2. Removes dev_cocoon and its hardcoded mockery (partial reason for the image diffs) 3. Adds `IntegrationServerAdapter` (which is an `AppEngineCocoonService`) to wrap and make fake http calls to the `IntegrationServer`.
1 parent 9e74710 commit 8009533

119 files changed

Lines changed: 1656 additions & 1136 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app_dart/analysis_options.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
include: ../analysis_options.yaml
22

3+
analyzer:
4+
exclude:
5+
# Optional: exclude the generated file if you don't want it analyzed
6+
- hook/build.dart
7+
38
linter:
49
rules:
510
# a few rules listed below are the ones we would like to exclude from flutter_lint package, for app_dart

app_dart/bin/gae_server.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:cocoon_service/cocoon_service.dart';
1111
import 'package:cocoon_service/server.dart';
1212
import 'package:cocoon_service/src/foundation/appengine_utils.dart';
1313
import 'package:cocoon_service/src/foundation/providers.dart';
14+
import 'package:cocoon_service/src/request_handling/http_io.dart';
1415
import 'package:cocoon_service/src/service/big_query.dart';
1516
import 'package:cocoon_service/src/service/build_status_service.dart';
1617
import 'package:cocoon_service/src/service/commit_service.dart';
@@ -143,7 +144,9 @@ Future<void> main() async {
143144
);
144145

145146
return runAppEngine(
146-
server,
147+
(HttpRequest request) async {
148+
await server(request.toRequest());
149+
},
147150
onAcceptingConnections: (InternetAddress address, int port) {
148151
final host = address.isLoopback ? 'localhost' : address.host;
149152
print('Serving requests at http://$host:$port/');

app_dart/hook/build.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2026 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:io';
6+
7+
import 'package:native_assets_cli/native_assets_cli.dart';
8+
9+
void main(List<String> args) async {
10+
await build(args, (config, output) async {
11+
// 1. Read the source file (e.g., your App Engine config)
12+
final configFile = File('config.yaml');
13+
final content = await configFile.readAsString();
14+
15+
// 2. Define the path for the generated code
16+
// It's best to put this in 'lib/src/generated_config.dart'
17+
final outputFile = File('lib/src/generated_config.dart');
18+
19+
// 3. Write the file as a raw string constant
20+
await outputFile.writeAsString("""
21+
// GENERATED CODE - DO NOT MODIFY BY HAND
22+
// Generated by build.dart hook
23+
24+
const String configFileContent =
25+
r\'\'\'$content\'\'\';
26+
""");
27+
28+
// 4. (Optional) Tell Dart that this hook depends on the config file
29+
// This ensures that if config.yaml changes, the hook runs again.
30+
output.addDependency(configFile.uri);
31+
});
32+
}

app_dart/lib/cocoon_service.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
export 'src/foundation/context.dart';
66
export 'src/foundation/utils.dart';
7+
export 'src/model/firestore/base.dart' hide AppDocument;
8+
export 'src/model/firestore/commit.dart';
9+
export 'src/model/firestore/presubmit_check.dart';
10+
export 'src/model/firestore/presubmit_guard.dart';
11+
export 'src/model/firestore/suppressed_test.dart';
12+
export 'src/model/firestore/task.dart';
13+
export 'src/model/firestore/tree_status_change.dart';
714
export 'src/request_handlers/check_flaky_builders.dart';
815
export 'src/request_handlers/create_branch.dart';
916
export 'src/request_handlers/dart_internal_subscription.dart';
@@ -35,6 +42,7 @@ export 'src/request_handling/authentication.dart';
3542
export 'src/request_handling/cache_request_handler.dart';
3643
export 'src/request_handling/checkrun_authentication.dart';
3744
export 'src/request_handling/dashboard_authentication.dart';
45+
export 'src/request_handling/http_utils.dart';
3846
export 'src/request_handling/pubsub.dart';
3947
export 'src/request_handling/pubsub_authentication.dart';
4048
export 'src/request_handling/request_handler.dart';
@@ -47,6 +55,7 @@ export 'src/service/build_bucket_client.dart';
4755
export 'src/service/cache_service.dart';
4856
export 'src/service/config.dart';
4957
export 'src/service/firestore.dart';
58+
export 'src/service/flags/dynamic_config.dart';
5059
export 'src/service/gerrit_service.dart';
5160
export 'src/service/github_checks_service.dart';
5261
export 'src/service/luci_build_service.dart';

app_dart/lib/server.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:io';
65
import 'dart:math';
76

87
import 'cocoon_service.dart';
@@ -25,7 +24,7 @@ import 'src/service/content_aware_hash_service.dart';
2524
import 'src/service/discord_service.dart';
2625
import 'src/service/scheduler/ci_yaml_fetcher.dart';
2726

28-
typedef Server = Future<void> Function(HttpRequest);
27+
typedef Server = Future<void> Function(Request);
2928

3029
/// Creates a service with the given dependencies.
3130
Server createServer({
@@ -404,7 +403,7 @@ Server createServer({
404403
'/readiness_check': ReadinessCheck(config: config),
405404
};
406405

407-
return (HttpRequest request) async {
406+
return (Request request) async {
408407
if (handlers.containsKey(request.uri.path)) {
409408
final handler = handlers[request.uri.path]!;
410409
await handler.service(request);

app_dart/lib/src/foundation/github_checks_util.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
// found in the LICENSE file.
44

55
import 'dart:core';
6-
import 'dart:io';
76

87
import 'package:cocoon_server/logging.dart';
98
import 'package:github/github.dart' as github;
109
import 'package:github/hooks.dart';
1110
import 'package:retry/retry.dart';
1211

12+
import '../request_handling/http_utils.dart';
1313
import '../service/config.dart';
1414

1515
/// Wrapper class for github checkrun service. This is used to simplify

app_dart/lib/src/foundation/utils.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import 'dart:async';
66
import 'dart:convert';
7-
import 'dart:io';
87

98
import 'package:cocoon_server/logging.dart';
109
import 'package:github/github.dart';

app_dart/lib/src/generated_config.dart

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app_dart/lib/src/model/firestore/account.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:io';
6-
75
import 'package:googleapis/firestore/v1.dart' as g;
86
import 'package:path/path.dart' as p;
97

8+
import '../../request_handling/http_utils.dart';
109
import '../../service/firestore.dart';
1110
import 'base.dart';
1211

app_dart/lib/src/model/firestore/commit.dart

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,12 @@
55
/// @docImport 'task.dart';
66
library;
77

8-
import 'dart:io';
9-
108
import 'package:github/github.dart';
119
import 'package:googleapis/firestore/v1.dart' hide Status;
1210
import 'package:path/path.dart' as p;
1311
import 'package:truncate/truncate.dart';
1412

1513
import '../../../cocoon_service.dart';
16-
import '../../service/firestore.dart';
1714
import '../commit_ref.dart';
1815
import 'base.dart';
1916

0 commit comments

Comments
 (0)