diff --git a/lib/features/mongodb/mongo_stats_view.dart b/lib/features/mongodb/mongo_stats_view.dart index f9d4dcc9..62708e70 100644 --- a/lib/features/mongodb/mongo_stats_view.dart +++ b/lib/features/mongodb/mongo_stats_view.dart @@ -610,10 +610,12 @@ class _MongoStatsViewState extends material.State material.Widget _memoryCard( material.BuildContext context, Map status) { final mem = status['mem'] as Map?; - final resident = _getInt(mem, 'resident') ?? 0; - final virtual = _getInt(mem, 'virtual') ?? 0; - final mapped = _getInt(mem, 'mapped') ?? 0; - final mappedWithJournal = _getInt(mem, 'mappedWithJournal') ?? 0; + // serverStatus reports `mem` in MiB, not bytes. + const mib = 1024 * 1024; + final resident = (_getInt(mem, 'resident') ?? 0) * mib; + final virtual = (_getInt(mem, 'virtual') ?? 0) * mib; + final mapped = (_getInt(mem, 'mapped') ?? 0) * mib; + final mappedWithJournal = (_getInt(mem, 'mappedWithJournal') ?? 0) * mib; return _card( context, 'Memory', @@ -799,12 +801,7 @@ class _MongoStatsViewState extends material.State return v?.toString(); } - int? _getInt(Map? map, String key) { - final v = map?[key]; - if (v is int) return v; - if (v is num) return v.toInt(); - return null; - } + int? _getInt(Map? map, String key) => mongoStatInt(map?[key]); int? _getNestedInt(Map? map, String key1, String key2, [String? key3]) { @@ -813,15 +810,9 @@ class _MongoStatsViewState extends material.State if (key3 != null) { final m2 = m1[key2] as Map?; if (m2 == null) return null; - final v = m2[key3]; - if (v is int) return v; - if (v is num) return v.toInt(); - return null; + return mongoStatInt(m2[key3]); } - final v = m1[key2]; - if (v is int) return v; - if (v is num) return v.toInt(); - return null; + return mongoStatInt(m1[key2]); } Map _extractServerInfo(Map status) { @@ -892,3 +883,14 @@ class _MongoStatsViewState extends material.State return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(1)} GB'; } } + +/// A `serverStatus` number as an [int]: [int], [num], or bson `Int64`, which is +/// not a Dart [num] (counters such as `opcounters` and `network.bytesIn` come +/// as Int64 and used to read as 0). +@visibleForTesting +int? mongoStatInt(Object? v) { + if (v == null) return null; + if (v is int) return v; + if (v is num) return v.toInt(); + return int.tryParse(v.toString()); +} diff --git a/test/features/mongodb/mongo_stats_numbers_test.dart b/test/features/mongodb/mongo_stats_numbers_test.dart new file mode 100644 index 00000000..5bfe03f1 --- /dev/null +++ b/test/features/mongodb/mongo_stats_numbers_test.dart @@ -0,0 +1,22 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:querya_desktop/features/mongodb/mongo_stats_view.dart'; + +/// Stands in for bson's `Int64`: not a Dart [num], prints its value. +class _Int64Like { + const _Int64Like(this.value); + final int value; + + @override + String toString() => '$value'; +} + +void main() { + test('serverStatus numbers read as ints, Int64 included', () { + expect(mongoStatInt(42), 42); + expect(mongoStatInt(42.9), 42); + // opcounters and network.bytesIn arrive as Int64; they used to read as 0. + expect(mongoStatInt(const _Int64Like(577674)), 577674); + expect(mongoStatInt(null), isNull); + expect(mongoStatInt('not a number'), isNull); + }); +}