-
Notifications
You must be signed in to change notification settings - Fork 362
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integrated cupertino_http with package_http_profile #1079
Merged
brianquinlan
merged 34 commits into
dart-lang:master
from
brianquinlan:cupertino_profile
May 23, 2024
Merged
Changes from 32 commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
206a7ff
Populate package:http_profile
derekxu16 6618444
Address comments
derekxu16 5d8b3b8
Add examples showing how to use the `cookies` setters
derekxu16 359a156
Update
derekxu16 d7f3d95
Integrate cupertino_http with http_profile
brianquinlan 1fd25f0
Add note
brianquinlan a1feec6
Merge branch 'master' into cupertino_profile
brianquinlan 603d783
Update
brianquinlan c8ab149
Changes
brianquinlan 4af722d
Update
brianquinlan b80eaf9
Merge remote-tracking branch 'upstream/master' into cupertino_profile
brianquinlan 57e367f
Changelog/Pubspec
brianquinlan 618f47b
Update CHANGELOG.md
brianquinlan 82590dd
Fix lints
brianquinlan 22c184f
Update cupertino_client.dart
brianquinlan 779f9ac
Add tests
brianquinlan 9f717d1
Update client_profile_test.dart
brianquinlan 671b781
Set content-length request header
brianquinlan fd44043
Merge branch 'master' into cupertino_profile
brianquinlan 173238b
Update profile
brianquinlan f6f79be
Merge branch 'master' into cupertino_profile
brianquinlan 969c0f4
Add tests
brianquinlan 61a2d58
Merge branch 'master' into cupertino_profile
brianquinlan 03e8ffc
Add redirect tests
brianquinlan 70f6f77
Merge branch 'master' into cupertino_profile
brianquinlan 14b4e32
Lots of reverts
brianquinlan ca72168
Update pubspec.yaml
brianquinlan d3a48a3
Update cupertino_client.dart
brianquinlan 81deb02
Update cupertino_client.dart
brianquinlan 5df70a7
Merge remote-tracking branch 'upstream/master' into cupertino_profile
brianquinlan 26d048c
Fix versions
brianquinlan f1ae74e
Release prep
brianquinlan 3213eb5
Merge remote-tracking branch 'upstream/master' into cupertino_profile
brianquinlan f956003
Review fixes
brianquinlan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
335 changes: 335 additions & 0 deletions
335
pkgs/cupertino_http/example/integration_test/client_profile_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,335 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'dart:async'; | ||
import 'dart:io'; | ||
|
||
import 'package:cupertino_http/src/cupertino_client.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
import 'package:http/http.dart'; | ||
import 'package:http_profile/http_profile.dart'; | ||
import 'package:integration_test/integration_test.dart'; | ||
|
||
void main() { | ||
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); | ||
|
||
group('profile', () { | ||
final profilingEnabled = HttpClientRequestProfile.profilingEnabled; | ||
|
||
setUpAll(() { | ||
HttpClientRequestProfile.profilingEnabled = true; | ||
}); | ||
|
||
tearDownAll(() { | ||
HttpClientRequestProfile.profilingEnabled = profilingEnabled; | ||
}); | ||
|
||
group('non-streamed POST', () { | ||
late HttpServer successServer; | ||
late Uri successServerUri; | ||
late HttpClientRequestProfile profile; | ||
|
||
setUpAll(() async { | ||
successServer = (await HttpServer.bind('localhost', 0)) | ||
..listen((request) async { | ||
await request.drain<void>(); | ||
request.response.headers.set('Content-Type', 'text/plain'); | ||
request.response.headers.set('Content-Length', '11'); | ||
request.response.write('Hello World'); | ||
await request.response.close(); | ||
}); | ||
successServerUri = Uri.http('localhost:${successServer.port}'); | ||
final client = CupertinoClientWithProfile.defaultSessionConfiguration(); | ||
await client.post(successServerUri, | ||
headers: {'Content-Type': 'text/plain'}, body: 'Hi'); | ||
profile = client.profile!; | ||
}); | ||
tearDownAll(() { | ||
successServer.close(); | ||
}); | ||
|
||
test('profile attributes', () { | ||
expect(profile.events, isEmpty); | ||
expect(profile.requestMethod, 'POST'); | ||
expect(profile.requestUri, successServerUri.toString()); | ||
expect(profile.connectionInfo, | ||
containsPair('package', 'package:cupertino_http')); | ||
}); | ||
|
||
test('request attributes', () { | ||
expect(profile.requestData.bodyBytes, 'Hi'.codeUnits); | ||
expect(profile.requestData.contentLength, 2); | ||
expect(profile.requestData.endTime, isNotNull); | ||
expect(profile.requestData.error, isNull); | ||
expect( | ||
profile.requestData.headers, containsPair('Content-Length', ['2'])); | ||
expect(profile.requestData.headers, | ||
containsPair('Content-Type', ['text/plain; charset=utf-8'])); | ||
expect(profile.requestData.persistentConnection, isNull); | ||
expect(profile.requestData.proxyDetails, isNull); | ||
expect(profile.requestData.startTime, isNotNull); | ||
}); | ||
|
||
test('response attributes', () { | ||
expect(profile.responseData.bodyBytes, 'Hello World'.codeUnits); | ||
expect(profile.responseData.compressionState, isNull); | ||
expect(profile.responseData.contentLength, 11); | ||
expect(profile.responseData.endTime, isNotNull); | ||
expect(profile.responseData.error, isNull); | ||
expect(profile.responseData.headers, | ||
containsPair('content-type', ['text/plain'])); | ||
expect(profile.responseData.headers, | ||
containsPair('content-length', ['11'])); | ||
expect(profile.responseData.isRedirect, false); | ||
expect(profile.responseData.persistentConnection, isNull); | ||
expect(profile.responseData.reasonPhrase, 'OK'); | ||
expect(profile.responseData.redirects, isEmpty); | ||
expect(profile.responseData.startTime, isNotNull); | ||
expect(profile.responseData.statusCode, 200); | ||
}); | ||
}); | ||
|
||
group('streaming POST request', () { | ||
late HttpServer successServer; | ||
late Uri successServerUri; | ||
late HttpClientRequestProfile profile; | ||
|
||
setUpAll(() async { | ||
successServer = (await HttpServer.bind('localhost', 0)) | ||
..listen((request) async { | ||
await request.drain<void>(); | ||
request.response.headers.set('Content-Type', 'text/plain'); | ||
request.response.headers.set('Content-Length', '11'); | ||
request.response.write('Hello World'); | ||
await request.response.close(); | ||
}); | ||
successServerUri = Uri.http('localhost:${successServer.port}'); | ||
final client = CupertinoClientWithProfile.defaultSessionConfiguration(); | ||
final request = StreamedRequest('POST', successServerUri); | ||
final stream = () async* { | ||
for (var i = 0; i < 1000; ++i) { | ||
await Future<void>.delayed(const Duration()); | ||
// The request has started but not finished. | ||
expect(client.profile!.requestData.startTime, isNotNull); | ||
expect(client.profile!.requestData.endTime, isNull); | ||
expect(client.profile!.responseData.startTime, isNull); | ||
expect(client.profile!.responseData.endTime, isNull); | ||
yield 'Hello'.codeUnits; | ||
} | ||
}(); | ||
unawaited( | ||
request.sink.addStream(stream).then((_) => request.sink.close())); | ||
|
||
await client.send(request); | ||
profile = client.profile!; | ||
}); | ||
tearDownAll(() { | ||
successServer.close(); | ||
}); | ||
|
||
test('request attributes', () async { | ||
expect(profile.requestData.bodyBytes, ('Hello' * 1000).codeUnits); | ||
expect(profile.requestData.contentLength, isNull); | ||
expect(profile.requestData.endTime, isNotNull); | ||
expect(profile.requestData.startTime, isNotNull); | ||
expect(profile.requestData.headers, isNot(contains('Content-Length'))); | ||
}); | ||
}); | ||
|
||
group('failed POST request', () { | ||
late HttpClientRequestProfile profile; | ||
|
||
setUpAll(() async { | ||
final client = CupertinoClientWithProfile.defaultSessionConfiguration(); | ||
try { | ||
await client.post(Uri.http('thisisnotahost'), | ||
headers: {'Content-Type': 'text/plain'}, body: 'Hi'); | ||
fail('expected exception'); | ||
} on ClientException { | ||
// Expected exception. | ||
} | ||
profile = client.profile!; | ||
}); | ||
|
||
test('profile attributes', () { | ||
expect(profile.events, isEmpty); | ||
expect(profile.requestMethod, 'POST'); | ||
expect(profile.requestUri, 'http://thisisnotahost'); | ||
expect(profile.connectionInfo, | ||
containsPair('package', 'package:cupertino_http')); | ||
}); | ||
|
||
test('request attributes', () { | ||
expect(profile.requestData.bodyBytes, 'Hi'.codeUnits); | ||
expect(profile.requestData.contentLength, 2); | ||
expect(profile.requestData.endTime, isNotNull); | ||
expect(profile.requestData.error, startsWith('ClientException:')); | ||
expect( | ||
profile.requestData.headers, containsPair('Content-Length', ['2'])); | ||
expect(profile.requestData.headers, | ||
containsPair('Content-Type', ['text/plain; charset=utf-8'])); | ||
expect(profile.requestData.persistentConnection, isNull); | ||
expect(profile.requestData.proxyDetails, isNull); | ||
expect(profile.requestData.startTime, isNotNull); | ||
}); | ||
|
||
test('response attributes', () { | ||
expect(profile.responseData.bodyBytes, isEmpty); | ||
expect(profile.responseData.compressionState, isNull); | ||
expect(profile.responseData.contentLength, isNull); | ||
expect(profile.responseData.endTime, isNull); | ||
expect(profile.responseData.error, isNull); | ||
expect(profile.responseData.headers, isNull); | ||
expect(profile.responseData.isRedirect, isNull); | ||
expect(profile.responseData.persistentConnection, isNull); | ||
expect(profile.responseData.reasonPhrase, isNull); | ||
expect(profile.responseData.redirects, isEmpty); | ||
expect(profile.responseData.startTime, isNull); | ||
expect(profile.responseData.statusCode, isNull); | ||
}); | ||
}); | ||
|
||
group('failed POST response', () { | ||
late HttpServer successServer; | ||
late Uri successServerUri; | ||
late HttpClientRequestProfile profile; | ||
|
||
setUpAll(() async { | ||
successServer = (await HttpServer.bind('localhost', 0)) | ||
..listen((request) async { | ||
await request.drain<void>(); | ||
request.response.headers.set('Content-Type', 'text/plain'); | ||
request.response.headers.set('Content-Length', '11'); | ||
final socket = await request.response.detachSocket(); | ||
await socket.close(); | ||
}); | ||
successServerUri = Uri.http('localhost:${successServer.port}'); | ||
final client = CupertinoClientWithProfile.defaultSessionConfiguration(); | ||
|
||
try { | ||
await client.post(successServerUri, | ||
headers: {'Content-Type': 'text/plain'}, body: 'Hi'); | ||
fail('expected exception'); | ||
} on ClientException { | ||
// Expected exception. | ||
} | ||
profile = client.profile!; | ||
}); | ||
tearDownAll(() { | ||
successServer.close(); | ||
}); | ||
|
||
test('profile attributes', () { | ||
expect(profile.events, isEmpty); | ||
expect(profile.requestMethod, 'POST'); | ||
expect(profile.requestUri, successServerUri.toString()); | ||
expect(profile.connectionInfo, | ||
containsPair('package', 'package:cupertino_http')); | ||
}); | ||
|
||
test('request attributes', () { | ||
expect(profile.requestData.bodyBytes, 'Hi'.codeUnits); | ||
expect(profile.requestData.contentLength, 2); | ||
expect(profile.requestData.endTime, isNotNull); | ||
expect(profile.requestData.error, isNull); | ||
expect( | ||
profile.requestData.headers, containsPair('Content-Length', ['2'])); | ||
expect(profile.requestData.headers, | ||
containsPair('Content-Type', ['text/plain; charset=utf-8'])); | ||
expect(profile.requestData.persistentConnection, isNull); | ||
expect(profile.requestData.proxyDetails, isNull); | ||
expect(profile.requestData.startTime, isNotNull); | ||
}); | ||
|
||
test('response attributes', () { | ||
expect(profile.responseData.bodyBytes, isEmpty); | ||
expect(profile.responseData.compressionState, isNull); | ||
expect(profile.responseData.contentLength, 11); | ||
expect(profile.responseData.endTime, isNotNull); | ||
expect(profile.responseData.error, startsWith('ClientException:')); | ||
expect(profile.responseData.headers, | ||
containsPair('content-type', ['text/plain'])); | ||
expect(profile.responseData.headers, | ||
containsPair('content-length', ['11'])); | ||
expect(profile.responseData.isRedirect, false); | ||
expect(profile.responseData.persistentConnection, isNull); | ||
expect(profile.responseData.reasonPhrase, 'OK'); | ||
expect(profile.responseData.redirects, isEmpty); | ||
expect(profile.responseData.startTime, isNotNull); | ||
expect(profile.responseData.statusCode, 200); | ||
}); | ||
}); | ||
|
||
group('redirects', () { | ||
late HttpServer successServer; | ||
late Uri successServerUri; | ||
late HttpClientRequestProfile profile; | ||
|
||
setUpAll(() async { | ||
successServer = (await HttpServer.bind('localhost', 0)) | ||
..listen((request) async { | ||
if (request.requestedUri.pathSegments.isEmpty) { | ||
unawaited(request.response.close()); | ||
} else { | ||
final n = int.parse(request.requestedUri.pathSegments.last); | ||
final nextPath = n - 1 == 0 ? '' : '${n - 1}'; | ||
unawaited(request.response | ||
.redirect(successServerUri.replace(path: '/$nextPath'))); | ||
} | ||
}); | ||
successServerUri = Uri.http('localhost:${successServer.port}'); | ||
}); | ||
tearDownAll(() { | ||
successServer.close(); | ||
}); | ||
|
||
test('no redirects', () async { | ||
final client = CupertinoClientWithProfile.defaultSessionConfiguration(); | ||
await client.get(successServerUri); | ||
profile = client.profile!; | ||
|
||
expect(profile.responseData.redirects, isEmpty); | ||
}); | ||
|
||
test('follow redirects', () async { | ||
final client = CupertinoClientWithProfile.defaultSessionConfiguration(); | ||
await client.send(Request('GET', successServerUri.replace(path: '/3')) | ||
..followRedirects = true | ||
..maxRedirects = 4); | ||
profile = client.profile!; | ||
|
||
expect(profile.requestData.followRedirects, true); | ||
expect(profile.requestData.maxRedirects, 4); | ||
expect(profile.responseData.isRedirect, false); | ||
|
||
expect(profile.responseData.redirects, [ | ||
HttpProfileRedirectData( | ||
statusCode: 302, | ||
method: 'GET', | ||
location: successServerUri.replace(path: '/2').toString()), | ||
HttpProfileRedirectData( | ||
statusCode: 302, | ||
method: 'GET', | ||
location: successServerUri.replace(path: '/1').toString()), | ||
HttpProfileRedirectData( | ||
statusCode: 302, | ||
method: 'GET', | ||
location: successServerUri.replace(path: '/').toString(), | ||
) | ||
]); | ||
}); | ||
|
||
test('no follow redirects', () async { | ||
final client = CupertinoClientWithProfile.defaultSessionConfiguration(); | ||
await client.send(Request('GET', successServerUri.replace(path: '/3')) | ||
..followRedirects = false); | ||
profile = client.profile!; | ||
|
||
expect(profile.requestData.followRedirects, false); | ||
expect(profile.responseData.isRedirect, true); | ||
expect(profile.responseData.redirects, isEmpty); | ||
}); | ||
}); | ||
}); | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done