This commit is contained in:
Adam Velebil 2023-01-10 09:16:19 +01:00
commit 05ce987038
No known key found for this signature in database
GPG Key ID: C9B1E4A3CBBD2E10
12 changed files with 50 additions and 55 deletions

View File

@ -61,7 +61,7 @@ Future<void> grantCameraPermissions(WidgetTester tester) async {
var manualEntryBtn = find.byKey(android_keys.manualEntryButton).hitTestable();
if (manualEntryBtn.evaluate().isEmpty) {
tester.testLog(false, 'Allow camera permission');
tester.testLog(true, 'Allow camera permission');
manualEntryBtn = await tester.waitForFinder(manualEntryBtn);
}

View File

@ -26,8 +26,8 @@ void main() {
var binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
group('OATH UI tests', () {
appTest('Menu items exist', (WidgetTester tester) async {
group('UI tests', () {
appTest('OATH Menu items exist', (WidgetTester tester) async {
await tester.tapDeviceButton();
expect(find.byKey(keys.addAccountAction), findsOneWidget);
expect(find.byKey(keys.setOrManagePasswordAction), findsOneWidget);
@ -35,8 +35,8 @@ void main() {
});
});
group('OATH Account tests', () {
appTest('Create account', (WidgetTester tester) async {
group('Account tests', () {
appTest('Create OATH account', (WidgetTester tester) async {
// account with issuer
var testAccount = const Account(
issuer: 'IssuerForTests',
@ -45,7 +45,7 @@ void main() {
);
await tester.deleteAccount(testAccount);
await tester.addAccount(testAccount, quiet: false);
await tester.addAccount(testAccount);
// account without issuer
testAccount = const Account(
@ -54,24 +54,24 @@ void main() {
);
await tester.deleteAccount(testAccount);
await tester.addAccount(testAccount, quiet: false);
await tester.addAccount(testAccount);
});
/// deletes accounts created in previous test
appTest('Delete account', (WidgetTester tester) async {
appTest('Delete OATH account', (WidgetTester tester) async {
var testAccount =
const Account(issuer: 'IssuerForTests', name: 'NameForTests');
await tester.deleteAccount(testAccount, quiet: false);
await tester.deleteAccount(testAccount);
expect(await tester.findAccount(testAccount), isNull);
testAccount = const Account(issuer: null, name: 'NoIssuerName');
await tester.deleteAccount(testAccount, quiet: false);
await tester.deleteAccount(testAccount);
expect(await tester.findAccount(testAccount), isNull);
});
/// adds an account, renames, verifies
appTest('Rename account', (WidgetTester tester) async {
appTest('Rename OATH account', (WidgetTester tester) async {
var testAccount =
const Account(issuer: 'IssuerToRename', name: 'NameToRename');
@ -85,7 +85,7 @@ void main() {
});
});
group('OATH Password tests', () {
group('Password tests', () {
/// note that the password groups should be run as whole
/// TODO implement test for password replacement
@ -94,27 +94,27 @@ void main() {
/// });
// cannot restart the app on Android to be able to unlock
group('OATH: remove oath password when unlocked', skip: isAndroid, () {
group('Desktop password tests', skip: isAndroid, () {
var testPassword = 'testPassword';
appTest('OATH: set oath password', (WidgetTester tester) async {
appTest('Set OATH password', (WidgetTester tester) async {
await tester.setOathPassword(testPassword);
});
appTest('OATH: remove oath password', (WidgetTester tester) async {
appTest('Remove OATH password', (WidgetTester tester) async {
await tester.unlockOathSession(testPassword);
await tester.removeOathPassword(testPassword);
});
});
group('OATH: remove oath password when locked', () {
group('All password tests', () {
var testPassword = 'testPasswordX';
appTest('OATH: set oath password', (WidgetTester tester) async {
appTest('Set OATH password', (WidgetTester tester) async {
await tester.setOathPassword(testPassword);
});
appTest('OATH: remove oath password', (WidgetTester tester) async {
appTest('Remove OATH password', (WidgetTester tester) async {
await tester.removeOathPassword(testPassword);
});
});

View File

@ -111,6 +111,7 @@ extension OathFunctions on WidgetTester {
return null;
}
await shortWait();
/// find an AccountView with issuer/name in the account list
var matchingAccounts = find.descendant(
of: findAccountList(),
@ -174,6 +175,7 @@ extension OathFunctions on WidgetTester {
expect(deleteButton, findsOneWidget);
await tap(deleteButton);
await longWait();
await longWait();
/// try to find account
var deletedAccountView = await findAccount(a);
@ -202,6 +204,7 @@ extension OathFunctions on WidgetTester {
/// TODO verify this is correct for the FW of the YubiKey
if (renameIconButton.evaluate().isEmpty) {
/// close the dialog and return
testLog(false, 'This YubiKey does not support account renaming');
await tapAt(const Offset(10, 10));
await shortWait();
return;
@ -218,7 +221,7 @@ extension OathFunctions on WidgetTester {
var nameTextField = find.byKey(keys.nameField).hitTestable();
await tap(nameTextField);
await enterText(nameTextField, newName);
await shortestWait();
await shortWait();
var saveButton = find.byKey(keys.saveButton).hitTestable();
expect(saveButton, findsOneWidget);
@ -300,7 +303,10 @@ extension OathFunctions on WidgetTester {
await shortWait();
var unlockButton = find.byKey(keys.unlockButton);
await tap(unlockButton);
await longWait();
/// TODO:
/// the following pump is because of NEO keys
await pump(const Duration(seconds: 1));
expect(find.byKey(keys.unlockButton).hitTestable(), findsNothing);
}
@ -315,7 +321,10 @@ extension OathFunctions on WidgetTester {
await enterText(currentPasswordEntry, currentPassword);
await shortWait();
await tap(find.byKey(keys.removePasswordButton));
await longWait();
/// TODO:
/// the following pump is because of NEO keys
await pump(const Duration(seconds: 1));
expect(find.byKey(keys.removePasswordButton).hitTestable(), findsNothing);
}

View File

@ -27,10 +27,8 @@ import 'android/util.dart' as android_test_util;
import 'approved_yubikeys.dart';
import 'desktop/util.dart' as desktop_test_util;
const shortestWaitMs = 10;
const shortWaitMs = 50;
const longWaitMs = 200;
const veryLongWaitS = 10; // seconds
const shortWaitMs = 10;
const longWaitMs = 50;
/// information about YubiKey as seen by the app
String? yubiKeyName;
@ -39,10 +37,6 @@ String? yubiKeySerialNumber;
bool collectedYubiKeyInformation = false;
extension AppWidgetTester on WidgetTester {
Future<void> shortestWait() async {
await pump(const Duration(milliseconds: shortestWaitMs));
}
Future<void> shortWait() async {
await pump(const Duration(milliseconds: shortWaitMs));
}
@ -51,10 +45,6 @@ extension AppWidgetTester on WidgetTester {
await pump(const Duration(milliseconds: longWaitMs));
}
Future<void> veryLongWait() async {
await pump(const Duration(seconds: veryLongWaitS));
}
/// waits up to [timeOutSec] seconds evaluating whether [Finder] f is
/// visible
Future<Finder> waitForFinder(Finder f, [int timeOutSec = 20]) async {

View File

@ -57,9 +57,7 @@ Future<Widget> initialize() async {
Application.oath,
]),
prefProvider.overrideWithValue(await SharedPreferences.getInstance()),
logLevelProvider.overrideWith(
(ref) => ref.watch(androidLogProvider.notifier),
),
logLevelProvider.overrideWith((ref) => AndroidLogger()),
attachedDevicesProvider
.overrideWith(
() => AndroidAttachedDevicesNotifier(),
@ -71,7 +69,7 @@ Future<Widget> initialize() async {
credentialListProvider
.overrideWithProvider(androidCredentialListProvider),
currentAppProvider.overrideWith(
(ref) => ref.watch(androidSubPageProvider.notifier),
(ref) => AndroidSubPageNotifier(ref.watch(supportedAppsProvider))
),
managementStateProvider.overrideWithProvider(androidManagementState),
currentDeviceProvider.overrideWith(
@ -92,9 +90,6 @@ Future<Widget> initialize() async {
child: DismissKeyboard(
child: YubicoAuthenticatorApp(page: Consumer(
builder: (context, ref, child) {
// activates the sub page provider
ref.read(androidSubPageProvider);
// activates window state provider
ref.read(androidWindowStateProvider);

View File

@ -15,15 +15,11 @@
*/
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logging/logging.dart';
import 'package:yubico_authenticator/app/logging.dart';
final _log = Logger('android.logger');
final androidLogProvider =
StateNotifierProvider<LogLevelNotifier, Level>((ref) => AndroidLogger());
class AndroidLogger extends LogLevelNotifier {
final MethodChannel _channel = const MethodChannel('android.log.redirect');

View File

@ -74,13 +74,8 @@ final androidSupportedThemesProvider = StateProvider<List<ThemeMode>>((ref) {
}
});
final androidSubPageProvider =
StateNotifierProvider<CurrentAppNotifier, Application>((ref) {
return _AndroidSubPageNotifier(ref.watch(supportedAppsProvider));
});
class _AndroidSubPageNotifier extends CurrentAppNotifier {
_AndroidSubPageNotifier(super.supportedApps) {
class AndroidSubPageNotifier extends CurrentAppNotifier {
AndroidSubPageNotifier(super.supportedApps) {
_handleSubPage(state);
}

View File

@ -83,6 +83,11 @@ class UsbDeviceNotifier extends StateNotifier<List<UsbYubiKeyNode>> {
try {
var scan = await rpc.command('scan', ['usb']);
if (!mounted) {
return;
}
final pids = {
for (var e in (scan['pids'] as Map).entries)
UsbPid.fromValue(int.parse(e.key)): e.value as int

View File

@ -125,7 +125,7 @@ class AccountDialog extends ConsumerWidget with AccountMixin {
}
final code = getCode(ref);
if (code == null) {
if (isValid(ref) && code == null) {
if (isDesktop ||
(isAndroid &&
currentDeviceData.value?.node.transport == Transport.usb)) {

View File

@ -50,6 +50,11 @@ mixin AccountMixin {
@protected
OathCode? getCode(WidgetRef ref) => ref.watch(codeProvider(credential));
@protected
bool isValid(WidgetRef ref) =>
ref.watch(credentialsProvider)?.any((c) => credential.id == c.id) ??
false;
@protected
String formatCode(OathCode? code) {
final value = code?.value;

View File

@ -225,7 +225,7 @@ packages:
name: flutter_riverpod
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.1.3"
flutter_test:
dependency: "direct dev"
description: flutter
@ -462,7 +462,7 @@ packages:
name: riverpod
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.1.3"
screen_retriever:
dependency: transitive
description:

View File

@ -45,7 +45,7 @@ dependencies:
logging: ^1.1.0
collection: ^1.16.0
shared_preferences: ^2.0.12
flutter_riverpod: ^2.1.1
flutter_riverpod: ^2.1.3
json_annotation: ^4.7.0
freezed_annotation: ^2.2.0
window_manager: ^0.2.7