Skip to content

Commit

Permalink
Add a dio_test project and move request integration test (#2077)
Browse files Browse the repository at this point in the history
This was supposed to be just an attempt but while moving the integration
test, I found a bug since one of the tests failed for the
`Http2Adapter`.
So I think this is a good approach, I will move more tests in future
PRs.

* run tests for all adapters
* fix redirect bug for `Http2Adapter`

<!-- Write down your pull request descriptions. -->

### New Pull Request Checklist

- [x] I have read the
[Documentation](https://pub.dev/documentation/dio/latest/)
- [x] I have searched for a similar pull request in the
[project](https://github.com/cfug/dio/pulls) and found none
- [x] I have updated this branch with the latest `main` branch to avoid
conflicts (via merge from master or rebase)
- [x] I have added the required tests to prove the fix/feature I'm
adding
- [x] I have updated the documentation (if necessary)
- [x] I have run the tests without failures
- [x] I have updated the `CHANGELOG.md` in the corresponding package

### Additional context and info (if any)

<!-- Provide more context and info about the PR. -->
  • Loading branch information
kuhnroyal authored Mar 8, 2024
1 parent c14aca4 commit b7d7f34
Show file tree
Hide file tree
Showing 32 changed files with 587 additions and 537 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ jobs:
- name: '[Verify step] Analyze Flutter packages'
run: melos exec $(eval echo $IGNORED_PACKAGES) --flutter -- "flutter analyze --fatal-infos"
- name: '[Verify step] Publish dry-run'
run: melos exec $(eval echo $IGNORED_PACKAGES) --ignore="*example*" -- "dart pub publish --dry-run"
run: melos exec $(eval echo $IGNORED_PACKAGES) --ignore="*example*" --ignore="dio_test" -- "dart pub publish --dry-run"
- name: '[Verify step] Test Dart packages [VM]'
run: melos exec $(eval echo $IGNORED_PACKAGES) --ignore="*example*" --no-flutter -- "MELOS_ROOT_PATH/scripts/dart_test.sh --platform=vm"
run: melos exec $(eval echo $IGNORED_PACKAGES) --ignore="*example*" --ignore="dio_test" --no-flutter -- "MELOS_ROOT_PATH/scripts/dart_test.sh --platform=vm"
- name: '[Verify step] Test Dart packages [Chrome]'
run: melos exec $(eval echo $IGNORED_PACKAGES) --ignore="*example*" --ignore="*http2*" --no-flutter -- "MELOS_ROOT_PATH/scripts/dart_test.sh --platform=chrome"
run: melos exec $(eval echo $IGNORED_PACKAGES) --ignore="*example*" --ignore="*http2*" --ignore="dio_test" --no-flutter -- "MELOS_ROOT_PATH/scripts/dart_test.sh --platform=chrome"
- name: '[Verify step] Test Dart packages [Firefox]'
run: melos exec $(eval echo $IGNORED_PACKAGES) --ignore="*example*" --ignore="*http2*" --no-flutter -- "MELOS_ROOT_PATH/scripts/dart_test.sh --platform=firefox"
run: melos exec $(eval echo $IGNORED_PACKAGES) --ignore="*example*" --ignore="*http2*" --ignore="dio_test" --no-flutter -- "MELOS_ROOT_PATH/scripts/dart_test.sh --platform=firefox"
- name: '[Verify step] Test Flutter packages'
run: melos exec $(eval echo $IGNORED_PACKAGES) --ignore="*example*" --flutter -- "flutter test"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ plugins/http2_adapter/test/*_pinning.txt

# FVM
.fvm
.fmvrc

# Miscellaneous
.DS_Store
Expand Down
1 change: 1 addition & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions dio/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ dev_dependencies:
crypto: ^3.0.2
mockito: ^5.2.0
build_runner: any
dio_test:
path: ../dio_test
4 changes: 2 additions & 2 deletions dio/test/basic_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import 'dart:async';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:dio/src/utils.dart';
import 'package:test/test.dart';

import 'mock/adapters.dart';
import 'utils.dart';

void main() {
test('send with an invalid URL', () async {
Expand All @@ -15,7 +15,7 @@ void main() {
allOf([
isA<DioException>(),
(DioException e) => e.type == (DioExceptionType.connectionError),
if (!isWeb) (DioException e) => e.error is SocketException,
if (!kIsWeb) (DioException e) => e.error is SocketException,
]),
),
);
Expand Down
30 changes: 0 additions & 30 deletions dio/test/cancel_token_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import 'package:mockito/mockito.dart';
import 'package:test/test.dart';

import 'mock/http_mock.mocks.dart';
import 'utils.dart';

void main() {
group(CancelToken, () {
Expand All @@ -30,35 +29,6 @@ void main() {
CancelToken().cancel();
});

test(
'cancels streamed responses',
() async {
final dio = Dio()..options.baseUrl = 'https://httpbun.com/';

final cancelToken = CancelToken();

final response = await dio.get(
'bytes/${1024 * 1024 * 100}',
options: Options(responseType: ResponseType.stream),
cancelToken: cancelToken,
onReceiveProgress: (c, t) {
if (c > 5000) {
cancelToken.cancel();
}
},
);

await expectLater(
(response.data as ResponseBody).stream.last,
throwsDioException(
DioExceptionType.cancel,
stackTraceContains: 'test/cancel_token_test.dart',
),
);
},
testOn: 'vm',
);

test('cancels multiple requests', () async {
final client = MockHttpClient();
final token = CancelToken();
Expand Down
1 change: 1 addition & 0 deletions dio/test/download_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:dio_test/util.dart';
import 'package:path/path.dart' as p;
import 'package:test/test.dart';

Expand Down
3 changes: 1 addition & 2 deletions dio/test/response/response_stream_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import 'dart:async';
import 'dart:typed_data';

import 'package:dio/dio.dart';
import 'package:dio_test/util.dart';
import 'package:dio/src/response/response_stream_handler.dart';
import 'package:test/test.dart';

import '../utils.dart';

void main() {
group(handleResponseStream, () {
late StreamController<Uint8List> source;
Expand Down
8 changes: 8 additions & 0 deletions dio/test/test_suite_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'package:dio/dio.dart';
import 'package:dio_test/tests.dart';

void main() {
dioAdapterTestSuite(
() => Dio(BaseOptions(baseUrl: 'https://httpbun.com/')),
);
}
134 changes: 0 additions & 134 deletions dio/test/timeout_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'dart:async';
import 'dart:io';

import 'package:dio/dio.dart';
Expand All @@ -15,19 +14,6 @@ void main() {

group('Timeout exception of', () {
group('connectTimeout', () {
test('with response', () async {
dio.options.connectTimeout = Duration(milliseconds: 3);
await expectLater(
dio.get('/'),
allOf(
throwsA(isA<DioException>()),
throwsA(predicate((DioException e) =>
e.type == DioExceptionType.connectionTimeout &&
e.message!.contains('${dio.options.connectTimeout}'))),
),
);
});

test('update between calls', () async {
final client = HttpClient();
final dio = Dio()
Expand All @@ -48,125 +34,5 @@ void main() {
expect(client.connectionTimeout, dio.options.connectTimeout);
}, testOn: 'vm');
});

group('receiveTimeout', () {
test('with normal response', () async {
dio.options.receiveTimeout = Duration(seconds: 1);
await expectLater(
dio.get('/drip', queryParameters: {'delay': 2}),
allOf([
throwsA(isA<DioException>()),
throwsA(
predicate<DioException>(
(e) => e.type == DioExceptionType.receiveTimeout,
),
),
throwsA(
predicate<DioException>(
(e) => e.message!.contains('${dio.options.receiveTimeout}'),
),
),
]),
);
});

test('with streamed response', () async {
dio.options.receiveTimeout = Duration(seconds: 1);
final completer = Completer<void>();
final streamedResponse = await dio.get(
'/drip',
queryParameters: {'delay': 0, 'duration': 20},
options: Options(responseType: ResponseType.stream),
);
(streamedResponse.data as ResponseBody).stream.listen(
(event) {},
onError: (error) {
if (!completer.isCompleted) {
completer.completeError(error);
}
},
onDone: () {
if (!completer.isCompleted) {
completer.complete();
}
},
);
await expectLater(
completer.future,
allOf([
throwsA(isA<DioException>()),
throwsA(
predicate<DioException>(
(e) => e.type == DioExceptionType.receiveTimeout,
),
),
throwsA(
predicate<DioException>(
(e) => e.message!.contains('${dio.options.receiveTimeout}'),
),
),
]),
);
}, testOn: 'vm');
});
});

test('no DioException when receiveTimeout > request duration', () async {
dio.options.receiveTimeout = Duration(seconds: 5);

await dio.get('/drip?delay=1&numbytes=1');
});

test('ignores zero duration timeouts', () async {
final dio = Dio(
BaseOptions(
baseUrl: 'https://httpbun.com/',
connectTimeout: Duration.zero,
receiveTimeout: Duration.zero,
),
);
// Ignores zero duration timeouts from the base options.
await dio.get('/drip-lines?delay=1');
// Reset the base options.
dio.options.receiveTimeout = Duration(milliseconds: 10);
await expectLater(
dio.get('/drip-lines?delay=1'),
allOf([
throwsA(isA<DioException>()),
throwsA(
predicate<DioException>(
(e) => e.type == DioExceptionType.receiveTimeout,
),
),
throwsA(
predicate<DioException>(
(e) => e.message!.contains('0:00:00.010000'),
),
),
]),
);
dio.options.connectTimeout = Duration(milliseconds: 10);
await expectLater(
dio.get('/drip-lines?delay=1'),
allOf([
throwsA(isA<DioException>()),
throwsA(
predicate<DioException>(
(e) => e.type == DioExceptionType.connectionTimeout,
),
),
throwsA(
predicate<DioException>(
(e) => e.message!.contains('0:00:00.010000'),
),
),
]),
);
dio.options.connectTimeout = Duration.zero;
// Override with request options.
await dio.get(
'/drip-lines?delay=1',
options: Options(receiveTimeout: Duration.zero),
);
});
}
33 changes: 0 additions & 33 deletions dio/test/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ Encoding requiredEncodingForCharset(String charset) =>
/// The URL for the current server instance.
Uri get serverUrl => Uri.parse('http://localhost:${_server?.port}');

const isWeb = bool.hasEnvironment('dart.library.js_util')
? bool.fromEnvironment('dart.library.js_util')
: identical(0, 0.0);

/// Starts a new HTTP server.
Future<void> startServer() async {
_server = (await HttpServer.bind('localhost', 0))
Expand Down Expand Up @@ -175,35 +171,6 @@ final Matcher throwsDioExceptionConnectionError = throwsA(
]),
);

/// A matcher for functions that throw [DioException] of a specified type,
/// with an optional matcher for the stackTrace containing the specified text.
Matcher throwsDioException(
DioExceptionType type, {
String? stackTraceContains,
Object? matcher,
}) =>
throwsA(
matchesDioException(
type,
stackTraceContains: stackTraceContains,
matcher: matcher,
),
);

Matcher matchesDioException(
DioExceptionType type, {
String? stackTraceContains,
Object? matcher,
}) =>
allOf([
isA<DioException>(),
(DioException e) => e.type == type,
if (stackTraceContains != null)
(DioException e) =>
e.stackTrace.toString().contains(stackTraceContains),
if (matcher != null) matcher,
]);

/// A stream of chunks of bytes representing a single piece of data.
class ByteStream extends StreamView<List<int>> {
ByteStream(Stream<List<int>> stream) : super(stream);
Expand Down
18 changes: 18 additions & 0 deletions dio_test/dart_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
file_reporters:
json: build/reports/test-results.json

tags:
tls:
skip: "Skipping TLS test with specific setup requirements by default. Use '-P all' to run all tests."
presets:
all:
skip: false

override_platforms:
chrome:
settings:
headless: true
firefox:
settings:
# headless argument has to be set explicitly for non-chrome browsers
arguments: --headless
16 changes: 16 additions & 0 deletions dio_test/dio_test.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Dart Packages" level="project" />
</component>
</module>
Loading

0 comments on commit b7d7f34

Please sign in to comment.