Skip to content

Commit

Permalink
feat: add DatabaseConnection wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
eseidel committed Mar 3, 2024
1 parent d6ce450 commit 3a5105e
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 103 deletions.
152 changes: 79 additions & 73 deletions packages/cli/test/plan/market_scores_test.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:cli/cache/market_price_snapshot.dart';
import 'package:cli/cache/systems_cache.dart';
import 'package:cli/config.dart';
import 'package:cli/logger.dart';
import 'package:cli/nav/system_connectivity.dart';
import 'package:cli/plan/market_scores.dart';
Expand All @@ -17,80 +18,85 @@ class _MockShipNav extends Mock implements ShipNav {}
class _MockSystemConnectivity extends Mock implements SystemConnectivity {}

void main() {
test('findBetterTradeLocation smoke test', () {
final fs = MemoryFileSystem.test();
final aSymbol = WaypointSymbol.fromString('S-A-A');
final bSymbol = WaypointSymbol.fromString('S-A-B');
final cSymbol = WaypointSymbol.fromString('S-A-C');
final dSymbol = WaypointSymbol.fromString('S-A-D');
final now = DateTime(2021);
final marketPrices = MarketPriceSnapshot(
[
MarketPrice(
waypointSymbol: aSymbol,
symbol: TradeSymbol.ADVANCED_CIRCUITRY,
supply: SupplyLevel.ABUNDANT,
purchasePrice: 1,
sellPrice: 2,
tradeVolume: 100,
timestamp: now,
activity: ActivityLevel.WEAK,
),
MarketPrice(
waypointSymbol: bSymbol,
symbol: TradeSymbol.ADVANCED_CIRCUITRY,
supply: SupplyLevel.ABUNDANT,
purchasePrice: 100,
sellPrice: 200,
tradeVolume: 100,
timestamp: now,
activity: ActivityLevel.WEAK,
),
],
);
final shipLocation = cSymbol;
const shipSymbol = ShipSymbol('A', 1);
final ship = _MockShip();
when(() => ship.symbol).thenReturn(shipSymbol.symbol);
final shipNav = _MockShipNav();
when(() => ship.nav).thenReturn(shipNav);
when(() => shipNav.systemSymbol).thenReturn(shipLocation.systemString);
test(
'findBetterTradeLocation smoke test',
() {
final fs = MemoryFileSystem.test();
final aSymbol = WaypointSymbol.fromString('S-A-A');
final bSymbol = WaypointSymbol.fromString('S-A-B');
final cSymbol = WaypointSymbol.fromString('S-A-C');
final dSymbol = WaypointSymbol.fromString('S-A-D');
final now = DateTime(2021);
final marketPrices = MarketPriceSnapshot(
[
MarketPrice(
waypointSymbol: aSymbol,
symbol: TradeSymbol.ADVANCED_CIRCUITRY,
supply: SupplyLevel.ABUNDANT,
purchasePrice: 1,
sellPrice: 2,
tradeVolume: 100,
timestamp: now,
activity: ActivityLevel.WEAK,
),
MarketPrice(
waypointSymbol: bSymbol,
symbol: TradeSymbol.ADVANCED_CIRCUITRY,
supply: SupplyLevel.ABUNDANT,
purchasePrice: 100,
sellPrice: 200,
tradeVolume: 100,
timestamp: now,
activity: ActivityLevel.WEAK,
),
],
);
final shipLocation = cSymbol;
const shipSymbol = ShipSymbol('A', 1);
final ship = _MockShip();
when(() => ship.symbol).thenReturn(shipSymbol.symbol);
final shipNav = _MockShipNav();
when(() => ship.nav).thenReturn(shipNav);
when(() => shipNav.systemSymbol).thenReturn(shipLocation.systemString);

final system = System.test(
shipLocation.system,
type: SystemType.BLUE_STAR,
waypoints: [
SystemWaypoint.test(aSymbol),
SystemWaypoint.test(bSymbol),
SystemWaypoint.test(shipLocation),
SystemWaypoint.test(dSymbol, type: WaypointType.JUMP_GATE),
],
);
final systems = [system];
final systemsCache = SystemsCache(systems, fs: fs);
final systemConnectivity = _MockSystemConnectivity();
when(() => systemConnectivity.systemsReachableFrom(system.symbol))
.thenReturn(systems.map((s) => s.symbol));
final system = System.test(
shipLocation.system,
type: SystemType.BLUE_STAR,
waypoints: [
SystemWaypoint.test(aSymbol),
SystemWaypoint.test(bSymbol),
SystemWaypoint.test(shipLocation),
SystemWaypoint.test(dSymbol, type: WaypointType.JUMP_GATE),
],
);
final systems = [system];
final systemsCache = SystemsCache(systems, fs: fs);
final systemConnectivity = _MockSystemConnectivity();
when(() => systemConnectivity.systemsReachableFrom(system.symbol))
.thenReturn(systems.map((s) => s.symbol));

CostedDeal? findNextDeal(Ship ship, WaypointSymbol startSymbol) {
return null;
}
CostedDeal? findNextDeal(Ship ship, WaypointSymbol startSymbol) {
return null;
}

final logger = _MockLogger();
final result = runWithLogger(
logger,
() => findBetterTradeLocation(
systemsCache,
systemConnectivity,
marketPrices,
ship,
findDeal: findNextDeal,
avoidSystems: <SystemSymbol>{},
profitPerSecondThreshold: 6,
),
);
verify(() => logger.detail('🛸#1 No deal found for A-1 at S-A')).called(1);
verify(() => logger.info('No nearby markets for A-1')).called(1);
expect(result, isNull);
});
final logger = _MockLogger();
final result = runWithLogger(
logger,
() => findBetterTradeLocation(
systemsCache,
systemConnectivity,
marketPrices,
ship,
findDeal: findNextDeal,
avoidSystems: <SystemSymbol>{},
profitPerSecondThreshold: 6,
),
);
verify(() => logger.detail('🛸#1 No deal found for A-1 at S-A'))
.called(1);
verify(() => logger.info('No nearby markets for A-1')).called(1);
expect(result, isNull);
},
skip: config.disableFindBetterTradeLocation,
);
}
53 changes: 37 additions & 16 deletions packages/db/lib/db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,37 @@ Future<pg.Connection> _defaultOpenConnection(
return pg.Connection.open(endpoint, settings: settings);
}

