Skip to content

Commit

Permalink
Update login_client for dart 3 (#108)
Browse files Browse the repository at this point in the history
Co-authored-by: Albert Wolszon <[email protected]>
  • Loading branch information
shilangyu and Albert221 authored Jun 7, 2023
1 parent aa89427 commit aee0f53
Show file tree
Hide file tree
Showing 19 changed files with 81 additions and 254 deletions.
2 changes: 2 additions & 0 deletions packages/login_client/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

- Bumped `http` dependency to `1.0.0`. (#105)
- **Breaking:** Bump minimum Dart version to 3.0. (#105)
- Mark the following as `abstract interface`: `CredentialsStorage` and `AuthorizationStrategy`. (#107)
- To migrate simply implement them rather than extend.

# 2.1.0+2

Expand Down
2 changes: 1 addition & 1 deletion packages/login_client/LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2021 LeanCode Sp. z o.o.
Copyright 2023 LeanCode Sp. z o.o.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
4 changes: 2 additions & 2 deletions packages/login_client/lib/login_client.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -13,7 +13,7 @@
// limitations under the License.

/// An OAuth2 compliant login client library.
library login_client;
library;

export 'package:oauth2/oauth2.dart'
show AuthorizationException, Credentials, ExpirationException;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -15,7 +15,7 @@
import 'package:oauth2/oauth2.dart' as oauth2;

/// An interface describing the storage for [oauth2.Credentials].
abstract class CredentialsStorage {
abstract interface class CredentialsStorage {
/// Get saved [oauth2.Credentials] or null when none could be found.
Future<oauth2.Credentials?> read();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -17,7 +17,7 @@ import 'package:oauth2/oauth2.dart' as oauth2;
import 'credentials_storage.dart';

/// A [CredentialsStorage] implementation storing credentials in the memory.
class InMemoryCredentialsStorage extends CredentialsStorage {
class InMemoryCredentialsStorage implements CredentialsStorage {
oauth2.Credentials? _credentials;

@override
Expand Down
2 changes: 1 addition & 1 deletion packages/login_client/lib/src/login_client.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion packages/login_client/lib/src/oauth2/custom_grant.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion packages/login_client/lib/src/oauth_settings.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion packages/login_client/lib/src/refresh_exception.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -19,7 +19,7 @@ import '../login_client.dart';
import '../oauth_settings.dart';

/// An interface describing a strategy of logging in to the [LoginClient].
abstract class AuthorizationStrategy {
abstract interface class AuthorizationStrategy {
/// Execute this [AuthorizationStrategy] and create an [oauth2.Client] that
/// is authorized.
Future<oauth2.Client> execute(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion packages/login_client/lib/src/utils.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 LeanCode Sp. z o.o.
// Copyright 2023 LeanCode Sp. z o.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
3 changes: 1 addition & 2 deletions packages/login_client/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ dependencies:
oauth2: ^2.0.0

dev_dependencies:
build_runner: ^2.0.0
coverage: ^1.6.3
leancode_lint: ^4.0.0+1
mockito: ^5.0.0
mocktail: ^0.3.0
test: ^1.16.4
95 changes: 59 additions & 36 deletions packages/login_client/test/login_client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,40 @@ import 'package:http/http.dart'
StreamedRequest,
StreamedResponse;
import 'package:login_client/login_client.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:mocktail/mocktail.dart';
import 'package:oauth2/oauth2.dart';
import 'package:test/test.dart';

import 'login_client_test.mocks.dart';
class MockOAuthSettings extends Mock implements OAuthSettings {}

class MockCredentialsStorage extends Mock implements CredentialsStorage {}

class MockClient extends Mock implements Client {}

class MockAuthorizationStrategy extends Mock implements AuthorizationStrategy {}

class FakeBaseRequest extends Fake implements BaseRequest {}

@GenerateMocks([
AuthorizationStrategy,
CredentialsStorage,
Client,
OAuthSettings,
])
void main() {
group('LoginClient', () {
late OAuthSettings oAuthSettings;
late CredentialsStorage credentialsStorage;
late void Function(String) logger;
late LoginClient loginClient;

setUpAll(() {
registerFallbackValue(
OAuthSettings(authorizationUri: Uri(), clientId: ''),
);
registerFallbackValue(MockClient());
registerFallbackValue(Credentials(''));
registerFallbackValue(FakeBaseRequest());
});

setUp(() {
oAuthSettings = MockOAuthSettings();
when(oAuthSettings.clientId).thenReturn('client id');
when(oAuthSettings.clientSecret).thenReturn('client secret');
when(() => oAuthSettings.clientId).thenReturn('client id');
when(() => oAuthSettings.clientSecret).thenReturn('client secret');
credentialsStorage = MockCredentialsStorage();
logger = MockLogger();
loginClient = LoginClient(
Expand All @@ -45,7 +56,8 @@ void main() {
() async {
final credentials = Credentials('some token');

when(credentialsStorage.read()).thenAnswer((_) async => credentials);
when(() => credentialsStorage.read())
.thenAnswer((_) async => credentials);

unawaited(
expectLater(loginClient.onCredentialsChanged, emits(credentials)),
Expand All @@ -55,8 +67,9 @@ void main() {

expect(loginClient.loggedIn, true);

verify(credentialsStorage.read()).called(1);
verify(logger('Successfully initialized with credentials.')).called(1);
verify(() => credentialsStorage.read()).called(1);
verify(() => logger('Successfully initialized with credentials.'))
.called(1);
},
);

Expand All @@ -65,9 +78,11 @@ void main() {
() async {
final client = MockClient();
final credentials = Credentials('access token');
when(client.credentials).thenReturn(credentials);
when(() => client.credentials).thenReturn(credentials);
final strategy = MockAuthorizationStrategy();
when(strategy.execute(any, any, any)).thenAnswer((_) async => client);
when(() => strategy.execute(any(), any(), any()))
.thenAnswer((_) async => client);
when(() => credentialsStorage.save(any())).thenAnswer((_) async {});

unawaited(
expectLater(
Expand All @@ -80,9 +95,10 @@ void main() {

expect(loginClient.loggedIn, true);

verify(credentialsStorage.save(credentials)).called(1);
verify(logger('Successfully logged in and saved the credentials.'))
.called(1);
verify(() => credentialsStorage.save(credentials)).called(1);
verify(
() => logger('Successfully logged in and saved the credentials.'),
).called(1);
},
);

Expand All @@ -93,7 +109,9 @@ void main() {
AuthorizationException('Error', 'Description', Uri());

final strategy = MockAuthorizationStrategy();
when(strategy.execute(any, any, any)).thenThrow(authorizationException);
when(() => strategy.execute(any(), any(), any()))
.thenThrow(authorizationException);
when(() => credentialsStorage.clear()).thenAnswer((_) async {});

unawaited(expectLater(loginClient.onCredentialsChanged, emits(null)));

Expand All @@ -104,9 +122,9 @@ void main() {

expect(loginClient.loggedIn, false);

verify(credentialsStorage.clear()).called(1);
verify(() => credentialsStorage.clear()).called(1);
verify(
logger(
() => logger(
'An error while logging in occured, '
'successfully logged out and cleared credentials.',
),
Expand All @@ -124,36 +142,40 @@ void main() {
test('refresh() calls the refresh credentials', () async {
final authorizedClient = MockClient();
final refreshedClient = MockClient();
when(authorizedClient.refreshCredentials(any))
when(() => authorizedClient.refreshCredentials(any()))
.thenAnswer((_) async => refreshedClient);

loginClient.setAuthorizedClient(authorizedClient);
await loginClient.refresh();

expect(loginClient.loggedIn, true);

verify(authorizedClient.refreshCredentials(any)).called(1);
verify(() => authorizedClient.refreshCredentials(any())).called(1);
});

test('logOut() logs out, calls callback and logs', () async {
when(() => credentialsStorage.clear()).thenAnswer((_) async {});

unawaited(expectLater(loginClient.onCredentialsChanged, emits(null)));

await loginClient.logOut();

expect(loginClient.loggedIn, false);

verify(credentialsStorage.clear()).called(1);
verify(logger('Successfully logged out and cleared the credentials.'))
.called(1);
verify(() => credentialsStorage.clear()).called(1);
verify(
() => logger('Successfully logged out and cleared the credentials.'),
).called(1);
});

test(
'send() logs out, logs and rethrows on AuthorizationException',
() async {
final request = FakeRequest();
final mockOauthClient = MockClient();
when(mockOauthClient.send(request))
when(() => mockOauthClient.send(request))
.thenThrow(AuthorizationException('Error', 'Description', Uri()));
when(() => credentialsStorage.clear()).thenAnswer((_) async {});

loginClient.setAuthorizedClient(mockOauthClient);

Expand All @@ -166,9 +188,9 @@ void main() {

expect(loginClient.loggedIn, false);

verify(credentialsStorage.clear()).called(1);
verify(() => credentialsStorage.clear()).called(1);
verify(
logger(
() => logger(
'An error while sending a request occured, '
'successfully logged out and cleared credentials.',
),
Expand All @@ -182,29 +204,29 @@ void main() {
final request = Request('POST', Uri.parse('http://www.example.com'));
final mockOauthClient = MockClient();

when(mockOauthClient.send(any)).thenAnswer(
when(() => mockOauthClient.send(any())).thenAnswer(
(_) async => StreamedResponse(
const Stream.empty(),
200,
),
);

when(mockOauthClient.send(request)).thenAnswer(
when(() => mockOauthClient.send(request)).thenAnswer(
(_) async => StreamedResponse(
const Stream.empty(),
401,
request: request,
),
);

when(mockOauthClient.refreshCredentials(any))
when(() => mockOauthClient.refreshCredentials(any()))
.thenAnswer((_) async => mockOauthClient);

loginClient.setAuthorizedClient(mockOauthClient);

await loginClient.send(request);

verify(mockOauthClient.refreshCredentials(any)).called(1);
verify(() => mockOauthClient.refreshCredentials(any())).called(1);
},
);

Expand All @@ -213,15 +235,16 @@ void main() {
() async {
final request = Request('POST', Uri.parse('http://www.example.com'));
final mockOauthClient = MockClient();
when(() => credentialsStorage.clear()).thenAnswer((_) async {});

when(mockOauthClient.send(any)).thenAnswer(
when(() => mockOauthClient.send(any())).thenAnswer(
(_) async => StreamedResponse(
const Stream.empty(),
401,
),
);

when(mockOauthClient.refreshCredentials(any))
when(() => mockOauthClient.refreshCredentials(any()))
.thenAnswer((_) async => mockOauthClient);

loginClient.setAuthorizedClient(mockOauthClient);
Expand Down
Loading

0 comments on commit aee0f53

Please sign in to comment.