Skip to content

Commit

Permalink
test: ratings service and model (ubuntu#1439)
Browse files Browse the repository at this point in the history
* test: add ratings_service_test

* test: add ratings_model_test

* test(snap_page): add missing ratings model mocks
  • Loading branch information
d-loose authored Oct 5, 2023
1 parent d84cb1b commit e38976a
Show file tree
Hide file tree
Showing 9 changed files with 739 additions and 370 deletions.
9 changes: 7 additions & 2 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:io';

import 'package:app_center_ratings_client/ratings_client.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:github/github.dart';
Expand Down Expand Up @@ -44,8 +45,12 @@ Future<void> main(List<String> args) async {
final config = ConfigService();
config.load();

final ratings =
RatingsService(config.ratingServiceUrl, config.ratingsServicePort);
final ratings = RatingsService(
RatingsClient(
config.ratingServiceUrl,
config.ratingsServicePort,
),
);
registerServiceInstance(config);
registerServiceInstance(ratings);

Expand Down
4 changes: 2 additions & 2 deletions lib/src/ratings/ratings_model.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import 'package:clock/clock.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:snapd/snapd.dart';
import 'package:ubuntu_service/ubuntu_service.dart';

import 'exports.dart';

import 'ratings_service.dart';

final ratingsModelProvider =
Expand Down Expand Up @@ -72,7 +72,7 @@ class RatingsModel extends ChangeNotifier {
snapId: snapId,
snapRevision: int.parse(snapRevision),
voteUp: voteUp, // using voteUp directly here
dateTime: DateTime.now(),
dateTime: clock.now(),
);
await ratings.vote(vote);
_vote = castVote;
Expand Down
21 changes: 10 additions & 11 deletions lib/src/ratings/ratings_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@ import 'package:crypto/crypto.dart';
import 'package:flutter/material.dart';
import 'package:glib/glib.dart';
import 'package:jwt_decode/jwt_decode.dart';

import 'exports.dart';

class RatingsService {
RatingsService(String url, int port,
[@visibleForTesting RatingsClient? client])
: _client = client ?? RatingsClient(url, port),
_id = _generateId();
RatingsService(this.client, {@visibleForTesting String? id})
: _id = id ?? _generateId();

final RatingsClient _client;
final RatingsClient client;
String? _jwt;
final String _id;

Expand All @@ -26,32 +25,32 @@ class RatingsService {

Future<void> _ensureValidToken() async {
if (_jwt == null || Jwt.isExpired(_jwt!)) {
_jwt = await _client.authenticate(_id);
_jwt = await client.authenticate(_id);
}
}

Future<Rating?> getRating(String snapId) async {
await _ensureValidToken();
return _client.getRating(snapId, _jwt!);
return client.getRating(snapId, _jwt!);
}

Future<void> vote(Vote vote) async {
await _ensureValidToken();
await _client.vote(vote.snapId, vote.snapRevision, vote.voteUp, _jwt!);
await client.vote(vote.snapId, vote.snapRevision, vote.voteUp, _jwt!);
}

Future<void> delete() async {
await _ensureValidToken();
await _client.delete(_jwt!);
await client.delete(_jwt!);
}

Future<List<Vote>> listMyVotes(String snapFilter) async {
await _ensureValidToken();
return await _client.listMyVotes(snapFilter, _jwt!);
return await client.listMyVotes(snapFilter, _jwt!);
}

Future<List<Vote>> getSnapVotes(String snapId) async {
await _ensureValidToken();
return await _client.getSnapVotes(snapId, _jwt!);
return await client.getSnapVotes(snapId, _jwt!);
}
}
3 changes: 2 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dependencies:
collection: ^1.17.0
dbus: ^0.7.8
app_center_ratings_client:
git:
git:
url: https://github.com/matthew-hagemann/app_center_ratings_client.dart.git
ref: main
crypto: ^3.0.3
Expand Down Expand Up @@ -52,6 +52,7 @@ dependencies:
yaru_icons: ^1.0.4
yaru_widgets: ^2.6.0
yaru_test: ^0.1.4
clock: ^1.1.1

dev_dependencies:
build_runner: ^2.4.5
Expand Down
70 changes: 70 additions & 0 deletions test/ratings_model_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import 'package:app_center/ratings.dart';
import 'package:clock/clock.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';

import 'test_utils.dart';

void main() {
test('init', () async {
final mockService = createMockRatingsService(
rating: const Rating(
snapId: 'firefox',
totalVotes: 1337,
ratingsBand: RatingsBand.veryGood,
),
snapVotes: [
Vote(
snapId: 'firefox',
snapRevision: 42,
voteUp: true,
dateTime: DateTime(1970),
),
],
);
final model = RatingsModel(
ratings: mockService,
snapId: 'firefox',
snapRevision: '42',
);

await model.init();
expect(model.state.hasValue, isTrue);
expect(
model.snapRating,
equals(
const Rating(
snapId: 'firefox',
totalVotes: 1337,
ratingsBand: RatingsBand.veryGood,
),
),
);
expect(model.vote, equals(VoteStatus.up));
});

test('cast vote', () async {
final mockService = createMockRatingsService();
final model = RatingsModel(
ratings: mockService,
snapId: 'firefox',
snapRevision: '42',
);

await model.init();
await withClock(
Clock.fixed(DateTime(1984)),
() => model.castVote(VoteStatus.up),
);
verify(
mockService.vote(
Vote(
dateTime: DateTime(1984),
snapId: 'firefox',
snapRevision: 42,
voteUp: true,
),
),
).called(1);
});
}
120 changes: 120 additions & 0 deletions test/ratings_service_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import 'package:app_center/src/ratings/exports.dart';
import 'package:app_center/src/ratings/ratings_service.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';

import 'test_utils.dart';

void main() {
test('get rating', () async {
final mockClient = createMockRatingsClient(
token: 'jwt',
rating: const Rating(
snapId: 'firefox',
totalVotes: 1337,
ratingsBand: RatingsBand.veryGood,
),
);
final service = RatingsService(mockClient, id: 'myId');

final rating = await service.getRating('firefox');
verify(mockClient.authenticate('myId')).called(1);
expect(
rating,
equals(
const Rating(
snapId: 'firefox',
totalVotes: 1337,
ratingsBand: RatingsBand.veryGood,
),
),
);
});

test('vote', () async {
final mockClient = createMockRatingsClient(token: 'jwt');
final service = RatingsService(mockClient, id: 'myId');

await service.vote(
Vote(
snapId: 'thunderbird',
snapRevision: 42,
voteUp: true,
dateTime: DateTime(1970),
),
);
verify(mockClient.authenticate('myId')).called(1);
verify(mockClient.vote('thunderbird', 42, true, 'jwt')).called(1);
});

test('delete', () async {
final mockClient = createMockRatingsClient(token: 'jwt');
final service = RatingsService(mockClient, id: 'myId');

await service.delete();
verify(mockClient.authenticate('myId')).called(1);
verify(mockClient.delete('jwt')).called(1);
});

test('list my votes', () async {
final mockClient = createMockRatingsClient(
token: 'jwt',
myVotes: [
Vote(
snapId: 'testsnap',
snapRevision: 1,
voteUp: false,
dateTime: DateTime(1984),
),
],
);
final service = RatingsService(mockClient, id: 'myId');

final votes = await service.listMyVotes('testsnap');
verify(mockClient.authenticate('myId')).called(1);
expect(
votes,
equals(
[
Vote(
snapId: 'testsnap',
snapRevision: 1,
voteUp: false,
dateTime: DateTime(1984),
),
],
),
);
});

test('snap votes', () async {
final mockClient = createMockRatingsClient(
token: 'jwt',
snapVotes: [
Vote(
snapId: 'testsnap2',
snapRevision: 2,
voteUp: true,
dateTime: DateTime(1999),
),
],
);
final service = RatingsService(mockClient, id: 'myId');

final votes = await service.getSnapVotes('testsnap2');
verify(mockClient.authenticate('myId')).called(1);
expect(
votes,
equals(
[
Vote(
snapId: 'testsnap2',
snapRevision: 2,
voteUp: true,
dateTime: DateTime(1999),
),
],
),
);
});
}
8 changes: 6 additions & 2 deletions test/snap_page_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,14 @@ void main() {
);
final snapLauncher = createMockSnapLauncher(isLaunchable: true);
final updatesModel = createMockUpdatesModel();
final ratingsModel = createMockRatingsModel();

await tester.pumpApp((_) => ProviderScope(
overrides: [
snapModelProvider.overrideWith((ref, arg) => snapModel),
launchProvider.overrideWith((ref, arg) => snapLauncher),
updatesModelProvider.overrideWith((ref) => updatesModel)
updatesModelProvider.overrideWith((ref) => updatesModel),
ratingsModelProvider.overrideWith((ref, arg) => ratingsModel),
],
child: SnapPage(snapName: storeSnap.name),
));
Expand Down Expand Up @@ -313,12 +315,14 @@ void main() {
);
final snapLauncher = createMockSnapLauncher(isLaunchable: true);
final updatesModel = createMockUpdatesModel();
final ratingsModel = createMockRatingsModel();

await tester.pumpApp((_) => ProviderScope(
overrides: [
snapModelProvider.overrideWith((ref, arg) => snapModel),
launchProvider.overrideWith((ref, arg) => snapLauncher),
updatesModelProvider.overrideWith((ref) => updatesModel)
updatesModelProvider.overrideWith((ref) => updatesModel),
ratingsModelProvider.overrideWith((ref, arg) => ratingsModel),
],
child: SnapPage(snapName: storeSnap.name),
));
Expand Down
37 changes: 35 additions & 2 deletions test/test_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:app_center/ratings.dart';
import 'package:app_center/snapd.dart';
import 'package:app_center/src/deb/deb_model.dart';
import 'package:app_center/src/manage/manage_model.dart';
import 'package:app_center_ratings_client/ratings_client.dart';
import 'package:appstream/appstream.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -282,12 +283,44 @@ MockPackageKitTransaction createMockPackageKitTransaction({
}

@GenerateMocks([RatingsService])
MockRatingsService createMockRatingsService() {
MockRatingsService createMockRatingsService({
Rating? rating,
List<Vote>? snapVotes,
}) {
final service = MockRatingsService();
when(service.vote(any)).thenAnswer((_) async => {});
when(service.getRating(any)).thenAnswer((_) async =>
rating ??
const Rating(
snapId: '',
totalVotes: 0,
ratingsBand: RatingsBand.insufficientVotes,
));
when(service.getSnapVotes(any)).thenAnswer((_) async => snapVotes ?? []);

return service;
}

@GenerateMocks([RatingsClient])
MockRatingsClient createMockRatingsClient({
String? token,
Rating? rating,
List<Vote>? myVotes,
List<Vote>? snapVotes,
}) {
final client = MockRatingsClient();
when(client.authenticate(any)).thenAnswer((_) async => token ?? '');
when(client.getRating(any, any)).thenAnswer((_) async =>
rating ??
const Rating(
snapId: '',
totalVotes: 0,
ratingsBand: RatingsBand.insufficientVotes,
));
when(client.listMyVotes(any, any)).thenAnswer((_) async => myVotes ?? []);
when(client.getSnapVotes(any, any)).thenAnswer((_) async => snapVotes ?? []);
return client;
}

@GenerateMocks([AppstreamService])
MockAppstreamService createMockAppstreamService({
AppstreamComponent? component,
Expand Down
Loading

0 comments on commit e38976a

Please sign in to comment.