mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Add simple retry logic to the base provider's fetch method
This should take care of simple transient errors, or other network hiccups that might happen on the user's device.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (C) 2020, 2021 wger Team
|
||||
* Copyright (c) 2026 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
@@ -16,19 +16,27 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/http.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:wger/core/exceptions/http_exception.dart';
|
||||
import 'package:wger/providers/auth.dart';
|
||||
import 'package:wger/providers/helpers.dart';
|
||||
|
||||
/// initial delay for fetch retries, in milliseconds
|
||||
const FETCH_INITIAL_DELAY = 250;
|
||||
|
||||
/// Base provider class.
|
||||
///
|
||||
/// Provides a couple of comfort functions so we avoid a bit of boilerplate.
|
||||
class WgerBaseProvider {
|
||||
final _logger = Logger('WgerBaseProvider');
|
||||
|
||||
AuthProvider auth;
|
||||
late http.Client client;
|
||||
|
||||
@@ -56,21 +64,53 @@ class WgerBaseProvider {
|
||||
}
|
||||
|
||||
/// Fetch and retrieve the overview list of objects, returns the JSON parsed response
|
||||
Future<dynamic> fetch(Uri uri) async {
|
||||
// Future<Map<String, dynamic> | List<dynamic>> fetch(Uri uri) async {
|
||||
// Send the request
|
||||
final response = await client.get(
|
||||
uri,
|
||||
headers: getDefaultHeaders(includeAuth: true),
|
||||
);
|
||||
/// with a simple retry mechanism for transient errors.
|
||||
Future<dynamic> fetch(
|
||||
Uri uri, {
|
||||
int maxRetries = 3,
|
||||
Duration initialDelay = const Duration(milliseconds: 250),
|
||||
}) async {
|
||||
int attempt = 0;
|
||||
final random = math.Random();
|
||||
|
||||
// Something wrong with our request
|
||||
if (response.statusCode >= 400) {
|
||||
throw WgerHttpException(response);
|
||||
Future<void> wait(String reason) async {
|
||||
final backoff = (initialDelay.inMilliseconds * math.pow(2, attempt - 1)).toInt();
|
||||
final jitter = random.nextInt((backoff * 0.25).toInt() + 1); // up to 25% jitter
|
||||
final delay = backoff + jitter;
|
||||
_logger.info('Retrying fetch for $uri, attempt $attempt (${delay}ms), reason: $reason');
|
||||
|
||||
await Future.delayed(Duration(milliseconds: delay));
|
||||
}
|
||||
|
||||
// Process the response
|
||||
return json.decode(utf8.decode(response.bodyBytes)) as dynamic;
|
||||
while (true) {
|
||||
try {
|
||||
final response = await client
|
||||
.get(uri, headers: getDefaultHeaders(includeAuth: true))
|
||||
.timeout(const Duration(seconds: 5));
|
||||
|
||||
if (response.statusCode >= 400) {
|
||||
// Retry on server errors (5xx); e.g. 502 might be transient
|
||||
if (response.statusCode >= 500 && attempt < maxRetries) {
|
||||
attempt++;
|
||||
await wait('status code ${response.statusCode}');
|
||||
continue;
|
||||
}
|
||||
throw WgerHttpException(response);
|
||||
}
|
||||
|
||||
return json.decode(utf8.decode(response.bodyBytes)) as dynamic;
|
||||
} catch (e) {
|
||||
final isRetryable =
|
||||
e is SocketException || e is http.ClientException || e is TimeoutException;
|
||||
if (isRetryable && attempt < maxRetries) {
|
||||
attempt++;
|
||||
await wait(e.toString());
|
||||
continue;
|
||||
}
|
||||
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch and retrieve the overview list of objects, returns the JSON parsed response
|
||||
|
||||
@@ -1100,9 +1100,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i2.WgerBaseProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i18.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i18.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i18.Future<dynamic>.value(),
|
||||
)
|
||||
as _i18.Future<dynamic>);
|
||||
|
||||
@@ -402,9 +402,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i2.WgerBaseProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i14.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i14.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i14.Future<dynamic>.value(),
|
||||
)
|
||||
as _i14.Future<dynamic>);
|
||||
|
||||
@@ -175,9 +175,17 @@ class MockGalleryProvider extends _i1.Mock implements _i4.GalleryProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i6.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i6.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i6.Future<dynamic>.value(),
|
||||
)
|
||||
as _i6.Future<dynamic>);
|
||||
|
||||
@@ -175,9 +175,17 @@ class MockGalleryProvider extends _i1.Mock implements _i4.GalleryProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i6.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i6.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i6.Future<dynamic>.value(),
|
||||
)
|
||||
as _i6.Future<dynamic>);
|
||||
|
||||
@@ -112,9 +112,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i5.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i5.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i5.Future<dynamic>.value(),
|
||||
)
|
||||
as _i5.Future<dynamic>);
|
||||
|
||||
@@ -122,9 +122,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i5.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i5.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i5.Future<dynamic>.value(),
|
||||
)
|
||||
as _i5.Future<dynamic>);
|
||||
|
||||
@@ -357,9 +357,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i8.WgerBaseProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i5.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i5.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i5.Future<dynamic>.value(),
|
||||
)
|
||||
as _i5.Future<dynamic>);
|
||||
|
||||
135
test/providers/base_provider.dart
Normal file
135
test/providers/base_provider.dart
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (c) 2026 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:wger/core/exceptions/http_exception.dart';
|
||||
import 'package:wger/providers/base_provider.dart';
|
||||
|
||||
import '../utils.dart';
|
||||
import 'base_provider.mocks.dart';
|
||||
|
||||
@GenerateMocks([Client])
|
||||
void main() {
|
||||
final Uri testUri = Uri(scheme: 'https', host: 'localhost', path: 'api/v2/test/');
|
||||
|
||||
test('Retry on SocketException then succeeds', () async {
|
||||
// Arrange
|
||||
final mockClient = MockClient();
|
||||
var callCount = 0;
|
||||
when(mockClient.get(testUri, headers: anyNamed('headers'))).thenAnswer((_) {
|
||||
if (callCount == 0) {
|
||||
callCount++;
|
||||
return Future.error(const SocketException('conn fail'));
|
||||
}
|
||||
return Future.value(Response('{"ok": true}', 200));
|
||||
});
|
||||
|
||||
// Act
|
||||
final provider = WgerBaseProvider(testAuthProvider, mockClient);
|
||||
final result = await provider.fetch(testUri, initialDelay: const Duration(milliseconds: 1));
|
||||
|
||||
// Assert
|
||||
expect(result, isA<Map>());
|
||||
expect(result['ok'], isTrue);
|
||||
verify(mockClient.get(testUri, headers: anyNamed('headers'))).called(2);
|
||||
});
|
||||
|
||||
test('Retry on 5xx then succeeds', () async {
|
||||
// Arrange
|
||||
final mockClient = MockClient();
|
||||
var callCount = 0;
|
||||
when(mockClient.get(testUri, headers: anyNamed('headers'))).thenAnswer((_) {
|
||||
if (callCount == 0) {
|
||||
callCount++;
|
||||
return Future.value(Response('{"msg":"error"}', 502));
|
||||
}
|
||||
return Future.value(Response('{"ok": true}', 200));
|
||||
});
|
||||
|
||||
// Act
|
||||
final provider = WgerBaseProvider(testAuthProvider, mockClient);
|
||||
final result = await provider.fetch(testUri, initialDelay: const Duration(milliseconds: 1));
|
||||
|
||||
// Assert
|
||||
expect(result, isA<Map>());
|
||||
expect(result['ok'], isTrue);
|
||||
verify(mockClient.get(testUri, headers: anyNamed('headers'))).called(2);
|
||||
});
|
||||
|
||||
test('Do not retry on 4xx client error', () async {
|
||||
// Arrange
|
||||
final mockClient = MockClient();
|
||||
when(
|
||||
mockClient.get(testUri, headers: anyNamed('headers')),
|
||||
).thenAnswer((_) => Future.value(Response('{"error":"bad"}', 400)));
|
||||
|
||||
// Act
|
||||
final provider = WgerBaseProvider(testAuthProvider, mockClient);
|
||||
|
||||
// Assert
|
||||
await expectLater(
|
||||
provider.fetch(testUri, initialDelay: const Duration(milliseconds: 1)),
|
||||
throwsA(isA<WgerHttpException>()),
|
||||
);
|
||||
verify(mockClient.get(testUri, headers: anyNamed('headers'))).called(1);
|
||||
});
|
||||
|
||||
test('Exceed max retries and rethrow after retries', () async {
|
||||
// Arrange
|
||||
final mockClient = MockClient();
|
||||
when(
|
||||
mockClient.get(testUri, headers: anyNamed('headers')),
|
||||
).thenAnswer((_) => Future.error(ClientException('conn fail')));
|
||||
|
||||
// Act
|
||||
final provider = WgerBaseProvider(testAuthProvider, mockClient);
|
||||
dynamic caught;
|
||||
try {
|
||||
await provider.fetch(testUri, initialDelay: const Duration(milliseconds: 1));
|
||||
} catch (e) {
|
||||
caught = e;
|
||||
}
|
||||
|
||||
// Assert
|
||||
expect(caught, isA<ClientException>());
|
||||
// initial try + 3 retries = 4 calls
|
||||
verify(mockClient.get(testUri, headers: anyNamed('headers'))).called(4);
|
||||
});
|
||||
|
||||
test('Request succeeds without retries', () async {
|
||||
// Arrange
|
||||
final mockClient = MockClient();
|
||||
when(
|
||||
mockClient.get(testUri, headers: anyNamed('headers')),
|
||||
).thenAnswer((_) => Future.value(Response('{"ok": true}', 200)));
|
||||
|
||||
// Act
|
||||
final provider = WgerBaseProvider(testAuthProvider, mockClient);
|
||||
final result = await provider.fetch(testUri);
|
||||
|
||||
// Assert
|
||||
expect(result, isA<Map>());
|
||||
expect(result['ok'], isTrue);
|
||||
verify(mockClient.get(testUri, headers: anyNamed('headers'))).called(1);
|
||||
});
|
||||
}
|
||||
218
test/providers/base_provider.mocks.dart
Normal file
218
test/providers/base_provider.mocks.dart
Normal file
@@ -0,0 +1,218 @@
|
||||
// Mocks generated by Mockito 5.4.6 from annotations
|
||||
// in wger/test/providers/base_provider.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _i3;
|
||||
import 'dart:convert' as _i4;
|
||||
import 'dart:typed_data' as _i6;
|
||||
|
||||
import 'package:http/http.dart' as _i2;
|
||||
import 'package:mockito/mockito.dart' as _i1;
|
||||
import 'package:mockito/src/dummies.dart' as _i5;
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: avoid_redundant_argument_values
|
||||
// ignore_for_file: avoid_setters_without_getters
|
||||
// ignore_for_file: comment_references
|
||||
// ignore_for_file: deprecated_member_use
|
||||
// ignore_for_file: deprecated_member_use_from_same_package
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
||||
// ignore_for_file: must_be_immutable
|
||||
// ignore_for_file: prefer_const_constructors
|
||||
// ignore_for_file: unnecessary_parenthesis
|
||||
// ignore_for_file: camel_case_types
|
||||
// ignore_for_file: subtype_of_sealed_class
|
||||
// ignore_for_file: invalid_use_of_internal_member
|
||||
|
||||
class _FakeResponse_0 extends _i1.SmartFake implements _i2.Response {
|
||||
_FakeResponse_0(Object parent, Invocation parentInvocation) : super(parent, parentInvocation);
|
||||
}
|
||||
|
||||
class _FakeStreamedResponse_1 extends _i1.SmartFake implements _i2.StreamedResponse {
|
||||
_FakeStreamedResponse_1(Object parent, Invocation parentInvocation)
|
||||
: super(parent, parentInvocation);
|
||||
}
|
||||
|
||||
/// A class which mocks [Client].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockClient extends _i1.Mock implements _i2.Client {
|
||||
MockClient() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
||||
@override
|
||||
_i3.Future<_i2.Response> head(Uri? url, {Map<String, String>? headers}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#head, [url], {#headers: headers}),
|
||||
returnValue: _i3.Future<_i2.Response>.value(
|
||||
_FakeResponse_0(
|
||||
this,
|
||||
Invocation.method(#head, [url], {#headers: headers}),
|
||||
),
|
||||
),
|
||||
)
|
||||
as _i3.Future<_i2.Response>);
|
||||
|
||||
@override
|
||||
_i3.Future<_i2.Response> get(Uri? url, {Map<String, String>? headers}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#get, [url], {#headers: headers}),
|
||||
returnValue: _i3.Future<_i2.Response>.value(
|
||||
_FakeResponse_0(
|
||||
this,
|
||||
Invocation.method(#get, [url], {#headers: headers}),
|
||||
),
|
||||
),
|
||||
)
|
||||
as _i3.Future<_i2.Response>);
|
||||
|
||||
@override
|
||||
_i3.Future<_i2.Response> post(
|
||||
Uri? url, {
|
||||
Map<String, String>? headers,
|
||||
Object? body,
|
||||
_i4.Encoding? encoding,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#post,
|
||||
[url],
|
||||
{#headers: headers, #body: body, #encoding: encoding},
|
||||
),
|
||||
returnValue: _i3.Future<_i2.Response>.value(
|
||||
_FakeResponse_0(
|
||||
this,
|
||||
Invocation.method(
|
||||
#post,
|
||||
[url],
|
||||
{#headers: headers, #body: body, #encoding: encoding},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
as _i3.Future<_i2.Response>);
|
||||
|
||||
@override
|
||||
_i3.Future<_i2.Response> put(
|
||||
Uri? url, {
|
||||
Map<String, String>? headers,
|
||||
Object? body,
|
||||
_i4.Encoding? encoding,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#put,
|
||||
[url],
|
||||
{#headers: headers, #body: body, #encoding: encoding},
|
||||
),
|
||||
returnValue: _i3.Future<_i2.Response>.value(
|
||||
_FakeResponse_0(
|
||||
this,
|
||||
Invocation.method(
|
||||
#put,
|
||||
[url],
|
||||
{#headers: headers, #body: body, #encoding: encoding},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
as _i3.Future<_i2.Response>);
|
||||
|
||||
@override
|
||||
_i3.Future<_i2.Response> patch(
|
||||
Uri? url, {
|
||||
Map<String, String>? headers,
|
||||
Object? body,
|
||||
_i4.Encoding? encoding,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#patch,
|
||||
[url],
|
||||
{#headers: headers, #body: body, #encoding: encoding},
|
||||
),
|
||||
returnValue: _i3.Future<_i2.Response>.value(
|
||||
_FakeResponse_0(
|
||||
this,
|
||||
Invocation.method(
|
||||
#patch,
|
||||
[url],
|
||||
{#headers: headers, #body: body, #encoding: encoding},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
as _i3.Future<_i2.Response>);
|
||||
|
||||
@override
|
||||
_i3.Future<_i2.Response> delete(
|
||||
Uri? url, {
|
||||
Map<String, String>? headers,
|
||||
Object? body,
|
||||
_i4.Encoding? encoding,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#delete,
|
||||
[url],
|
||||
{#headers: headers, #body: body, #encoding: encoding},
|
||||
),
|
||||
returnValue: _i3.Future<_i2.Response>.value(
|
||||
_FakeResponse_0(
|
||||
this,
|
||||
Invocation.method(
|
||||
#delete,
|
||||
[url],
|
||||
{#headers: headers, #body: body, #encoding: encoding},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
as _i3.Future<_i2.Response>);
|
||||
|
||||
@override
|
||||
_i3.Future<String> read(Uri? url, {Map<String, String>? headers}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#read, [url], {#headers: headers}),
|
||||
returnValue: _i3.Future<String>.value(
|
||||
_i5.dummyValue<String>(
|
||||
this,
|
||||
Invocation.method(#read, [url], {#headers: headers}),
|
||||
),
|
||||
),
|
||||
)
|
||||
as _i3.Future<String>);
|
||||
|
||||
@override
|
||||
_i3.Future<_i6.Uint8List> readBytes(
|
||||
Uri? url, {
|
||||
Map<String, String>? headers,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#readBytes, [url], {#headers: headers}),
|
||||
returnValue: _i3.Future<_i6.Uint8List>.value(_i6.Uint8List(0)),
|
||||
)
|
||||
as _i3.Future<_i6.Uint8List>);
|
||||
|
||||
@override
|
||||
_i3.Future<_i2.StreamedResponse> send(_i2.BaseRequest? request) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#send, [request]),
|
||||
returnValue: _i3.Future<_i2.StreamedResponse>.value(
|
||||
_FakeStreamedResponse_1(
|
||||
this,
|
||||
Invocation.method(#send, [request]),
|
||||
),
|
||||
),
|
||||
)
|
||||
as _i3.Future<_i2.StreamedResponse>);
|
||||
|
||||
@override
|
||||
void close() => super.noSuchMethod(
|
||||
Invocation.method(#close, []),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
}
|
||||
@@ -201,9 +201,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i20.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i20.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i20.Future<dynamic>.value(),
|
||||
)
|
||||
as _i20.Future<dynamic>);
|
||||
|
||||
@@ -112,9 +112,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i5.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i5.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i5.Future<dynamic>.value(),
|
||||
)
|
||||
as _i5.Future<dynamic>);
|
||||
|
||||
@@ -151,9 +151,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i11.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i11.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i11.Future<dynamic>.value(),
|
||||
)
|
||||
as _i11.Future<dynamic>);
|
||||
|
||||
@@ -112,9 +112,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i5.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i5.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i5.Future<dynamic>.value(),
|
||||
)
|
||||
as _i5.Future<dynamic>);
|
||||
|
||||
@@ -112,9 +112,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i5.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i5.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i5.Future<dynamic>.value(),
|
||||
)
|
||||
as _i5.Future<dynamic>);
|
||||
|
||||
@@ -112,9 +112,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider {
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i5.Future<dynamic> fetch(Uri? uri) =>
|
||||
_i5.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 500),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i5.Future<dynamic>.value(),
|
||||
)
|
||||
as _i5.Future<dynamic>);
|
||||
|
||||
Reference in New Issue
Block a user