Example #1
0
    def test_create_client_with_api_version(self):
        url = self.account_url(self.tables_storage_account_name, "table")
        client = TableServiceClient(url, credential=self.credential)
        assert client._client._config.version == "2019-02-02"
        table = client.get_table_client('tablename')
        assert table._client._config.version == "2019-02-02"

        client = TableServiceClient(url, credential=self.credential, api_version="2019-07-07")
        assert client._client._config.version == "2019-07-07"
        table = client.get_table_client('tablename')
        assert table._client._config.version == "2019-07-07"

        with pytest.raises(ValueError):
            TableServiceClient(url, credential=self.credential, api_version="foo")
Example #2
0
    def test_set_table_acl_with_signed_identifiers(self, tables_storage_account_name, tables_primary_storage_account_key):
        # Arrange
        account_url = self.account_url(tables_storage_account_name, "table")

        ts = TableServiceClient(credential=tables_primary_storage_account_key, endpoint=account_url)

        table = self._create_table(ts)
        client = ts.get_table_client(table_name=table.table_name)

        # Act
        start = datetime(2021, 6, 8, 2, 10, 9) - timedelta(minutes=5)
        expiry = datetime(2021, 6, 8, 2, 10, 9) + timedelta(hours=1)
        identifiers = {'testid': TableAccessPolicy(start=start, expiry=expiry, permission='r')}
        try:
            client.set_table_access_policy(signed_identifiers=identifiers)
            # Assert
            acl = client.get_table_access_policy()
            assert acl is not None
            assert len(acl) ==  1
            assert acl.get('testid')
            self._assert_policy_datetime(start, acl['testid'].start)
            self._assert_policy_datetime(expiry, acl['testid'].expiry)
            assert acl['testid'].permission == 'r'
        finally:
            ts.delete_table(table.table_name)
Example #3
0
    def test_create_service_with_socket_timeout(self):
        # Arrange

        for service_type in SERVICES.items():
            # Act
            default_service = service_type[0](
                self.account_url(self.tables_storage_account_name, "table"),
                credential=self.tables_primary_storage_account_key,
                table_name='foo')
            service = service_type[0](
                self.account_url(self.tables_storage_account_name, "table"),
                credential=self.tables_primary_storage_account_key,
                table_name='foo',
                connection_timeout=22)

            # Assert
            self.validate_standard_account_endpoints(
                service, self.tables_storage_account_name,
                self.tables_primary_storage_account_key)
            assert service._client._client._pipeline._transport.connection_config.timeout == 22
            assert default_service._client._client._pipeline._transport.connection_config.timeout == 300

        # Assert Parent transport is shared with child client
        service = TableServiceClient(
            self.account_url(self.tables_storage_account_name, "table"),
            credential=self.tables_primary_storage_account_key,
            connection_timeout=22)
        assert service._client._client._pipeline._transport.connection_config.timeout == 22
        table = service.get_table_client('tablename')
        assert table._client._client._pipeline._transport._transport.connection_config.timeout == 22
Example #4
0
    def test_set_table_acl_with_signed_identifiers(self, resource_group,
                                                   location, storage_account,
                                                   storage_account_key):
        # Arrange
        url = self.account_url(storage_account, "table")
        if 'cosmos' in url:
            pytest.skip("Cosmos endpoint does not support this")
        ts = TableServiceClient(url, storage_account_key)
        table = self._create_table(ts)
        client = ts.get_table_client(table_name=table.table_name)

        # Act
        identifiers = dict()
        identifiers['testid'] = AccessPolicy(
            start=datetime.utcnow() - timedelta(minutes=5),
            expiry=datetime.utcnow() + timedelta(hours=1),
            permission='r')
        try:
            client.set_table_access_policy(signed_identifiers=identifiers)
            # Assert
            acl = client.get_table_access_policy()
            self.assertIsNotNone(acl)
            self.assertEqual(len(acl), 1)
            self.assertTrue('testid' in acl)
        finally:
            # self._delete_table(table)
            ts.delete_table(table.table_name)
    def test_set_table_acl_with_signed_identifiers(self, resource_group, location, cosmos_account,
                                                   cosmos_account_key):
        # Arrange
        url = self.account_url(cosmos_account, "cosmos")
        if 'cosmos' in url:
            pytest.skip("Cosmos endpoint does not support this")
        ts = TableServiceClient(url, cosmos_account_key)
        table = self._create_table(ts)
        client = ts.get_table_client(table_name=table.table_name)

        # Act
        identifiers = dict()
        identifiers['testid'] = AccessPolicy(start=datetime.utcnow() - timedelta(minutes=5),
                                             expiry=datetime.utcnow() + timedelta(hours=1),
                                             permission='r')
        try:
            client.set_table_access_policy(signed_identifiers=identifiers)
            # Assert
            acl = client.get_table_access_policy()
            assert acl is not None
            assert len(acl) ==  1
            assert 'testid' in acl
        finally:
            ts.delete_table(table.table_name)

        if self.is_live:
            sleep(SLEEP_DELAY)
    def test_set_table_acl_with_signed_identifiers(
            self, tables_cosmos_account_name,
            tables_primary_cosmos_account_key):
        # Arrange
        url = self.account_url(tables_cosmos_account_name, "cosmos")
        ts = TableServiceClient(url, tables_primary_cosmos_account_key)
        table = self._create_table(ts)
        client = ts.get_table_client(table_name=table.table_name)

        # Act
        identifiers = dict()
        identifiers['testid'] = AccessPolicy(
            start=datetime.utcnow() - timedelta(minutes=5),
            expiry=datetime.utcnow() + timedelta(hours=1),
            permission='r')
        try:
            client.set_table_access_policy(signed_identifiers=identifiers)
            # Assert
            acl = client.get_table_access_policy()
            assert acl is not None
            assert len(acl) == 1
            assert 'testid' in acl
        finally:
            ts.delete_table(table.table_name)

        if self.is_live:
            sleep(SLEEP_DELAY)
Example #7
0
    def test_batch_sas_auth(self, tables_cosmos_account_name,
                            tables_primary_cosmos_account_key):
        # this can be reverted to set_bodiless_matcher() after tests are re-recorded and don't contain these headers
        set_custom_default_matcher(
            compare_bodies=False,
            excluded_headers=
            "Authorization,Content-Length,x-ms-client-request-id,x-ms-request-id"
        )

        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key,
                     url="cosmos")
        try:
            token = self.generate_sas(
                generate_table_sas,
                tables_primary_cosmos_account_key,
                self.table_name,
                permission=TableSasPermissions(add=True,
                                               read=True,
                                               update=True,
                                               delete=True),
                expiry=datetime.utcnow() + timedelta(hours=1),
                start=datetime.utcnow() - timedelta(minutes=1),
            )
            token = AzureSasCredential(token)

            # Act
            service = TableServiceClient(
                self.account_url(tables_cosmos_account_name, "cosmos"),
                credential=token,
            )
            table = service.get_table_client(self.table_name)

            entity = TableEntity()
            entity['PartitionKey'] = 'batch_inserts'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)

            batch = []
            transaction_count = 0
            for i in range(10):
                entity['RowKey'] = str(i)
                batch.append(('create', entity.copy()))
                transaction_count += 1
            transaction_result = table.submit_transaction(batch)

            assert transaction_result

            total_entities = 0
            for e in table.list_entities():
                total_entities += 1

            assert total_entities == transaction_count
        finally:
            self._tear_down()
Example #8
0
    def test_batch_sas_auth(self, tables_storage_account_name,
                            tables_primary_storage_account_key):
        set_bodiless_matcher()

        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:

            token = self.generate_sas(
                generate_table_sas,
                tables_primary_storage_account_key,
                self.table_name,
                permission=TableSasPermissions(add=True,
                                               read=True,
                                               update=True,
                                               delete=True),
                expiry=datetime.utcnow() + timedelta(hours=1),
                start=datetime.utcnow() - timedelta(minutes=1),
            )
            token = AzureSasCredential(token)

            # Act
            service = TableServiceClient(
                self.account_url(tables_storage_account_name, "table"),
                credential=token,
            )
            table = service.get_table_client(self.table_name)

            entity = TableEntity()
            entity['PartitionKey'] = 'batch_inserts'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)

            batch = []
            transaction_count = 0
            for i in range(10):
                entity['RowKey'] = str(i)
                batch.append(('create', entity.copy()))
                transaction_count += 1
            transaction_result = table.submit_transaction(batch)

            assert transaction_result

            total_entities = 0
            for e in table.list_entities():
                total_entities += 1

            assert total_entities == transaction_count
        finally:
            self._tear_down()
Example #9
0
    def test_batch_sas_auth(self, tables_storage_account_name,
                            tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:

            token = generate_table_sas(
                tables_storage_account_name,
                tables_primary_storage_account_key,
                self.table_name,
                permission=TableSasPermissions(add=True,
                                               read=True,
                                               update=True,
                                               delete=True),
                expiry=datetime.utcnow() + timedelta(hours=1),
                start=datetime.utcnow() - timedelta(minutes=1),
            )
            token = AzureSasCredential(token)

            # Act
            service = TableServiceClient(
                self.account_url(tables_storage_account_name, "table"),
                credential=token,
            )
            table = service.get_table_client(self.table_name)

            entity = TableEntity()
            entity.PartitionKey = 'batch_inserts'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)

            batch = table.create_batch()
            transaction_count = 0
            for i in range(10):
                entity.RowKey = str(i)
                batch.create_entity(entity)
                transaction_count += 1
            transaction_result = table.send_batch(batch)

            assert transaction_result is not None

            total_entities = 0
            for e in table.list_entities():
                total_entities += 1

            assert total_entities == transaction_count
        finally:
            self._tear_down()
Example #10
0
    def test_create_table(self, tables_storage_account_name, tables_primary_storage_account_key):
        # # Arrange
        account_url = self.account_url(tables_storage_account_name, "table")
        ts = TableServiceClient(credential=tables_primary_storage_account_key, endpoint=account_url)

        table_name = self._get_table_reference()

        # Act
        table = ts.get_table_client(table_name)
        created = table.create_table()

        # Assert
        assert created.name == table_name
        ts.delete_table(table_name)
    def test_create_table(self, tables_cosmos_account_name,
                          tables_primary_cosmos_account_key):
        # Arrange
        ts = TableServiceClient(self.account_url(tables_cosmos_account_name,
                                                 "cosmos"),
                                credential=tables_primary_cosmos_account_key)

        table_name = self._get_table_reference()

        # Act
        table = ts.get_table_client(table_name)
        created = table.create_table()

        # Assert
        assert created.name == table_name
        ts.delete_table(table_name)
Example #12
0
    def test_account_sas(self, tables_storage_account_name,
                         tables_primary_storage_account_key):
        account_url = self.account_url(tables_storage_account_name, "table")
        tsc = TableServiceClient(credential=tables_primary_storage_account_key,
                                 endpoint=account_url)

        table = self._create_table(tsc)
        try:
            entity = {
                'PartitionKey': u'test',
                'RowKey': u'test1',
                'text': u'hello',
            }
            table.upsert_entity(mode=UpdateMode.MERGE, entity=entity)

            entity['RowKey'] = u'test2'
            table.upsert_entity(mode=UpdateMode.MERGE, entity=entity)

            token = AzureSasCredential(
                self.generate_sas(
                    generate_account_sas,
                    tables_primary_storage_account_key,
                    resource_types=ResourceTypes(object=True),
                    permission=AccountSasPermissions(read=True),
                    expiry=datetime.utcnow() + timedelta(hours=1),
                    start=datetime.utcnow() - timedelta(minutes=1),
                ))

            account_url = self.account_url(tables_storage_account_name,
                                           "table")

            service = TableServiceClient(credential=token,
                                         endpoint=account_url)

            # Act

            sas_table = service.get_table_client(table.table_name)
            entities = list(sas_table.list_entities())

            # Assert
            assert len(entities) == 2
            assert entities[0]['text'] == u'hello'
            assert entities[1]['text'] == u'hello'
        finally:
            tsc.delete_table(table.table_name)
Example #13
0
    def test_account_sas(self, resource_group, location, storage_account,
                         storage_account_key):
        # SAS URL is calculated from storage key, so this test runs live only

        # Arrange
        url = self.account_url(storage_account, "table")
        if 'cosmos' in url:
            pytest.skip("Cosmos Tables does not yet support sas")
        tsc = TableServiceClient(url, storage_account_key)
        table = self._create_table(tsc)
        try:
            entity = {
                'PartitionKey': 'test',
                'RowKey': 'test1',
                'text': 'hello',
            }
            table.upsert_entity(mode=UpdateMode.MERGE, entity=entity)

            entity['RowKey'] = 'test2'
            table.upsert_entity(mode=UpdateMode.MERGE, entity=entity)

            token = generate_account_sas(
                storage_account.name,
                storage_account_key,
                resource_types=ResourceTypes(object=True),
                permission=AccountSasPermissions(read=True),
                expiry=datetime.utcnow() + timedelta(hours=1),
                start=datetime.utcnow() - timedelta(minutes=1),
            )

            # Act
            service = TableServiceClient(
                self.account_url(storage_account, "table"),
                credential=token,
            )
            sas_table = service.get_table_client(table.table_name)
            entities = list(sas_table.list_entities())

            # Assert
            self.assertEqual(len(entities), 2)
            self.assertEqual(entities[0].text, 'hello')
            self.assertEqual(entities[1].text, 'hello')
        finally:
            self._delete_table(table=table, ts=tsc)
    def test_account_sas(self, tables_cosmos_account_name,
                         tables_primary_cosmos_account_key):
        # SAS URL is calculated from storage key, so this test runs live only

        # Arrange
        url = self.account_url(tables_cosmos_account_name, "cosmos")
        tsc = TableServiceClient(url, tables_primary_cosmos_account_key)
        table = self._create_table(tsc)
        try:
            entity = {
                'PartitionKey': 'test',
                'RowKey': 'test1',
                'text': 'hello',
            }
            table.upsert_entity(mode=UpdateMode.MERGE, entity=entity)

            entity['RowKey'] = 'test2'
            table.upsert_entity(mode=UpdateMode.MERGE, entity=entity)

            token = generate_account_sas(
                tables_cosmos_account_name,
                tables_primary_cosmos_account_key,
                resource_types=ResourceTypes(object=True),
                permission=AccountSasPermissions(read=True),
                expiry=datetime.utcnow() + timedelta(hours=1),
                start=datetime.utcnow() - timedelta(minutes=1),
            )

            # Act
            service = TableServiceClient(
                self.account_url(tables_cosmos_account_name, "cosmos"),
                credential=token,
            )
            sas_table = service.get_table_client(table.table_name)
            entities = list(sas_table.list_entities())

            # Assert
            assert len(entities) == 2
            assert entities[0].text == 'hello'
            assert entities[1].text == 'hello'
        finally:
            self._delete_table(table=table, ts=tsc)
Example #15
0
class StorageRetryTest(AzureTestCase, TableTestCase):
    def _set_up(self,
                tables_storage_account_name,
                tables_primary_storage_account_key,
                url='table',
                default_table=True,
                **kwargs):
        self.table_name = self.get_resource_name('uttable')
        self.ts = TableServiceClient(
            self.account_url(tables_storage_account_name, url),
            credential=tables_primary_storage_account_key,
            **kwargs)
        self.table = self.ts.get_table_client(self.table_name)
        if self.is_live and default_table:
            try:
                self.ts.create_table(self.table_name)
            except ResourceExistsError:
                pass

        self.query_tables = []

    def _tear_down(self, **kwargs):
        if self.is_live:
            try:
                self.ts.delete_table(self.table_name, **kwargs)
            except:
                pass

            try:
                for table_name in self.query_tables:
                    try:
                        self.ts.delete_table(table_name, **kwargs)
                    except:
                        pass
            except AttributeError:
                pass

    # --Test Cases --------------------------------------------
    @TablesPreparer()
    def test_retry_on_server_error(self, tables_storage_account_name,
                                   tables_primary_storage_account_key):
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key,
                     default_table=False)
        try:
            callback = ResponseCallback(status=201,
                                        new_status=500).override_status

            new_table_name = self.get_resource_name('uttable')
            # The initial create will return 201, but we overwrite it with 500 and retry.
            # The retry will then get a 409 conflict.
            with pytest.raises(ResourceExistsError):
                self.ts.create_table(new_table_name,
                                     raw_response_hook=callback)
        finally:
            self.ts.delete_table(new_table_name)
            self._tear_down()

    @TablesPreparer()
    def test_retry_on_timeout(self, tables_storage_account_name,
                              tables_primary_storage_account_key):
        retry = ExponentialRetry(initial_backoff=1, increment_base=2)
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key,
                     retry_policy=retry,
                     default_table=False)

        new_table_name = self.get_resource_name('uttable')
        callback = ResponseCallback(status=201, new_status=408).override_status

        try:
            # The initial create will return 201, but we overwrite it with 408 and retry.
            # The retry will then get a 409 conflict.
            with pytest.raises(ResourceExistsError):
                self.ts.create_table(new_table_name,
                                     raw_response_hook=callback)
        finally:
            self.ts.delete_table(new_table_name)
            self._tear_down()

    @TablesPreparer()
    def test_retry_callback_and_retry_context(
            self, tables_storage_account_name,
            tables_primary_storage_account_key):
        retry = LinearRetry(backoff=1)
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key,
                     retry_policy=retry,
                     default_table=False)

        new_table_name = self.get_resource_name('uttable')
        callback = ResponseCallback(status=201, new_status=408).override_status

        def assert_exception_is_present_on_retry_context(**kwargs):
            self.assertIsNotNone(kwargs.get('response'))
            self.assertEqual(kwargs['response'].status_code, 408)

        try:
            # The initial create will return 201, but we overwrite it with 408 and retry.
            # The retry will then get a 409 conflict.
            with pytest.raises(ResourceExistsError):
                self.ts.create_table(
                    new_table_name,
                    raw_response_hook=callback,
                    retry_hook=assert_exception_is_present_on_retry_context)
        finally:
            self.ts.delete_table(new_table_name)
            self._tear_down()

    @pytest.mark.live_test_only
    @TablesPreparer()
    def test_retry_on_socket_timeout(self, tables_storage_account_name,
                                     tables_primary_storage_account_key):
        retry = LinearRetry(backoff=1)
        retry_transport = RetryRequestTransport(connection_timeout=11,
                                                read_timeout=0.000000000001)
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key,
                     retry_policy=retry,
                     transport=retry_transport,
                     default_table=False)

        new_table_name = self.get_resource_name('uttable')
        try:
            with pytest.raises(AzureError) as error:
                self.ts.create_table(new_table_name)

            # 3 retries + 1 original == 4
            assert retry_transport.count == 4
            # This call should succeed on the server side, but fail on the client side due to socket timeout
            self.assertTrue(
                'read timeout' in str(error.value),
                'Expected socket timeout but got different exception.')

        finally:
            # we must make the timeout normal again to let the delete operation succeed
            self.ts.delete_table(new_table_name, connection_timeout=(11, 11))
            self._tear_down(connection_timeout=(11, 11))
