Skip to content

Commit

Permalink
Implement metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
PlugFox committed May 23, 2024
1 parent f02b6d3 commit 31830fb
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 19 deletions.
66 changes: 49 additions & 17 deletions lib/src/model/metric.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,52 +107,68 @@ sealed class SpinifyMetrics implements Comparable<SpinifyMetrics> {
@immutable
final class SpinifyMetrics$Immutable extends SpinifyMetrics {
/// {@macro metrics}
const SpinifyMetrics$Immutable();
const SpinifyMetrics$Immutable({
required this.timestamp,
required this.initializedAt,
required this.commandId,
required this.state,
required this.connects,
required this.lastConnectAt,
required this.reconnectUrl,
required this.reconnectAttempts,
required this.nextReconnectAt,
required this.disconnects,
required this.lastDisconnectAt,
required this.bytesReceived,
required this.bytesSent,
required this.messagesReceived,
required this.messagesSent,
});

@override
DateTime get timestamp => throw UnimplementedError();
final DateTime timestamp;

@override
DateTime get initializedAt => throw UnimplementedError();
final DateTime initializedAt;

@override
int get commandId => throw UnimplementedError();
final int commandId;

@override
SpinifyState get state => throw UnimplementedError();
final SpinifyState state;

@override
int get connects => throw UnimplementedError();
final int connects;

@override
DateTime? get lastConnectAt => throw UnimplementedError();
final DateTime? lastConnectAt;

@override
String? get reconnectUrl => throw UnimplementedError();
final String? reconnectUrl;

@override
int? get reconnectAttempts => throw UnimplementedError();
final int? reconnectAttempts;

@override
DateTime? get nextReconnectAt => throw UnimplementedError();
final DateTime? nextReconnectAt;

@override
int get disconnects => throw UnimplementedError();
final int disconnects;

@override
DateTime? get lastDisconnectAt => throw UnimplementedError();
final DateTime? lastDisconnectAt;

@override
BigInt get bytesReceived => throw UnimplementedError();
final BigInt bytesReceived;

@override
BigInt get bytesSent => throw UnimplementedError();
final BigInt bytesSent;

@override
BigInt get messagesReceived => throw UnimplementedError();
final BigInt messagesReceived;

@override
BigInt get messagesSent => throw UnimplementedError();
final BigInt messagesSent;
}

/// {@macro metrics}
Expand Down Expand Up @@ -206,5 +222,21 @@ final class SpinifyMetrics$Mutable extends SpinifyMetrics {
BigInt messagesSent = BigInt.zero;

/// Freezes the metrics.
SpinifyMetrics$Immutable freeze() => const SpinifyMetrics$Immutable();
SpinifyMetrics$Immutable freeze() => SpinifyMetrics$Immutable(
timestamp: timestamp,
initializedAt: initializedAt,
commandId: commandId,
state: state,
connects: connects,
lastConnectAt: lastConnectAt,
reconnectUrl: reconnectUrl,
reconnectAttempts: reconnectAttempts,
nextReconnectAt: nextReconnectAt,
disconnects: disconnects,
lastDisconnectAt: lastDisconnectAt,
bytesReceived: bytesReceived,
bytesSent: bytesSent,
messagesReceived: messagesReceived,
messagesSent: messagesSent,
);
}
9 changes: 9 additions & 0 deletions lib/src/transport_fake.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// ignore_for_file: avoid_setters_without_getters

import 'dart:async';
import 'dart:convert';
import 'dart:math' as math;

import 'package:fixnum/fixnum.dart';
Expand Down Expand Up @@ -69,6 +70,9 @@ class SpinifyTransportFake implements ISpinifyTransport {
@override
Future<void> send(SpinifyCommand command) async {
if (!_isConnected) throw StateError('Not connected');
metrics
..bytesSent += BigInt.one
..messagesSent += BigInt.one;
await _sleep();
switch (command) {
case SpinifyPingRequest(:int id):
Expand Down Expand Up @@ -156,6 +160,8 @@ class SpinifyTransportFake implements ISpinifyTransport {
id: id,
timestamp: now,
data: switch (method) {
'getCurrentYear' =>
utf8.encode('{"year": ${DateTime.now().year}}'),
'echo' => data,
_ => throw ArgumentError('Unknown method: $method'),
},
Expand Down Expand Up @@ -190,6 +196,9 @@ class SpinifyTransportFake implements ISpinifyTransport {
Duration(milliseconds: delay),
() {
if (!_isConnected) return;
metrics
..bytesReceived += BigInt.one
..messagesReceived += BigInt.one;
_onReply?.call(reply(DateTime.now())).ignore();
},
);
Expand Down
124 changes: 123 additions & 1 deletion test/unit/spinify_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ void main() {
}));

test(
'rpc_request',
'Rpc_requests',
() => fakeAsync((async) {
final client = createFakeClient()
..connect('ws://localhost:8000/connection/websocket');
Expand Down Expand Up @@ -131,10 +131,132 @@ void main() {
}

async.elapse(client.config.timeout);
expect(client.state, isA<SpinifyState$Connected>());
client.disconnect();
async.elapse(client.config.timeout);
expect(client.state, isA<SpinifyState$Disconnected>());
client.connect('ws://localhost:8000/connection/websocket');
async.elapse(client.config.timeout);
expect(client.state, isA<SpinifyState$Connected>());

// Another request
expect(
client.rpc('getCurrentYear', <int>[]),
completion(isA<List<int>>().having(
(data) => jsonDecode(utf8.decode(data))['year'],
'year',
DateTime.now().year,
)),
);
async.elapse(client.config.timeout);

expect(client.state, isA<SpinifyState$Connected>());
client.close();
async.elapse(client.config.timeout);
expect(client.state, isA<SpinifyState$Closed>());
}));

test(
'Metrics',
() => fakeAsync((async) {
final client = createFakeClient();
expect(() => client.metrics, returnsNormally);
expect(
client.metrics,
allOf([
isA<SpinifyMetrics$Immutable>().having(
(m) => m.state.isConnected,
'isConnected',
isFalse,
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.state,
'state',
equals(client.state),
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.connects,
'connects',
0,
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.disconnects,
'disconnects',
0,
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.messagesReceived,
'messagesReceived',
equals(BigInt.zero),
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.messagesSent,
'messagesSent',
equals(BigInt.zero),
),
]));
client.connect('ws://localhost:8000/connection/websocket');
async.elapse(client.config.timeout);
expect(
client.metrics,
allOf([
isA<SpinifyMetrics$Immutable>().having(
(m) => m.state.isConnected,
'isConnected',
isTrue,
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.state,
'state',
equals(client.state),
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.connects,
'connects',
1,
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.disconnects,
'disconnects',
0,
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.messagesReceived,
'messagesReceived',
greaterThan(BigInt.zero),
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.messagesSent,
'messagesSent',
greaterThan(BigInt.zero),
),
]));
client.close();
async.elapse(client.config.timeout);
expect(
client.metrics,
allOf([
isA<SpinifyMetrics$Immutable>().having(
(m) => m.state.isConnected,
'isConnected',
isFalse,
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.state,
'state',
equals(client.state),
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.connects,
'connects',
1,
),
isA<SpinifyMetrics$Immutable>().having(
(m) => m.disconnects,
'disconnects',
1,
),
]));
}));
});
}
7 changes: 6 additions & 1 deletion tool/echo/echo.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,13 @@ func Centrifuge() (*centrifuge.Node, error) {
log.Printf("[user %s] sent RPC, data: %s, method: %s", client.UserID(), string(e.Data), e.Method)
switch e.Method {
case "getCurrentYear":
cb(centrifuge.RPCReply{Data: []byte(`{"year": "2020"}`)}, nil)
// Return current year.
cb(centrifuge.RPCReply{Data: []byte(`{"year": ` + strconv.Itoa(time.Now().Year()) + `}`)}, nil)
case "echo":
// Return back input data.
cb(centrifuge.RPCReply{Data: e.Data}, nil)
default:
// Method not found.
cb(centrifuge.RPCReply{}, centrifuge.ErrorMethodNotFound)
}
})
Expand Down

0 comments on commit 31830fb

Please sign in to comment.