7
7
import platform
8
8
9
9
10
- def test_flush_metrics ( test_microvm_with_api ):
10
+ def _validate_metrics ( metrics ):
11
11
"""
12
- Check the `FlushMetrics` vmm action.
12
+ This functions makes sure that all components
13
+ of FirecrackerMetrics struct are present.
14
+ In depth validation of metrics for each component
15
+ should be implemented in its own test.
16
+ e.g. validation of NetDeviceMetrics should implement
17
+ _validate_net_metrics() to check for breaking change etc.
13
18
"""
14
- microvm = test_microvm_with_api
15
- microvm .spawn ()
16
- microvm .basic_config ()
17
- microvm .start ()
18
-
19
- metrics = microvm .flush_metrics ()
20
-
21
19
exp_keys = [
22
20
"utc_timestamp_ms" ,
23
21
"api_server" ,
@@ -44,7 +42,7 @@ def test_flush_metrics(test_microvm_with_api):
44
42
if platform .machine () == "aarch64" :
45
43
exp_keys .append ("rtc" )
46
44
47
- assert set (metrics .keys ()) == set ( exp_keys )
45
+ assert set (exp_keys ). issubset ( metrics .keys ())
48
46
49
47
utc_time = datetime .datetime .now (datetime .timezone .utc )
50
48
utc_timestamp_ms = math .floor (utc_time .timestamp () * 1000 )
@@ -54,3 +52,130 @@ def test_flush_metrics(test_microvm_with_api):
54
52
# Epoch.Regression test for:
55
53
# https://github.com/firecracker-microvm/firecracker/issues/2639
56
54
assert abs (utc_timestamp_ms - metrics ["utc_timestamp_ms" ]) < 1000
55
+
56
+
57
+ class FcDeviceMetrics :
58
+ """
59
+ Provides functions to validate breaking change and
60
+ aggregation of metrics
61
+ """
62
+
63
+ def __init__ (self , name , validate_fn , num_dev ):
64
+ self .dev_name = name
65
+ self .validate_dev_metrics = validate_fn
66
+ self .num_dev = num_dev
67
+
68
+ def validate (self , microvm ):
69
+ """
70
+ validate breaking change of device metrics
71
+ """
72
+ fc_metrics = microvm .flush_metrics ()
73
+
74
+ # make sure all items of FirecrackerMetrics are as expected
75
+ _validate_metrics (fc_metrics )
76
+
77
+ # check for breaking change in device specific metrics
78
+ self .validate_dev_metrics (fc_metrics [self .dev_name ])
79
+
80
+ # make sure "{self.name}" is aggregate of "{self.name}_*"
81
+ # and that there are only {num_dev} entries of "{self.name}_*"
82
+ self .validate_aggregation (fc_metrics )
83
+ print (f"\n successfully validated aggregate of { self .dev_name } metrics" )
84
+
85
+ def validate_aggregation (self , fc_metrics ):
86
+ """
87
+ validate aggregation of device metrics
88
+ """
89
+ metrics_aggregate = fc_metrics [self .dev_name ]
90
+ metrics_calculated = {}
91
+ actual_num_devices = 0
92
+ print (f"In aggregation of { self .dev_name } expected { self .num_dev = } " )
93
+ for component_metric_names , component_metric_values in fc_metrics .items ():
94
+ if f"{ self .dev_name } _" in component_metric_names :
95
+ print (f"found { component_metric_names } during aggr of { self .dev_name } " )
96
+ actual_num_devices += 1
97
+ for metrics_name , metric_value in component_metric_values .items ():
98
+ if metrics_name not in metrics_calculated :
99
+ metrics_calculated [metrics_name ] = 0
100
+ metrics_calculated [metrics_name ] += metric_value
101
+ assert metrics_aggregate == metrics_calculated
102
+ assert self .num_dev == actual_num_devices
103
+
104
+
105
+ def test_flush_metrics (test_microvm_with_api ):
106
+ """
107
+ Check the `FlushMetrics` vmm action.
108
+ """
109
+ microvm = test_microvm_with_api
110
+ microvm .spawn ()
111
+ microvm .basic_config ()
112
+ microvm .start ()
113
+
114
+ metrics = microvm .flush_metrics ()
115
+ _validate_metrics (metrics )
116
+
117
+
118
+ def _validate_net_metrics (net_metrics ):
119
+ exp_keys = [
120
+ "activate_fails" ,
121
+ "cfg_fails" ,
122
+ "mac_address_updates" ,
123
+ "no_rx_avail_buffer" ,
124
+ "no_tx_avail_buffer" ,
125
+ "event_fails" ,
126
+ "rx_queue_event_count" ,
127
+ "rx_event_rate_limiter_count" ,
128
+ "rx_partial_writes" ,
129
+ "rx_rate_limiter_throttled" ,
130
+ "rx_tap_event_count" ,
131
+ "rx_bytes_count" ,
132
+ "rx_packets_count" ,
133
+ "rx_fails" ,
134
+ "rx_count" ,
135
+ "tap_read_fails" ,
136
+ "tap_write_fails" ,
137
+ "tx_bytes_count" ,
138
+ "tx_malformed_frames" ,
139
+ "tx_fails" ,
140
+ "tx_count" ,
141
+ "tx_packets_count" ,
142
+ "tx_partial_reads" ,
143
+ "tx_queue_event_count" ,
144
+ "tx_rate_limiter_event_count" ,
145
+ "tx_rate_limiter_throttled" ,
146
+ "tx_spoofed_mac_count" ,
147
+ ]
148
+ assert set (net_metrics .keys ()) == set (exp_keys )
149
+
150
+
151
+ def test_net_metrics (test_microvm_with_api ):
152
+ """
153
+ Validate that NetDeviceMetrics doesn't have a breaking change
154
+ and "net" is aggregate of all "net_*" in the json object.
155
+ """
156
+ test_microvm = test_microvm_with_api
157
+ test_microvm .spawn ()
158
+
159
+ # Set up a basic microVM.
160
+ test_microvm .basic_config ()
161
+
162
+ # randomly selected 10 as the number of net devices to test
163
+ num_net_devices = 10
164
+
165
+ net_metrics = FcDeviceMetrics ("net" , _validate_net_metrics , num_net_devices )
166
+
167
+ # create more than 1 net devices to test aggregation
168
+ for _ in range (num_net_devices ):
169
+ test_microvm .add_net_iface ()
170
+ test_microvm .start ()
171
+
172
+ # check that the started microvm has "net" and "NUM_NET_DEVICES" number of "net_" metrics
173
+ net_metrics .validate (test_microvm )
174
+
175
+ for i in range (num_net_devices ):
176
+ # Test that network devices attached are operational.
177
+ # Verify if guest can run commands.
178
+ exit_code , _ , _ = test_microvm .ssh_iface (i ).run ("sync" )
179
+ # test that we get metrics while interacting with different interfaces
180
+ net_metrics .validate (test_microvm )
181
+ assert exit_code == 0
0 commit comments