class StorageTableBatchTest(AzureTestCase, TableTestCase):
    def _set_up(self, tables_storage_account_name,
                tables_primary_storage_account_key):
        self.ts = TableServiceClient(
            self.account_url(tables_storage_account_name, "table"),
            tables_primary_storage_account_key)
        self.table_name = self.get_resource_name('uttable')
        self.table = self.ts.get_table_client(self.table_name)
        if self.is_live:
            try:
                self.ts.create_table(self.table_name)
            except ResourceExistsError:
                pass

        self.test_tables = []

    def _tear_down(self):
        if self.is_live:
            try:
                self.ts.delete_table(self.table_name)
            except:
                pass

            for table_name in self.test_tables:
                try:
                    self.ts.delete_table(table_name)
                except:
                    pass

    #--Helpers-----------------------------------------------------------------

    def _get_table_reference(self, prefix=TEST_TABLE_PREFIX):
        table_name = self.get_resource_name(prefix)
        self.test_tables.append(table_name)
        return self.ts.get_table_client(table_name)

    def _create_pk_rk(self, pk, rk):
        try:
            pk = pk if pk is not None else self.get_resource_name('pk').decode(
                'utf-8')
            rk = rk if rk is not None else self.get_resource_name('rk').decode(
                'utf-8')
        except AttributeError:
            pk = pk if pk is not None else self.get_resource_name('pk')
            rk = rk if rk is not None else self.get_resource_name('rk')
        return pk, rk

    def _create_random_entity_dict(self, pk=None, rk=None):
        """
        Creates a dictionary-based entity with fixed values, using all
        of the supported data types.
        """
        # partition = pk if pk is not None else self.get_resource_name('pk').decode('utf-8')
        # row = rk if rk is not None else self.get_resource_name('rk').decode('utf-8')
        partition, row = self._create_pk_rk(pk, rk)
        properties = {
            'PartitionKey': partition,
            'RowKey': row,
            'age': 39,
            'sex': u'male',
            'married': True,
            'deceased': False,
            'optional': None,
            'ratio': 3.1,
            'evenratio': 3.0,
            'large': 933311100,
            'Birthday': datetime(1973, 10, 4, tzinfo=tzutc()),
            'birthday': datetime(1970, 10, 4, tzinfo=tzutc()),
            'binary': b'binary',
            'other': EntityProperty(value=20, type=EdmType.INT32),
            'clsid': uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833')
        }
        return TableEntity(**properties)

    def _create_updated_entity_dict(self, partition, row):
        '''
        Creates a dictionary-based entity with fixed values, with a
        different set of values than the default entity. It
        adds fields, changes field values, changes field types,
        and removes fields when compared to the default entity.
        '''
        return {
            'PartitionKey': partition,
            'RowKey': row,
            'age': u'abc',
            'sex': u'female',
            'sign': u'aquarius',
            'birthday': datetime(1991, 10, 4, tzinfo=tzutc())
        }

    def _assert_default_entity(self, entity):
        '''
        Asserts that the entity passed in matches the default entity.
        '''
        assert entity['age'] == 39
        assert entity['sex'] == 'male'
        assert entity['married'] == True
        assert entity['deceased'] == False
        assert not "optional" in entity
        assert entity['ratio'] == 3.1
        assert entity['evenratio'] == 3.0
        assert entity['large'] == 933311100
        assert entity['Birthday'] == datetime(1973, 10, 4, tzinfo=tzutc())
        assert entity['birthday'] == datetime(1970, 10, 4, tzinfo=tzutc())
        assert entity['binary'].value == b'binary'
        assert entity['other'] == 20
        assert entity['clsid'] == uuid.UUID(
            'c9da6455-213d-42c9-9a79-3e9149a57833')
        assert '_metadata' in entity

    def _assert_updated_entity(self, entity):
        '''
        Asserts that the entity passed in matches the updated entity.
        '''
        assert entity.age == 'abc'
        assert entity.sex == 'female'
        assert not hasattr(entity, "married")
        assert not hasattr(entity, "deceased")
        assert entity.sign == 'aquarius'
        assert not hasattr(entity, "optional")
        assert not hasattr(entity, "ratio")
        assert not hasattr(entity, "evenratio")
        assert not hasattr(entity, "large")
        assert not hasattr(entity, "Birthday")
        assert entity.birthday, datetime(1991, 10, 4, tzinfo=tzutc())
        assert not hasattr(entity, "other")
        assert not hasattr(entity, "clsid")
        assert entity['_metadata']['etag'] is not None

    def _assert_valid_batch_transaction(self, transaction, length):
        assert length == len(transaction)

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_single_insert(self, tables_storage_account_name,
                                 tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = [('create', entity)]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            e = self.table.get_entity(row_key=entity.RowKey,
                                      partition_key=entity.PartitionKey)
            assert e.test == entity.test.value
            assert e.test2 == entity.test2
            assert e.test3 == entity.test3
            assert e.test4 == entity.test4.value
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_single_update(self, tables_storage_account_name,
                                 tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            resp = self.table.create_entity(entity)
            assert resp is not None

            entity.test3 = 5
            entity.test5 = datetime.utcnow()

            batch = [('update', entity, {'mode': UpdateMode.MERGE})]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]
            result = self.table.get_entity(row_key=entity.RowKey,
                                           partition_key=entity.PartitionKey)
            assert result.PartitionKey == u'001'
            assert result.RowKey == u'batch_insert'
            assert result.test3 == 5
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_update(self, tables_storage_account_name,
                          tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_update'
            entity.test = EntityProperty(True)
            entity.test2 = u'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)

            entity = self.table.get_entity(u'001', u'batch_update')
            assert 3 == entity.test3
            entity.test2 = u'value1'

            batch = [('update', entity)]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            result = self.table.get_entity('001', 'batch_update')

            assert 'value1' == result.test2
            assert entity.PartitionKey == u'001'
            assert entity.RowKey == u'batch_update'
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_merge(self, tables_storage_account_name,
                         tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_merge'
            entity.test = EntityProperty(True)
            entity.test2 = u'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)

            resp_entity = self.table.get_entity(partition_key=u'001',
                                                row_key=u'batch_merge')
            assert 3 == entity.test3
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_merge'
            entity.test2 = u'value1'

            batch = [('update', entity, {'mode': UpdateMode.MERGE})]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            resp_entity = self.table.get_entity(partition_key=u'001',
                                                row_key=u'batch_merge')
            assert entity.test2 == resp_entity.test2
            assert 1234567890 == resp_entity.test4
            assert entity.PartitionKey == resp_entity.PartitionKey
            assert entity.RowKey == resp_entity.RowKey
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_update_if_match(self, tables_storage_account_name,
                                   tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict()
            resp = self.table.create_entity(entity=entity)
            etag = resp['etag']

            # Act
            sent_entity = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])
            batch = [('update', sent_entity, {
                'etag': etag,
                'match_condition': MatchConditions.IfNotModified,
                'mode': UpdateMode.REPLACE
            })]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            entity = self.table.get_entity(
                partition_key=entity['PartitionKey'], row_key=entity['RowKey'])
            self._assert_updated_entity(entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_update_if_doesnt_match(self, tables_storage_account_name,
                                          tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict()
            self.table.create_entity(entity)

            # Act
            sent_entity1 = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])

            batch = [('update', sent_entity1, {
                'etag': u'W/"datetime\'2012-06-15T22%3A51%3A44.9662825Z\'"',
                'match_condition': MatchConditions.IfNotModified
            })]
            with pytest.raises(TableTransactionError):
                self.table.submit_transaction(batch)

            # Assert
            received_entity = self.table.get_entity(entity['PartitionKey'],
                                                    entity['RowKey'])
            self._assert_default_entity(received_entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_single_op_if_doesnt_match(
            self, tables_storage_account_name,
            tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = 'batch_inserts'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)

            batch = []
            transaction_count = 0
            for i in range(10):
                entity.RowKey = str(i)
                batch.append(('create', entity.copy()))
                transaction_count += 1

            entity = self._create_random_entity_dict()
            self.table.create_entity(entity)

            # Act
            sent_entity1 = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])

            batch = [('update', sent_entity1, {
                'etag': u'W/"datetime\'2012-06-15T22%3A51%3A44.9662825Z\'"',
                'match_condition': MatchConditions.IfNotModified
            })]

            with pytest.raises(TableTransactionError):
                self.table.submit_transaction(batch)

            # Assert
            received_entity = self.table.get_entity(entity['PartitionKey'],
                                                    entity['RowKey'])
            self._assert_default_entity(received_entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_insert_replace(self, tables_storage_account_name,
                                  tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert_replace'
            entity.test = True
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = [('upsert', entity, {'mode': UpdateMode.REPLACE})]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            entity = self.table.get_entity('001', 'batch_insert_replace')
            assert entity is not None
            assert 'value' == entity.test2
            assert 1234567890 == entity.test4
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_insert_merge(self, tables_storage_account_name,
                                tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert_merge'
            entity.test = True
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = [('upsert', entity, {'mode': UpdateMode.MERGE})]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            entity = self.table.get_entity('001', 'batch_insert_merge')
            assert entity is not None
            assert 'value' == entity.test2
            assert 1234567890 == entity.test4
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_delete(self, tables_storage_account_name,
                          tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_delete'
            entity.test = EntityProperty(True)
            entity.test2 = u'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)

            entity = self.table.get_entity(partition_key=u'001',
                                           row_key=u'batch_delete')
            assert 3 == entity.test3

            batch = [('delete', entity)]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' not in transaction_result[0]

            with pytest.raises(ResourceNotFoundError):
                entity = self.table.get_entity(
                    partition_key=entity.PartitionKey, row_key=entity.RowKey)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_inserts(self, tables_storage_account_name,
                           tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = 'batch_inserts'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)

            transaction_count = 0
            batch = []
            for i in range(100):
                entity.RowKey = str(i)
                batch.append(('create', entity.copy()))
                transaction_count += 1
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result,
                                                 transaction_count)
            assert 'etag' in transaction_result[0]

            entities = list(
                self.table.query_entities("PartitionKey eq 'batch_inserts'"))

            # Assert
            assert entities is not None
            assert transaction_count == len(entities)
            e = self.table.get_entity('batch_inserts', '1')
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_all_operations_together(self, tables_storage_account_name,
                                           tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '003'
            entity.RowKey = 'batch_all_operations_together-1'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-2'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-3'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-4'
            self.table.create_entity(entity)
            transaction_count = 0

            batch = []
            entity.RowKey = 'batch_all_operations_together'
            batch.append((TransactionOperation.CREATE, entity.copy()))
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-1'
            batch.append((TransactionOperation.DELETE, entity.copy()))
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-2'
            entity.test3 = 10
            batch.append((TransactionOperation.UPDATE, entity.copy()))
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-3'
            entity.test3 = 100
            batch.append((TransactionOperation.UPDATE, entity.copy(), {
                'mode': UpdateMode.REPLACE
            }))
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-4'
            entity.test3 = 10
            batch.append((TransactionOperation.UPSERT, entity.copy()))
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-5'
            batch.append((TransactionOperation.UPSERT, entity.copy(), {
                'mode': UpdateMode.REPLACE
            }))
            transaction_count += 1

            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result,
                                                 transaction_count)
            assert 'etag' in transaction_result[0]
            assert 'etag' not in transaction_result[1]
            assert 'etag' in transaction_result[2]
            assert 'etag' in transaction_result[3]
            assert 'etag' in transaction_result[4]
            assert 'etag' in transaction_result[5]

            # Assert
            entities = list(self.table.query_entities("PartitionKey eq '003'"))
            assert 5 == len(entities)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_reuse(self, tables_storage_account_name,
                         tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            table2 = self._get_table_reference('table2')
            table2.create_table()

            # Act
            entity = TableEntity()
            entity.PartitionKey = '003'
            entity.RowKey = 'batch_all_operations_together-1'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = []
            batch.append(('upsert', entity.copy()))
            entity.RowKey = 'batch_all_operations_together-2'
            batch.append(('upsert', entity.copy()))
            entity.RowKey = 'batch_all_operations_together-3'
            batch.append(('upsert', entity.copy()))
            entity.RowKey = 'batch_all_operations_together-4'
            batch.append(('upsert', entity.copy()))

            resp1 = self.table.submit_transaction(batch)
            resp2 = table2.submit_transaction(batch)

            entities = list(self.table.query_entities("PartitionKey eq '003'"))
            assert 4 == len(entities)
            table2 = list(table2.query_entities("PartitionKey eq '003'"))
            assert 4 == len(entities)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_same_row_operations_fail(
            self, tables_storage_account_name,
            tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            batch = []

            entity = self._create_updated_entity_dict('001',
                                                      'batch_negative_1')
            batch.append(('update', entity.copy()))

            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            batch.append(('update', entity.copy(), {
                'mode': UpdateMode.REPLACE
            }))

            # Assert

            with pytest.raises(TableTransactionError):
                self.table.submit_transaction(batch)

        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_different_partition_operations_fail(
            self, tables_storage_account_name,
            tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            batch = []

            entity = self._create_updated_entity_dict('001',
                                                      'batch_negative_1')
            batch.append(('update', entity.copy()))

            entity = self._create_random_entity_dict('002', 'batch_negative_1')
            batch.append(('update', entity.copy()))

            with pytest.raises(ValueError):
                self.table.submit_transaction(batch)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_too_many_ops(self, tables_storage_account_name,
                                tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            with pytest.raises(TableTransactionError):
                batch = []
                for i in range(0, 101):
                    entity = TableEntity()
                    entity.PartitionKey = 'large'
                    entity.RowKey = 'item{0}'.format(i)
                    batch.append(('create', entity.copy()))
                self.table.submit_transaction(batch)

            # Assert
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_batch_different_partition_keys(
            self, tables_storage_account_name,
            tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            entity2 = self._create_random_entity_dict('002',
                                                      'batch_negative_1')

            batch = [('create', entity), ('create', entity2)]
            with pytest.raises(ValueError):
                self.table.submit_transaction(batch)

            # Assert
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_new_non_existent_table(self, tables_storage_account_name,
                                    tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')

            tc = self.ts.get_table_client("doesntexist")

            batch = [('create', entity)]

            with pytest.raises(TableTransactionError):
                resp = tc.submit_transaction(batch)
            # Assert
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_new_invalid_key(self, tables_storage_account_name,
                             tables_primary_storage_account_key):
        # Arrange
        invalid_key = tables_primary_storage_account_key[
            0:-6] + "=="  # cut off a bit from the end to invalidate
        self.ts = TableServiceClient(
            self.account_url(tables_storage_account_name, "table"),
            invalid_key)
        self.table_name = self.get_resource_name('uttable')
        self.table = self.ts.get_table_client(self.table_name)

        entity = self._create_random_entity_dict('001', 'batch_negative_1')

        batch = [('create', entity)]

        with pytest.raises(ClientAuthenticationError):
            resp = self.table.submit_transaction(batch)

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @TablesPreparer()
    def test_new_delete_nonexistent_entity(self, tables_storage_account_name,
                                           tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')

            batch = [('delete', entity)]

            with pytest.raises(TableTransactionError):
                resp = self.table.submit_transaction(batch)

        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @pytest.mark.live_test_only
    @TablesPreparer()
    def test_batch_sas_auth(self, tables_storage_account_name,
                            tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:

            token = generate_table_sas(
                tables_storage_account_name,
                tables_primary_storage_account_key,
                self.table_name,
                permission=TableSasPermissions(add=True,
                                               read=True,
                                               update=True,
                                               delete=True),
                expiry=datetime.utcnow() + timedelta(hours=1),
                start=datetime.utcnow() - timedelta(minutes=1),
            )
            token = AzureSasCredential(token)

            # Act
            service = TableServiceClient(
                self.account_url(tables_storage_account_name, "table"),
                credential=token,
            )
            table = service.get_table_client(self.table_name)

            entity = TableEntity()
            entity.PartitionKey = 'batch_inserts'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)

            batch = []
            transaction_count = 0
            for i in range(10):
                entity.RowKey = str(i)
                batch.append(('create', entity.copy()))
                transaction_count += 1
            transaction_result = table.submit_transaction(batch)

            assert transaction_result

            total_entities = 0
            for e in table.list_entities():
                total_entities += 1

            assert total_entities == transaction_count
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @pytest.mark.live_test_only  # Request bodies are very large
    @TablesPreparer()
    def test_batch_request_too_large(self, tables_storage_account_name,
                                     tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:

            batch = []
            entity = {
                'PartitionKey': 'pk001',
                'Foo': os.urandom(1024 * 64),
                'Bar': os.urandom(1024 * 64),
                'Baz': os.urandom(1024 * 64)
            }
            for i in range(50):
                entity['RowKey'] = str(i)
                batch.append(('create', entity.copy()))

            with pytest.raises(RequestTooLargeError):
                self.table.submit_transaction(batch)

        finally:
            self._tear_down()
class StorageTableClientTest(TableTestCase):

    def _set_up(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        self.ts = TableServiceClient(self.account_url(tables_cosmos_account_name, "cosmos"), tables_primary_cosmos_account_key)
        self.table_name = self.get_resource_name('uttable')
        self.table = self.ts.get_table_client(self.table_name)
        if self.is_live:
            try:
                self.ts.create_table(self.table_name)
            except ResourceExistsError:
                pass

        self.test_tables = []

    def _tear_down(self):
        if self.is_live:
            try:
                self.ts.delete_table(self.table_name)
            except:
                pass

            for table_name in self.test_tables:
                try:
                    self.ts.delete_table(table_name)
                except:
                    pass
            sleep(SLEEP_DELAY)

    #--Helpers-----------------------------------------------------------------

    def _get_table_reference(self, prefix=TEST_TABLE_PREFIX):
        table_name = self.get_resource_name(prefix)
        self.test_tables.append(table_name)
        return self.ts.get_table_client(table_name)

    def _create_random_entity_dict(self, pk=None, rk=None):
        '''
        Creates a dictionary-based entity with fixed values, using all
        of the supported data types.
        '''
        partition = pk if pk is not None else self.get_resource_name('pk')
        row = rk if rk is not None else self.get_resource_name('rk')
        properties = {
            'PartitionKey': partition,
            'RowKey': row,
            'age': 39,
            'sex': 'male',
            'married': True,
            'deceased': False,
            'optional': None,
            'ratio': 3.1,
            'evenratio': 3.0,
            'large': 933311100,
            'Birthday': datetime(1973, 10, 4, tzinfo=tzutc()),
            'birthday': datetime(1970, 10, 4, tzinfo=tzutc()),
            'binary': b'binary',
            'other': EntityProperty(20, EdmType.INT32),
            'clsid': uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833')
        }
        return TableEntity(**properties)

    def _create_updated_entity_dict(self, partition, row):
        '''
        Creates a dictionary-based entity with fixed values, with a
        different set of values than the default entity. It
        adds fields, changes field values, changes field types,
        and removes fields when compared to the default entity.
        '''
        return {
            'PartitionKey': partition,
            'RowKey': row,
            'age': 'abc',
            'sex': 'female',
            'sign': 'aquarius',
            'birthday': datetime(1991, 10, 4, tzinfo=tzutc())
        }

    def _assert_default_entity(self, entity):
        '''
        Asserts that the entity passed in matches the default entity.
        '''
        assert entity['age'] ==  39
        assert entity['sex'] ==  'male'
        assert entity['married'] ==  True
        assert entity['deceased'] ==  False
        assert not "optional" in entity
        assert entity['ratio'] ==  3.1
        assert entity['evenratio'] ==  3.0
        assert entity['large'] ==  933311100
        assert entity['Birthday'] == datetime(1973, 10, 4, tzinfo=tzutc())
        assert entity['birthday'] == datetime(1970, 10, 4, tzinfo=tzutc())
        assert entity['binary'].value ==  b'binary'
        assert entity['other'] ==  20
        assert entity['clsid'] ==  uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833')
        assert '_metadata' in entity

    def _assert_updated_entity(self, entity):
        '''
        Asserts that the entity passed in matches the updated entity.
        '''
        assert entity.age ==  'abc'
        assert entity.sex ==  'female'
        assert not hasattr(entity, "married")
        assert not hasattr(entity, "deceased")
        assert entity.sign ==  'aquarius'
        assert not hasattr(entity, "optional")
        assert not hasattr(entity, "ratio")
        assert not hasattr(entity, "evenratio")
        assert not hasattr(entity, "large")
        assert not hasattr(entity, "Birthday")
        assert entity.birthday, datetime(1991, 10, 4, tzinfo=tzutc())
        assert not hasattr(entity, "other")
        assert not hasattr(entity, "clsid")
        assert entity['_metadata']['etag'] is not None

    #--Test cases for batch ---------------------------------------------

    def test_inferred_types(self):
        # Arrange
        # Act
        entity = TableEntity()
        entity.PartitionKey = '003'
        entity.RowKey = 'batch_all_operations_together-1'
        entity.test = EntityProperty(True)
        entity.test2 = EntityProperty(b'abcdef')
        entity.test3 = EntityProperty(u'c9da6455-213d-42c9-9a79-3e9149a57833')
        entity.test4 = EntityProperty(datetime(1973, 10, 4, tzinfo=tzutc()))
        entity.test5 = EntityProperty(u"stringystring")
        entity.test6 = EntityProperty(3.14159)
        entity.test7 = EntityProperty(100)
        entity.test8 = EntityProperty(10, EdmType.INT64)

        # Assert
        assert entity.test.type ==  EdmType.BOOLEAN
        assert entity.test2.type ==  EdmType.BINARY
        assert entity.test3.type ==  EdmType.GUID
        assert entity.test4.type ==  EdmType.DATETIME
        assert entity.test5.type ==  EdmType.STRING
        assert entity.test6.type ==  EdmType.DOUBLE
        assert entity.test7.type ==  EdmType.INT32
        assert entity.test8.type ==  EdmType.INT64

    def _assert_valid_batch_transaction(self, transaction, length):
        assert isinstance(transaction,  BatchTransactionResult)
        assert length ==  len(transaction.entities)
        assert length ==  len(transaction.results)
        assert length ==  len(transaction.requests)

    @pytest.mark.skip("pending")
    @CosmosPreparer()
    def test_batch_insert(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            # Act
            entity = Entity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = self.table.create_batch()
            batch.create_item(entity)
            resp = self.table.commit_batch(batch)

            # Assert
            assert resp is not None
            result, headers = self.table.read_item('001', 'batch_insert', response_hook=lambda e, h: (e, h))
            assert list(resp)[0].headers['Etag'] ==  headers['etag']
        finally:
            self._tear_down()

    @pytest.mark.skip("merge operations fail in cosmos: https://github.com/Azure/azure-sdk-for-python/issues/13844")
    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_update(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_update'
            entity.test = EntityProperty(True)
            entity.test2 = u'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)

            entity = self.table.get_entity(u'001', u'batch_update')
            assert 3 ==  entity.test3.value
            entity.test2 = u'value1'

            batch = self.table.create_batch()
            batch.update_entity(entity)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert transaction_result.get_entity(entity.RowKey) is not None
            result = self.table.get_entity('001', 'batch_update')
            assert 'value1' ==  result.test2.value
            assert entity.PartitionKey ==  u'001'
            assert entity.RowKey ==  u'batch_update'
        finally:
            self._tear_down()

    @pytest.mark.skip("merge operations fail in cosmos: https://github.com/Azure/azure-sdk-for-python/issues/13844")
    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_merge(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_merge'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)

            entity = self.table.get_entity('001', 'batch_merge')
            assert 3 ==  entity.test3
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_merge'
            entity.test2 = 'value1'

            batch = self.table.create_batch()
            batch.update_entity(entity, mode='MERGE')
            resp = self.table.send_batch(batch)

            # Assert
            assert resp is not None
            entity, headers = self.table.get_entity('001', 'batch_merge', response_hook=lambda e, h: (e, h))
            assert 'value1' ==  entity.test2
            assert 1234567890 ==  entity.test4
            assert list(resp)[0].headers['Etag'] ==  headers['etag']
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_update_if_match(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict()
            resp = self.table.create_entity(entity=entity)
            etag = resp['etag']

            # Act
            sent_entity = self._create_updated_entity_dict(entity['PartitionKey'], entity['RowKey'])
            batch = self.table.create_batch()
            batch.update_entity(
                sent_entity,
                etag=etag,
                match_condition=MatchConditions.IfNotModified,
                mode=UpdateMode.REPLACE
            )
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert transaction_result.get_entity(sent_entity['RowKey']) is not None

            entity = self.table.get_entity(partition_key=entity['PartitionKey'], row_key=entity['RowKey'])
            self._assert_updated_entity(entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_update_if_doesnt_match(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict()
            self.table.create_entity(entity)

            # Act
            sent_entity1 = self._create_updated_entity_dict(entity['PartitionKey'], entity['RowKey'])

            batch = self.table.create_batch()
            batch.update_entity(
                sent_entity1,
                etag=u'W/"datetime\'2012-06-15T22%3A51%3A44.9662825Z\'"',
                match_condition=MatchConditions.IfNotModified
            )

            with pytest.raises(HttpResponseError):
                self.table.send_batch(batch)

            # Assert
            received_entity = self.table.get_entity(entity['PartitionKey'], entity['RowKey'])
            self._assert_default_entity(received_entity)
        finally:
            self._tear_down()

    @pytest.mark.skip("merge operations fail in cosmos: https://github.com/Azure/azure-sdk-for-python/issues/13844")
    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_insert_replace(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert_replace'
            entity.test = True
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = self.table.create_batch()
            batch.upsert_item(entity)
            resp = self.table.send_batch(batch)

            # Assert
            assert resp is not None
            entity, headers = self.table.get_entity('001', 'batch_insert_replace', response_hook=lambda e, h: (e, h))
            assert entity is not None
            assert 'value' ==  entity.test2
            assert 1234567890 ==  entity.test4
            assert list(resp)[0].headers['Etag'] ==  headers['etag']
        finally:
            self._tear_down()

    @pytest.mark.skip("merge operations fail in cosmos: https://github.com/Azure/azure-sdk-for-python/issues/13844")
    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_insert_merge(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert_merge'
            entity.test = True
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = self.table.create_batch()
            batch.upsert_item(entity, mode='MERGE')
            resp = self.table.send_batch(batch)

            # Assert
            assert resp is not None
            entity, headers = self.table.get_entity('001', 'batch_insert_merge', response_hook=lambda e, h: (e, h))
            assert entity is not None
            assert 'value' ==  entity.test2
            assert 1234567890 ==  entity.test4
            assert list(resp)[0].headers['Etag'] ==  headers['etag']
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_delete(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_delete'
            entity.test = EntityProperty(True)
            entity.test2 = u'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)

            entity = self.table.get_entity(partition_key=u'001', row_key=u'batch_delete')
            assert 3 ==  entity.test3

            batch = self.table.create_batch()
            batch.delete_entity(partition_key=entity.PartitionKey, row_key=entity.RowKey)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert transaction_result.get_entity(entity.RowKey) is not None

            with pytest.raises(ResourceNotFoundError):
                entity = self.table.get_entity(partition_key=entity.PartitionKey, row_key=entity.RowKey)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_inserts(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = 'batch_inserts'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)

            batch = self.table.create_batch()
            transaction_count = 0
            for i in range(20):
                entity.RowKey = str(i)
                batch.create_entity(entity)
                transaction_count += 1
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, transaction_count)
            assert transaction_result.get_entity(entity.RowKey) is not None

            entities = list(self.table.query_entities("PartitionKey eq 'batch_inserts'"))

            # Assert
            assert entities is not None
            assert transaction_count ==  len(entities)
            e = self.table.get_entity('batch_inserts', '1')
        finally:
            self._tear_down()

    @pytest.mark.skip("merge operations fail in cosmos: https://github.com/Azure/azure-sdk-for-python/issues/13844")
    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_all_operations_together(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '003'
            entity.RowKey = 'batch_all_operations_together-1'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-2'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-3'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-4'
            self.table.create_entity(entity)

            batch = self.table.create_batch()
            entity.RowKey = 'batch_all_operations_together'
            batch.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-1'
            batch.delete_item(entity.PartitionKey, entity.RowKey)
            entity.RowKey = 'batch_all_operations_together-2'
            entity.test3 = 10
            batch.update_entity(entity)
            entity.RowKey = 'batch_all_operations_together-3'
            entity.test3 = 100
            batch.update_entity(entity, mode='MERGE')
            entity.RowKey = 'batch_all_operations_together-4'
            entity.test3 = 10
            batch.upsert_item(entity)
            entity.RowKey = 'batch_all_operations_together-5'
            batch.upsert_item(entity, mode='MERGE')
            resp = self.table.send_batch(batch)

            # Assert
            assert 6 ==  len(list(resp))
            entities = list(self.table.query_items("PartitionKey eq '003'"))
            assert 5 ==  len(entities)
        finally:
            self._tear_down()

    @pytest.mark.skip("merge operations fail in cosmos: https://github.com/Azure/azure-sdk-for-python/issues/13844")
    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_all_operations_together_context_manager(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '003'
            entity.RowKey = 'batch_all_operations_together-1'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-2'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-3'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-4'
            self.table.create_entity(entity)

            with self.table.create_batch() as batch:
                entity.RowKey = 'batch_all_operations_together'
                batch.create_entity(entity)
                entity.RowKey = 'batch_all_operations_together-1'
                batch.delete_item(entity.PartitionKey, entity.RowKey)
                entity.RowKey = 'batch_all_operations_together-2'
                entity.test3 = 10
                batch.update_entity(entity)
                entity.RowKey = 'batch_all_operations_together-3'
                entity.test3 = 100
                batch.update_entity(entity, mode='MERGE')
                entity.RowKey = 'batch_all_operations_together-4'
                entity.test3 = 10
                batch.upsert_item(entity)
                entity.RowKey = 'batch_all_operations_together-5'
                batch.upsert_item(entity, mode='MERGE')

            # Assert
            entities = list(self.table.query_items("PartitionKey eq '003'"))
            assert 5 ==  len(entities)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_same_row_operations_fail(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            batch = self.table.create_batch()

            entity = self._create_updated_entity_dict(
                '001', 'batch_negative_1')
            batch.update_entity(entity)
            entity = self._create_random_entity_dict(
                '001', 'batch_negative_1')
            batch.update_entity(entity, mode=UpdateMode.MERGE)
            # Assert
            with pytest.raises(BatchErrorException):
                self.table.send_batch(batch)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_different_partition_operations_fail(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            batch = self.table.create_batch()

            entity = self._create_updated_entity_dict(
                '001', 'batch_negative_1')
            batch.update_entity(entity)

            entity = self._create_random_entity_dict(
                '002', 'batch_negative_1')

            # Assert
            with pytest.raises(ValueError):
                batch.create_entity(entity)
        finally:
            self._tear_down()

    @pytest.mark.skip("On Cosmos, the limit is not specified.")
    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_too_many_ops(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            with pytest.raises(BatchErrorException):
                batch = self.table.create_batch()
                for i in range(0, 101):
                    entity = TableEntity()
                    entity.PartitionKey = 'large'
                    entity.RowKey = 'item{0}'.format(i)
                    batch.create_entity(entity)

            # Assert
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_new_non_existent_table(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')

            tc = self.ts.get_table_client("doesntexist")

            batch = tc.create_batch()
            batch.create_entity(entity)

            with pytest.raises(ResourceNotFoundError):
                resp = tc.send_batch(batch)
            # Assert
        finally:
            self._tear_down()

    @pytest.mark.skip("Cannot fake cosmos credential")
    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_new_invalid_key(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        invalid_key = tables_primary_cosmos_account_key[0:-6] + "==" # cut off a bit from the end to invalidate
        key_list = list(tables_primary_cosmos_account_key)

        key_list[-6:] = list("0000==")
        invalid_key = ''.join(key_list)

        self.ts = TableServiceClient(self.account_url(tables_cosmos_account_name, "table"), invalid_key)
        self.table_name = self.get_resource_name('uttable')
        self.table = self.ts.get_table_client(self.table_name)

        entity = self._create_random_entity_dict('001', 'batch_negative_1')

        batch = self.table.create_batch()
        batch.create_entity(entity)

        with pytest.raises(ClientAuthenticationError):
            resp = self.table.send_batch(batch)

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_new_delete_nonexistent_entity(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')

            batch = self.table.create_batch()
            batch.delete_entity(entity['PartitionKey'], entity['RowKey'])

            with pytest.raises(ResourceNotFoundError):
                resp = self.table.send_batch(batch)

        finally:
            self._tear_down()
Example #18
0
class StorageTableBatchTest(AzureTestCase, TableTestCase):
    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_single_insert(self, tables_storage_account_name,
                                 tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = '001'
            entity['RowKey'] = 'batch_insert'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()

            batch = [('create', entity)]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            e = self.table.get_entity(row_key=entity['RowKey'],
                                      partition_key=entity['PartitionKey'])
            assert e['test'] == entity['test'].value
            assert e['test2'] == entity['test2']
            assert e['test3'] == entity['test3']
            assert e['test4'] == entity['test4'].value
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_single_update(self, tables_storage_account_name,
                                 tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = '001'
            entity['RowKey'] = 'batch_insert'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()

            resp = self.table.create_entity(entity)
            assert resp is not None

            entity['test3'] = 5
            entity['test5'] = datetime.utcnow()

            batch = [('update', entity, {'mode': UpdateMode.MERGE})]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]
            result = self.table.get_entity(
                row_key=entity['RowKey'], partition_key=entity['PartitionKey'])
            assert result['PartitionKey'] == u'001'
            assert result['RowKey'] == u'batch_insert'
            assert result['test3'] == 5
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_update(self, tables_storage_account_name,
                          tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = u'001'
            entity['RowKey'] = u'batch_update'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = u'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()
            entity['test6'] = (2**40, "Edm.Int64")
            self.table.create_entity(entity)

            entity = self.table.get_entity(u'001', u'batch_update')
            assert 3 == entity['test3']
            entity['test2'] = u'value1'

            batch = [('update', entity)]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            result = self.table.get_entity('001', 'batch_update')

            assert 'value1' == result['test2']
            assert entity['PartitionKey'] == u'001'
            assert entity['RowKey'] == u'batch_update'
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_merge(self, tables_storage_account_name,
                         tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = u'001'
            entity['RowKey'] = u'batch_merge'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = u'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()
            self.table.create_entity(entity)

            resp_entity = self.table.get_entity(partition_key=u'001',
                                                row_key=u'batch_merge')
            assert 3 == entity['test3']
            entity = TableEntity()
            entity['PartitionKey'] = u'001'
            entity['RowKey'] = u'batch_merge'
            entity['test2'] = u'value1'

            batch = [('update', entity, {'mode': UpdateMode.MERGE})]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            resp_entity = self.table.get_entity(partition_key=u'001',
                                                row_key=u'batch_merge')
            assert entity['test2'] == resp_entity['test2']
            assert 1234567890 == resp_entity['test4']
            assert entity['PartitionKey'] == resp_entity['PartitionKey']
            assert entity['RowKey'] == resp_entity['RowKey']
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_update_if_match(self, tables_storage_account_name,
                                   tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict()
            resp = self.table.create_entity(entity=entity)
            etag = resp['etag']

            # Act
            sent_entity = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])
            batch = [('update', sent_entity, {
                'etag': etag,
                'match_condition': MatchConditions.IfNotModified,
                'mode': UpdateMode.REPLACE
            })]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            entity = self.table.get_entity(
                partition_key=entity['PartitionKey'], row_key=entity['RowKey'])
            self._assert_updated_entity(entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_update_if_doesnt_match(self, tables_storage_account_name,
                                          tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict()
            self.table.create_entity(entity)

            # Act
            sent_entity1 = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])

            batch = [('update', sent_entity1, {
                'etag': u'W/"datetime\'2012-06-15T22%3A51%3A44.9662825Z\'"',
                'match_condition': MatchConditions.IfNotModified
            })]
            with pytest.raises(TableTransactionError) as error:
                self.table.submit_transaction(batch)
            assert error.value.status_code == 412
            assert error.value.error_code == TableErrorCode.update_condition_not_satisfied

            # Assert
            received_entity = self.table.get_entity(entity['PartitionKey'],
                                                    entity['RowKey'])
            self._assert_default_entity(received_entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_single_op_if_doesnt_match(
            self, tables_storage_account_name,
            tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = 'batch_inserts'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)

            batch = []
            transaction_count = 0
            for i in range(10):
                entity['RowKey'] = str(i)
                batch.append(('create', entity.copy()))
                transaction_count += 1

            entity = self._create_random_entity_dict()
            self.table.create_entity(entity)

            # Act
            sent_entity1 = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])

            batch = [('update', sent_entity1, {
                'etag': u'W/"datetime\'2012-06-15T22%3A51%3A44.9662825Z\'"',
                'match_condition': MatchConditions.IfNotModified
            })]

            with pytest.raises(TableTransactionError) as error:
                self.table.submit_transaction(batch)
            assert error.value.status_code == 412
            assert error.value.error_code == TableErrorCode.update_condition_not_satisfied

            # Assert
            received_entity = self.table.get_entity(entity['PartitionKey'],
                                                    entity['RowKey'])
            self._assert_default_entity(received_entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_insert_replace(self, tables_storage_account_name,
                                  tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = '001'
            entity['RowKey'] = 'batch_insert_replace'
            entity['test'] = True
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()

            batch = [('upsert', entity, {'mode': UpdateMode.REPLACE})]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            entity = self.table.get_entity('001', 'batch_insert_replace')
            assert entity is not None
            assert 'value' == entity['test2']
            assert 1234567890 == entity['test4']
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_insert_merge(self, tables_storage_account_name,
                                tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = '001'
            entity['RowKey'] = 'batch_insert_merge'
            entity['test'] = True
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()

            batch = [('upsert', entity, {'mode': UpdateMode.MERGE})]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            entity = self.table.get_entity('001', 'batch_insert_merge')
            assert entity is not None
            assert 'value' == entity['test2']
            assert 1234567890 == entity['test4']
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_delete(self, tables_storage_account_name,
                          tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = u'001'
            entity['RowKey'] = u'batch_delete'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = u'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()
            self.table.create_entity(entity)

            entity = self.table.get_entity(partition_key=u'001',
                                           row_key=u'batch_delete')
            assert 3 == entity['test3']

            batch = [('delete', entity)]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' not in transaction_result[0]

            with pytest.raises(ResourceNotFoundError):
                entity = self.table.get_entity(
                    partition_key=entity['PartitionKey'],
                    row_key=entity['RowKey'])
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_inserts(self, tables_storage_account_name,
                           tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = 'batch_inserts'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)

            transaction_count = 0
            batch = []
            for i in range(100):
                entity['RowKey'] = str(i)
                batch.append(('create', entity.copy()))
                transaction_count += 1
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result,
                                                 transaction_count)
            assert 'etag' in transaction_result[0]

            entities = list(
                self.table.query_entities("PartitionKey eq 'batch_inserts'"))

            # Assert
            assert entities is not None
            assert transaction_count == len(entities)
            e = self.table.get_entity('batch_inserts', '1')
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_all_operations_together(self, tables_storage_account_name,
                                           tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = '003'
            entity['RowKey'] = 'batch_all_operations_together-1'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()

            self.table.create_entity(entity)
            entity['RowKey'] = 'batch_all_operations_together-2'
            self.table.create_entity(entity)
            entity['RowKey'] = 'batch_all_operations_together-3'
            self.table.create_entity(entity)
            entity['RowKey'] = 'batch_all_operations_together-4'
            self.table.create_entity(entity)
            transaction_count = 0

            batch = []
            entity['RowKey'] = 'batch_all_operations_together'
            batch.append((TransactionOperation.CREATE, entity.copy()))
            transaction_count += 1

            entity['RowKey'] = 'batch_all_operations_together-1'
            batch.append((TransactionOperation.DELETE, entity.copy()))
            transaction_count += 1

            entity['RowKey'] = 'batch_all_operations_together-2'
            entity['test3'] = 10
            batch.append((TransactionOperation.UPDATE, entity.copy()))
            transaction_count += 1

            entity['RowKey'] = 'batch_all_operations_together-3'
            entity['test3'] = 100
            batch.append((TransactionOperation.UPDATE, entity.copy(), {
                'mode': UpdateMode.REPLACE
            }))
            transaction_count += 1

            entity['RowKey'] = 'batch_all_operations_together-4'
            entity['test3'] = 10
            batch.append((TransactionOperation.UPSERT, entity.copy()))
            transaction_count += 1

            entity['RowKey'] = 'batch_all_operations_together-5'
            batch.append((TransactionOperation.UPSERT, entity.copy(), {
                'mode': UpdateMode.REPLACE
            }))
            transaction_count += 1

            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result,
                                                 transaction_count)
            assert 'etag' in transaction_result[0]
            assert 'etag' not in transaction_result[1]
            assert 'etag' in transaction_result[2]
            assert 'etag' in transaction_result[3]
            assert 'etag' in transaction_result[4]
            assert 'etag' in transaction_result[5]

            # Assert
            entities = list(self.table.query_entities("PartitionKey eq '003'"))
            assert 5 == len(entities)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_reuse(self, tables_storage_account_name,
                         tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            table2_name = self._get_table_reference('table2')
            table2 = self.ts.get_table_client(table2_name)
            table2.create_table()

            # Act
            entity = TableEntity()
            entity['PartitionKey'] = '003'
            entity['RowKey'] = 'batch_all_operations_together-1'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()

            batch = []
            batch.append(('upsert', entity.copy()))
            entity['RowKey'] = 'batch_all_operations_together-2'
            batch.append(('upsert', entity.copy()))
            entity['RowKey'] = 'batch_all_operations_together-3'
            batch.append(('upsert', entity.copy()))
            entity['RowKey'] = 'batch_all_operations_together-4'
            batch.append(('upsert', entity.copy()))

            resp1 = self.table.submit_transaction(batch)
            resp2 = table2.submit_transaction(batch)

            entities = list(self.table.query_entities("PartitionKey eq '003'"))
            assert 4 == len(entities)
            table2 = list(table2.query_entities("PartitionKey eq '003'"))
            assert 4 == len(entities)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_same_row_operations_fail(
            self, tables_storage_account_name,
            tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            batch = []

            entity = self._create_updated_entity_dict('001',
                                                      'batch_negative_1')
            batch.append(('update', entity.copy()))

            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            batch.append(('update', entity.copy(), {
                'mode': UpdateMode.REPLACE
            }))

            # Assert

            with pytest.raises(TableTransactionError):
                self.table.submit_transaction(batch)

        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_different_partition_operations_fail(
            self, tables_storage_account_name,
            tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            batch = []

            entity = self._create_updated_entity_dict('001',
                                                      'batch_negative_1')
            batch.append(('update', entity.copy()))

            entity = self._create_random_entity_dict('002', 'batch_negative_1')
            batch.append(('update', entity.copy()))

            with pytest.raises(ValueError):
                self.table.submit_transaction(batch)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_too_many_ops(self, tables_storage_account_name,
                                tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            with pytest.raises(TableTransactionError):
                batch = []
                for i in range(0, 101):
                    entity = TableEntity()
                    entity['PartitionKey'] = 'large'
                    entity['RowKey'] = 'item{0}'.format(i)
                    batch.append(('create', entity.copy()))
                self.table.submit_transaction(batch)

            # Assert
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_batch_different_partition_keys(
            self, tables_storage_account_name,
            tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            entity2 = self._create_random_entity_dict('002',
                                                      'batch_negative_1')

            batch = [('create', entity), ('create', entity2)]
            with pytest.raises(ValueError):
                self.table.submit_transaction(batch)

            # Assert
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_new_non_existent_table(self, tables_storage_account_name,
                                    tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')

            tc = self.ts.get_table_client("doesntexist")

            batch = [('create', entity)]

            with pytest.raises(TableTransactionError):
                resp = tc.submit_transaction(batch)
            # Assert
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_new_invalid_key(self, tables_storage_account_name,
                             tables_primary_storage_account_key):
        invalid_key = tables_primary_storage_account_key.named_key.key[
            0:-6] + "=="  # cut off a bit from the end to invalidate
        tables_primary_storage_account_key = AzureNamedKeyCredential(
            tables_storage_account_name, invalid_key)
        credential = AzureNamedKeyCredential(
            name=tables_storage_account_name,
            key=tables_primary_storage_account_key.named_key.key)
        self.ts = TableServiceClient(self.account_url(
            tables_storage_account_name, "table"),
                                     credential=credential)
        self.table_name = self.get_resource_name('uttable')
        self.table = self.ts.get_table_client(self.table_name)

        entity = self._create_random_entity_dict('001', 'batch_negative_1')

        batch = [('create', entity)]

        with pytest.raises(ClientAuthenticationError):
            resp = self.table.submit_transaction(batch)

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_new_delete_nonexistent_entity(self, tables_storage_account_name,
                                           tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')

            batch = [('delete', entity)]

            with pytest.raises(TableTransactionError):
                resp = self.table.submit_transaction(batch)

        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @tables_decorator
    def test_delete_batch_with_bad_kwarg(self, tables_storage_account_name,
                                         tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            received = self.table.get_entity(entity["PartitionKey"],
                                             entity["RowKey"])
            good_etag = received.metadata["etag"]
            received.metadata[
                "etag"] = u'W/"datetime\'2012-06-15T22%3A51%3A44.9662825Z\'"'

            batch = [('delete', received, {
                "match_condition": MatchConditions.IfNotModified
            })]

            with pytest.raises(TableTransactionError) as error:
                self.table.submit_transaction(batch)
            assert error.value.status_code == 412
            assert error.value.error_code == TableErrorCode.update_condition_not_satisfied

            received.metadata["etag"] = good_etag
            batch = [('delete', received, {
                "match_condition": MatchConditions.IfNotModified
            })]
            resp = self.table.submit_transaction(batch)

            assert resp is not None
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @pytest.mark.live_test_only
    @tables_decorator
    def test_batch_sas_auth(self, tables_storage_account_name,
                            tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:

            token = self.generate_sas(
                generate_table_sas,
                tables_primary_storage_account_key,
                self.table_name,
                permission=TableSasPermissions(add=True,
                                               read=True,
                                               update=True,
                                               delete=True),
                expiry=datetime.utcnow() + timedelta(hours=1),
                start=datetime.utcnow() - timedelta(minutes=1),
            )
            token = AzureSasCredential(token)

            # Act
            service = TableServiceClient(
                self.account_url(tables_storage_account_name, "table"),
                credential=token,
            )
            table = service.get_table_client(self.table_name)

            entity = TableEntity()
            entity['PartitionKey'] = 'batch_inserts'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)

            batch = []
            transaction_count = 0
            for i in range(10):
                entity['RowKey'] = str(i)
                batch.append(('create', entity.copy()))
                transaction_count += 1
            transaction_result = table.submit_transaction(batch)

            assert transaction_result

            total_entities = 0
            for e in table.list_entities():
                total_entities += 1

            assert total_entities == transaction_count
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @pytest.mark.live_test_only  # Request bodies are very large
    @tables_decorator
    def test_batch_request_too_large(self, tables_storage_account_name,
                                     tables_primary_storage_account_key):
        # Arrange
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key)
        try:

            batch = []
            entity = {
                'PartitionKey': 'pk001',
                'Foo': os.urandom(1024 * 64),
                'Bar': os.urandom(1024 * 64),
                'Baz': os.urandom(1024 * 64)
            }
            for i in range(50):
                entity['RowKey'] = str(i)
                batch.append(('create', entity.copy()))

            with pytest.raises(RequestTooLargeError):
                self.table.submit_transaction(batch)

        finally:
            self._tear_down()
class StorageTableClientTest(AzureTestCase, TableTestCase):
    def _set_up(self, tables_cosmos_account_name,
                tables_primary_cosmos_account_key):
        self.ts = TableServiceClient(
            self.account_url(tables_cosmos_account_name, "cosmos"),
            tables_primary_cosmos_account_key)
        self.table_name = self.get_resource_name('uttable')
        self.table = self.ts.get_table_client(self.table_name)
        if self.is_live:
            try:
                self.ts.create_table(self.table_name)
            except ResourceExistsError:
                pass

        self.test_tables = []

    def _tear_down(self):
        if self.is_live:
            try:
                self.ts.delete_table(self.table_name)
            except:
                pass

            for table_name in self.test_tables:
                try:
                    self.ts.delete_table(table_name)
                except:
                    pass
            sleep(SLEEP_DELAY)

    #--Helpers-----------------------------------------------------------------

    def _get_table_reference(self, prefix=TEST_TABLE_PREFIX):
        table_name = self.get_resource_name(prefix)
        self.test_tables.append(table_name)
        return self.ts.get_table_client(table_name)

    def _create_pk_rk(self, pk, rk):
        try:
            pk = pk if pk is not None else self.get_resource_name('pk').decode(
                'utf-8')
            rk = rk if rk is not None else self.get_resource_name('rk').decode(
                'utf-8')
        except AttributeError:
            pk = pk if pk is not None else self.get_resource_name('pk')
            rk = rk if rk is not None else self.get_resource_name('rk')
        return pk, rk

    def _create_random_entity_dict(self, pk=None, rk=None):
        '''
        Creates a dictionary-based entity with fixed values, using all
        of the supported data types.
        '''
        partition, row = self._create_pk_rk(pk, rk)
        properties = {
            'PartitionKey': partition,
            'RowKey': row,
            'age': 39,
            'sex': u'male',
            'married': True,
            'deceased': False,
            'optional': None,
            'ratio': 3.1,
            'evenratio': 3.0,
            'large': 933311100,
            'Birthday': datetime(1973, 10, 4, tzinfo=tzutc()),
            'birthday': datetime(1970, 10, 4, tzinfo=tzutc()),
            'binary': b'binary',
            'other': EntityProperty(value=20, type=EdmType.INT32),
            'clsid': uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833')
        }
        return TableEntity(**properties)

    def _create_updated_entity_dict(self, partition, row):
        '''
        Creates a dictionary-based entity with fixed values, with a
        different set of values than the default entity. It
        adds fields, changes field values, changes field types,
        and removes fields when compared to the default entity.
        '''
        return {
            'PartitionKey': partition,
            'RowKey': row,
            'age': u'abc',
            'sex': u'female',
            'sign': u'aquarius',
            'birthday': datetime(1991, 10, 4, tzinfo=tzutc())
        }

    def _assert_default_entity(self, entity):
        '''
        Asserts that the entity passed in matches the default entity.
        '''
        assert entity['age'] == 39
        assert entity['sex'] == 'male'
        assert entity['married'] == True
        assert entity['deceased'] == False
        assert not "optional" in entity
        assert entity['ratio'] == 3.1
        assert entity['evenratio'] == 3.0
        assert entity['large'] == 933311100
        assert entity['Birthday'] == datetime(1973, 10, 4, tzinfo=tzutc())
        assert entity['birthday'] == datetime(1970, 10, 4, tzinfo=tzutc())
        assert entity['binary'].value == b'binary'
        assert entity['other'] == 20
        assert entity['clsid'] == uuid.UUID(
            'c9da6455-213d-42c9-9a79-3e9149a57833')
        assert '_metadata' in entity

    def _assert_updated_entity(self, entity):
        '''
        Asserts that the entity passed in matches the updated entity.
        '''
        assert entity.age == 'abc'
        assert entity.sex == 'female'
        assert not hasattr(entity, "married")
        assert not hasattr(entity, "deceased")
        assert entity.sign == 'aquarius'
        assert not hasattr(entity, "optional")
        assert not hasattr(entity, "ratio")
        assert not hasattr(entity, "evenratio")
        assert not hasattr(entity, "large")
        assert not hasattr(entity, "Birthday")
        assert entity.birthday, datetime(1991, 10, 4, tzinfo=tzutc())
        assert not hasattr(entity, "other")
        assert not hasattr(entity, "clsid")
        assert entity['_metadata']['etag'] is not None

    #--Test cases for batch ---------------------------------------------
    def _assert_valid_batch_transaction(self, transaction, length):
        assert isinstance(transaction, BatchTransactionResult)
        assert length == len(transaction.entities)
        assert length == len(transaction.results)
        assert length == len(transaction.requests)

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_insert(self, tables_cosmos_account_name,
                          tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert_replace'
            entity.test = True
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = self.table.create_batch()
            batch.upsert_entity(entity)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert transaction_result.get_entity(entity.RowKey) is not None

            entity = self.table.get_entity('001', 'batch_insert_replace')
            assert entity is not None
            assert 'value' == entity.test2
            assert 1234567890 == entity.test4
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_update(self, tables_cosmos_account_name,
                          tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_update'
            entity.test = EntityProperty(True)
            entity.test2 = u'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)

            entity = self.table.get_entity(u'001', u'batch_update')
            assert 3 == entity.test3
            entity.test2 = u'value1'

            batch = self.table.create_batch()
            batch.update_entity(entity)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert transaction_result.get_entity(entity.RowKey) is not None
            result = self.table.get_entity('001', 'batch_update')
            assert 'value1' == result.test2
            assert entity.PartitionKey == u'001'
            assert entity.RowKey == u'batch_update'
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_merge(self, tables_cosmos_account_name,
                         tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_merge'
            entity.test = EntityProperty(True)
            entity.test2 = u'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)

            resp_entity = self.table.get_entity(partition_key=u'001',
                                                row_key=u'batch_merge')
            assert 3 == entity.test3
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_merge'
            entity.test2 = u'value1'

            batch = self.table.create_batch()
            batch.update_entity(entity, mode=UpdateMode.MERGE)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert transaction_result.get_entity(entity.RowKey) is not None

            resp_entity = self.table.get_entity(partition_key=u'001',
                                                row_key=u'batch_merge')
            assert entity.test2 == resp_entity.test2
            assert 1234567890 == resp_entity.test4
            assert entity.PartitionKey == resp_entity.PartitionKey
            assert entity.RowKey == resp_entity.RowKey
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_update_if_match(self, tables_cosmos_account_name,
                                   tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict()
            resp = self.table.create_entity(entity=entity)
            etag = resp['etag']

            # Act
            sent_entity = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])
            batch = self.table.create_batch()
            batch.update_entity(sent_entity,
                                etag=etag,
                                match_condition=MatchConditions.IfNotModified,
                                mode=UpdateMode.REPLACE)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert transaction_result.get_entity(
                sent_entity['RowKey']) is not None

            entity = self.table.get_entity(
                partition_key=entity['PartitionKey'], row_key=entity['RowKey'])
            self._assert_updated_entity(entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_update_if_doesnt_match(self, tables_cosmos_account_name,
                                          tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict()
            self.table.create_entity(entity)

            # Act
            sent_entity1 = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])

            batch = self.table.create_batch()
            batch.update_entity(
                sent_entity1,
                etag=u'W/"datetime\'2012-06-15T22%3A51%3A44.9662825Z\'"',
                match_condition=MatchConditions.IfNotModified)

            with pytest.raises(BatchErrorException):
                self.table.send_batch(batch)

            # Assert
            received_entity = self.table.get_entity(entity['PartitionKey'],
                                                    entity['RowKey'])
            self._assert_default_entity(received_entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_insert_replace(self, tables_cosmos_account_name,
                                  tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert_replace'
            entity.test = True
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = self.table.create_batch()
            batch.upsert_entity(entity)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert transaction_result.get_entity(entity.RowKey) is not None

            entity = self.table.get_entity('001', 'batch_insert_replace')
            assert entity is not None
            assert 'value' == entity.test2
            assert 1234567890 == entity.test4
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_insert_merge(self, tables_cosmos_account_name,
                                tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert_merge'
            entity.test = True
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = self.table.create_batch()
            batch.upsert_entity(entity, mode=UpdateMode.MERGE)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert transaction_result.get_entity(entity.RowKey) is not None

            entity = self.table.get_entity('001', 'batch_insert_merge')
            assert entity is not None
            assert 'value' == entity.test2
            assert 1234567890 == entity.test4
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_delete(self, tables_cosmos_account_name,
                          tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_delete'
            entity.test = EntityProperty(True)
            entity.test2 = u'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)

            entity = self.table.get_entity(partition_key=u'001',
                                           row_key=u'batch_delete')
            assert 3 == entity.test3

            batch = self.table.create_batch()
            batch.delete_entity(partition_key=entity.PartitionKey,
                                row_key=entity.RowKey)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert transaction_result.get_entity(entity.RowKey) is not None

            with pytest.raises(ResourceNotFoundError):
                entity = self.table.get_entity(
                    partition_key=entity.PartitionKey, row_key=entity.RowKey)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_inserts(self, tables_cosmos_account_name,
                           tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = 'batch_inserts'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)

            batch = self.table.create_batch()
            transaction_count = 0
            for i in range(20):
                entity.RowKey = str(i)
                batch.create_entity(entity)
                transaction_count += 1
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result,
                                                 transaction_count)
            assert transaction_result.get_entity(entity.RowKey) is not None

            entities = list(
                self.table.query_entities("PartitionKey eq 'batch_inserts'"))

            # Assert
            assert entities is not None
            assert transaction_count == len(entities)
            e = self.table.get_entity('batch_inserts', '1')
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_all_operations_together(self, tables_cosmos_account_name,
                                           tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '003'
            entity.RowKey = 'batch_all_operations_together-1'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-2'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-3'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-4'
            self.table.create_entity(entity)
            transaction_count = 0

            batch = self.table.create_batch()
            entity.RowKey = 'batch_all_operations_together'
            batch.create_entity(entity)
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-1'
            batch.delete_entity(entity.PartitionKey, entity.RowKey)
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-2'
            entity.test3 = 10
            batch.update_entity(entity)
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-3'
            entity.test3 = 100
            batch.update_entity(entity, mode=UpdateMode.MERGE)
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-4'
            entity.test3 = 10
            batch.upsert_entity(entity)
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-5'
            batch.upsert_entity(entity, mode=UpdateMode.MERGE)
            transaction_count += 1

            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result,
                                                 transaction_count)
            assert transaction_result.get_entity(
                'batch_all_operations_together') is not None
            assert transaction_result.get_entity(
                'batch_all_operations_together-1') is not None
            assert transaction_result.get_entity(
                'batch_all_operations_together-2') is not None
            assert transaction_result.get_entity(
                'batch_all_operations_together-3') is not None
            assert transaction_result.get_entity(
                'batch_all_operations_together-4') is not None
            assert transaction_result.get_entity(
                'batch_all_operations_together-5') is not None

            # Assert
            entities = list(self.table.query_entities("PartitionKey eq '003'"))
            assert 5 == len(entities)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_all_operations_together_context_manager(
            self, tables_cosmos_account_name,
            tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '003'
            entity.RowKey = 'batch_all_operations_together-1'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-2'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-3'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-4'
            self.table.create_entity(entity)

            with self.table.create_batch() as batch:
                entity.RowKey = 'batch_all_operations_together'
                batch.create_entity(entity)
                entity.RowKey = 'batch_all_operations_together-1'
                batch.delete_entity(entity.PartitionKey, entity.RowKey)
                entity.RowKey = 'batch_all_operations_together-2'
                entity.test3 = 10
                batch.update_entity(entity)
                entity.RowKey = 'batch_all_operations_together-3'
                entity.test3 = 100
                batch.update_entity(entity, mode=UpdateMode.MERGE)
                entity.RowKey = 'batch_all_operations_together-4'
                entity.test3 = 10
                batch.upsert_entity(entity)
                entity.RowKey = 'batch_all_operations_together-5'
                batch.upsert_entity(entity, mode=UpdateMode.MERGE)

            # Assert
            entities = list(self.table.query_entities("PartitionKey eq '003'"))
            assert 4 == len(entities)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_batch_different_partition_operations_fail(
            self, tables_cosmos_account_name,
            tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            batch = self.table.create_batch()

            entity = self._create_updated_entity_dict('001',
                                                      'batch_negative_1')
            batch.update_entity(entity)

            entity = self._create_random_entity_dict('002', 'batch_negative_1')

            # Assert
            with pytest.raises(ValueError):
                batch.create_entity(entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_new_non_existent_table(self, tables_cosmos_account_name,
                                    tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')

            tc = self.ts.get_table_client("doesntexist")

            batch = tc.create_batch()
            batch.create_entity(entity)

            with pytest.raises(ResourceNotFoundError):
                resp = tc.send_batch(batch)
            # Assert
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CosmosPreparer()
    def test_new_delete_nonexistent_entity(self, tables_cosmos_account_name,
                                           tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')

            batch = self.table.create_batch()
            batch.delete_entity(entity['PartitionKey'], entity['RowKey'])

            with pytest.raises(ResourceNotFoundError):
                resp = self.table.send_batch(batch)

        finally:
            self._tear_down()
class TableTestCase(object):
    def connection_string(self, account, key):
        return ("DefaultEndpointsProtocol=https;AccountName=" + account +
                ";AccountKey=" + str(key) + ";EndpointSuffix=core.windows.net")

    def account_url(self, account, endpoint_type):
        """Return an url of storage account.

        :param str storage_account: Storage account name
        :param str storage_type: The Storage type part of the URL. Should be "table", or "cosmos", etc.
        """
        try:
            if endpoint_type == "table":
                return account.primary_endpoints.table.rstrip("/")
            if endpoint_type == "cosmos":
                return "https://{}.table.cosmos.azure.com".format(account.name)
        except AttributeError:  # Didn't find "primary_endpoints"
            if endpoint_type == "table":
                return "https://{}.{}.core.windows.net".format(
                    account, endpoint_type)
            if endpoint_type == "cosmos":
                return "https://{}.table.cosmos.azure.com".format(account)

    def generate_sas_token(self):
        fake_key = "a" * 30 + "b" * 30

        return "?" + generate_account_sas(
            credential=AzureNamedKeyCredential(name="fakename", key=fake_key),
            resource_types=ResourceTypes(object=True),
            permission=AccountSasPermissions(read=True, list=True),
            start=datetime.now() - timedelta(hours=24),
            expiry=datetime.now() + timedelta(days=8),
        )

    def get_token_credential(self):
        if is_live():
            return DefaultAzureCredential()
        return self.generate_fake_token()

    def generate_fake_token(self):
        return FakeTokenCredential()

    def _get_table_reference(self, prefix=TEST_TABLE_PREFIX):
        table_name = self.get_resource_name(prefix)
        return table_name

    def _create_table(self, ts, prefix=TEST_TABLE_PREFIX, table_list=None):
        table_name = self._get_table_reference(prefix)
        try:
            table = ts.create_table(table_name)
            if table_list is not None:
                table_list.append(table)
        except ResourceExistsError:
            table = ts.get_table_client(table_name)
        return table

    def _delete_all_tables(self, ts):
        if self.is_live:
            for table in ts.list_tables():
                ts.delete_table(table.name)
            self.sleep(10)

    def _create_pk_rk(self, pk, rk):
        try:
            pk = pk if pk is not None else self.get_resource_name("pk").decode(
                "utf-8")
            rk = rk if rk is not None else self.get_resource_name("rk").decode(
                "utf-8")
        except AttributeError:
            pk = pk if pk is not None else self.get_resource_name("pk")
            rk = rk if rk is not None else self.get_resource_name("rk")
        return pk, rk

    def _create_random_base_entity_dict(self):
        """
        Creates a dict-based entity with only pk and rk.
        """
        partition, row = self._create_pk_rk(None, None)
        return {
            "PartitionKey": partition,
            "RowKey": row,
        }

    def _create_random_entity_dict(self, pk=None, rk=None):
        """
        Creates a dictionary-based entity with fixed values, using all
        of the supported data types.
        """
        partition, row = self._create_pk_rk(pk, rk)
        properties = {
            "PartitionKey": partition,
            "RowKey": row,
            "age": 39,
            "sex": u"male",
            "married": True,
            "deceased": False,
            "optional": None,
            "ratio": 3.1,
            "evenratio": 3.0,
            "double": (5, EdmType.DOUBLE),
            "large": 933311100,
            "Birthday": datetime(1973, 10, 4, tzinfo=tzutc()),
            "birthday": datetime(1970, 10, 4, tzinfo=tzutc()),
            "binary": b"binary",
            "other": EntityProperty(20, EdmType.INT32),
            "clsid": uuid.UUID("c9da6455-213d-42c9-9a79-3e9149a57833"),
        }
        return TableEntity(**properties)

    def _create_updated_entity_dict(self, partition, row):
        """
        Creates a dictionary-based entity with fixed values, with a
        different set of values than the default entity. It
        adds fields, changes field values, changes field types,
        and removes fields when compared to the default entity.
        """
        return {
            "PartitionKey": partition,
            "RowKey": row,
            "age": u"abc",
            "sex": u"female",
            "sign": u"aquarius",
            "birthday": datetime(1991, 10, 4, tzinfo=tzutc()),
        }

    def _assert_default_entity(self, entity):
        """
        Asserts that the entity passed in matches the default entity.
        """
        assert entity["age"] == 39
        assert entity["sex"] == "male"
        assert entity["married"] == True
        assert entity["deceased"] == False
        assert not "optional" in entity
        assert entity["ratio"] == 3.1
        assert entity["evenratio"] == 3.0
        assert entity["double"] == 5.0
        assert entity["large"] == 933311100
        assert entity["Birthday"] == datetime(1973, 10, 4, tzinfo=tzutc())
        assert entity["birthday"] == datetime(1970, 10, 4, tzinfo=tzutc())
        assert entity["binary"] == b"binary"
        assert entity["other"] == 20
        assert entity["clsid"] == uuid.UUID(
            "c9da6455-213d-42c9-9a79-3e9149a57833")
        assert entity.metadata.pop("etag", None)
        assert isinstance(entity.metadata.pop("timestamp", None), datetime)
        assert not entity.metadata, "Found metadata: {}".format(
            entity.metadata)

    def _assert_default_entity_json_full_metadata(self, entity, headers=None):
        """
        Asserts that the entity passed in matches the default entity.
        """
        assert entity["age"] == 39
        assert entity["sex"] == "male"
        assert entity["married"] == True
        assert entity["deceased"] == False
        assert not "optional" in entity
        assert not "aquarius" in entity
        assert entity["ratio"] == 3.1
        assert entity["evenratio"] == 3.0
        assert entity["double"] == 5.0
        assert entity["large"] == 933311100
        assert entity["Birthday"] == datetime(1973, 10, 4, tzinfo=tzutc())
        assert entity["birthday"] == datetime(1970, 10, 4, tzinfo=tzutc())
        assert entity["binary"] == b"binary"
        assert entity["other"] == 20
        assert entity["clsid"] == uuid.UUID(
            "c9da6455-213d-42c9-9a79-3e9149a57833")
        assert entity.metadata.pop("etag", None)
        assert isinstance(entity.metadata.pop("timestamp", None), datetime)
        assert sorted(list(entity.metadata.keys())) == [
            'editLink', 'id', 'type'
        ], "Found metadata: {}".format(entity.metadata)

    def _assert_default_entity_json_no_metadata(self, entity, headers=None):
        """
        Asserts that the entity passed in matches the default entity.
        """
        assert entity["age"] == 39
        assert entity["sex"] == "male"
        assert entity["married"] == True
        assert entity["deceased"] == False
        assert not "optional" in entity
        assert not "aquarius" in entity
        assert entity["ratio"] == 3.1
        assert entity["evenratio"] == 3.0
        assert entity["double"] == 5.0
        assert entity["large"] == 933311100
        assert entity["Birthday"].startswith("1973-10-04T00:00:00")
        assert entity["birthday"].startswith("1970-10-04T00:00:00")
        assert entity["Birthday"].endswith("00Z")
        assert entity["birthday"].endswith("00Z")
        assert entity["binary"] == b64encode(b"binary").decode("utf-8")
        assert entity["other"] == 20
        assert entity["clsid"] == "c9da6455-213d-42c9-9a79-3e9149a57833"
        assert entity.metadata.pop("etag", None)
        assert isinstance(entity.metadata.pop("timestamp", None), datetime)
        assert not entity.metadata

    def _assert_updated_entity(self, entity):
        """
        Asserts that the entity passed in matches the updated entity.
        """
        assert entity["age"] == "abc"
        assert entity["sex"] == "female"
        assert not "married" in entity
        assert not "deceased" in entity
        assert entity["sign"] == "aquarius"
        assert not "optional" in entity
        assert not "ratio" in entity
        assert not "evenratio" in entity
        assert not "double" in entity
        assert not "large" in entity
        assert not "Birthday" in entity
        assert entity["birthday"] == datetime(1991, 10, 4, tzinfo=tzutc())
        assert not "other" in entity
        assert not "clsid" in entity
        assert entity.metadata["etag"]
        assert entity.metadata["timestamp"]

    def _assert_merged_entity(self, entity):
        """
        Asserts that the entity passed in matches the default entity
        merged with the updated entity.
        """
        assert entity["age"] == "abc"
        assert entity["sex"] == "female"
        assert entity["sign"] == "aquarius"
        assert entity["married"] == True
        assert entity["deceased"] == False
        assert entity["ratio"] == 3.1
        assert entity["evenratio"] == 3.0
        assert entity["double"] == 5.0
        assert entity["large"] == 933311100
        assert entity["Birthday"] == datetime(1973, 10, 4, tzinfo=tzutc())
        assert entity["birthday"] == datetime(1991, 10, 4, tzinfo=tzutc())
        assert entity["other"] == 20
        assert isinstance(entity["clsid"], uuid.UUID)
        assert str(entity["clsid"]) == "c9da6455-213d-42c9-9a79-3e9149a57833"
        assert entity.metadata["etag"]
        assert entity.metadata["timestamp"]

    def _assert_valid_metadata(self, metadata):
        keys = metadata.keys()
        assert "version" in keys
        assert "date" in keys
        assert "etag" in keys
        assert len(keys) == 3

    def _assert_valid_batch_transaction(self, transaction, length):
        assert length == len(transaction)

    def _assert_properties_default(self, prop):
        assert prop is not None

        self._assert_logging_equal(prop["analytics_logging"],
                                   TableAnalyticsLogging())
        self._assert_metrics_equal(prop["hour_metrics"], TableMetrics())
        self._assert_metrics_equal(prop["minute_metrics"], TableMetrics())
        self._assert_cors_equal(prop["cors"], list())

    def _assert_policy_datetime(self, val1, val2):
        assert isinstance(val2, datetime)
        assert val1.year == val2.year
        assert val1.month == val2.month
        assert val1.day == val2.day
        assert val1.hour == val2.hour
        assert val1.minute == val2.minute
        assert val1.second == val2.second

    def _assert_logging_equal(self, log1, log2):
        if log1 is None or log2 is None:
            assert log1 == log2
            return

        assert log1.version == log2.version
        assert log1.read == log2.read
        assert log1.write == log2.write
        assert log1.delete == log2.delete
        self._assert_retention_equal(log1.retention_policy,
                                     log2.retention_policy)

    def _assert_delete_retention_policy_equal(self, policy1, policy2):
        if policy1 is None or policy2 is None:
            assert policy1 == policy2
            return

        assert policy1.enabled == policy2.enabled
        assert policy1.days == policy2.days

    def _assert_static_website_equal(self, prop1, prop2):
        if prop1 is None or prop2 is None:
            assert prop1 == prop2
            return

        assert prop1.enabled == prop2.enabled
        assert prop1.index_document == prop2.index_document
        assert prop1.error_document404_path == prop2.error_document404_path

    def _assert_delete_retention_policy_not_equal(self, policy1, policy2):
        if policy1 is None or policy2 is None:
            assert policy1 != policy2
            return

        assert policy1.enabled == policy2.enabled and policy1.days == policy2.days

    def _assert_metrics_equal(self, metrics1, metrics2):
        if metrics1 is None or metrics2 is None:
            assert metrics1 == metrics2
            return

        assert metrics1.version == metrics2.version
        assert metrics1.enabled == metrics2.enabled
        assert metrics1.include_apis == metrics2.include_apis
        self._assert_retention_equal(metrics1.retention_policy,
                                     metrics2.retention_policy)

    def _assert_cors_equal(self, cors1, cors2):
        if cors1 is None or cors2 is None:
            assert cors1 == cors2
            return

        assert len(cors1) == len(cors2)
        for i in range(0, len(cors1)):
            rule1 = cors1[i]
            rule2 = cors2[i]
            assert sorted(rule1.allowed_origins) == sorted(
                rule2.allowed_origins)
            assert sorted(rule1.allowed_methods) == sorted(
                rule2.allowed_methods)
            assert rule1.max_age_in_seconds == rule2.max_age_in_seconds
            assert sorted(rule1.exposed_headers) == sorted(
                rule2.exposed_headers)
            assert sorted(rule1.allowed_headers) == sorted(
                rule2.allowed_headers)

    def _assert_retention_equal(self, ret1, ret2):
        assert ret1.enabled == ret2.enabled
        assert ret1.days == ret2.days

    def _tear_down(self):
        if is_live():
            self._delete_all_tables(self.ts)
            self.test_tables = []
            self.ts.close()

    def _create_query_table(self, entity_count):
        """
        Creates a table with the specified name and adds entities with the
        default set of values. PartitionKey is set to 'MyPartition' and RowKey
        is set to a unique counter value starting at 1 (as a string).
        """
        table_name = self.get_resource_name("querytable")
        table = self.ts.create_table(table_name)
        self.query_tables.append(table_name)
        client = self.ts.get_table_client(table_name)
        entity = self._create_random_entity_dict()
        for i in range(1, entity_count + 1):
            entity["RowKey"] = entity["RowKey"] + str(i)
            client.create_entity(entity)
        return client

    def _insert_two_opposite_entities(self, pk=None, rk=None):
        entity1 = self._create_random_entity_dict()
        resp = self.table.create_entity(entity1)

        partition, row = self._create_pk_rk(pk, rk)
        properties = {
            "PartitionKey": partition + u"1",
            "RowKey": row + u"1",
            "age": 49,
            "sex": u"female",
            "married": False,
            "deceased": True,
            "optional": None,
            "ratio": 5.2,
            "evenratio": 6.0,
            "large": 39999011,
            "Birthday": datetime(1993, 4, 1, tzinfo=tzutc()),
            "birthday": datetime(1990, 4, 1, tzinfo=tzutc()),
            "binary": b"binary-binary",
            "other": EntityProperty(40, EdmType.INT32),
            "clsid": uuid.UUID("c8da6455-213e-42d9-9b79-3f9149a57833"),
        }
        self.table.create_entity(properties)
        return entity1, resp

    def _insert_random_entity(self, pk=None, rk=None):
        entity = self._create_random_entity_dict(pk, rk)
        metadata = self.table.create_entity(entity)
        return entity, metadata["etag"]

    def _set_up(self, account_name, credential, url="table"):
        self.table_name = self.get_resource_name("uttable")
        self.ts = TableServiceClient(self.account_url(account_name, url),
                                     credential=credential,
                                     table_name=self.table_name)
        self.table = self.ts.get_table_client(self.table_name)
        if self.is_live:
            try:
                self.ts.create_table(self.table_name)
            except ResourceExistsError:
                pass

        self.query_tables = []

    def _assert_stats_default(self, stats):
        assert stats is not None
        assert stats["geo_replication"] is not None

        assert stats["geo_replication"]["status"] == "live"
        assert stats["geo_replication"]["last_sync_time"] is not None

    def _assert_stats_unavailable(self, stats):
        assert stats is not None
        assert stats["geo_replication"] is not None

        assert stats["geo_replication"]["status"] == "unavailable"
        assert stats["geo_replication"]["last_sync_time"] is None

    @staticmethod
    def override_response_body_with_unavailable_status(response):
        response.http_response.text = lambda _: SERVICE_UNAVAILABLE_RESP_BODY

    @staticmethod
    def override_response_body_with_live_status(response):
        response.http_response.text = lambda _: SERVICE_LIVE_RESP_BODY
class AsyncTableTestCase(TableTestCase):
    def generate_fake_token(self):
        return AsyncFakeTokenCredential()

    def _get_table_reference(self, prefix=TEST_TABLE_PREFIX):
        table_name = self.get_resource_name(prefix)
        return table_name

    async def _create_table(self, ts, prefix=TEST_TABLE_PREFIX, table_list=None):
        table_name = self._get_table_reference(prefix)
        try:
            table = await ts.create_table(table_name)
            if table_list is not None:
                table_list.append(table)
        except ResourceExistsError:
            table = ts.get_table_client(table_name)
        return table

    async def _delete_all_tables(self, account_name, key):
        client = TableServiceClient(self.account_url(account_name, "cosmos"), key)
        async for table in client.list_tables():
            await client.delete_table(table.name)

        if self.is_live:
            self.sleep(10)

    async def _tear_down(self):
        if is_live():
            async for table in self.ts.list_tables():
                await self.ts.delete_table(table.name)
            if self.ts._cosmos_endpoint:
                self.sleep(SLEEP_DELAY)
            self.test_tables = []
            await self.ts.close()

    async def _create_query_table(self, entity_count):
        """
        Creates a table with the specified name and adds entities with the
        default set of values. PartitionKey is set to 'MyPartition' and RowKey
        is set to a unique counter value starting at 1 (as a string).
        """
        table_name = self.get_resource_name("querytable")
        table = await self.ts.create_table(table_name)
        self.query_tables.append(table_name)
        client = self.ts.get_table_client(table_name)
        entity = self._create_random_entity_dict()
        for i in range(1, entity_count + 1):
            entity["RowKey"] = entity["RowKey"] + str(i)
            await client.create_entity(entity=entity)
        return client

    async def _insert_two_opposite_entities(self, pk=None, rk=None):
        entity1 = self._create_random_entity_dict()
        resp = await self.table.create_entity(entity1)

        partition, row = self._create_pk_rk(pk, rk)
        properties = {
            "PartitionKey": partition + u"1",
            "RowKey": row + u"1",
            "age": 49,
            "sex": u"female",
            "married": False,
            "deceased": True,
            "optional": None,
            "ratio": 5.2,
            "evenratio": 6.0,
            "large": 39999011,
            "Birthday": datetime(1993, 4, 1, tzinfo=tzutc()),
            "birthday": datetime(1990, 4, 1, tzinfo=tzutc()),
            "binary": b"binary-binary",
            "other": EntityProperty(40, EdmType.INT32),
            "clsid": uuid.UUID("c8da6455-213e-42d9-9b79-3f9149a57833"),
        }
        await self.table.create_entity(properties)
        return entity1, resp

    async def _insert_random_entity(self, pk=None, rk=None):
        entity = self._create_random_entity_dict(pk, rk)
        metadata = await self.table.create_entity(entity=entity)
        return entity, metadata["etag"]

    async def _set_up(self, account_name, account_key, url="table"):
        account_url = self.account_url(account_name, url)
        self.ts = TableServiceClient(account_url, account_key)
        self.table_name = self.get_resource_name("uttable")
        self.table = self.ts.get_table_client(self.table_name)
        if self.is_live:
            try:
                await self.ts.create_table(table_name=self.table_name)
            except ResourceExistsError:
                pass

        self.query_tables = []
Example #22
0
class StorageTableBatchTest(TableTestCase):
    def _set_up(self, storage_account, storage_account_key):
        self.ts = TableServiceClient(
            self.account_url(storage_account, "table"), storage_account_key)
        self.table_name = self.get_resource_name('uttable')
        self.table = self.ts.get_table_client(self.table_name)
        if self.is_live:
            try:
                self.ts.create_table(self.table_name)
            except ResourceExistsError:
                pass

        self.test_tables = []

    def _tear_down(self):
        if self.is_live:
            try:
                self.ts.delete_table(self.table_name)
            except:
                pass

            for table_name in self.test_tables:
                try:
                    self.ts.delete_table(table_name)
                except:
                    pass

    #--Helpers-----------------------------------------------------------------

    def _get_table_reference(self, prefix=TEST_TABLE_PREFIX):
        table_name = self.get_resource_name(prefix)
        self.test_tables.append(table_name)
        return self.ts.get_table_client(table_name)

    def _create_pk_rk(self, pk, rk):
        try:
            pk = pk if pk is not None else self.get_resource_name('pk').decode(
                'utf-8')
            rk = rk if rk is not None else self.get_resource_name('rk').decode(
                'utf-8')
        except AttributeError:
            pk = pk if pk is not None else self.get_resource_name('pk')
            rk = rk if rk is not None else self.get_resource_name('rk')
        return pk, rk

    def _create_random_entity_dict(self, pk=None, rk=None):
        """
        Creates a dictionary-based entity with fixed values, using all
        of the supported data types.
        """
        # partition = pk if pk is not None else self.get_resource_name('pk').decode('utf-8')
        # row = rk if rk is not None else self.get_resource_name('rk').decode('utf-8')
        partition, row = self._create_pk_rk(pk, rk)
        properties = {
            'PartitionKey': partition,
            'RowKey': row,
            'age': 39,
            'sex': u'male',
            'married': True,
            'deceased': False,
            'optional': None,
            'ratio': 3.1,
            'evenratio': 3.0,
            'large': 933311100,
            'Birthday': datetime(1973, 10, 4, tzinfo=tzutc()),
            'birthday': datetime(1970, 10, 4, tzinfo=tzutc()),
            'binary': b'binary',
            'other': EntityProperty(value=20, type=EdmType.INT32),
            'clsid': uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833')
        }
        return TableEntity(**properties)

    def _create_updated_entity_dict(self, partition, row):
        '''
        Creates a dictionary-based entity with fixed values, with a
        different set of values than the default entity. It
        adds fields, changes field values, changes field types,
        and removes fields when compared to the default entity.
        '''
        return {
            'PartitionKey': partition,
            'RowKey': row,
            'age': u'abc',
            'sex': u'female',
            'sign': u'aquarius',
            'birthday': datetime(1991, 10, 4, tzinfo=tzutc())
        }

    def _assert_default_entity(self, entity):
        '''
        Asserts that the entity passed in matches the default entity.
        '''
        self.assertEqual(entity['age'].value, 39)
        self.assertEqual(entity['sex'].value, u'male')
        self.assertEqual(entity['married'], True)
        self.assertEqual(entity['deceased'], False)
        self.assertFalse("optional" in entity)
        self.assertEqual(entity['ratio'], 3.1)
        self.assertEqual(entity['evenratio'], 3.0)
        self.assertEqual(entity['large'].value, 933311100)
        self.assertEqual(entity['Birthday'],
                         datetime(1973, 10, 4, tzinfo=tzutc()))
        self.assertEqual(entity['birthday'],
                         datetime(1970, 10, 4, tzinfo=tzutc()))
        self.assertEqual(entity['binary'].value, b'binary')
        self.assertIsInstance(entity['other'], EntityProperty)
        self.assertEqual(entity['other'].type, EdmType.INT32)
        self.assertEqual(entity['other'].value, 20)
        self.assertEqual(entity['clsid'],
                         uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833'))
        self.assertTrue('_metadata' in entity)

    def _assert_updated_entity(self, entity):
        '''
        Asserts that the entity passed in matches the updated entity.
        '''
        self.assertEqual(entity.age.value, 'abc')
        self.assertEqual(entity.sex.value, 'female')
        self.assertFalse(hasattr(entity, "married"))
        self.assertFalse(hasattr(entity, "deceased"))
        self.assertEqual(entity.sign.value, 'aquarius')
        self.assertFalse(hasattr(entity, "optional"))
        self.assertFalse(hasattr(entity, "ratio"))
        self.assertFalse(hasattr(entity, "evenratio"))
        self.assertFalse(hasattr(entity, "large"))
        self.assertFalse(hasattr(entity, "Birthday"))
        self.assertEqual(entity.birthday, datetime(1991, 10, 4,
                                                   tzinfo=tzutc()))
        self.assertFalse(hasattr(entity, "other"))
        self.assertFalse(hasattr(entity, "clsid"))
        self.assertIsNotNone(entity['_metadata']['etag'])

    def _assert_valid_batch_transaction(self, transaction, length):
        self.assertIsInstance(transaction, BatchTransactionResult)
        self.assertEqual(length, len(transaction.entities))
        self.assertEqual(length, len(transaction.results))
        self.assertEqual(length, len(transaction.requests))

    #--Test cases for batch ---------------------------------------------
    def test_inferred_types(self):
        # Arrange
        # Act
        entity = TableEntity()
        entity.PartitionKey = '003'
        entity.RowKey = 'batch_all_operations_together-1'
        entity.test = EntityProperty(True)
        entity.test2 = EntityProperty(b'abcdef')
        entity.test3 = EntityProperty(u'c9da6455-213d-42c9-9a79-3e9149a57833')
        entity.test4 = EntityProperty(datetime(1973, 10, 4, tzinfo=tzutc()))
        entity.test5 = EntityProperty(u"stringystring")
        entity.test6 = EntityProperty(3.14159)
        entity.test7 = EntityProperty(100)
        entity.test8 = EntityProperty(2**33, EdmType.INT64)

        # Assert
        self.assertEqual(entity.test.type, EdmType.BOOLEAN)
        self.assertEqual(entity.test2.type, EdmType.BINARY)
        self.assertEqual(entity.test3.type, EdmType.GUID)
        self.assertEqual(entity.test4.type, EdmType.DATETIME)
        self.assertEqual(entity.test5.type, EdmType.STRING)
        self.assertEqual(entity.test6.type, EdmType.DOUBLE)
        self.assertEqual(entity.test7.type, EdmType.INT32)
        self.assertEqual(entity.test8.type, EdmType.INT64)

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_single_insert(self, resource_group, location,
                                 storage_account, storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = self.table.create_batch()
            batch.create_entity(entity)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            sent_entity = transaction_result.get_entity(entity.RowKey)
            self.assertIsNotNone(sent_entity)
            e = self.table.get_entity(row_key=entity.RowKey,
                                      partition_key=entity.PartitionKey)
            self.assertEqual(e.test, entity.test.value)
            self.assertEqual(e.test2.value, entity.test2)
            self.assertEqual(e.test3.value, entity.test3)
            self.assertEqual(e.test4.value, entity.test4.value)
            self.assertEqual(sent_entity['test'], entity.test.value)
            self.assertEqual(sent_entity['test2'], entity.test2)
            self.assertEqual(sent_entity['test3'], entity.test3)
            self.assertEqual(sent_entity['test4'], entity.test4.value)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_single_update(self, resource_group, location,
                                 storage_account, storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            resp = self.table.create_entity(entity)
            self.assertIsNotNone(resp)

            entity.test3 = 5
            entity.test5 = datetime.utcnow()

            batch = self.table.create_batch()
            batch.update_entity(entity, mode=UpdateMode.MERGE)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            self.assertIsNotNone(transaction_result.get_entity(entity.RowKey))
            result = self.table.get_entity(row_key=entity.RowKey,
                                           partition_key=entity.PartitionKey)
            self.assertEqual(result.PartitionKey, u'001')
            self.assertEqual(result.RowKey, u'batch_insert')
            self.assertEqual(result.test3.value, 5)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_update(self, resource_group, location, storage_account,
                          storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_update'
            entity.test = EntityProperty(True)
            entity.test2 = u'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)

            entity = self.table.get_entity(u'001', u'batch_update')
            self.assertEqual(3, entity.test3.value)
            entity.test2 = u'value1'

            batch = self.table.create_batch()
            batch.update_entity(entity)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            self.assertIsNotNone(transaction_result.get_entity(entity.RowKey))
            result = self.table.get_entity('001', 'batch_update')
            self.assertEqual('value1', result.test2.value)
            self.assertEqual(entity.PartitionKey, u'001')
            self.assertEqual(entity.RowKey, u'batch_update')
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_merge(self, resource_group, location, storage_account,
                         storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_merge'
            entity.test = EntityProperty(True)
            entity.test2 = u'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)

            resp_entity = self.table.get_entity(partition_key=u'001',
                                                row_key=u'batch_merge')
            self.assertEqual(3, entity.test3)
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_merge'
            entity.test2 = u'value1'

            batch = self.table.create_batch()
            batch.update_entity(entity, mode=UpdateMode.MERGE)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            self.assertIsNotNone(transaction_result.get_entity(entity.RowKey))

            resp_entity = self.table.get_entity(partition_key=u'001',
                                                row_key=u'batch_merge')
            self.assertEqual(entity.test2, resp_entity.test2.value)
            self.assertEqual(1234567890, resp_entity.test4.value)
            self.assertEqual(entity.PartitionKey, resp_entity.PartitionKey)
            self.assertEqual(entity.RowKey, resp_entity.RowKey)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_update_if_match(self, resource_group, location,
                                   storage_account, storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            entity = self._create_random_entity_dict()
            resp = self.table.create_entity(entity=entity)
            etag = resp['etag']

            # Act
            sent_entity = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])
            batch = self.table.create_batch()
            batch.update_entity(sent_entity,
                                etag=etag,
                                match_condition=MatchConditions.IfNotModified,
                                mode=UpdateMode.REPLACE)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            self.assertIsNotNone(
                transaction_result.get_entity(sent_entity['RowKey']))

            entity = self.table.get_entity(
                partition_key=entity['PartitionKey'], row_key=entity['RowKey'])
            self._assert_updated_entity(entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_update_if_doesnt_match(self, resource_group, location,
                                          storage_account,
                                          storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            entity = self._create_random_entity_dict()
            self.table.create_entity(entity)

            # Act
            sent_entity1 = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])

            batch = self.table.create_batch()
            batch.update_entity(
                sent_entity1,
                etag=u'W/"datetime\'2012-06-15T22%3A51%3A44.9662825Z\'"',
                match_condition=MatchConditions.IfNotModified)

            with self.assertRaises(HttpResponseError):
                self.table.send_batch(batch)

            # Assert
            received_entity = self.table.get_entity(entity['PartitionKey'],
                                                    entity['RowKey'])
            self._assert_default_entity(received_entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_single_op_if_doesnt_match(self, resource_group, location,
                                             storage_account,
                                             storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = 'batch_inserts'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)

            batch = self.table.create_batch()
            transaction_count = 0
            for i in range(10):
                entity.RowKey = str(i)
                batch.create_entity(entity)
                transaction_count += 1

            entity = self._create_random_entity_dict()
            self.table.create_entity(entity)

            # Act
            sent_entity1 = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])

            batch = self.table.create_batch()
            batch.update_entity(
                sent_entity1,
                etag=u'W/"datetime\'2012-06-15T22%3A51%3A44.9662825Z\'"',
                match_condition=MatchConditions.IfNotModified)

            with self.assertRaises(HttpResponseError):
                self.table.send_batch(batch)

            # Assert
            received_entity = self.table.get_entity(entity['PartitionKey'],
                                                    entity['RowKey'])
            self._assert_default_entity(received_entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_insert_replace(self, resource_group, location,
                                  storage_account, storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert_replace'
            entity.test = True
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = self.table.create_batch()
            batch.upsert_entity(entity)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            self.assertIsNotNone(transaction_result.get_entity(entity.RowKey))

            entity = self.table.get_entity('001', 'batch_insert_replace')
            self.assertIsNotNone(entity)
            self.assertEqual('value', entity.test2.value)
            self.assertEqual(1234567890, entity.test4.value)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_insert_merge(self, resource_group, location,
                                storage_account, storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '001'
            entity.RowKey = 'batch_insert_merge'
            entity.test = True
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = self.table.create_batch()
            batch.upsert_entity(entity, mode=UpdateMode.MERGE)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            self.assertIsNotNone(transaction_result.get_entity(entity.RowKey))

            entity = self.table.get_entity('001', 'batch_insert_merge')
            self.assertIsNotNone(entity)
            self.assertEqual('value', entity.test2.value)
            self.assertEqual(1234567890, entity.test4.value)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_delete(self, resource_group, location, storage_account,
                          storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = u'001'
            entity.RowKey = u'batch_delete'
            entity.test = EntityProperty(True)
            entity.test2 = u'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)

            entity = self.table.get_entity(partition_key=u'001',
                                           row_key=u'batch_delete')
            self.assertEqual(3, entity.test3.value)

            batch = self.table.create_batch()
            batch.delete_entity(partition_key=entity.PartitionKey,
                                row_key=entity.RowKey)
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            self.assertIsNotNone(transaction_result.get_entity(entity.RowKey))

            with self.assertRaises(ResourceNotFoundError):
                entity = self.table.get_entity(
                    partition_key=entity.PartitionKey, row_key=entity.RowKey)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_inserts(self, resource_group, location, storage_account,
                           storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = 'batch_inserts'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)

            batch = self.table.create_batch()
            transaction_count = 0
            for i in range(100):
                entity.RowKey = str(i)
                batch.create_entity(entity)
                transaction_count += 1
            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result,
                                                 transaction_count)
            self.assertIsNotNone(transaction_result.get_entity(entity.RowKey))

            entities = list(
                self.table.query_entities("PartitionKey eq 'batch_inserts'"))

            # Assert
            self.assertIsNotNone(entities)
            self.assertEqual(100, len(entities))
            e = self.table.get_entity('batch_inserts', '1')
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_all_operations_together(self, resource_group, location,
                                           storage_account,
                                           storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '003'
            entity.RowKey = 'batch_all_operations_together-1'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-2'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-3'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-4'
            self.table.create_entity(entity)
            transaction_count = 0

            batch = self.table.create_batch()
            entity.RowKey = 'batch_all_operations_together'
            batch.create_entity(entity)
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-1'
            batch.delete_entity(entity.PartitionKey, entity.RowKey)
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-2'
            entity.test3 = 10
            batch.update_entity(entity)
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-3'
            entity.test3 = 100
            batch.update_entity(entity, mode=UpdateMode.MERGE)
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-4'
            entity.test3 = 10
            batch.upsert_entity(entity)
            transaction_count += 1

            entity.RowKey = 'batch_all_operations_together-5'
            batch.upsert_entity(entity, mode=UpdateMode.MERGE)
            transaction_count += 1

            transaction_result = self.table.send_batch(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result,
                                                 transaction_count)
            self.assertIsNotNone(
                transaction_result.get_entity('batch_all_operations_together'))
            self.assertIsNotNone(
                transaction_result.get_entity(
                    'batch_all_operations_together-1'))
            self.assertIsNotNone(
                transaction_result.get_entity(
                    'batch_all_operations_together-2'))
            self.assertIsNotNone(
                transaction_result.get_entity(
                    'batch_all_operations_together-3'))
            self.assertIsNotNone(
                transaction_result.get_entity(
                    'batch_all_operations_together-4'))
            self.assertIsNotNone(
                transaction_result.get_entity(
                    'batch_all_operations_together-5'))

            # Assert
            entities = list(self.table.query_entities("PartitionKey eq '003'"))
            self.assertEqual(5, len(entities))
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_all_operations_together_context_manager(
            self, resource_group, location, storage_account,
            storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            # Act
            entity = TableEntity()
            entity.PartitionKey = '003'
            entity.RowKey = 'batch_all_operations_together-1'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-2'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-3'
            self.table.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-4'
            self.table.create_entity(entity)

            with self.table.create_batch() as batch:
                entity.RowKey = 'batch_all_operations_together'
                batch.create_entity(entity)
                entity.RowKey = 'batch_all_operations_together-1'
                batch.delete_entity(entity.PartitionKey, entity.RowKey)
                entity.RowKey = 'batch_all_operations_together-2'
                entity.test3 = 10
                batch.update_entity(entity)
                entity.RowKey = 'batch_all_operations_together-3'
                entity.test3 = 100
                batch.update_entity(entity, mode=UpdateMode.MERGE)
                entity.RowKey = 'batch_all_operations_together-4'
                entity.test3 = 10
                batch.upsert_entity(entity)
                entity.RowKey = 'batch_all_operations_together-5'
                batch.upsert_entity(entity, mode=UpdateMode.MERGE)

            # Assert
            entities = list(self.table.query_entities("PartitionKey eq '003'"))
            self.assertEqual(4, len(entities))
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_reuse(self, resource_group, location, storage_account,
                         storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            table2 = self._get_table_reference('table2')
            table2.create_table()

            # Act
            entity = TableEntity()
            entity.PartitionKey = '003'
            entity.RowKey = 'batch_all_operations_together-1'
            entity.test = EntityProperty(True)
            entity.test2 = 'value'
            entity.test3 = 3
            entity.test4 = EntityProperty(1234567890)
            entity.test5 = datetime.utcnow()

            batch = self.table.create_batch()
            batch.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-2'
            batch.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-3'
            batch.create_entity(entity)
            entity.RowKey = 'batch_all_operations_together-4'
            batch.create_entity(entity)

            self.table.send_batch(batch)
            with self.assertRaises(HttpResponseError):
                resp = table2.send_batch(batch)

            entities = list(self.table.query_entities("PartitionKey eq '003'"))
            self.assertEqual(4, len(entities))
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_same_row_operations_fail(self, resource_group, location,
                                            storage_account,
                                            storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            batch = self.table.create_batch()

            entity = self._create_updated_entity_dict('001',
                                                      'batch_negative_1')
            batch.update_entity(entity)
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            batch.update_entity(entity, mode=UpdateMode.MERGE)
            # Assert
            with self.assertRaises(HttpResponseError):
                self.table.send_batch(batch)

        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_different_partition_operations_fail(self, resource_group,
                                                       location,
                                                       storage_account,
                                                       storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            batch = self.table.create_batch()

            entity = self._create_updated_entity_dict('001',
                                                      'batch_negative_1')
            batch.update_entity(entity)

            entity = self._create_random_entity_dict('002', 'batch_negative_1')
            with self.assertRaises(ValueError):
                batch.create_entity(entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_too_many_ops(self, resource_group, location,
                                storage_account, storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            with self.assertRaises(HttpResponseError):
                batch = self.table.create_batch()
                for i in range(0, 101):
                    entity = TableEntity()
                    entity.PartitionKey = 'large'
                    entity.RowKey = 'item{0}'.format(i)
                    batch.create_entity(entity)
                self.table.send_batch(batch)

            # Assert
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @CachedResourceGroupPreparer(name_prefix="tablestest")
    @CachedStorageAccountPreparer(name_prefix="tablestest")
    def test_batch_different_partition_keys(self, resource_group, location,
                                            storage_account,
                                            storage_account_key):
        # Arrange
        self._set_up(storage_account, storage_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            entity2 = self._create_random_entity_dict('002',
                                                      'batch_negative_1')

            batch = self.table.create_batch()
            batch.create_entity(entity)
            with self.assertRaises(ValueError):
                batch.create_entity(entity2)

            # Assert
        finally:
            self._tear_down()
Example #23
0
class StorageTableClientTest(AzureTestCase, TableTestCase):
    def _set_up(self, tables_cosmos_account_name,
                tables_primary_cosmos_account_key):
        self.ts = TableServiceClient(
            self.account_url(tables_cosmos_account_name, "cosmos"),
            tables_primary_cosmos_account_key)
        self.table_name = self.get_resource_name('uttable')
        self.table = self.ts.get_table_client(self.table_name)
        if self.is_live:
            try:
                self.ts.create_table(self.table_name)
            except ResourceExistsError:
                pass

        self.test_tables = []

    def _tear_down(self):
        if self.is_live:
            try:
                self.ts.delete_table(self.table_name)
            except:
                pass

            for table_name in self.test_tables:
                try:
                    self.ts.delete_table(table_name)
                except:
                    pass
            self.sleep(SLEEP_DELAY)

    #--Helpers-----------------------------------------------------------------

    def _get_table_reference(self, prefix=TEST_TABLE_PREFIX):
        table_name = self.get_resource_name(prefix)
        self.test_tables.append(table_name)
        return self.ts.get_table_client(table_name)

    def _create_pk_rk(self, pk, rk):
        try:
            pk = pk if pk is not None else self.get_resource_name('pk').decode(
                'utf-8')
            rk = rk if rk is not None else self.get_resource_name('rk').decode(
                'utf-8')
        except AttributeError:
            pk = pk if pk is not None else self.get_resource_name('pk')
            rk = rk if rk is not None else self.get_resource_name('rk')
        return pk, rk

    def _create_random_entity_dict(self, pk=None, rk=None):
        '''
        Creates a dictionary-based entity with fixed values, using all
        of the supported data types.
        '''
        partition, row = self._create_pk_rk(pk, rk)
        properties = {
            'PartitionKey': partition,
            'RowKey': row,
            'age': 39,
            'sex': u'male',
            'married': True,
            'deceased': False,
            'optional': None,
            'ratio': 3.1,
            'evenratio': 3.0,
            'large': 933311100,
            'Birthday': datetime(1973, 10, 4, tzinfo=tzutc()),
            'birthday': datetime(1970, 10, 4, tzinfo=tzutc()),
            'binary': b'binary',
            'other': EntityProperty(20, EdmType.INT32),
            'clsid': uuid.UUID('c9da6455-213d-42c9-9a79-3e9149a57833')
        }
        return TableEntity(**properties)

    def _create_updated_entity_dict(self, partition, row):
        '''
        Creates a dictionary-based entity with fixed values, with a
        different set of values than the default entity. It
        adds fields, changes field values, changes field types,
        and removes fields when compared to the default entity.
        '''
        return {
            'PartitionKey': partition,
            'RowKey': row,
            'age': u'abc',
            'sex': u'female',
            'sign': u'aquarius',
            'birthday': datetime(1991, 10, 4, tzinfo=tzutc())
        }

    def _assert_default_entity(self, entity):
        '''
        Asserts that the entity passed in matches the default entity.
        '''
        assert entity['age'] == 39
        assert entity['sex'] == 'male'
        assert entity['married'] == True
        assert entity['deceased'] == False
        assert not "optional" in entity
        assert entity['ratio'] == 3.1
        assert entity['evenratio'] == 3.0
        assert entity['large'] == 933311100
        assert entity['Birthday'] == datetime(1973, 10, 4, tzinfo=tzutc())
        assert entity['birthday'] == datetime(1970, 10, 4, tzinfo=tzutc())
        assert entity['binary'].value == b'binary'
        assert entity['other'] == 20
        assert entity['clsid'] == uuid.UUID(
            'c9da6455-213d-42c9-9a79-3e9149a57833')
        assert entity.metadata['etag']
        assert entity.metadata['timestamp']

    def _assert_updated_entity(self, entity):
        '''
        Asserts that the entity passed in matches the updated entity.
        '''
        assert entity['age'] == 'abc'
        assert entity['sex'] == 'female'
        assert not "married" in entity
        assert not "deceased" in entity
        assert entity['sign'] == 'aquarius'
        assert not "optional" in entity
        assert not "ratio" in entity
        assert not "evenratio" in entity
        assert not "large" in entity
        assert not "Birthday" in entity
        assert entity['birthday'] == datetime(1991, 10, 4, tzinfo=tzutc())
        assert not "other" in entity
        assert not "clsid" in entity
        assert entity.metadata['etag']
        assert entity.metadata['timestamp']

    #--Test cases for batch ---------------------------------------------
    def _assert_valid_batch_transaction(self, transaction, length):
        assert length == len(transaction)

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_batch_insert(self, tables_cosmos_account_name,
                          tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = '001'
            entity['RowKey'] = 'batch_insert_replace'
            entity['test'] = True
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()

            batch = [('upsert', entity)]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            entity = self.table.get_entity('001', 'batch_insert_replace')
            assert entity is not None
            assert 'value' == entity['test2']
            assert 1234567890 == entity['test4']
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_batch_update(self, tables_cosmos_account_name,
                          tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = u'001'
            entity['RowKey'] = u'batch_update'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = u'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()
            self.table.create_entity(entity)

            entity = self.table.get_entity(u'001', u'batch_update')
            assert 3 == entity['test3']
            entity['test2'] = u'value1'

            batch = [('update', entity)]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            result = self.table.get_entity('001', 'batch_update')
            assert 'value1' == result['test2']
            assert entity['PartitionKey'] == u'001'
            assert entity['RowKey'] == u'batch_update'
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_batch_merge(self, tables_cosmos_account_name,
                         tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = u'001'
            entity['RowKey'] = u'batch_merge'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = u'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()
            self.table.create_entity(entity)

            resp_entity = self.table.get_entity(partition_key=u'001',
                                                row_key=u'batch_merge')
            assert 3 == entity['test3']
            entity = TableEntity()
            entity['PartitionKey'] = u'001'
            entity['RowKey'] = u'batch_merge'
            entity['test2'] = u'value1'

            batch = [('update', entity, {'mode': UpdateMode.MERGE})]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            resp_entity = self.table.get_entity(partition_key=u'001',
                                                row_key=u'batch_merge')
            assert entity['test2'] == resp_entity['test2']
            assert 1234567890 == resp_entity['test4']
            assert entity['PartitionKey'] == resp_entity['PartitionKey']
            assert entity['RowKey'] == resp_entity['RowKey']
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_batch_update_if_match(self, tables_cosmos_account_name,
                                   tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict()
            resp = self.table.create_entity(entity=entity)
            etag = resp['etag']

            # Act
            sent_entity = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])
            batch = [('update', sent_entity, {
                'mode': UpdateMode.REPLACE,
                'etag': etag,
                'match_condition': MatchConditions.IfNotModified,
                'mode': UpdateMode.REPLACE
            })]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            entity = self.table.get_entity(
                partition_key=entity['PartitionKey'], row_key=entity['RowKey'])
            self._assert_updated_entity(entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_batch_update_if_doesnt_match(self, tables_cosmos_account_name,
                                          tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict()
            self.table.create_entity(entity)

            # Act
            sent_entity1 = self._create_updated_entity_dict(
                entity['PartitionKey'], entity['RowKey'])

            batch = [('update', sent_entity1, {
                'etag': u'W/"datetime\'2012-06-15T22%3A51%3A44.9662825Z\'"',
                'match_condition': MatchConditions.IfNotModified
            })]
            with pytest.raises(TableTransactionError):
                self.table.submit_transaction(batch)

            # Assert
            received_entity = self.table.get_entity(entity['PartitionKey'],
                                                    entity['RowKey'])
            self._assert_default_entity(received_entity)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_batch_insert_replace(self, tables_cosmos_account_name,
                                  tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = '001'
            entity['RowKey'] = 'batch_insert_replace'
            entity['test'] = True
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()

            batch = [('upsert', entity, {'mode': UpdateMode.REPLACE})]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            entity = self.table.get_entity('001', 'batch_insert_replace')
            assert entity is not None
            assert 'value' == entity['test2']
            assert 1234567890 == entity['test4']
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_batch_insert_merge(self, tables_cosmos_account_name,
                                tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = '001'
            entity['RowKey'] = 'batch_insert_merge'
            entity['test'] = True
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()

            batch = [('upsert', entity, {'mode': UpdateMode.MERGE})]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' in transaction_result[0]

            entity = self.table.get_entity('001', 'batch_insert_merge')
            assert entity is not None
            assert 'value' == entity['test2']
            assert 1234567890 == entity['test4']
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_batch_delete(self, tables_cosmos_account_name,
                          tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = u'001'
            entity['RowKey'] = u'batch_delete'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = u'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()
            self.table.create_entity(entity)

            entity = self.table.get_entity(partition_key=u'001',
                                           row_key=u'batch_delete')
            assert 3 == entity['test3']

            batch = [('delete', entity)]
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result, 1)
            assert 'etag' not in transaction_result[0]

            with pytest.raises(ResourceNotFoundError):
                entity = self.table.get_entity(
                    partition_key=entity['PartitionKey'],
                    row_key=entity['RowKey'])
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_batch_inserts(self, tables_cosmos_account_name,
                           tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = 'batch_inserts'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)

            transaction_count = 0
            batch = []
            for i in range(100):
                entity['RowKey'] = str(i)
                batch.append(('create', entity.copy()))
                transaction_count += 1
            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result,
                                                 transaction_count)
            assert 'etag' in transaction_result[0]

            entities = list(
                self.table.query_entities("PartitionKey eq 'batch_inserts'"))

            # Assert
            assert entities is not None
            assert transaction_count == len(entities)
            e = self.table.get_entity('batch_inserts', '1')
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_batch_all_operations_together(self, tables_cosmos_account_name,
                                           tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            # Act
            entity = TableEntity()
            entity['PartitionKey'] = '003'
            entity['RowKey'] = 'batch_all_operations_together-1'
            entity['test'] = EntityProperty(True, EdmType.BOOLEAN)
            entity['test2'] = 'value'
            entity['test3'] = 3
            entity['test4'] = EntityProperty(1234567890, EdmType.INT32)
            entity['test5'] = datetime.utcnow()

            self.table.create_entity(entity)
            entity['RowKey'] = 'batch_all_operations_together-2'
            self.table.create_entity(entity)
            entity['RowKey'] = 'batch_all_operations_together-3'
            self.table.create_entity(entity)
            entity['RowKey'] = 'batch_all_operations_together-4'
            self.table.create_entity(entity)
            transaction_count = 0

            batch = []
            entity['RowKey'] = 'batch_all_operations_together'
            batch.append((TransactionOperation.CREATE, entity.copy()))
            transaction_count += 1

            entity['RowKey'] = 'batch_all_operations_together-1'
            batch.append((TransactionOperation.DELETE, entity.copy()))
            transaction_count += 1

            entity['RowKey'] = 'batch_all_operations_together-2'
            entity['test3'] = 10
            batch.append((TransactionOperation.UPDATE, entity.copy()))
            transaction_count += 1

            entity['RowKey'] = 'batch_all_operations_together-3'
            entity['test3'] = 100
            batch.append((TransactionOperation.UPDATE, entity.copy(), {
                'mode': UpdateMode.REPLACE
            }))
            transaction_count += 1

            entity['RowKey'] = 'batch_all_operations_together-4'
            entity['test3'] = 10
            batch.append((TransactionOperation.UPSERT, entity.copy()))
            transaction_count += 1

            entity['RowKey'] = 'batch_all_operations_together-5'
            batch.append((TransactionOperation.UPSERT, entity.copy(), {
                'mode': UpdateMode.REPLACE
            }))
            transaction_count += 1

            transaction_result = self.table.submit_transaction(batch)

            # Assert
            self._assert_valid_batch_transaction(transaction_result,
                                                 transaction_count)
            assert 'etag' in transaction_result[0]
            assert 'etag' not in transaction_result[1]
            assert 'etag' in transaction_result[2]
            assert 'etag' in transaction_result[3]
            assert 'etag' in transaction_result[4]
            assert 'etag' in transaction_result[5]

            # Assert
            entities = list(self.table.query_entities("PartitionKey eq '003'"))
            assert 5 == len(entities)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_batch_different_partition_operations_fail(
            self, tables_cosmos_account_name,
            tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            # Act
            batch = []

            entity = self._create_updated_entity_dict('001',
                                                      'batch_negative_1')
            batch.append(('update', entity.copy()))

            entity = self._create_random_entity_dict('002', 'batch_negative_1')
            batch.append(('update', entity.copy()))

            with pytest.raises(ValueError):
                self.table.submit_transaction(batch)
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_new_non_existent_table(self, tables_cosmos_account_name,
                                    tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')

            tc = self.ts.get_table_client("doesntexist")

            batch = [('create', entity)]

            with pytest.raises(TableTransactionError):
                resp = tc.submit_transaction(batch)
            # Assert
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_new_delete_nonexistent_entity(self, tables_cosmos_account_name,
                                           tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')

            batch = [('delete', entity)]
            with pytest.raises(TableTransactionError):
                resp = self.table.submit_transaction(batch)

        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @cosmos_decorator
    def test_delete_batch_with_bad_kwarg(self, tables_cosmos_account_name,
                                         tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            entity = self._create_random_entity_dict('001', 'batch_negative_1')
            self.table.create_entity(entity)

            received = self.table.get_entity(entity["PartitionKey"],
                                             entity["RowKey"])
            good_etag = received.metadata["etag"]
            received.metadata[
                "etag"] = u'W/"datetime\'2012-06-15T22%3A51%3A44.9662825Z\'"'

            batch = [('delete', received, {
                "match_condition": MatchConditions.IfNotModified
            })]

            with pytest.raises(TableTransactionError):
                self.table.submit_transaction(batch)

            received.metadata["etag"] = good_etag
            batch = [('delete', received, {
                "match_condition": MatchConditions.IfNotModified
            })]
            resp = self.table.submit_transaction(batch)

            assert resp is not None
        finally:
            self._tear_down()

    @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
    @pytest.mark.live_test_only  # Request bodies are very large
    @cosmos_decorator
    def test_batch_request_too_large(self, tables_cosmos_account_name,
                                     tables_primary_cosmos_account_key):
        # Arrange
        self._set_up(tables_cosmos_account_name,
                     tables_primary_cosmos_account_key)
        try:
            batch = []
            entity = {
                'PartitionKey': 'pk001',
                'Foo': os.urandom(1024 * 64),
                'Bar': os.urandom(1024 * 64),
                'Baz': os.urandom(1024 * 64)
            }
            for i in range(50):
                entity['RowKey'] = str(i)
                batch.append(('create', entity.copy()))

            with pytest.raises(RequestTooLargeError):
                self.table.submit_transaction(batch)

        finally:
            self._tear_down()
Example #24
0
class TestStorageRetry(AzureRecordedTestCase, TableTestCase):
    def _set_up(self,
                tables_storage_account_name,
                tables_primary_storage_account_key,
                url='table',
                default_table=True,
                **kwargs):
        self.table_name = self.get_resource_name('uttable')
        self.ts = TableServiceClient(
            self.account_url(tables_storage_account_name, url),
            credential=tables_primary_storage_account_key,
            **kwargs)
        self.table = self.ts.get_table_client(self.table_name)
        if self.is_live and default_table:
            try:
                self.ts.create_table(self.table_name)
            except ResourceExistsError:
                pass

        self.query_tables = []

    # TODO: Figure out why this is needed by the "test_retry_on_socket_timeout" test
    def _tear_down(self, **kwargs):
        if self.is_live:
            try:
                self.ts.delete_table(self.table_name, **kwargs)
            except:
                pass

            try:
                for table_name in self.query_tables:
                    try:
                        self.ts.delete_table(table_name, **kwargs)
                    except:
                        pass
            except AttributeError:
                pass

    # --Test Cases --------------------------------------------
    @tables_decorator
    @recorded_by_proxy
    def test_retry_on_server_error(self, tables_storage_account_name,
                                   tables_primary_storage_account_key):
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key,
                     default_table=False)
        try:
            callback = ResponseCallback(status=201,
                                        new_status=500).override_status

            new_table_name = self.get_resource_name('uttable')
            # The initial create will return 201, but we overwrite it with 500 and retry.
            # The retry will then get a 409 conflict.
            with pytest.raises(ResourceExistsError):
                self.ts.create_table(new_table_name,
                                     raw_response_hook=callback)
        finally:
            self.ts.delete_table(new_table_name)
            self._tear_down()

    @tables_decorator
    @recorded_by_proxy
    def test_retry_on_timeout(self, tables_storage_account_name,
                              tables_primary_storage_account_key):
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key,
                     default_table=False,
                     retry_mode=RetryMode.Exponential,
                     retry_backoff_factor=1)

        callback = ResponseCallback(status=200,
                                    new_status=408).override_first_status
        try:
            # The initial get will return 200, but we overwrite it with 408 and retry.
            # The retry will then succeed.
            self.ts.get_service_properties(raw_response_hook=callback)
        finally:
            self._tear_down()

    @pytest.mark.live_test_only
    @tables_decorator
    def test_retry_on_socket_timeout(self, tables_storage_account_name,
                                     tables_primary_storage_account_key):
        retry_transport = RetryRequestTransport(connection_timeout=11,
                                                read_timeout=0.000000000001)
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key,
                     transport=retry_transport,
                     default_table=False,
                     retry_mode=RetryMode.Fixed,
                     retry_backoff_factor=1)

        with pytest.raises(AzureError) as error:
            self.ts.get_service_properties()

        # 3 retries + 1 original == 4
        assert retry_transport.count == 4
        # This call should succeed on the server side, but fail on the client side due to socket timeout
        assert 'read timeout' in str(
            error.value
        ), 'Expected socket timeout but got different exception.'

    @tables_decorator
    @recorded_by_proxy
    def test_no_retry(self, tables_storage_account_name,
                      tables_primary_storage_account_key):
        self._set_up(tables_storage_account_name,
                     tables_primary_storage_account_key,
                     retry_total=0,
                     default_table=False)

        new_table_name = self.get_resource_name('uttable')

        # Force the create call to 'timeout' with a 408
        callback = ResponseCallback(status=201, new_status=500).override_status

        try:
            with pytest.raises(HttpResponseError) as error:
                self.ts.create_table(new_table_name,
                                     raw_response_hook=callback)
            assert error.value.response.status_code == 500
            assert error.value.reason == 'Created'

        finally:
            self.ts.delete_table(new_table_name)
            self._tear_down()