/// Wrapper around a database connection.
class DatabaseConnection {
/// Create a new database connection.
DatabaseConnection(this._connection);

/// The underlying connection, private to this class. Methods on this class
/// should use execute().
final pg.Connection _connection;

/// Close the database connection.
Future<void> close() => _connection.close();

/// Wait for a notification on a channel.
Future<void> waitOnChannel(String channel) async {
await _connection.channels[channel].first;
}

/// Execute a query.
Future<pg.Result> execute(Query query) {
return _connection.execute(
pg.Sql.named(query.fmtString),
parameters: query.parameters,
);
}

/// Execute a query.
Future<pg.Result> executeSql(String sql) {
return _connection.execute(sql);
}
}

/// Abstraction around a database connection.
class Database {
/// Create a new database connection.
Expand All @@ -55,17 +86,14 @@ class Database {
: endpoint = pg.Endpoint(host: 'localhost', database: 'test'),
settings = null;

/// The underlying connection, private to this class. Methods on this class
/// should use execute() where possible. Callers outside this class should
/// add queries to this class.
late final pg.Connection _connection;

/// Configure the database connection.
final pg.Endpoint endpoint;

/// Configure the database connection.
final pg.ConnectionSettings? settings;

late final DatabaseConnection _connection;

/// Open the database connection.
Future<void> open({
@visibleForTesting
Expand All @@ -74,7 +102,7 @@ class Database {
pg.ConnectionSettings? settings,
) openConnection = _defaultOpenConnection,
}) async {
_connection = await openConnection(endpoint, settings);
_connection = DatabaseConnection(await openConnection(endpoint, settings));
}

/// Close the database connection.
Expand All @@ -96,23 +124,16 @@ class Database {

/// Wait for a notification on a channel.
Future<void> waitOnChannel(String channel) async {
await _connection.channels[channel].first;
await _connection.waitOnChannel(channel);
}

/// Execute a query.
@protected
Future<pg.Result> execute(Query query) {
return _connection.execute(
pg.Sql.named(query.fmtString),
parameters: query.parameters,
);
}
Future<pg.Result> execute(Query query) => _connection.execute(query);

/// Execute a query.
@protected
Future<pg.Result> executeSql(String sql) {
return _connection.execute(sql);
}
Future<pg.Result> executeSql(String sql) => _connection.executeSql(sql);

/// Query for multiple records using the provided query.
@protected
Expand Down
21 changes: 7 additions & 14 deletions packages/db/test/db_test.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import 'package:db/db.dart';
import 'package:db/src/transaction.dart';
import 'package:db/src/query.dart';
import 'package:mocktail/mocktail.dart';
import 'package:postgres/postgres.dart' as pg;
import 'package:test/test.dart';
import 'package:types/types.dart';

class _MockConnection extends Mock implements pg.Connection {}

class _MockDatabaseConnection extends Mock implements DatabaseConnection {}

class _MockPostgreSQLResult extends Mock implements pg.Result {}

void main() {
Expand All @@ -28,24 +30,15 @@ void main() {
});

test('insertTransaction', () {
final connection = _MockConnection();
final connection = _MockDatabaseConnection();
final db = Database.test(connection);

final transaction = Transaction.fallbackValue();
when(
() => connection.execute(
any(),
parameters: any(named: 'parameters'),
),
).thenAnswer((_) async {
registerFallbackValue(const Query(''));
when(() => connection.execute(any())).thenAnswer((_) async {
return _MockPostgreSQLResult();
});
db.insertTransaction(transaction);
verify(
() => connection.execute(
any(),
parameters: transactionToColumnMap(transaction),
),
).called(1);
verify(() => connection.execute(any())).called(1);
});
}

0 comments on commit 3a5105e

Please sign in to comment.