[inspect][dart] Health node API
TESTED=fx run-host-tests fuchsia_inspect_package_unittests
Change-Id: I785fb2df3d4731f1f641522c7d18f682dcc98ff4
diff --git a/public/dart/fuchsia_inspect/lib/src/inspect/inspect.dart b/public/dart/fuchsia_inspect/lib/src/inspect/inspect.dart
index 85c86f0..d961693 100644
--- a/public/dart/fuchsia_inspect/lib/src/inspect/inspect.dart
+++ b/public/dart/fuchsia_inspect/lib/src/inspect/inspect.dart
@@ -136,4 +136,9 @@
///
/// This node can't be deleted; trying to delete it is a NOP.
Node get root => _singleton.root;
+
+ /// The health [Node] of this Inspect tree.
+ ///
+ /// This node can't be deleted once created; but its creation is on demand.
+ HealthNode get health => _singleton.health;
}
diff --git a/public/dart/fuchsia_inspect/lib/src/inspect/internal/_inspect_impl.dart b/public/dart/fuchsia_inspect/lib/src/inspect/internal/_inspect_impl.dart
index e102a66..ebe2078 100644
--- a/public/dart/fuchsia_inspect/lib/src/inspect/internal/_inspect_impl.dart
+++ b/public/dart/fuchsia_inspect/lib/src/inspect/internal/_inspect_impl.dart
@@ -8,6 +8,8 @@
import '../../vmo/vmo_writer.dart';
import '../inspect.dart';
+const _kHealthNodeName = 'fuchsia.inspect.Health';
+
/// A concrete implementation of the [Inspect] interface.
///
/// This class is not intended to be used directly by authors but instead
@@ -15,6 +17,7 @@
class InspectImpl implements Inspect {
Node _root;
Vmo _vmo;
+ HealthNode _healthNodeSingleton;
/// The default constructor for this instance.
InspectImpl(vfs.PseudoDir directory, String fileName, VmoWriter writer) {
@@ -27,6 +30,10 @@
@override
Node get root => _root;
+ @override
+ HealthNode get health =>
+ _healthNodeSingleton ??= HealthNode(_root.child(_kHealthNodeName));
+
/// For use in testing only. There's probably no way to put @visibleForTesting
/// because this needs to be used by the Validator Puppet, outside the current
/// library.
diff --git a/public/dart/fuchsia_inspect/lib/src/inspect/node.dart b/public/dart/fuchsia_inspect/lib/src/inspect/node.dart
index aa886e6..339877d 100644
--- a/public/dart/fuchsia_inspect/lib/src/inspect/node.dart
+++ b/public/dart/fuchsia_inspect/lib/src/inspect/node.dart
@@ -4,6 +4,9 @@
part of 'inspect.dart';
+const _kHealthMessageName = 'message';
+const _kHealthStatusName = 'status';
+
/// A named node in the Inspect tree that can have [Node]s and
/// properties under it.
class Node {
@@ -210,3 +213,59 @@
@override
void delete() {}
}
+
+enum _Status {
+ startingUp,
+ ok,
+ unhealthy,
+}
+
+/// Contains subsystem health information.
+class HealthNode {
+ _Status _status;
+ Node _node;
+
+ /// Creates a new health node on the given node.
+ HealthNode(Node node) {
+ _node = node;
+ _setStatus(_Status.startingUp);
+ }
+
+ /// Sets the status of the health node to STARTING_UP.
+ void setStartingUp() {
+ _setStatus(_Status.startingUp);
+ }
+
+ /// Sets the status of the health node to OK.
+ void setOk() {
+ _setStatus(_Status.ok);
+ }
+
+ /// Sets the status of the health node to UNHEALTHY and records the given
+ /// `message`.
+ void setUnhealthy(String message) {
+ _setStatus(_Status.unhealthy, message: message);
+ }
+
+ String _statusString() {
+ switch (_status) {
+ case _Status.startingUp:
+ return 'STARTING_UP';
+ case _Status.ok:
+ return 'OK';
+ case _Status.unhealthy:
+ return 'UNHEALTHY';
+ }
+ return 'UNKNOWN';
+ }
+
+ void _setStatus(_Status status, {String message}) {
+ _status = status;
+ _node.stringProperty(_kHealthStatusName).setValue(_statusString());
+ if (message != null) {
+ _node.stringProperty(_kHealthMessageName).setValue(message);
+ } else {
+ _node.stringProperty(_kHealthMessageName).delete();
+ }
+ }
+}
diff --git a/public/dart/fuchsia_inspect/test/inspect/node_test.dart b/public/dart/fuchsia_inspect/test/inspect/node_test.dart
index f62caf8..c737744 100644
--- a/public/dart/fuchsia_inspect/test/inspect/node_test.dart
+++ b/public/dart/fuchsia_inspect/test/inspect/node_test.dart
@@ -15,14 +15,14 @@
void main() {
VmoHolder vmo;
+ Inspect inspect;
Node root;
setUp(() {
var context = StartupContext.fromStartupInfo();
vmo = FakeVmoHolder(512);
var writer = VmoWriter.withVmo(vmo);
- Inspect inspect =
- InspectImpl(context.outgoing.debugDir(), 'root.inspect', writer);
+ inspect = InspectImpl(context.outgoing.debugDir(), 'root.inspect', writer);
root = inspect.root;
});
@@ -210,4 +210,49 @@
expect(missingProperty.valid, false);
});
});
+
+ group('health', () {
+ test('health statuses', () {
+ const kNodeName = 'fuchsia.inspect.Health';
+
+ final health = inspect.health;
+
+ expect(VmoMatcher(vmo).node().at([kNodeName]), hasNoErrors);
+ expect(
+ VmoMatcher(vmo)
+ .node()
+ .at([kNodeName]).propertyEquals('status', 'STARTING_UP'),
+ hasNoErrors);
+ expect(VmoMatcher(vmo).node().at([kNodeName])..missingChild('message'),
+ hasNoErrors);
+
+ health.setOk();
+ expect(
+ VmoMatcher(vmo).node().at([kNodeName]).propertyEquals('status', 'OK'),
+ hasNoErrors);
+ expect(VmoMatcher(vmo).node().at([kNodeName])..missingChild('message'),
+ hasNoErrors);
+
+ health.setStartingUp();
+ expect(
+ VmoMatcher(vmo)
+ .node()
+ .at([kNodeName]).propertyEquals('status', 'STARTING_UP'),
+ hasNoErrors);
+ expect(VmoMatcher(vmo).node().at([kNodeName])..missingChild('message'),
+ hasNoErrors);
+
+ health.setUnhealthy('Oh no');
+ expect(
+ VmoMatcher(vmo)
+ .node()
+ .at([kNodeName]).propertyEquals('status', 'UNHEALTHY'),
+ hasNoErrors);
+ expect(
+ VmoMatcher(vmo)
+ .node()
+ .at([kNodeName]).propertyEquals('message', 'Oh no'),
+ hasNoErrors);
+ });
+ });
}