Skip to content

Commit 5c80c79

Browse files
committed
use time mocks
1 parent 4887830 commit 5c80c79

File tree

2 files changed

+33
-22
lines changed

2 files changed

+33
-22
lines changed

google/cloud/bigtable/data/_metrics/data_model.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ class ActiveAttemptMetric:
128128
"""
129129

130130
# keep monotonic timestamps for active attempts
131-
start_time_ns: int = field(default_factory=time.monotonic_ns)
131+
start_time_ns: int = field(default_factory=lambda: time.monotonic_ns())
132132
# the time taken by the backend, in nanoseconds. Taken from response header
133133
gfe_latency_ns: int | None = None
134134
# time waiting on user to process the response, in nanoseconds
@@ -157,7 +157,7 @@ class ActiveOperationMetric:
157157
)
158158
)
159159
# keep monotonic timestamps for active operations
160-
start_time_ns: int = field(default_factory=time.monotonic_ns)
160+
start_time_ns: int = field(default_factory=lambda: time.monotonic_ns())
161161
active_attempt: ActiveAttemptMetric | None = None
162162
cluster_id: str | None = None
163163
zone: str | None = None

tests/unit/data/_metrics/test_data_model.py

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,17 @@ def _make_one(self, *args, **kwargs):
2626

2727
return ActiveOperationMetric(*args, **kwargs)
2828

29-
def test_ctor_defaults(self):
29+
@mock.patch("time.monotonic_ns")
30+
def test_ctor_defaults(self, mock_monotonic_ns):
3031
"""
3132
create an instance with default values
3233
"""
34+
expected_timestamp = 123456789
35+
mock_monotonic_ns.return_value = expected_timestamp
3336
mock_type = mock.Mock()
3437
metric = self._make_one(mock_type)
3538
assert metric.op_type == mock_type
36-
assert metric.start_time_ns == pytest.approx(
37-
time.monotonic_ns(), abs=50e6
38-
) # 50 ms buffer
39+
assert metric.start_time_ns == expected_timestamp
3940
assert metric.active_attempt is None
4041
assert metric.cluster_id is None
4142
assert metric.zone is None
@@ -176,33 +177,39 @@ def test_error_invalid_states(self, method, args, valid_states, error_method_nam
176177
== f"Invalid state for {error_method_name}: {state}"
177178
)
178179

179-
def test_start(self):
180+
@mock.patch("time.monotonic_ns")
181+
def test_start(self, mock_monotonic_ns):
180182
"""
181183
calling start op operation should reset start_time
182184
"""
185+
expected_timestamp = 123456789
186+
mock_monotonic_ns.return_value = expected_timestamp
183187
orig_time = 0
184188
metric = self._make_one(mock.Mock(), start_time_ns=orig_time)
185189
assert metric.start_time_ns == 0
186190
metric.start()
187191
assert metric.start_time_ns != orig_time
188-
assert metric.start_time_ns == pytest.approx(time.monotonic_ns(), abs=50e6)
192+
assert metric.start_time_ns == expected_timestamp
189193
# should remain in CREATED state after completing
190194
assert metric.state == State.CREATED
191195

192-
def test_start_attempt(self):
196+
@mock.patch("time.monotonic_ns")
197+
def test_start_attempt(self, mock_monotonic_ns):
193198
"""
194199
calling start_attempt should create a new emptu atempt metric
195200
"""
196201
from google.cloud.bigtable.data._metrics.data_model import ActiveAttemptMetric
197202

203+
from google.cloud.bigtable.data._metrics.data_model import ActiveAttemptMetric
204+
205+
expected_timestamp = 123456789
206+
mock_monotonic_ns.return_value = expected_timestamp
198207
metric = self._make_one(mock.Mock())
199208
assert metric.active_attempt is None
200209
metric.start_attempt()
201210
assert isinstance(metric.active_attempt, ActiveAttemptMetric)
202211
# make sure it was initialized with the correct values
203-
assert metric.active_attempt.start_time_ns == pytest.approx(
204-
time.monotonic_ns(), abs=50e6
205-
)
212+
assert metric.active_attempt.start_time_ns == expected_timestamp
206213
assert metric.active_attempt.gfe_latency_ns is None
207214
assert metric.active_attempt.grpc_throttling_time_ns == 0
208215
# should be in ACTIVE_ATTEMPT state after completing
@@ -387,14 +394,17 @@ def test_add_response_metadata_server_timing_header(
387394
assert metric.cluster_id is None
388395
assert metric.zone is None
389396

390-
def test_end_attempt_with_status(self):
397+
@mock.patch("time.monotonic_ns")
398+
def test_end_attempt_with_status(self, mock_monotonic_ns):
391399
"""
392400
ending the attempt should:
393401
- add one to completed_attempts
394402
- reset active_attempt to None
395403
- update state
396404
- notify handlers
397405
"""
406+
expected_mock_time = 123456789
407+
mock_monotonic_ns.return_value = expected_mock_time
398408
expected_start_time = 1
399409
expected_status = object()
400410
expected_gfe_latency_ns = 5
@@ -415,8 +425,8 @@ def test_end_attempt_with_status(self):
415425
metric.end_attempt_with_status(expected_status)
416426
assert len(metric.completed_attempts) == 1
417427
got_attempt = metric.completed_attempts[0]
418-
expected_duration = time.monotonic_ns() - expected_start_time
419-
assert got_attempt.duration_ns == pytest.approx(expected_duration, abs=50e6)
428+
expected_duration = expected_mock_time - expected_start_time
429+
assert got_attempt.duration_ns == expected_duration
420430
assert got_attempt.grpc_throttling_time_ns == expected_grpc_throttle
421431
assert got_attempt.end_status == expected_status
422432
assert got_attempt.gfe_latency_ns == expected_gfe_latency_ns
@@ -447,7 +457,8 @@ def test_end_attempt_with_status_w_exception(self):
447457
assert mock_exc_to_status.call_args[0][0] == input_status
448458
assert metric.completed_attempts[0].end_status == expected_status
449459

450-
def test_end_with_status(self):
460+
@mock.patch("time.monotonic_ns")
461+
def test_end_with_status(self, mock_monotonic_ns):
451462
"""
452463
ending the operation should:
453464
- end active attempt
@@ -456,6 +467,8 @@ def test_end_with_status(self):
456467
"""
457468
from google.cloud.bigtable.data._metrics.data_model import ActiveAttemptMetric
458469

470+
expected_mock_time = 123456789
471+
mock_monotonic_ns.return_value = expected_mock_time
459472
expected_attempt_start_time = 0
460473
expected_attempt_gfe_latency_ns = 5
461474
expected_flow_time = 16
@@ -494,8 +507,8 @@ def test_end_with_status(self):
494507
assert len(h.on_operation_complete.call_args[0]) == 1
495508
called_with = h.on_operation_complete.call_args[0][0]
496509
assert called_with.op_type == expected_type
497-
expected_duration = time.monotonic_ns() - expected_start_time
498-
assert called_with.duration_ns == pytest.approx(expected_duration, abs=50e6)
510+
expected_duration = expected_mock_time - expected_start_time
511+
assert called_with.duration_ns == expected_duration
499512
assert called_with.final_status == expected_status
500513
assert called_with.cluster_id == expected_cluster
501514
assert called_with.zone == expected_zone
@@ -510,10 +523,8 @@ def test_end_with_status(self):
510523
final_attempt = called_with.completed_attempts[0]
511524
assert final_attempt.gfe_latency_ns == expected_attempt_gfe_latency_ns
512525
assert final_attempt.end_status == expected_status
513-
expected_duration = time.monotonic_ns() - expected_attempt_start_time
514-
assert final_attempt.duration_ns == pytest.approx(
515-
expected_duration, abs=50e6
516-
)
526+
expected_duration = expected_mock_time - expected_attempt_start_time
527+
assert final_attempt.duration_ns == expected_duration
517528

518529
def test_end_with_status_w_exception(self):
519530
"""

0 commit comments

Comments
 (0)