Skip to content

Commit

Permalink
Implementing HappyBase Table.put()/delete().
Browse files Browse the repository at this point in the history
These don't really do anything because Batch.put() and Batch.delete()
are not implemented yet.
  • Loading branch information
dhermes committed Sep 7, 2015
1 parent 7c49336 commit 031243b
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 22 deletions.
20 changes: 8 additions & 12 deletions gcloud_bigtable/happybase/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ def scan(self, row_start=None, row_stop=None, row_prefix=None,
"""
raise NotImplementedError('Temporarily not implemented.')

def put(self, row, data, timestamp=None, wal=True):
def put(self, row, data, timestamp=None, wal=_WAL_SENTINEL):
"""Insert data into a row in this table.
.. note::
Expand All @@ -359,18 +359,16 @@ def put(self, row, data, timestamp=None, wal=True):
:param timestamp: (Optional) Timestamp (in milliseconds since the
epoch) that the mutation will be applied at.
:type wal: :data:`NoneType <types.NoneType>`
:type wal: object
:param wal: Unused parameter (to be passed to a created batch).
Provided for compatibility with HappyBase, but irrelevant
for Cloud Bigtable since it does not have a Write Ahead
Log.
:raises: :class:`NotImplementedError <exceptions.NotImplementedError>`
temporarily until the method is implemented.
"""
raise NotImplementedError('Temporarily not implemented.')
with self.batch(timestamp=timestamp, wal=wal) as batch:
batch.put(row, data)

def delete(self, row, columns=None, timestamp=None, wal=True):
def delete(self, row, columns=None, timestamp=None, wal=_WAL_SENTINEL):
"""Delete data from a row in this table.
This method deletes the entire ``row`` if ``columns`` is not
Expand All @@ -397,16 +395,14 @@ def delete(self, row, columns=None, timestamp=None, wal=True):
:param timestamp: (Optional) Timestamp (in milliseconds since the
epoch) that the mutation will be applied at.
:type wal: :data:`NoneType <types.NoneType>`
:type wal: object
:param wal: Unused parameter (to be passed to a created batch).
Provided for compatibility with HappyBase, but irrelevant
for Cloud Bigtable since it does not have a Write Ahead
Log.
:raises: :class:`NotImplementedError <exceptions.NotImplementedError>`
temporarily until the method is implemented.
"""
raise NotImplementedError('Temporarily not implemented.')
with self.batch(timestamp=timestamp, wal=wal) as batch:
batch.delete(row, columns)

def batch(self, timestamp=None, batch_size=None, transaction=False,
wal=_WAL_SENTINEL):
Expand Down
98 changes: 88 additions & 10 deletions gcloud_bigtable/happybase/test_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,29 +265,86 @@ def test_scan(self):
limit=limit, sorted_columns=sorted_columns)

def test_put(self):
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable.happybase import table as MUT
from gcloud_bigtable.happybase.table import _WAL_SENTINEL

name = 'table-name'
connection = object()
table = self._makeOne(name, connection)
batches_created = []

def make_batch(*args, **kwargs):
result = _MockBatch(*args, **kwargs)
batches_created.append(result)
return result

row = 'row-key'
data = {'fam:col': 'foo'}
timestamp = None
with self.assertRaises(NotImplementedError):
table.put(row, data, timestamp=timestamp)
with _Monkey(MUT, Batch=make_batch):
result = table.put(row, data, timestamp=timestamp)

# There is no return value.
self.assertEqual(result, None)

# Check how the batch was created and used.
batch, = batches_created
self.assertTrue(isinstance(batch, _MockBatch))
self.assertEqual(batch.args, (table,))
expected_kwargs = {
'timestamp': timestamp,
'batch_size': None,
'transaction': False,
'wal': _WAL_SENTINEL,
}
self.assertEqual(batch.kwargs, expected_kwargs)
# Make sure it was a successful context manager
self.assertEqual(batch.exit_vals, [(None, None, None)])
self.assertEqual(batch.put_args, [(row, data)])
self.assertEqual(batch.delete_args, [])

def test_delete(self):
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable.happybase import table as MUT
from gcloud_bigtable.happybase.table import _WAL_SENTINEL

name = 'table-name'
connection = object()
table = self._makeOne(name, connection)
batches_created = []

def make_batch(*args, **kwargs):
result = _MockBatch(*args, **kwargs)
batches_created.append(result)
return result

row = 'row-key'
columns = ['fam:col1', 'fam:col2']
timestamp = None
with self.assertRaises(NotImplementedError):
table.delete(row, columns=columns, timestamp=timestamp)
with _Monkey(MUT, Batch=make_batch):
result = table.delete(row, columns=columns, timestamp=timestamp)

# There is no return value.
self.assertEqual(result, None)

# Check how the batch was created and used.
batch, = batches_created
self.assertTrue(isinstance(batch, _MockBatch))
self.assertEqual(batch.args, (table,))
expected_kwargs = {
'timestamp': timestamp,
'batch_size': None,
'transaction': False,
'wal': _WAL_SENTINEL,
}
self.assertEqual(batch.kwargs, expected_kwargs)
# Make sure it was a successful context manager
self.assertEqual(batch.exit_vals, [(None, None, None)])
self.assertEqual(batch.put_args, [])
self.assertEqual(batch.delete_args, [(row, columns)])

def test_batch(self):
from gcloud_bigtable._testing import _MockCalled
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable.happybase import table as MUT

Expand All @@ -300,20 +357,19 @@ def test_batch(self):
transaction = False # Must be False when batch_size is non-null
wal = object()

batch_result = object()
mock_batch = _MockCalled(batch_result)
with _Monkey(MUT, Batch=mock_batch):
with _Monkey(MUT, Batch=_MockBatch):
result = table.batch(timestamp=timestamp, batch_size=batch_size,
transaction=transaction, wal=wal)

self.assertEqual(result, batch_result)
self.assertTrue(isinstance(result, _MockBatch))
self.assertEqual(result.args, (table,))
expected_kwargs = {
'timestamp': timestamp,
'batch_size': batch_size,
'transaction': transaction,
'wal': wal,
}
mock_batch.check_called(self, [(table,)], [expected_kwargs])
self.assertEqual(result.kwargs, expected_kwargs)

def test_counter_get(self):
name = 'table-name'
Expand Down Expand Up @@ -383,3 +439,25 @@ class _Connection(object):

def __init__(self, cluster):
self._cluster = cluster


class _MockBatch(object):

def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
self.exit_vals = []
self.put_args = []
self.delete_args = []

def __enter__(self):
return self

def __exit__(self, exc_type, exc_value, traceback):
self.exit_vals.append((exc_type, exc_value, traceback))

def put(self, *args):
self.put_args.append(args)

def delete(self, *args):
self.delete_args.append(args)

0 comments on commit 031243b

Please sign in to comment.