def reload(self): """Reload this backup. Refresh the stored backup properties. :raises NotFound: if the backup does not exist """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) pb = api.get_backup(self.name, metadata=metadata) self._database = pb.database self._expire_time = _pb_timestamp_to_datetime(pb.expire_time) self._create_time = _pb_timestamp_to_datetime(pb.create_time) self._size_bytes = pb.size_bytes self._state = enums.Backup.State(pb.state) self._referencing_databases = pb.referencing_databases
def _get_value_from_value_pb(value_pb): """Given a protobuf for a Value, get the correct value. The Cloud Datastore Protobuf API returns a Property Protobuf which has one value set and the rest blank. This function retrieves the the one value provided. Some work is done to coerce the return value into a more useful type (particularly in the case of a timestamp value, or a key value). :type value_pb: :class:`.entity_pb2.Value` :param value_pb: The Value Protobuf. :rtype: object :returns: The value provided by the Protobuf. :raises: :class:`ValueError <exceptions.ValueError>` if no value type has been set. """ value_type = value_pb.WhichOneof('value_type') if value_type == 'timestamp_value': result = _pb_timestamp_to_datetime(value_pb.timestamp_value) elif value_type == 'key_value': result = key_from_protobuf(value_pb.key_value) elif value_type == 'boolean_value': result = value_pb.boolean_value elif value_type == 'double_value': result = value_pb.double_value elif value_type == 'integer_value': result = value_pb.integer_value elif value_type == 'string_value': result = value_pb.string_value elif value_type == 'blob_value': result = value_pb.blob_value elif value_type == 'entity_value': result = entity_from_protobuf(value_pb.entity_value) elif value_type == 'array_value': result = [_get_value_from_value_pb(value) for value in value_pb.array_value.values] elif value_type == 'geo_point_value': result = GeoPoint(value_pb.geo_point_value.latitude, value_pb.geo_point_value.longitude) elif value_type == 'null_value': result = None else: raise ValueError('Value protobuf did not have any value set') return result
def _get_value_from_value_pb(value_pb): """Given a protobuf for a Value, get the correct value. The Cloud Datastore Protobuf API returns a Property Protobuf which has one value set and the rest blank. This function retrieves the the one value provided. Some work is done to coerce the return value into a more useful type (particularly in the case of a timestamp value, or a key value). :type value_pb: :class:`google.cloud.datastore._generated.entity_pb2.Value` :param value_pb: The Value Protobuf. :rtype: object :returns: The value provided by the Protobuf. :raises: :class:`ValueError <exceptions.ValueError>` if no value type has been set. """ value_type = value_pb.WhichOneof('value_type') if value_type == 'timestamp_value': result = _pb_timestamp_to_datetime(value_pb.timestamp_value) elif value_type == 'key_value': result = key_from_protobuf(value_pb.key_value) elif value_type == 'boolean_value': result = value_pb.boolean_value elif value_type == 'double_value': result = value_pb.double_value elif value_type == 'integer_value': result = value_pb.integer_value elif value_type == 'string_value': result = value_pb.string_value elif value_type == 'blob_value': result = value_pb.blob_value elif value_type == 'entity_value': result = entity_from_protobuf(value_pb.entity_value) elif value_type == 'array_value': result = [_get_value_from_value_pb(value) for value in value_pb.array_value.values] elif value_type == 'geo_point_value': result = GeoPoint(value_pb.geo_point_value.latitude, value_pb.geo_point_value.longitude) elif value_type == 'null_value': result = None else: raise ValueError('Value protobuf did not have any value set') return result
def test__make_txn_selector_w_min_read_timestamp(self): from google.cloud._helpers import _pb_timestamp_to_datetime timestamp = self._makeTimestamp() session = _Session() snapshot = self._makeOne(session, min_read_timestamp=timestamp) selector = snapshot._make_txn_selector() options = selector.single_use self.assertEqual( _pb_timestamp_to_datetime(options.read_only.min_read_timestamp), timestamp)
def test__make_txn_selector_w_read_timestamp_w_multi_use(self): from google.cloud._helpers import _pb_timestamp_to_datetime timestamp = self._makeTimestamp() session = _Session() snapshot = self._make_one(session, read_timestamp=timestamp, multi_use=True) selector = snapshot._make_txn_selector() options = selector.begin self.assertEqual( _pb_timestamp_to_datetime(options.read_only.read_timestamp), timestamp )
def test__make_txn_selector_w_min_read_timestamp(self): from google.cloud._helpers import _pb_timestamp_to_datetime timestamp = self._makeTimestamp() session = _Session() snapshot = self._make_one(session, min_read_timestamp=timestamp) selector = snapshot._make_txn_selector() options = selector.single_use self.assertEqual( _pb_timestamp_to_datetime(options.read_only.min_read_timestamp), timestamp)
def test__make_txn_selector_w_read_timestamp_w_multi_use(self): from google.cloud._helpers import _pb_timestamp_to_datetime timestamp = self._makeTimestamp() session = _Session() snapshot = self._make_one( session, read_timestamp=timestamp, multi_use=True) selector = snapshot._make_txn_selector() options = selector.begin self.assertEqual( _pb_timestamp_to_datetime(options.read_only.read_timestamp), timestamp)
def decode_value(value, client): """Converts a Firestore protobuf ``Value`` to a native Python value. Args: value (google.cloud.firestore_v1beta1.types.Value): A Firestore protobuf to be decoded / parsed / converted. client (~.firestore_v1beta1.client.Client): A client that has a document factory. Returns: Union[NoneType, bool, int, float, datetime.datetime, \ str, bytes, dict, ~google.cloud.Firestore.GeoPoint]: A native Python value converted from the ``value``. Raises: NotImplementedError: If the ``value_type`` is ``reference_value``. ValueError: If the ``value_type`` is unknown. """ value_type = value.WhichOneof('value_type') if value_type == 'null_value': return None elif value_type == 'boolean_value': return value.boolean_value elif value_type == 'integer_value': return value.integer_value elif value_type == 'double_value': return value.double_value elif value_type == 'timestamp_value': # NOTE: This conversion is "lossy", Python ``datetime.datetime`` # has microsecond precision but ``timestamp_value`` has # nanosecond precision. return _pb_timestamp_to_datetime(value.timestamp_value) elif value_type == 'string_value': return value.string_value elif value_type == 'bytes_value': return value.bytes_value elif value_type == 'reference_value': return reference_value_to_document(value.reference_value, client) elif value_type == 'geo_point_value': return GeoPoint(value.geo_point_value.latitude, value.geo_point_value.longitude) elif value_type == 'array_value': return [ decode_value(element, client) for element in value.array_value.values ] elif value_type == 'map_value': return decode_dict(value.map_value.fields, client) else: raise ValueError('Unknown ``value_type``', value_type)
def decode_value(value, client): """Converts a Firestore protobuf ``Value`` to a native Python value. Args: value (google.cloud.firestore_v1beta1.types.Value): A Firestore protobuf to be decoded / parsed / converted. client (~.firestore_v1beta1.client.Client): A client that has a document factory. Returns: Union[NoneType, bool, int, float, datetime.datetime, \ str, bytes, dict, ~google.cloud.Firestore.GeoPoint]: A native Python value converted from the ``value``. Raises: NotImplementedError: If the ``value_type`` is ``reference_value``. ValueError: If the ``value_type`` is unknown. """ value_type = value.WhichOneof('value_type') if value_type == 'null_value': return None elif value_type == 'boolean_value': return value.boolean_value elif value_type == 'integer_value': return value.integer_value elif value_type == 'double_value': return value.double_value elif value_type == 'timestamp_value': # NOTE: This conversion is "lossy", Python ``datetime.datetime`` # has microsecond precision but ``timestamp_value`` has # nanosecond precision. return _pb_timestamp_to_datetime(value.timestamp_value) elif value_type == 'string_value': return value.string_value elif value_type == 'bytes_value': return value.bytes_value elif value_type == 'reference_value': return reference_value_to_document(value.reference_value, client) elif value_type == 'geo_point_value': return GeoPoint( value.geo_point_value.latitude, value.geo_point_value.longitude) elif value_type == 'array_value': return [decode_value(element, client) for element in value.array_value.values] elif value_type == 'map_value': return decode_dict(value.map_value.fields, client) else: raise ValueError('Unknown ``value_type``', value_type)
def test_create_document(client, cleanup): now = datetime.datetime.utcnow().replace(tzinfo=UTC) document_id = 'shun' + unique_resource_id('-') document = client.document('collek', document_id) # Add to clean-up before API request (in case ``create()`` fails). cleanup(document) data = { 'now': firestore.SERVER_TIMESTAMP, 'eenta-ger': 11, 'bites': b'\xe2\x98\x83 \xe2\x9b\xb5', 'also': { 'nestednow': firestore.SERVER_TIMESTAMP, 'quarter': 0.25, }, } write_result = document.create(data) updated = _pb_timestamp_to_datetime(write_result.update_time) delta = updated - now # Allow a bit of clock skew, but make sure timestamps are close. assert -300.0 < delta.total_seconds() < 300.0 with pytest.raises(Conflict) as exc_info: document.create({}) assert exc_info.value.message.startswith(ALREADY_EXISTS) assert document_id in exc_info.value.message # Verify the server times. snapshot = document.get() stored_data = snapshot.to_dict() server_now = stored_data['now'] delta = updated - server_now # NOTE: We could check the ``transform_results`` from the write result # for the document transform, but this value gets dropped. Instead # we make sure the timestamps are close. assert 0.0 <= delta.total_seconds() < 5.0 expected_data = { 'now': server_now, 'eenta-ger': data['eenta-ger'], 'bites': data['bites'], 'also': { 'nestednow': server_now, 'quarter': data['also']['quarter'], }, } assert stored_data == expected_data
def test_create_document(client, cleanup): now = datetime.datetime.utcnow().replace(tzinfo=UTC) collection_id = "doc-create" + UNIQUE_RESOURCE_ID document_id = "doc" + UNIQUE_RESOURCE_ID document = client.document(collection_id, document_id) # Add to clean-up before API request (in case ``create()`` fails). cleanup(document.delete) data = { "now": firestore.SERVER_TIMESTAMP, "eenta-ger": 11, "bites": b"\xe2\x98\x83 \xe2\x9b\xb5", "also": { "nestednow": firestore.SERVER_TIMESTAMP, "quarter": 0.25 }, } write_result = document.create(data) updated = _pb_timestamp_to_datetime(write_result.update_time) delta = updated - now # Allow a bit of clock skew, but make sure timestamps are close. assert -300.0 < delta.total_seconds() < 300.0 with pytest.raises(AlreadyExists): document.create(data) # Verify the server times. snapshot = document.get() stored_data = snapshot.to_dict() server_now = stored_data["now"] delta = updated - server_now # NOTE: We could check the ``transform_results`` from the write result # for the document transform, but this value gets dropped. Instead # we make sure the timestamps are close. assert 0.0 <= delta.total_seconds() < 5.0 expected_data = { "now": server_now, "eenta-ger": data["eenta-ger"], "bites": data["bites"], "also": { "nestednow": server_now, "quarter": data["also"]["quarter"] }, } assert stored_data == expected_data
def test_create_document(client, cleanup): now = datetime.datetime.utcnow().replace(tzinfo=UTC) document_id = 'shun' + unique_resource_id('-') document = client.document('collek', document_id) # Add to clean-up before API request (in case ``create()`` fails). cleanup(document) data = { 'now': firestore.SERVER_TIMESTAMP, 'eenta-ger': 11, 'bites': b'\xe2\x98\x83 \xe2\x9b\xb5', 'also': { 'nestednow': firestore.SERVER_TIMESTAMP, 'quarter': 0.25, }, } write_result = document.create(data) updated = _pb_timestamp_to_datetime(write_result.update_time) delta = updated - now # Allow a bit of clock skew, but make sure timestamps are close. assert -300.0 < delta.total_seconds() < 300.0 with pytest.raises(AlreadyExists): document.create(data) # Verify the server times. snapshot = document.get() stored_data = snapshot.to_dict() server_now = stored_data['now'] delta = updated - server_now # NOTE: We could check the ``transform_results`` from the write result # for the document transform, but this value gets dropped. Instead # we make sure the timestamps are close. assert 0.0 <= delta.total_seconds() < 5.0 expected_data = { 'now': server_now, 'eenta-ger': data['eenta-ger'], 'bites': data['bites'], 'also': { 'nestednow': server_now, 'quarter': data['also']['quarter'], }, } assert stored_data == expected_data
def reload(self): """Reload this database. Refresh any configured schema into :attr:`ddl_statements`. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDDL :raises NotFound: if the database does not exist """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) response = api.get_database_ddl(self.name, metadata=metadata) self._ddl_statements = tuple(response.statements) response = api.get_database(self.name, metadata=metadata) self._state = enums.Database.State(response.state) self._create_time = _pb_timestamp_to_datetime(response.create_time) self._restore_info = response.restore_info
def commit(self): """Commit mutations to the database. :rtype: datetime :returns: timestamp of the committed changes. """ self._check_state() database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) txn_options = TransactionOptions( read_write=TransactionOptions.ReadWrite()) response = api.commit(self._session.name, self._mutations, single_use_transaction=txn_options, metadata=metadata) self.committed = _pb_timestamp_to_datetime( response.commit_timestamp) return self.committed
def commit(self): """Commit mutations to the database. :rtype: datetime :returns: timestamp of the committed changes. :raises ValueError: if there are no mutations to commit. """ self._check_state() database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) response = api.commit(self._session.name, self._mutations, transaction_id=self._transaction_id, metadata=metadata) self.committed = _pb_timestamp_to_datetime(response.commit_timestamp) del self._session._transaction return self.committed
def commit(self): """Commit mutations to the database. :rtype: datetime :returns: timestamp of the committed changes. """ self._check_state() database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) txn_options = TransactionOptions(read_write=TransactionOptions.ReadWrite()) trace_attributes = {"num_mutations": len(self._mutations)} with trace_call("CloudSpanner.Commit", self._session, trace_attributes): response = api.commit( self._session.name, mutations=self._mutations, single_use_transaction=txn_options, metadata=metadata, ) self.committed = _pb_timestamp_to_datetime(response.commit_timestamp) return self.committed
def commit(self): """Commit mutations to the database. :rtype: datetime :returns: timestamp of the committed changes. :raises: :exc:`ValueError` if there are no mutations to commit. """ self._check_state() if len(self._mutations) == 0: raise ValueError("No mutations to commit") database = self._session._database api = database.spanner_api options = _options_with_prefix(database.name) response = api.commit(self._session.name, self._mutations, transaction_id=self._id, options=options) self.committed = _pb_timestamp_to_datetime(response.commit_timestamp) return self.committed
def commit(self): """Commit mutations to the database. :rtype: datetime :returns: timestamp of the committed changes. :raises ValueError: if there are no mutations to commit. """ self._check_state() database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) response = api.commit( self._session.name, self._mutations, transaction_id=self._transaction_id, metadata=metadata, ) self.committed = _pb_timestamp_to_datetime(response.commit_timestamp) del self._session._transaction return self.committed
def test_create_document(client, cleanup): now = datetime.datetime.utcnow().replace(tzinfo=UTC) document_id = "shun" + unique_resource_id("-") document = client.document("collek", document_id) # Add to clean-up before API request (in case ``create()`` fails). cleanup(document) data = { "now": firestore.SERVER_TIMESTAMP, "eenta-ger": 11, "bites": b"\xe2\x98\x83 \xe2\x9b\xb5", "also": {"nestednow": firestore.SERVER_TIMESTAMP, "quarter": 0.25}, } write_result = document.create(data) updated = _pb_timestamp_to_datetime(write_result.update_time) delta = updated - now # Allow a bit of clock skew, but make sure timestamps are close. assert -300.0 < delta.total_seconds() < 300.0 with pytest.raises(AlreadyExists): document.create(data) # Verify the server times. snapshot = document.get() stored_data = snapshot.to_dict() server_now = stored_data["now"] delta = updated - server_now # NOTE: We could check the ``transform_results`` from the write result # for the document transform, but this value gets dropped. Instead # we make sure the timestamps are close. assert 0.0 <= delta.total_seconds() < 5.0 expected_data = { "now": server_now, "eenta-ger": data["eenta-ger"], "bites": data["bites"], "also": {"nestednow": server_now, "quarter": data["also"]["quarter"]}, } assert stored_data == expected_data
def test_begin_w_gax_error(self): from google.gax.errors import GaxError from google.cloud._helpers import _pb_timestamp_to_datetime database = _Database() api = database.spanner_api = _FauxSpannerAPI(_random_gax_error=True) timestamp = self._makeTimestamp() session = _Session(database) snapshot = self._make_one(session, read_timestamp=timestamp, multi_use=True) with self.assertRaises(GaxError): snapshot.begin() session_id, txn_options, options = api._begun self.assertEqual(session_id, session.name) self.assertEqual( _pb_timestamp_to_datetime(txn_options.read_only.read_timestamp), timestamp) self.assertEqual(options.kwargs['metadata'], [('google-cloud-resource-prefix', database.name)])
def commit(self): """Commit mutations to the database. :rtype: datetime :returns: timestamp of the committed changes. :raises ValueError: if there are no mutations to commit. """ self._check_state() database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) trace_attributes = {"num_mutations": len(self._mutations)} with trace_call("CloudSpanner.Commit", self._session, trace_attributes): response = api.commit( self._session.name, mutations=self._mutations, transaction_id=self._transaction_id, metadata=metadata, ) self.committed = _pb_timestamp_to_datetime(response.commit_timestamp) del self._session._transaction return self.committed
def test_write_entries_w_extra_properties(self): # pylint: disable=too-many-statements from datetime import datetime from google.logging.type.log_severity_pb2 import WARNING from google.logging.v2.log_entry_pb2 import LogEntry from google.cloud._helpers import UTC, _pb_timestamp_to_datetime NOW = datetime.utcnow().replace(tzinfo=UTC) TEXT = 'TEXT' LOG_PATH = 'projects/%s/logs/%s' % (self.PROJECT, self.LOG_NAME) SEVERITY = 'WARNING' LABELS = { 'foo': 'bar', } IID = 'IID' REQUEST_METHOD = 'GET' REQUEST_URL = 'http://example.com/requested' STATUS = 200 REQUEST_SIZE = 256 RESPONSE_SIZE = 1024 REFERRER_URL = 'http://example.com/referer' USER_AGENT = 'Agent/1.0' REMOTE_IP = '1.2.3.4' REQUEST = { 'requestMethod': REQUEST_METHOD, 'requestUrl': REQUEST_URL, 'status': STATUS, 'requestSize': REQUEST_SIZE, 'responseSize': RESPONSE_SIZE, 'referer': REFERRER_URL, 'userAgent': USER_AGENT, 'remoteIp': REMOTE_IP, 'cacheHit': False, } PRODUCER = 'PRODUCER' OPID = 'OPID' OPERATION = { 'producer': PRODUCER, 'id': OPID, 'first': False, 'last': True, } ENTRY = { 'logName': LOG_PATH, 'resource': { 'type': 'global' }, 'textPayload': TEXT, 'severity': SEVERITY, 'labels': LABELS, 'insertId': IID, 'timestamp': NOW, 'httpRequest': REQUEST, 'operation': OPERATION, } gax_api = _GAXLoggingAPI() api = self._makeOne(gax_api) api.write_entries([ENTRY]) entries, log_name, resource, labels, partial_success, options = ( gax_api._write_log_entries_called_with) self.assertEqual(len(entries), 1) entry = entries[0] self.assertIsInstance(entry, LogEntry) self.assertEqual(entry.log_name, LOG_PATH) self.assertEqual(entry.resource.type, 'global') self.assertEqual(entry.text_payload, TEXT) self.assertEqual(entry.severity, WARNING) self.assertEqual(entry.labels, LABELS) self.assertEqual(entry.insert_id, IID) stamp = _pb_timestamp_to_datetime(entry.timestamp) self.assertEqual(stamp, NOW) request = entry.http_request self.assertEqual(request.request_method, REQUEST_METHOD) self.assertEqual(request.request_url, REQUEST_URL) self.assertEqual(request.status, STATUS) self.assertEqual(request.request_size, REQUEST_SIZE) self.assertEqual(request.response_size, RESPONSE_SIZE) self.assertEqual(request.referer, REFERRER_URL) self.assertEqual(request.user_agent, USER_AGENT) self.assertEqual(request.remote_ip, REMOTE_IP) self.assertEqual(request.cache_hit, False) operation = entry.operation self.assertEqual(operation.producer, PRODUCER) self.assertEqual(operation.id, OPID) self.assertFalse(operation.first) self.assertTrue(operation.last) self.assertIsNone(log_name) self.assertIsNone(resource) self.assertIsNone(labels) self.assertEqual(partial_success, False) self.assertIsNone(options)
def _call_fut(self, timestamp): from google.cloud._helpers import _pb_timestamp_to_datetime return _pb_timestamp_to_datetime(timestamp)
def assert_timestamp_less(timestamp_pb1, timestamp_pb2): dt_val1 = _pb_timestamp_to_datetime(timestamp_pb1) dt_val2 = _pb_timestamp_to_datetime(timestamp_pb2) assert dt_val1 < dt_val2
def __init__(self, backup, create_time, source_database): self.backup = backup self.create_time = _pb_timestamp_to_datetime(create_time) self.source_database = source_database
def test_write_entries_w_extra_properties(self): # pylint: disable=too-many-statements from datetime import datetime from google.logging.type.log_severity_pb2 import WARNING from google.logging.v2.log_entry_pb2 import LogEntry from google.cloud._helpers import UTC, _pb_timestamp_to_datetime NOW = datetime.utcnow().replace(tzinfo=UTC) TEXT = 'TEXT' LOG_PATH = 'projects/%s/logs/%s' % (self.PROJECT, self.LOG_NAME) SEVERITY = 'WARNING' LABELS = { 'foo': 'bar', } IID = 'IID' REQUEST_METHOD = 'GET' REQUEST_URL = 'http://example.com/requested' STATUS = 200 REQUEST_SIZE = 256 RESPONSE_SIZE = 1024 REFERRER_URL = 'http://example.com/referer' USER_AGENT = 'Agent/1.0' REMOTE_IP = '1.2.3.4' REQUEST = { 'requestMethod': REQUEST_METHOD, 'requestUrl': REQUEST_URL, 'status': STATUS, 'requestSize': REQUEST_SIZE, 'responseSize': RESPONSE_SIZE, 'referer': REFERRER_URL, 'userAgent': USER_AGENT, 'remoteIp': REMOTE_IP, 'cacheHit': False, } PRODUCER = 'PRODUCER' OPID = 'OPID' OPERATION = { 'producer': PRODUCER, 'id': OPID, 'first': False, 'last': True, } ENTRY = { 'logName': LOG_PATH, 'resource': {'type': 'global'}, 'textPayload': TEXT, 'severity': SEVERITY, 'labels': LABELS, 'insertId': IID, 'timestamp': NOW, 'httpRequest': REQUEST, 'operation': OPERATION, } gax_api = _GAXLoggingAPI() api = self._makeOne(gax_api) api.write_entries([ENTRY]) entries, log_name, resource, labels, partial_success, options = ( gax_api._write_log_entries_called_with) self.assertEqual(len(entries), 1) entry = entries[0] self.assertIsInstance(entry, LogEntry) self.assertEqual(entry.log_name, LOG_PATH) self.assertEqual(entry.resource.type, 'global') self.assertEqual(entry.text_payload, TEXT) self.assertEqual(entry.severity, WARNING) self.assertEqual(entry.labels, LABELS) self.assertEqual(entry.insert_id, IID) stamp = _pb_timestamp_to_datetime(entry.timestamp) self.assertEqual(stamp, NOW) request = entry.http_request self.assertEqual(request.request_method, REQUEST_METHOD) self.assertEqual(request.request_url, REQUEST_URL) self.assertEqual(request.status, STATUS) self.assertEqual(request.request_size, REQUEST_SIZE) self.assertEqual(request.response_size, RESPONSE_SIZE) self.assertEqual(request.referer, REFERRER_URL) self.assertEqual(request.user_agent, USER_AGENT) self.assertEqual(request.remote_ip, REMOTE_IP) self.assertEqual(request.cache_hit, False) operation = entry.operation self.assertEqual(operation.producer, PRODUCER) self.assertEqual(operation.id, OPID) self.assertFalse(operation.first) self.assertTrue(operation.last) self.assertIsNone(log_name) self.assertIsNone(resource) self.assertIsNone(labels) self.assertEqual(partial_success, False) self.assertIsNone(options)