683 lines
24 KiB
Python
683 lines
24 KiB
Python
|
# Copyright 2016 Google Inc. All rights reserved.
|
||
|
#
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at
|
||
|
#
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
#
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
|
||
|
|
||
|
import sys
|
||
|
|
||
|
import unittest2
|
||
|
|
||
|
|
||
|
class Test__get_instance(unittest2.TestCase):
|
||
|
|
||
|
def _callFUT(self, timeout=None):
|
||
|
from gcloud.bigtable.happybase.connection import _get_instance
|
||
|
return _get_instance(timeout=timeout)
|
||
|
|
||
|
def _helper(self, timeout=None, instances=(), failed_locations=()):
|
||
|
from functools import partial
|
||
|
from gcloud._testing import _Monkey
|
||
|
from gcloud.bigtable.happybase import connection as MUT
|
||
|
|
||
|
client_with_instances = partial(
|
||
|
_Client, instances=instances, failed_locations=failed_locations)
|
||
|
with _Monkey(MUT, Client=client_with_instances):
|
||
|
result = self._callFUT(timeout=timeout)
|
||
|
|
||
|
# If we've reached this point, then _callFUT didn't fail, so we know
|
||
|
# there is exactly one instance.
|
||
|
instance, = instances
|
||
|
self.assertEqual(result, instance)
|
||
|
client = instance.client
|
||
|
self.assertEqual(client.args, ())
|
||
|
expected_kwargs = {'admin': True}
|
||
|
if timeout is not None:
|
||
|
expected_kwargs['timeout_seconds'] = timeout / 1000.0
|
||
|
self.assertEqual(client.kwargs, expected_kwargs)
|
||
|
self.assertEqual(client.start_calls, 1)
|
||
|
self.assertEqual(client.stop_calls, 1)
|
||
|
|
||
|
def test_default(self):
|
||
|
instance = _Instance()
|
||
|
self._helper(instances=[instance])
|
||
|
|
||
|
def test_with_timeout(self):
|
||
|
instance = _Instance()
|
||
|
self._helper(timeout=2103, instances=[instance])
|
||
|
|
||
|
def test_with_no_instances(self):
|
||
|
with self.assertRaises(ValueError):
|
||
|
self._helper()
|
||
|
|
||
|
def test_with_too_many_instances(self):
|
||
|
instances = [_Instance(), _Instance()]
|
||
|
with self.assertRaises(ValueError):
|
||
|
self._helper(instances=instances)
|
||
|
|
||
|
def test_with_failed_locations(self):
|
||
|
instance = _Instance()
|
||
|
failed_location = 'us-central1-c'
|
||
|
with self.assertRaises(ValueError):
|
||
|
self._helper(instances=[instance],
|
||
|
failed_locations=[failed_location])
|
||
|
|
||
|
|
||
|
class TestConnection(unittest2.TestCase):
|
||
|
|
||
|
def _getTargetClass(self):
|
||
|
from gcloud.bigtable.happybase.connection import Connection
|
||
|
return Connection
|
||
|
|
||
|
def _makeOne(self, *args, **kwargs):
|
||
|
return self._getTargetClass()(*args, **kwargs)
|
||
|
|
||
|
def test_constructor_defaults(self):
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
self.assertEqual(instance._client.start_calls, 0)
|
||
|
connection = self._makeOne(instance=instance)
|
||
|
self.assertEqual(instance._client.start_calls, 1)
|
||
|
self.assertEqual(instance._client.stop_calls, 0)
|
||
|
|
||
|
self.assertEqual(connection._instance, instance)
|
||
|
self.assertEqual(connection.table_prefix, None)
|
||
|
self.assertEqual(connection.table_prefix_separator, '_')
|
||
|
|
||
|
def test_constructor_no_autoconnect(self):
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
self.assertEqual(instance._client.start_calls, 0)
|
||
|
self.assertEqual(instance._client.stop_calls, 0)
|
||
|
self.assertEqual(connection.table_prefix, None)
|
||
|
self.assertEqual(connection.table_prefix_separator, '_')
|
||
|
|
||
|
def test_constructor_missing_instance(self):
|
||
|
from gcloud._testing import _Monkey
|
||
|
from gcloud.bigtable.happybase import connection as MUT
|
||
|
|
||
|
instance = _Instance()
|
||
|
timeout = object()
|
||
|
get_instance_called = []
|
||
|
|
||
|
def mock_get_instance(timeout):
|
||
|
get_instance_called.append(timeout)
|
||
|
return instance
|
||
|
|
||
|
with _Monkey(MUT, _get_instance=mock_get_instance):
|
||
|
connection = self._makeOne(autoconnect=False, instance=None,
|
||
|
timeout=timeout)
|
||
|
self.assertEqual(connection.table_prefix, None)
|
||
|
self.assertEqual(connection.table_prefix_separator, '_')
|
||
|
self.assertEqual(connection._instance, instance)
|
||
|
|
||
|
self.assertEqual(get_instance_called, [timeout])
|
||
|
|
||
|
def test_constructor_explicit(self):
|
||
|
autoconnect = False
|
||
|
table_prefix = 'table-prefix'
|
||
|
table_prefix_separator = 'sep'
|
||
|
instance_copy = _Instance()
|
||
|
instance = _Instance(copies=[instance_copy])
|
||
|
|
||
|
connection = self._makeOne(
|
||
|
autoconnect=autoconnect,
|
||
|
table_prefix=table_prefix,
|
||
|
table_prefix_separator=table_prefix_separator,
|
||
|
instance=instance)
|
||
|
self.assertEqual(connection.table_prefix, table_prefix)
|
||
|
self.assertEqual(connection.table_prefix_separator,
|
||
|
table_prefix_separator)
|
||
|
|
||
|
def test_constructor_with_unknown_argument(self):
|
||
|
instance = _Instance()
|
||
|
with self.assertRaises(TypeError):
|
||
|
self._makeOne(instance=instance, unknown='foo')
|
||
|
|
||
|
def test_constructor_with_legacy_args(self):
|
||
|
from gcloud._testing import _Monkey
|
||
|
from gcloud.bigtable.happybase import connection as MUT
|
||
|
|
||
|
warned = []
|
||
|
|
||
|
def mock_warn(msg):
|
||
|
warned.append(msg)
|
||
|
|
||
|
instance = _Instance()
|
||
|
with _Monkey(MUT, _WARN=mock_warn):
|
||
|
self._makeOne(instance=instance, host=object(),
|
||
|
port=object(), compat=object(),
|
||
|
transport=object(), protocol=object())
|
||
|
|
||
|
self.assertEqual(len(warned), 1)
|
||
|
self.assertIn('host', warned[0])
|
||
|
self.assertIn('port', warned[0])
|
||
|
self.assertIn('compat', warned[0])
|
||
|
self.assertIn('transport', warned[0])
|
||
|
self.assertIn('protocol', warned[0])
|
||
|
|
||
|
def test_constructor_with_timeout_and_instance(self):
|
||
|
instance = _Instance()
|
||
|
with self.assertRaises(ValueError):
|
||
|
self._makeOne(instance=instance, timeout=object())
|
||
|
|
||
|
def test_constructor_non_string_prefix(self):
|
||
|
table_prefix = object()
|
||
|
|
||
|
with self.assertRaises(TypeError):
|
||
|
self._makeOne(autoconnect=False,
|
||
|
table_prefix=table_prefix)
|
||
|
|
||
|
def test_constructor_non_string_prefix_separator(self):
|
||
|
table_prefix_separator = object()
|
||
|
|
||
|
with self.assertRaises(TypeError):
|
||
|
self._makeOne(autoconnect=False,
|
||
|
table_prefix_separator=table_prefix_separator)
|
||
|
|
||
|
def test_open(self):
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
self.assertEqual(instance._client.start_calls, 0)
|
||
|
connection.open()
|
||
|
self.assertEqual(instance._client.start_calls, 1)
|
||
|
self.assertEqual(instance._client.stop_calls, 0)
|
||
|
|
||
|
def test_close(self):
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
self.assertEqual(instance._client.stop_calls, 0)
|
||
|
connection.close()
|
||
|
self.assertEqual(instance._client.stop_calls, 1)
|
||
|
self.assertEqual(instance._client.start_calls, 0)
|
||
|
|
||
|
def test___del__with_instance(self):
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
self.assertEqual(instance._client.stop_calls, 0)
|
||
|
connection.__del__()
|
||
|
self.assertEqual(instance._client.stop_calls, 1)
|
||
|
|
||
|
def test___del__no_instance(self):
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
self.assertEqual(instance._client.stop_calls, 0)
|
||
|
del connection._instance
|
||
|
connection.__del__()
|
||
|
self.assertEqual(instance._client.stop_calls, 0)
|
||
|
|
||
|
def test__table_name_with_prefix_set(self):
|
||
|
table_prefix = 'table-prefix'
|
||
|
table_prefix_separator = '<>'
|
||
|
instance = _Instance()
|
||
|
|
||
|
connection = self._makeOne(
|
||
|
autoconnect=False,
|
||
|
table_prefix=table_prefix,
|
||
|
table_prefix_separator=table_prefix_separator,
|
||
|
instance=instance)
|
||
|
|
||
|
name = 'some-name'
|
||
|
prefixed = connection._table_name(name)
|
||
|
self.assertEqual(prefixed,
|
||
|
table_prefix + table_prefix_separator + name)
|
||
|
|
||
|
def test__table_name_with_no_prefix_set(self):
|
||
|
instance = _Instance()
|
||
|
connection = self._makeOne(autoconnect=False,
|
||
|
instance=instance)
|
||
|
|
||
|
name = 'some-name'
|
||
|
prefixed = connection._table_name(name)
|
||
|
self.assertEqual(prefixed, name)
|
||
|
|
||
|
def test_table_factory(self):
|
||
|
from gcloud.bigtable.happybase.table import Table
|
||
|
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
|
||
|
name = 'table-name'
|
||
|
table = connection.table(name)
|
||
|
|
||
|
self.assertTrue(isinstance(table, Table))
|
||
|
self.assertEqual(table.name, name)
|
||
|
self.assertEqual(table.connection, connection)
|
||
|
|
||
|
def _table_factory_prefix_helper(self, use_prefix=True):
|
||
|
from gcloud.bigtable.happybase.table import Table
|
||
|
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
table_prefix = 'table-prefix'
|
||
|
table_prefix_separator = '<>'
|
||
|
connection = self._makeOne(
|
||
|
autoconnect=False, table_prefix=table_prefix,
|
||
|
table_prefix_separator=table_prefix_separator,
|
||
|
instance=instance)
|
||
|
|
||
|
name = 'table-name'
|
||
|
table = connection.table(name, use_prefix=use_prefix)
|
||
|
|
||
|
self.assertTrue(isinstance(table, Table))
|
||
|
prefixed_name = table_prefix + table_prefix_separator + name
|
||
|
if use_prefix:
|
||
|
self.assertEqual(table.name, prefixed_name)
|
||
|
else:
|
||
|
self.assertEqual(table.name, name)
|
||
|
self.assertEqual(table.connection, connection)
|
||
|
|
||
|
def test_table_factory_with_prefix(self):
|
||
|
self._table_factory_prefix_helper(use_prefix=True)
|
||
|
|
||
|
def test_table_factory_with_ignored_prefix(self):
|
||
|
self._table_factory_prefix_helper(use_prefix=False)
|
||
|
|
||
|
def test_tables(self):
|
||
|
from gcloud.bigtable.table import Table
|
||
|
|
||
|
table_name1 = 'table-name1'
|
||
|
table_name2 = 'table-name2'
|
||
|
instance = _Instance(list_tables_result=[
|
||
|
Table(table_name1, None),
|
||
|
Table(table_name2, None),
|
||
|
])
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
result = connection.tables()
|
||
|
self.assertEqual(result, [table_name1, table_name2])
|
||
|
|
||
|
def test_tables_with_prefix(self):
|
||
|
from gcloud.bigtable.table import Table
|
||
|
|
||
|
table_prefix = 'prefix'
|
||
|
table_prefix_separator = '<>'
|
||
|
unprefixed_table_name1 = 'table-name1'
|
||
|
|
||
|
table_name1 = (table_prefix + table_prefix_separator +
|
||
|
unprefixed_table_name1)
|
||
|
table_name2 = 'table-name2'
|
||
|
instance = _Instance(list_tables_result=[
|
||
|
Table(table_name1, None),
|
||
|
Table(table_name2, None),
|
||
|
])
|
||
|
connection = self._makeOne(
|
||
|
autoconnect=False, instance=instance, table_prefix=table_prefix,
|
||
|
table_prefix_separator=table_prefix_separator)
|
||
|
result = connection.tables()
|
||
|
self.assertEqual(result, [unprefixed_table_name1])
|
||
|
|
||
|
def test_create_table(self):
|
||
|
import operator
|
||
|
from gcloud._testing import _Monkey
|
||
|
from gcloud.bigtable.happybase import connection as MUT
|
||
|
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
mock_gc_rule = object()
|
||
|
called_options = []
|
||
|
|
||
|
def mock_parse_family_option(option):
|
||
|
called_options.append(option)
|
||
|
return mock_gc_rule
|
||
|
|
||
|
name = 'table-name'
|
||
|
col_fam1 = 'cf1'
|
||
|
col_fam_option1 = object()
|
||
|
col_fam2 = u'cf2'
|
||
|
col_fam_option2 = object()
|
||
|
col_fam3 = b'cf3'
|
||
|
col_fam_option3 = object()
|
||
|
families = {
|
||
|
col_fam1: col_fam_option1,
|
||
|
# A trailing colon is also allowed.
|
||
|
col_fam2 + ':': col_fam_option2,
|
||
|
col_fam3 + b':': col_fam_option3,
|
||
|
}
|
||
|
|
||
|
tables_created = []
|
||
|
|
||
|
def make_table(*args, **kwargs):
|
||
|
result = _MockLowLevelTable(*args, **kwargs)
|
||
|
tables_created.append(result)
|
||
|
return result
|
||
|
|
||
|
with _Monkey(MUT, _LowLevelTable=make_table,
|
||
|
_parse_family_option=mock_parse_family_option):
|
||
|
connection.create_table(name, families)
|
||
|
|
||
|
# Just one table would have been created.
|
||
|
table_instance, = tables_created
|
||
|
self.assertEqual(table_instance.args, (name, instance))
|
||
|
self.assertEqual(table_instance.kwargs, {})
|
||
|
self.assertEqual(table_instance.create_calls, 1)
|
||
|
|
||
|
# Check if our mock was called twice, but we don't know the order.
|
||
|
self.assertEqual(
|
||
|
set(called_options),
|
||
|
set([col_fam_option1, col_fam_option2, col_fam_option3]))
|
||
|
|
||
|
# We expect three column family instances created, but don't know the
|
||
|
# order due to non-deterministic dict.items().
|
||
|
col_fam_created = table_instance.col_fam_created
|
||
|
self.assertEqual(len(col_fam_created), 3)
|
||
|
col_fam_created.sort(key=operator.attrgetter('column_family_id'))
|
||
|
self.assertEqual(col_fam_created[0].column_family_id, col_fam1)
|
||
|
self.assertEqual(col_fam_created[0].gc_rule, mock_gc_rule)
|
||
|
self.assertEqual(col_fam_created[0].create_calls, 1)
|
||
|
self.assertEqual(col_fam_created[1].column_family_id, col_fam2)
|
||
|
self.assertEqual(col_fam_created[1].gc_rule, mock_gc_rule)
|
||
|
self.assertEqual(col_fam_created[1].create_calls, 1)
|
||
|
self.assertEqual(col_fam_created[2].column_family_id,
|
||
|
col_fam3.decode('utf-8'))
|
||
|
self.assertEqual(col_fam_created[2].gc_rule, mock_gc_rule)
|
||
|
self.assertEqual(col_fam_created[2].create_calls, 1)
|
||
|
|
||
|
def test_create_table_bad_type(self):
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
|
||
|
name = 'table-name'
|
||
|
families = None
|
||
|
with self.assertRaises(TypeError):
|
||
|
connection.create_table(name, families)
|
||
|
|
||
|
def test_create_table_bad_value(self):
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
|
||
|
name = 'table-name'
|
||
|
families = {}
|
||
|
with self.assertRaises(ValueError):
|
||
|
connection.create_table(name, families)
|
||
|
|
||
|
def _create_table_error_helper(self, err_val, err_type):
|
||
|
from gcloud._testing import _Monkey
|
||
|
from gcloud.bigtable.happybase import connection as MUT
|
||
|
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
|
||
|
tables_created = []
|
||
|
|
||
|
def make_table(*args, **kwargs):
|
||
|
kwargs['create_error'] = err_val
|
||
|
result = _MockLowLevelTable(*args, **kwargs)
|
||
|
tables_created.append(result)
|
||
|
return result
|
||
|
|
||
|
name = 'table-name'
|
||
|
families = {'foo': {}}
|
||
|
with _Monkey(MUT, _LowLevelTable=make_table):
|
||
|
with self.assertRaises(err_type):
|
||
|
connection.create_table(name, families)
|
||
|
|
||
|
self.assertEqual(len(tables_created), 1)
|
||
|
self.assertEqual(tables_created[0].create_calls, 1)
|
||
|
|
||
|
@unittest2.skipUnless(sys.version_info[:2] == (2, 7),
|
||
|
'gRPC only in Python 2.7')
|
||
|
def test_create_table_already_exists(self):
|
||
|
from grpc.beta import interfaces
|
||
|
from grpc.framework.interfaces.face import face
|
||
|
from gcloud.bigtable.happybase.connection import AlreadyExists
|
||
|
|
||
|
err_val = face.NetworkError(None, None,
|
||
|
interfaces.StatusCode.ALREADY_EXISTS, None)
|
||
|
self._create_table_error_helper(err_val, AlreadyExists)
|
||
|
|
||
|
@unittest2.skipUnless(sys.version_info[:2] == (2, 7),
|
||
|
'gRPC only in Python 2.7')
|
||
|
def test_create_table_connection_error(self):
|
||
|
from grpc.beta import interfaces
|
||
|
from grpc.framework.interfaces.face import face
|
||
|
err_val = face.NetworkError(None, None,
|
||
|
interfaces.StatusCode.INTERNAL, None)
|
||
|
self._create_table_error_helper(err_val, face.NetworkError)
|
||
|
|
||
|
@unittest2.skipUnless(sys.version_info[:2] == (2, 7),
|
||
|
'gRPC only in Python 2.7')
|
||
|
def test_create_table_other_error(self):
|
||
|
self._create_table_error_helper(RuntimeError, RuntimeError)
|
||
|
|
||
|
def _delete_table_helper(self, disable=False):
|
||
|
from gcloud._testing import _Monkey
|
||
|
from gcloud.bigtable.happybase import connection as MUT
|
||
|
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
|
||
|
tables_created = []
|
||
|
|
||
|
def make_table(*args, **kwargs):
|
||
|
result = _MockLowLevelTable(*args, **kwargs)
|
||
|
tables_created.append(result)
|
||
|
return result
|
||
|
|
||
|
name = 'table-name'
|
||
|
with _Monkey(MUT, _LowLevelTable=make_table):
|
||
|
connection.delete_table(name, disable=disable)
|
||
|
|
||
|
# Just one table would have been created.
|
||
|
table_instance, = tables_created
|
||
|
self.assertEqual(table_instance.args, (name, instance))
|
||
|
self.assertEqual(table_instance.kwargs, {})
|
||
|
self.assertEqual(table_instance.delete_calls, 1)
|
||
|
|
||
|
def test_delete_table(self):
|
||
|
self._delete_table_helper()
|
||
|
|
||
|
def test_delete_table_disable(self):
|
||
|
from gcloud._testing import _Monkey
|
||
|
from gcloud.bigtable.happybase import connection as MUT
|
||
|
|
||
|
warned = []
|
||
|
|
||
|
def mock_warn(msg):
|
||
|
warned.append(msg)
|
||
|
|
||
|
with _Monkey(MUT, _WARN=mock_warn):
|
||
|
self._delete_table_helper(disable=True)
|
||
|
|
||
|
self.assertEqual(warned, [MUT._DISABLE_DELETE_MSG])
|
||
|
|
||
|
def test_enable_table(self):
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
|
||
|
name = 'table-name'
|
||
|
with self.assertRaises(NotImplementedError):
|
||
|
connection.enable_table(name)
|
||
|
|
||
|
def test_disable_table(self):
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
|
||
|
name = 'table-name'
|
||
|
with self.assertRaises(NotImplementedError):
|
||
|
connection.disable_table(name)
|
||
|
|
||
|
def test_is_table_enabled(self):
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
|
||
|
name = 'table-name'
|
||
|
with self.assertRaises(NotImplementedError):
|
||
|
connection.is_table_enabled(name)
|
||
|
|
||
|
def test_compact_table(self):
|
||
|
instance = _Instance() # Avoid implicit environ check.
|
||
|
connection = self._makeOne(autoconnect=False, instance=instance)
|
||
|
|
||
|
name = 'table-name'
|
||
|
major = True
|
||
|
with self.assertRaises(NotImplementedError):
|
||
|
connection.compact_table(name, major=major)
|
||
|
|
||
|
|
||
|
class Test__parse_family_option(unittest2.TestCase):
|
||
|
|
||
|
def _callFUT(self, option):
|
||
|
from gcloud.bigtable.happybase.connection import _parse_family_option
|
||
|
return _parse_family_option(option)
|
||
|
|
||
|
def test_dictionary_no_keys(self):
|
||
|
option = {}
|
||
|
result = self._callFUT(option)
|
||
|
self.assertEqual(result, None)
|
||
|
|
||
|
def test_null(self):
|
||
|
option = None
|
||
|
result = self._callFUT(option)
|
||
|
self.assertEqual(result, None)
|
||
|
|
||
|
def test_dictionary_bad_key(self):
|
||
|
from gcloud._testing import _Monkey
|
||
|
from gcloud.bigtable.happybase import connection as MUT
|
||
|
|
||
|
warned = []
|
||
|
|
||
|
def mock_warn(msg):
|
||
|
warned.append(msg)
|
||
|
|
||
|
option = {'badkey': None}
|
||
|
with _Monkey(MUT, _WARN=mock_warn):
|
||
|
result = self._callFUT(option)
|
||
|
|
||
|
self.assertEqual(result, None)
|
||
|
self.assertEqual(len(warned), 1)
|
||
|
self.assertIn('badkey', warned[0])
|
||
|
|
||
|
def test_dictionary_versions_key(self):
|
||
|
from gcloud.bigtable.column_family import MaxVersionsGCRule
|
||
|
|
||
|
versions = 42
|
||
|
option = {'max_versions': versions}
|
||
|
result = self._callFUT(option)
|
||
|
|
||
|
gc_rule = MaxVersionsGCRule(versions)
|
||
|
self.assertEqual(result, gc_rule)
|
||
|
|
||
|
def test_dictionary_ttl_key(self):
|
||
|
import datetime
|
||
|
from gcloud.bigtable.column_family import MaxAgeGCRule
|
||
|
|
||
|
time_to_live = 24 * 60 * 60
|
||
|
max_age = datetime.timedelta(days=1)
|
||
|
option = {'time_to_live': time_to_live}
|
||
|
result = self._callFUT(option)
|
||
|
|
||
|
gc_rule = MaxAgeGCRule(max_age)
|
||
|
self.assertEqual(result, gc_rule)
|
||
|
|
||
|
def test_dictionary_both_keys(self):
|
||
|
import datetime
|
||
|
from gcloud.bigtable.column_family import GCRuleIntersection
|
||
|
from gcloud.bigtable.column_family import MaxAgeGCRule
|
||
|
from gcloud.bigtable.column_family import MaxVersionsGCRule
|
||
|
|
||
|
versions = 42
|
||
|
time_to_live = 24 * 60 * 60
|
||
|
option = {
|
||
|
'max_versions': versions,
|
||
|
'time_to_live': time_to_live,
|
||
|
}
|
||
|
result = self._callFUT(option)
|
||
|
|
||
|
max_age = datetime.timedelta(days=1)
|
||
|
# NOTE: This relies on the order of the rules in the method we are
|
||
|
# calling matching this order here.
|
||
|
gc_rule1 = MaxAgeGCRule(max_age)
|
||
|
gc_rule2 = MaxVersionsGCRule(versions)
|
||
|
gc_rule = GCRuleIntersection(rules=[gc_rule1, gc_rule2])
|
||
|
self.assertEqual(result, gc_rule)
|
||
|
|
||
|
def test_non_dictionary(self):
|
||
|
option = object()
|
||
|
self.assertFalse(isinstance(option, dict))
|
||
|
result = self._callFUT(option)
|
||
|
self.assertEqual(result, option)
|
||
|
|
||
|
|
||
|
class _Client(object):
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
self.instances = kwargs.pop('instances', [])
|
||
|
for instance in self.instances:
|
||
|
instance.client = self
|
||
|
self.failed_locations = kwargs.pop('failed_locations', [])
|
||
|
self.args = args
|
||
|
self.kwargs = kwargs
|
||
|
self.start_calls = 0
|
||
|
self.stop_calls = 0
|
||
|
|
||
|
def start(self):
|
||
|
self.start_calls += 1
|
||
|
|
||
|
def stop(self):
|
||
|
self.stop_calls += 1
|
||
|
|
||
|
def list_instances(self):
|
||
|
return self.instances, self.failed_locations
|
||
|
|
||
|
|
||
|
class _Instance(object):
|
||
|
|
||
|
def __init__(self, copies=(), list_tables_result=()):
|
||
|
self.copies = list(copies)
|
||
|
# Included to support Connection.__del__
|
||
|
self._client = _Client()
|
||
|
self.list_tables_result = list_tables_result
|
||
|
|
||
|
def copy(self):
|
||
|
if self.copies:
|
||
|
result = self.copies[0]
|
||
|
self.copies[:] = self.copies[1:]
|
||
|
return result
|
||
|
else:
|
||
|
return self
|
||
|
|
||
|
def list_tables(self):
|
||
|
return self.list_tables_result
|
||
|
|
||
|
|
||
|
class _MockLowLevelColumnFamily(object):
|
||
|
|
||
|
def __init__(self, column_family_id, gc_rule=None):
|
||
|
self.column_family_id = column_family_id
|
||
|
self.gc_rule = gc_rule
|
||
|
self.create_calls = 0
|
||
|
|
||
|
def create(self):
|
||
|
self.create_calls += 1
|
||
|
|
||
|
|
||
|
class _MockLowLevelTable(object):
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
self.args = args
|
||
|
self.kwargs = kwargs
|
||
|
self.create_error = kwargs.get('create_error')
|
||
|
self.delete_calls = 0
|
||
|
self.create_calls = 0
|
||
|
self.col_fam_created = []
|
||
|
|
||
|
def delete(self):
|
||
|
self.delete_calls += 1
|
||
|
|
||
|
def create(self):
|
||
|
self.create_calls += 1
|
||
|
if self.create_error:
|
||
|
raise self.create_error
|
||
|
|
||
|
def column_family(self, column_family_id, gc_rule=None):
|
||
|
result = _MockLowLevelColumnFamily(column_family_id, gc_rule=gc_rule)
|
||
|
self.col_fam_created.append(result)
|
||
|
return result
|