1# Copyright 2020 The Cirq Developers 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15from unittest import mock 16import datetime 17 18import pytest 19import freezegun 20from google.protobuf.duration_pb2 import Duration 21from google.protobuf.text_format import Merge 22from google.protobuf.timestamp_pb2 import Timestamp 23import cirq 24import cirq_google as cg 25from cirq_google.api import v2 26from cirq_google.engine.engine import EngineContext 27from cirq_google.engine.client.quantum_v1alpha1 import enums as qenums 28from cirq_google.engine.client.quantum_v1alpha1 import types as qtypes 29 30 31def _to_any(proto): 32 any_proto = qtypes.any_pb2.Any() 33 any_proto.Pack(proto) 34 return any_proto 35 36 37def _to_timestamp(json_string): 38 timestamp_proto = qtypes.timestamp_pb2.Timestamp() 39 timestamp_proto.FromJsonString(json_string) 40 return timestamp_proto 41 42 43_CALIBRATION = qtypes.QuantumCalibration( 44 name='projects/a/processors/p/calibrations/1562715599', 45 timestamp=_to_timestamp('2019-07-09T23:39:59Z'), 46 data=_to_any( 47 Merge( 48 """ 49 timestamp_ms: 1562544000021, 50 metrics: [{ 51 name: 'xeb', 52 targets: ['0_0', '0_1'], 53 values: [{ 54 double_val: .9999 55 }] 56 }, { 57 name: 'xeb', 58 targets: ['0_0', '1_0'], 59 values: [{ 60 double_val: .9998 61 }] 62 }, { 63 name: 't1', 64 targets: ['0_0'], 65 values: [{ 66 double_val: 321 67 }] 68 }, { 69 name: 't1', 70 targets: ['0_1'], 71 values: [{ 72 double_val: 911 73 }] 74 }, { 75 name: 't1', 76 targets: ['1_0'], 77 values: [{ 78 double_val: 505 79 }] 80 }, { 81 name: 'globalMetric', 82 values: [{ 83 int32_val: 12300 84 }] 85 }] 86""", 87 v2.metrics_pb2.MetricsSnapshot(), 88 ) 89 ), 90) 91 92_DEVICE_SPEC = _to_any( 93 Merge( 94 """ 95valid_gate_sets: [{ 96 name: 'test_set', 97 valid_gates: [{ 98 id: 'x', 99 number_of_qubits: 1, 100 gate_duration_picos: 1000, 101 valid_targets: ['1q_targets'] 102 }] 103}], 104valid_qubits: ['0_0', '1_1'], 105valid_targets: [{ 106 name: '1q_targets', 107 target_ordering: SYMMETRIC, 108 targets: [{ 109 ids: ['0_0'] 110 }] 111}] 112""", 113 v2.device_pb2.DeviceSpecification(), 114 ) 115) 116 117 118_GATE_SET = cg.SerializableGateSet( 119 gate_set_name='x_gate_set', 120 serializers=[cg.GateOpSerializer(gate_type=cirq.XPowGate, serialized_gate_id='x', args=[])], 121 deserializers=[ 122 cg.GateOpDeserializer(serialized_gate_id='x', gate_constructor=cirq.XPowGate, args=[]) 123 ], 124) 125 126 127@pytest.fixture(scope='session', autouse=True) 128def mock_grpc_client(): 129 with mock.patch( 130 'cirq_google.engine.engine_client.quantum.QuantumEngineServiceClient' 131 ) as _fixture: 132 yield _fixture 133 134 135def test_engine(): 136 processor = cg.EngineProcessor('a', 'p', EngineContext()) 137 assert processor.engine().project_id == 'a' 138 139 140@mock.patch('cirq_google.engine.engine_client.EngineClient.get_processor') 141def test_health(get_processor): 142 get_processor.return_value = qtypes.QuantumProcessor(health=qtypes.QuantumProcessor.Health.OK) 143 processor = cg.EngineProcessor( 144 'a', 145 'p', 146 EngineContext(), 147 _processor=qtypes.QuantumProcessor(health=qtypes.QuantumProcessor.Health.DOWN), 148 ) 149 assert processor.health() == 'OK' 150 151 152@mock.patch('cirq_google.engine.engine_client.EngineClient.get_processor') 153def test_expected_down_time(get_processor): 154 processor = cg.EngineProcessor('a', 'p', EngineContext(), _processor=qtypes.QuantumProcessor()) 155 assert not processor.expected_down_time() 156 157 get_processor.return_value = qtypes.QuantumProcessor( 158 expected_down_time=qtypes.timestamp_pb2.Timestamp(seconds=1581515101) 159 ) 160 161 assert cg.EngineProcessor('a', 'p', EngineContext()).expected_down_time() == datetime.datetime( 162 2020, 2, 12, 13, 45, 1 163 ) 164 get_processor.assert_called_once() 165 166 167def test_expected_recovery_time(): 168 processor = cg.EngineProcessor('a', 'p', EngineContext(), _processor=qtypes.QuantumProcessor()) 169 assert not processor.expected_recovery_time() 170 processor = cg.EngineProcessor( 171 'a', 172 'p', 173 EngineContext(), 174 _processor=qtypes.QuantumProcessor( 175 expected_recovery_time=qtypes.timestamp_pb2.Timestamp(seconds=1581515101) 176 ), 177 ) 178 assert processor.expected_recovery_time() == datetime.datetime(2020, 2, 12, 13, 45, 1) 179 180 181def test_supported_languages(): 182 processor = cg.EngineProcessor('a', 'p', EngineContext(), _processor=qtypes.QuantumProcessor()) 183 assert processor.supported_languages() == [] 184 processor = cg.EngineProcessor( 185 'a', 186 'p', 187 EngineContext(), 188 _processor=qtypes.QuantumProcessor(supported_languages=['lang1', 'lang2']), 189 ) 190 assert processor.supported_languages() == ['lang1', 'lang2'] 191 192 193def test_get_device_specification(): 194 processor = cg.EngineProcessor('a', 'p', EngineContext(), _processor=qtypes.QuantumProcessor()) 195 assert not processor.get_device_specification() 196 197 # Construct expected device proto based on example 198 expected = v2.device_pb2.DeviceSpecification() 199 gs = expected.valid_gate_sets.add() 200 gs.name = 'test_set' 201 gates = gs.valid_gates.add() 202 gates.id = 'x' 203 gates.number_of_qubits = 1 204 gates.gate_duration_picos = 1000 205 gates.valid_targets.extend(['1q_targets']) 206 expected.valid_qubits.extend(['0_0', '1_1']) 207 target = expected.valid_targets.add() 208 target.name = '1q_targets' 209 target.target_ordering = v2.device_pb2.TargetSet.SYMMETRIC 210 new_target = target.targets.add() 211 new_target.ids.extend(['0_0']) 212 213 processor = cg.EngineProcessor( 214 'a', 'p', EngineContext(), _processor=qtypes.QuantumProcessor(device_spec=_DEVICE_SPEC) 215 ) 216 assert processor.get_device_specification() == expected 217 218 219def test_get_device(): 220 processor = cg.EngineProcessor( 221 'a', 'p', EngineContext(), _processor=qtypes.QuantumProcessor(device_spec=_DEVICE_SPEC) 222 ) 223 device = processor.get_device(gate_sets=[_GATE_SET]) 224 assert device.qubits == [cirq.GridQubit(0, 0), cirq.GridQubit(1, 1)] 225 device.validate_operation(cirq.X(cirq.GridQubit(0, 0))) 226 with pytest.raises(ValueError): 227 device.validate_operation(cirq.X(cirq.GridQubit(1, 2))) 228 with pytest.raises(ValueError): 229 device.validate_operation(cirq.Y(cirq.GridQubit(0, 0))) 230 231 232def test_get_missing_device(): 233 processor = cg.EngineProcessor('a', 'p', EngineContext(), _processor=qtypes.QuantumProcessor()) 234 with pytest.raises(ValueError, match='device specification'): 235 _ = processor.get_device(gate_sets=[_GATE_SET]) 236 237 238@mock.patch('cirq_google.engine.engine_client.EngineClient.list_calibrations') 239def test_list_calibrations(list_calibrations): 240 list_calibrations.return_value = [_CALIBRATION] 241 processor = cg.EngineProcessor('a', 'p', EngineContext()) 242 assert [c.timestamp for c in processor.list_calibrations()] == [1562544000021] 243 list_calibrations.assert_called_with('a', 'p', '') 244 assert [c.timestamp for c in processor.list_calibrations(1562500000000)] == [1562544000021] 245 list_calibrations.assert_called_with('a', 'p', 'timestamp >= 1562500000000') 246 assert [ 247 c.timestamp for c in processor.list_calibrations(latest_timestamp_seconds=1562600000000) 248 ] == [1562544000021] 249 list_calibrations.assert_called_with('a', 'p', 'timestamp <= 1562600000000') 250 assert [c.timestamp for c in processor.list_calibrations(1562500000000, 1562600000000)] == [ 251 1562544000021 252 ] 253 list_calibrations.assert_called_with( 254 'a', 'p', 'timestamp >= 1562500000000 AND timestamp <= 1562600000000' 255 ) 256 257 258@mock.patch('cirq_google.engine.engine_client.EngineClient.get_calibration') 259def test_get_calibration(get_calibration): 260 get_calibration.return_value = _CALIBRATION 261 processor = cg.EngineProcessor('a', 'p', EngineContext()) 262 calibration = processor.get_calibration(1562544000021) 263 assert calibration.timestamp == 1562544000021 264 assert set(calibration.keys()) == {'xeb', 't1', 'globalMetric'} 265 get_calibration.assert_called_once_with('a', 'p', 1562544000021) 266 267 268@mock.patch('cirq_google.engine.engine_client.EngineClient.get_current_calibration') 269def test_current_calibration(get_current_calibration): 270 get_current_calibration.return_value = _CALIBRATION 271 processor = cg.EngineProcessor('a', 'p', EngineContext()) 272 calibration = processor.get_current_calibration() 273 assert calibration.timestamp == 1562544000021 274 assert set(calibration.keys()) == {'xeb', 't1', 'globalMetric'} 275 get_current_calibration.assert_called_once_with('a', 'p') 276 277 278@mock.patch('cirq_google.engine.engine_client.EngineClient.get_current_calibration') 279def test_missing_latest_calibration(get_current_calibration): 280 get_current_calibration.return_value = None 281 processor = cg.EngineProcessor('a', 'p', EngineContext()) 282 assert not processor.get_current_calibration() 283 get_current_calibration.assert_called_once_with('a', 'p') 284 285 286@mock.patch('cirq_google.engine.engine_client.EngineClient.create_reservation') 287def test_create_reservation(create_reservation): 288 name = 'projects/proj/processors/p0/reservations/psherman-wallaby-way' 289 result = qtypes.QuantumReservation( 290 name=name, 291 start_time=Timestamp(seconds=1000000000), 292 end_time=Timestamp(seconds=1000003600), 293 whitelisted_users=['dstrain@google.com'], 294 ) 295 create_reservation.return_value = result 296 processor = cg.EngineProcessor('proj', 'p0', EngineContext()) 297 assert processor.create_reservation( 298 datetime.datetime.fromtimestamp(1000000000), 299 datetime.datetime.fromtimestamp(1000003600), 300 ['dstrain@google.com'], 301 ) 302 create_reservation.assert_called_once_with( 303 'proj', 304 'p0', 305 datetime.datetime.fromtimestamp(1000000000), 306 datetime.datetime.fromtimestamp(1000003600), 307 ['dstrain@google.com'], 308 ) 309 310 311@mock.patch('cirq_google.engine.engine_client.EngineClient.delete_reservation') 312def test_delete_reservation(delete_reservation): 313 name = 'projects/proj/processors/p0/reservations/rid' 314 result = qtypes.QuantumReservation( 315 name=name, 316 start_time=Timestamp(seconds=1000000000), 317 end_time=Timestamp(seconds=1000003600), 318 whitelisted_users=['dstrain@google.com'], 319 ) 320 delete_reservation.return_value = result 321 processor = cg.EngineProcessor('proj', 'p0', EngineContext()) 322 assert processor._delete_reservation('rid') == result 323 delete_reservation.assert_called_once_with('proj', 'p0', 'rid') 324 325 326@mock.patch('cirq_google.engine.engine_client.EngineClient.cancel_reservation') 327def test_cancel_reservation(cancel_reservation): 328 name = 'projects/proj/processors/p0/reservations/rid' 329 result = qtypes.QuantumReservation( 330 name=name, 331 start_time=Timestamp(seconds=1000000000), 332 end_time=Timestamp(seconds=1000003600), 333 whitelisted_users=['dstrain@google.com'], 334 ) 335 cancel_reservation.return_value = result 336 processor = cg.EngineProcessor('proj', 'p0', EngineContext()) 337 assert processor._cancel_reservation('rid') == result 338 cancel_reservation.assert_called_once_with('proj', 'p0', 'rid') 339 340 341@mock.patch('cirq_google.engine.engine_client.EngineClient.get_reservation') 342@mock.patch('cirq_google.engine.engine_client.EngineClient.delete_reservation') 343def test_remove_reservation_delete(delete_reservation, get_reservation): 344 name = 'projects/proj/processors/p0/reservations/rid' 345 now = int(datetime.datetime.now().timestamp()) 346 result = qtypes.QuantumReservation( 347 name=name, 348 start_time=Timestamp(seconds=now + 20000), 349 end_time=Timestamp(seconds=now + 23610), 350 whitelisted_users=['dstrain@google.com'], 351 ) 352 get_reservation.return_value = result 353 delete_reservation.return_value = result 354 processor = cg.EngineProcessor( 355 'proj', 356 'p0', 357 EngineContext(), 358 qtypes.QuantumProcessor(schedule_frozen_period=Duration(seconds=10000)), 359 ) 360 assert processor.remove_reservation('rid') == result 361 delete_reservation.assert_called_once_with('proj', 'p0', 'rid') 362 363 364@mock.patch('cirq_google.engine.engine_client.EngineClient.get_reservation') 365@mock.patch('cirq_google.engine.engine_client.EngineClient.cancel_reservation') 366def test_remove_reservation_cancel(cancel_reservation, get_reservation): 367 name = 'projects/proj/processors/p0/reservations/rid' 368 now = int(datetime.datetime.now().timestamp()) 369 result = qtypes.QuantumReservation( 370 name=name, 371 start_time=Timestamp(seconds=now + 10), 372 end_time=Timestamp(seconds=now + 3610), 373 whitelisted_users=['dstrain@google.com'], 374 ) 375 get_reservation.return_value = result 376 cancel_reservation.return_value = result 377 processor = cg.EngineProcessor( 378 'proj', 379 'p0', 380 EngineContext(), 381 qtypes.QuantumProcessor(schedule_frozen_period=Duration(seconds=10000)), 382 ) 383 assert processor.remove_reservation('rid') == result 384 cancel_reservation.assert_called_once_with('proj', 'p0', 'rid') 385 386 387@mock.patch('cirq_google.engine.engine_client.EngineClient.get_reservation') 388def test_remove_reservation_not_found(get_reservation): 389 get_reservation.return_value = None 390 processor = cg.EngineProcessor( 391 'proj', 392 'p0', 393 EngineContext(), 394 qtypes.QuantumProcessor(schedule_frozen_period=Duration(seconds=10000)), 395 ) 396 with pytest.raises(ValueError): 397 processor.remove_reservation('rid') 398 399 400@mock.patch('cirq_google.engine.engine_client.EngineClient.get_processor') 401@mock.patch('cirq_google.engine.engine_client.EngineClient.get_reservation') 402def test_remove_reservation_failures(get_reservation, get_processor): 403 name = 'projects/proj/processors/p0/reservations/rid' 404 now = int(datetime.datetime.now().timestamp()) 405 result = qtypes.QuantumReservation( 406 name=name, 407 start_time=Timestamp(seconds=now + 10), 408 end_time=Timestamp(seconds=now + 3610), 409 whitelisted_users=['dstrain@google.com'], 410 ) 411 get_reservation.return_value = result 412 get_processor.return_value = None 413 414 # no processor 415 processor = cg.EngineProcessor('proj', 'p0', EngineContext()) 416 with pytest.raises(ValueError): 417 processor.remove_reservation('rid') 418 419 # No freeze period defined 420 processor = cg.EngineProcessor('proj', 'p0', EngineContext(), qtypes.QuantumProcessor()) 421 with pytest.raises(ValueError): 422 processor.remove_reservation('rid') 423 424 425@mock.patch('cirq_google.engine.engine_client.EngineClient.get_reservation') 426def test_get_reservation(get_reservation): 427 name = 'projects/proj/processors/p0/reservations/rid' 428 result = qtypes.QuantumReservation( 429 name=name, 430 start_time=Timestamp(seconds=1000000000), 431 end_time=Timestamp(seconds=1000003600), 432 whitelisted_users=['dstrain@google.com'], 433 ) 434 get_reservation.return_value = result 435 processor = cg.EngineProcessor('proj', 'p0', EngineContext()) 436 assert processor.get_reservation('rid') == result 437 get_reservation.assert_called_once_with('proj', 'p0', 'rid') 438 439 440@mock.patch('cirq_google.engine.engine_client.EngineClient.update_reservation') 441def test_update_reservation(update_reservation): 442 name = 'projects/proj/processors/p0/reservations/rid' 443 result = qtypes.QuantumReservation( 444 name=name, 445 start_time=Timestamp(seconds=1000000000), 446 end_time=Timestamp(seconds=1000003600), 447 whitelisted_users=['dstrain@google.com'], 448 ) 449 start = datetime.datetime.fromtimestamp(1000000000) 450 end = datetime.datetime.fromtimestamp(1000003600) 451 update_reservation.return_value = result 452 processor = cg.EngineProcessor('proj', 'p0', EngineContext()) 453 assert processor.update_reservation('rid', start, end, ['dstrain@google.com']) == result 454 update_reservation.assert_called_once_with( 455 'proj', 'p0', 'rid', start=start, end=end, whitelisted_users=['dstrain@google.com'] 456 ) 457 458 459@mock.patch('cirq_google.engine.engine_client.EngineClient.list_reservations') 460def test_list_reservation(list_reservations): 461 name = 'projects/proj/processors/p0/reservations/rid' 462 results = [ 463 qtypes.QuantumReservation( 464 name=name, 465 start_time=Timestamp(seconds=1000000000), 466 end_time=Timestamp(seconds=1000003600), 467 whitelisted_users=['dstrain@google.com'], 468 ), 469 qtypes.QuantumReservation( 470 name=name + '2', 471 start_time=Timestamp(seconds=1000003600), 472 end_time=Timestamp(seconds=1000007200), 473 whitelisted_users=['wcourtney@google.com'], 474 ), 475 ] 476 list_reservations.return_value = results 477 processor = cg.EngineProcessor('proj', 'p0', EngineContext()) 478 assert ( 479 processor.list_reservations( 480 datetime.datetime.fromtimestamp(1000000000), datetime.datetime.fromtimestamp(1000010000) 481 ) 482 == results 483 ) 484 list_reservations.assert_called_once_with( 485 'proj', 'p0', 'start_time < 1000010000 AND end_time > 1000000000' 486 ) 487 488 489@mock.patch('cirq_google.engine.engine_client.EngineClient.list_time_slots') 490def test_get_schedule(list_time_slots): 491 results = [ 492 qtypes.QuantumTimeSlot( 493 processor_name='potofgold', 494 start_time=Timestamp(seconds=1000020000), 495 end_time=Timestamp(seconds=1000040000), 496 slot_type=qenums.QuantumTimeSlot.TimeSlotType.MAINTENANCE, 497 maintenance_config=qtypes.QuantumTimeSlot.MaintenanceConfig( 498 title='Testing', 499 description='Testing some new configuration.', 500 ), 501 ), 502 qtypes.QuantumTimeSlot( 503 processor_name='potofgold', 504 start_time=Timestamp(seconds=1000010000), 505 end_time=Timestamp(seconds=1000020000), 506 slot_type=qenums.QuantumTimeSlot.TimeSlotType.RESERVATION, 507 reservation_config=qtypes.QuantumTimeSlot.ReservationConfig( 508 project_id='super_secret_quantum' 509 ), 510 ), 511 ] 512 list_time_slots.return_value = results 513 processor = cg.EngineProcessor('proj', 'p0', EngineContext()) 514 assert ( 515 processor.get_schedule( 516 datetime.datetime.fromtimestamp(1000000000), datetime.datetime.fromtimestamp(1000050000) 517 ) 518 == results 519 ) 520 list_time_slots.assert_called_once_with( 521 'proj', 'p0', 'start_time < 1000050000 AND end_time > 1000000000' 522 ) 523 524 525@mock.patch('cirq_google.engine.engine_client.EngineClient.list_time_slots') 526def test_get_schedule_filter_by_time_slot(list_time_slots): 527 results = [ 528 qtypes.QuantumTimeSlot( 529 processor_name='potofgold', 530 start_time=Timestamp(seconds=1000020000), 531 end_time=Timestamp(seconds=1000040000), 532 slot_type=qenums.QuantumTimeSlot.TimeSlotType.MAINTENANCE, 533 maintenance_config=qtypes.QuantumTimeSlot.MaintenanceConfig( 534 title='Testing', 535 description='Testing some new configuration.', 536 ), 537 ) 538 ] 539 list_time_slots.return_value = results 540 processor = cg.EngineProcessor('proj', 'p0', EngineContext()) 541 542 assert ( 543 processor.get_schedule( 544 datetime.datetime.fromtimestamp(1000000000), 545 datetime.datetime.fromtimestamp(1000050000), 546 qenums.QuantumTimeSlot.TimeSlotType.MAINTENANCE, 547 ) 548 == results 549 ) 550 list_time_slots.assert_called_once_with( 551 'proj', 552 'p0', 553 'start_time < 1000050000 AND end_time > 1000000000 AND ' + 'time_slot_type = MAINTENANCE', 554 ) 555 556 557def _allow_deprecated_freezegun(func): 558 # a local hack, as freeze_time walks through all the sys.modules, and retrieves all the 559 # attributes for all modules when it reaches deprecated module attributes, we throw an error 560 # as the deprecation module thinks Cirq is using something deprecated. This hack SHOULD NOT be 561 # used elsewhere, it is specific to freezegun functionality. 562 def wrapper(*args, **kwargs): 563 import os 564 from cirq.testing.deprecation import ALLOW_DEPRECATION_IN_TEST 565 566 orig_exist, orig_value = ( 567 ALLOW_DEPRECATION_IN_TEST in os.environ, 568 os.environ.get(ALLOW_DEPRECATION_IN_TEST, None), 569 ) 570 571 os.environ[ALLOW_DEPRECATION_IN_TEST] = 'True' 572 try: 573 return func(*args, **kwargs) 574 finally: 575 if orig_exist: 576 # mypy can't resolve that orig_exist ensures that orig_value 577 # of type Optional[str] can't be None 578 # coverage: ignore 579 os.environ[ALLOW_DEPRECATION_IN_TEST] = orig_value # type: ignore 580 else: 581 del os.environ[ALLOW_DEPRECATION_IN_TEST] 582 583 return wrapper 584 585 586@_allow_deprecated_freezegun 587@freezegun.freeze_time() 588@mock.patch('cirq_google.engine.engine_client.EngineClient.list_time_slots') 589def test_get_schedule_time_filter_behavior(list_time_slots): 590 list_time_slots.return_value = [] 591 processor = cg.EngineProcessor('proj', 'p0', EngineContext()) 592 593 now = int(datetime.datetime.now().timestamp()) 594 in_two_weeks = int((datetime.datetime.now() + datetime.timedelta(weeks=2)).timestamp()) 595 processor.get_schedule() 596 list_time_slots.assert_called_with( 597 'proj', 'p0', f'start_time < {in_two_weeks} AND end_time > {now}' 598 ) 599 600 with pytest.raises(ValueError, match='from_time of type'): 601 processor.get_schedule(from_time=object()) 602 603 with pytest.raises(ValueError, match='to_time of type'): 604 processor.get_schedule(to_time=object()) 605 606 processor.get_schedule(from_time=None, to_time=None) 607 list_time_slots.assert_called_with('proj', 'p0', '') 608 609 processor.get_schedule(from_time=datetime.timedelta(0), to_time=None) 610 list_time_slots.assert_called_with('proj', 'p0', f'end_time > {now}') 611 612 processor.get_schedule(from_time=datetime.timedelta(seconds=200), to_time=None) 613 list_time_slots.assert_called_with('proj', 'p0', f'end_time > {now + 200}') 614 615 test_timestamp = datetime.datetime.utcfromtimestamp(52) 616 utc_ts = int(test_timestamp.timestamp()) 617 processor.get_schedule(from_time=test_timestamp, to_time=None) 618 list_time_slots.assert_called_with('proj', 'p0', f'end_time > {utc_ts}') 619 620 processor.get_schedule(from_time=None, to_time=datetime.timedelta(0)) 621 list_time_slots.assert_called_with('proj', 'p0', f'start_time < {now}') 622 623 processor.get_schedule(from_time=None, to_time=datetime.timedelta(seconds=200)) 624 list_time_slots.assert_called_with('proj', 'p0', f'start_time < {now + 200}') 625 626 processor.get_schedule(from_time=None, to_time=test_timestamp) 627 list_time_slots.assert_called_with('proj', 'p0', f'start_time < {utc_ts}') 628 629 630@_allow_deprecated_freezegun 631@freezegun.freeze_time() 632@mock.patch('cirq_google.engine.engine_client.EngineClient.list_reservations') 633def test_list_reservations_time_filter_behavior(list_reservations): 634 list_reservations.return_value = [] 635 processor = cg.EngineProcessor('proj', 'p0', EngineContext()) 636 637 now = int(datetime.datetime.now().timestamp()) 638 in_two_weeks = int((datetime.datetime.now() + datetime.timedelta(weeks=2)).timestamp()) 639 processor.list_reservations() 640 list_reservations.assert_called_with( 641 'proj', 'p0', f'start_time < {in_two_weeks} AND end_time > {now}' 642 ) 643 644 with pytest.raises(ValueError, match='from_time of type'): 645 processor.list_reservations(from_time=object()) 646 647 with pytest.raises(ValueError, match='to_time of type'): 648 processor.list_reservations(to_time=object()) 649 650 processor.list_reservations(from_time=None, to_time=None) 651 list_reservations.assert_called_with('proj', 'p0', '') 652 653 processor.list_reservations(from_time=datetime.timedelta(0), to_time=None) 654 list_reservations.assert_called_with('proj', 'p0', f'end_time > {now}') 655 656 processor.list_reservations(from_time=datetime.timedelta(seconds=200), to_time=None) 657 list_reservations.assert_called_with('proj', 'p0', f'end_time > {now + 200}') 658 659 test_timestamp = datetime.datetime.utcfromtimestamp(52) 660 utc_ts = int(test_timestamp.timestamp()) 661 processor.list_reservations(from_time=test_timestamp, to_time=None) 662 list_reservations.assert_called_with('proj', 'p0', f'end_time > {utc_ts}') 663 664 processor.list_reservations(from_time=None, to_time=datetime.timedelta(0)) 665 list_reservations.assert_called_with('proj', 'p0', f'start_time < {now}') 666 667 processor.list_reservations(from_time=None, to_time=datetime.timedelta(seconds=200)) 668 list_reservations.assert_called_with('proj', 'p0', f'start_time < {now + 200}') 669 670 processor.list_reservations(from_time=None, to_time=test_timestamp) 671 list_reservations.assert_called_with('proj', 'p0', f'start_time < {utc_ts}') 672 673 674def test_str(): 675 processor = cg.EngineProcessor('a', 'p', EngineContext()) 676 assert str(processor) == 'EngineProcessor(project_id=\'a\', processor_id=\'p\')' 677