Skip to content

Commit 15ca673

Browse files
committed
Adding HappyBase system tests for families and counters.
These tests exposed an issue with regex filters. When a protobuf bytes field received a unicode object, bad things happened.
1 parent 72617b3 commit 15ca673

File tree

5 files changed

+94
-11
lines changed

5 files changed

+94
-11
lines changed

gcloud/bigtable/happybase/test_table.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,8 +1265,8 @@ def _column_helper(self, num_filters, versions=None, timestamp=None,
12651265

12661266
# Relies on the fact that RowFilter instances can
12671267
# only have one value set.
1268-
self.assertEqual(fam_filter.regex, col_fam)
1269-
self.assertEqual(qual_filter.regex, qual)
1268+
self.assertEqual(fam_filter.regex, col_fam.encode('utf-8'))
1269+
self.assertEqual(qual_filter.regex, qual.encode('utf-8'))
12701270

12711271
return result
12721272

@@ -1356,14 +1356,14 @@ def test_column_and_column_families(self):
13561356
filter2 = result.filters[1]
13571357

13581358
self.assertTrue(isinstance(filter1, FamilyNameRegexFilter))
1359-
self.assertEqual(filter1.regex, col_fam1)
1359+
self.assertEqual(filter1.regex, col_fam1.encode('utf-8'))
13601360

13611361
self.assertTrue(isinstance(filter2, RowFilterChain))
13621362
filter2a, filter2b = filter2.filters
13631363
self.assertTrue(isinstance(filter2a, FamilyNameRegexFilter))
1364-
self.assertEqual(filter2a.regex, col_fam2)
1364+
self.assertEqual(filter2a.regex, col_fam2.encode('utf-8'))
13651365
self.assertTrue(isinstance(filter2b, ColumnQualifierRegexFilter))
1366-
self.assertEqual(filter2b.regex, col_qual2)
1366+
self.assertEqual(filter2b.regex, col_qual2.encode('utf-8'))
13671367

13681368

13691369
class Test__row_keys_filter_helper(unittest2.TestCase):

gcloud/bigtable/row.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,7 @@ class _RegexFilter(RowFilter):
870870
"""
871871

872872
def __init__(self, regex):
873-
self.regex = regex
873+
self.regex = _to_bytes(regex)
874874

875875
def __eq__(self, other):
876876
if not isinstance(other, self.__class__):

gcloud/bigtable/test_row.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -771,24 +771,29 @@ def _makeOne(self, *args, **kwargs):
771771
return self._getTargetClass()(*args, **kwargs)
772772

773773
def test_constructor(self):
774-
regex = object()
774+
regex = b'abc'
775775
row_filter = self._makeOne(regex)
776776
self.assertTrue(row_filter.regex is regex)
777777

778+
def test_constructor_non_bytes(self):
779+
regex = u'abc'
780+
row_filter = self._makeOne(regex)
781+
self.assertEqual(row_filter.regex, b'abc')
782+
778783
def test___eq__type_differ(self):
779-
regex = object()
784+
regex = b'def-rgx'
780785
row_filter1 = self._makeOne(regex)
781786
row_filter2 = object()
782787
self.assertNotEqual(row_filter1, row_filter2)
783788

784789
def test___eq__same_value(self):
785-
regex = object()
790+
regex = b'trex-regex'
786791
row_filter1 = self._makeOne(regex)
787792
row_filter2 = self._makeOne(regex)
788793
self.assertEqual(row_filter1, row_filter2)
789794

790795
def test___ne__same_value(self):
791-
regex = object()
796+
regex = b'abc'
792797
row_filter1 = self._makeOne(regex)
793798
row_filter2 = self._makeOne(regex)
794799
comparison_val = (row_filter1 != row_filter2)

scripts/run_pylint.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
}
6767
TEST_RC_REPLACEMENTS = {
6868
'FORMAT': {
69-
'max-module-lines': 1825,
69+
'max-module-lines': 1830,
7070
},
7171
}
7272

system_tests/bigtable_happybase.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515

16+
import struct
1617
import time
1718

1819
import unittest2
@@ -23,6 +24,7 @@
2324
from gcloud.environment_vars import TESTS_PROJECT
2425

2526

27+
_PACK_I64 = struct.Struct('>q').pack
2628
_helpers.PROJECT = TESTS_PROJECT
2729
ZONE = 'us-central1-c'
2830
NOW_MILLIS = int(1000 * time.time())
@@ -38,6 +40,8 @@
3840
COL_FAM2: {'max_versions': 1, 'time_to_live': TTL_FOR_TEST},
3941
COL_FAM3: {}, # use defaults
4042
}
43+
ROW_KEY1 = 'row-key1'
44+
COL1 = COL_FAM1 + ':qual1'
4145

4246

4347
class Config(object):
@@ -111,3 +115,77 @@ def test_create_table_failure(self):
111115
with self.assertRaises(ValueError):
112116
connection.create_table(ALT_TABLE_NAME, empty_families)
113117
self.assertFalse(ALT_TABLE_NAME in connection.tables())
118+
119+
120+
class BaseTableTest(unittest2.TestCase):
121+
122+
def setUp(self):
123+
self.rows_to_delete = []
124+
125+
def tearDown(self):
126+
for row_key in self.rows_to_delete:
127+
Config.TABLE.delete(row_key)
128+
129+
130+
class TestTable_families(BaseTableTest):
131+
132+
def test_families(self):
133+
families = Config.TABLE.families()
134+
135+
self.assertEqual(set(families.keys()), set(FAMILIES.keys()))
136+
for col_fam, settings in FAMILIES.items():
137+
retrieved = families[col_fam]
138+
for key, value in settings.items():
139+
self.assertEqual(retrieved[key], value)
140+
141+
142+
class TestTableCounterMethods(BaseTableTest):
143+
144+
def test_counter_get(self):
145+
table = Config.TABLE
146+
147+
# Need to clean-up row1 after.
148+
self.rows_to_delete.append(ROW_KEY1)
149+
150+
self.assertEqual(table.row(ROW_KEY1, columns=[COL1]), {})
151+
initial_counter = table.counter_get(ROW_KEY1, COL1)
152+
self.assertEqual(initial_counter, 0)
153+
154+
self.assertEqual(table.row(ROW_KEY1, columns=[COL1]),
155+
{COL1: _PACK_I64(0)})
156+
157+
def test_counter_inc(self):
158+
table = Config.TABLE
159+
160+
# Need to clean-up row1 after.
161+
self.rows_to_delete.append(ROW_KEY1)
162+
163+
self.assertEqual(table.row(ROW_KEY1, columns=[COL1]), {})
164+
initial_counter = table.counter_get(ROW_KEY1, COL1)
165+
self.assertEqual(initial_counter, 0)
166+
167+
inc_value = 10
168+
updated_counter = table.counter_inc(ROW_KEY1, COL1, value=inc_value)
169+
self.assertEqual(updated_counter, inc_value)
170+
171+
# Check that the value is set (does not seem to occur on HBase).
172+
self.assertEqual(table.row(ROW_KEY1, columns=[COL1]),
173+
{COL1: _PACK_I64(inc_value)})
174+
175+
def test_counter_dec(self):
176+
table = Config.TABLE
177+
178+
# Need to clean-up row1 after.
179+
self.rows_to_delete.append(ROW_KEY1)
180+
181+
self.assertEqual(table.row(ROW_KEY1, columns=[COL1]), {})
182+
initial_counter = table.counter_get(ROW_KEY1, COL1)
183+
self.assertEqual(initial_counter, 0)
184+
185+
dec_value = 10
186+
updated_counter = table.counter_dec(ROW_KEY1, COL1, value=dec_value)
187+
self.assertEqual(updated_counter, -dec_value)
188+
189+
# Check that the value is set (does not seem to occur on HBase).
190+
self.assertEqual(table.row(ROW_KEY1, columns=[COL1]),
191+
{COL1: _PACK_I64(-dec_value)})

0 commit comments

Comments
 (0)