From 14fd6db996a38d5b3ba9121e897625894f0577b0 Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Mon, 14 Mar 2016 11:07:32 -0700 Subject: [PATCH] Adding system tests for HappyBase Table.cells() and scan(). --- system_tests/bigtable_happybase.py | 212 +++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) diff --git a/system_tests/bigtable_happybase.py b/system_tests/bigtable_happybase.py index 48cb44ce8a05..dbb45612dbf2 100644 --- a/system_tests/bigtable_happybase.py +++ b/system_tests/bigtable_happybase.py @@ -44,6 +44,7 @@ } ROW_KEY1 = 'row-key1' ROW_KEY2 = 'row-key2a' +ROW_KEY3 = 'row-key2b' COL1 = COL_FAM1 + ':qual1' COL2 = COL_FAM1 + ':qual2' COL3 = COL_FAM2 + ':qual1' @@ -406,6 +407,217 @@ def test_rows_with_timestamp(self): self.assertEqual(rows, [(ROW_KEY1, {COL2: (value3, ts3)})]) +class TestTable_cells(BaseTableTest): + + def test_cells(self): + table = Config.TABLE + value1 = 'value1' + value2 = 'value2' + value3 = 'value3' + + # Need to clean-up row1 after. + self.rows_to_delete.append(ROW_KEY1) + table.put(ROW_KEY1, {COL1: value1}) + table.put(ROW_KEY1, {COL1: value2}) + table.put(ROW_KEY1, {COL1: value3}) + + # Check with no extra arguments. + all_values = table.cells(ROW_KEY1, COL1) + self.assertEqual(all_values, [value3, value2, value1]) + + # Check the timestamp on all the cells. + all_cells = table.cells(ROW_KEY1, COL1, include_timestamp=True) + self.assertEqual(len(all_cells), 3) + + ts3 = all_cells[0][1] + ts2 = all_cells[1][1] + ts1 = all_cells[2][1] + self.assertEqual(all_cells, + [(value3, ts3), (value2, ts2), (value1, ts1)]) + + # Limit to the two latest cells. + latest_two = table.cells(ROW_KEY1, COL1, include_timestamp=True, + versions=2) + self.assertEqual(latest_two, [(value3, ts3), (value2, ts2)]) + + # Limit to cells before the 2nd timestamp (inclusive). + first_two = table.cells(ROW_KEY1, COL1, include_timestamp=True, + timestamp=ts2 + 1) + self.assertEqual(first_two, [(value2, ts2), (value1, ts1)]) + + # Limit to cells before the 2nd timestamp (exclusive). + first_cell = table.cells(ROW_KEY1, COL1, include_timestamp=True, + timestamp=ts2) + self.assertEqual(first_cell, [(value1, ts1)]) + + +class TestTable_scan(BaseTableTest): + + def test_scan_when_empty(self): + scan_result = list(Config.TABLE.scan()) + self.assertEqual(scan_result, []) + + def test_scan_single_row(self): + table = Config.TABLE + value1 = 'value1' + value2 = 'value2' + row1_data = {COL1: value1, COL2: value2} + + # Need to clean-up row1 after. + self.rows_to_delete.append(ROW_KEY1) + table.put(ROW_KEY1, row1_data) + + scan_result = list(table.scan()) + self.assertEqual(scan_result, [(ROW_KEY1, row1_data)]) + + scan_result_cols = list(table.scan(columns=[COL1])) + self.assertEqual(scan_result_cols, [(ROW_KEY1, {COL1: value1})]) + + scan_result_ts = list(table.scan(include_timestamp=True)) + self.assertEqual(len(scan_result_ts), 1) + only_row = scan_result_ts[0] + self.assertEqual(only_row[0], ROW_KEY1) + row_values = only_row[1] + ts = row_values[COL1][1] + self.assertEqual(row_values, {COL1: (value1, ts), COL2: (value2, ts)}) + + def test_scan_filters(self): + table = Config.TABLE + value1 = 'value1' + value2 = 'value2' + value3 = 'value3' + value4 = 'value4' + value5 = 'value5' + value6 = 'value6' + row1_data = {COL1: value1, COL2: value2} + row2_data = {COL2: value3, COL3: value4} + row3_data = {COL3: value5, COL4: value6} + + # Need to clean-up row1/2/3 after. + self.rows_to_delete.append(ROW_KEY1) + self.rows_to_delete.append(ROW_KEY2) + self.rows_to_delete.append(ROW_KEY3) + table.put(ROW_KEY1, row1_data) + table.put(ROW_KEY2, row2_data) + table.put(ROW_KEY3, row3_data) + + # Basic scan (no filters) + scan_result = list(table.scan()) + self.assertEqual(scan_result, [ + (ROW_KEY1, row1_data), + (ROW_KEY2, row2_data), + (ROW_KEY3, row3_data), + ]) + + # Limit the size of the scan + scan_result = list(table.scan(limit=1)) + self.assertEqual(scan_result, [ + (ROW_KEY1, row1_data), + ]) + + # Scan with a row prefix. + prefix = ROW_KEY2[:-1] + self.assertEqual(prefix, ROW_KEY3[:-1]) + scan_result_prefixed = list(table.scan(row_prefix=prefix)) + self.assertEqual(scan_result_prefixed, [ + (ROW_KEY2, row2_data), + (ROW_KEY3, row3_data), + ]) + + # Make sure our keys are sorted in order + row_keys = [ROW_KEY1, ROW_KEY2, ROW_KEY3] + self.assertEqual(row_keys, sorted(row_keys)) + + # row_start alone (inclusive) + scan_result_row_start = list(table.scan(row_start=ROW_KEY2)) + self.assertEqual(scan_result_row_start, [ + (ROW_KEY2, row2_data), + (ROW_KEY3, row3_data), + ]) + + # row_stop alone (exclusive) + scan_result_row_stop = list(table.scan(row_stop=ROW_KEY2)) + self.assertEqual(scan_result_row_stop, [ + (ROW_KEY1, row1_data), + ]) + + # Both row_start and row_stop + scan_result_row_stop_and_start = list( + table.scan(row_start=ROW_KEY1, row_stop=ROW_KEY3)) + self.assertEqual(scan_result_row_stop_and_start, [ + (ROW_KEY1, row1_data), + (ROW_KEY2, row2_data), + ]) + + def test_scan_timestamp(self): + table = Config.TABLE + value1 = 'value1' + value2 = 'value2' + value3 = 'value3' + value4 = 'value4' + value5 = 'value5' + value6 = 'value6' + + # Need to clean-up row1/2/3 after. + self.rows_to_delete.append(ROW_KEY1) + self.rows_to_delete.append(ROW_KEY2) + self.rows_to_delete.append(ROW_KEY3) + table.put(ROW_KEY3, {COL4: value6}) + table.put(ROW_KEY2, {COL3: value4}) + table.put(ROW_KEY2, {COL2: value3}) + table.put(ROW_KEY1, {COL2: value2}) + table.put(ROW_KEY3, {COL3: value5}) + table.put(ROW_KEY1, {COL1: value1}) + + # Retrieve all the timestamps so we can filter with them. + scan_result = list(table.scan(include_timestamp=True)) + self.assertEqual(len(scan_result), 3) + row1, row2, row3 = scan_result + self.assertEqual(row1[0], ROW_KEY1) + self.assertEqual(row2[0], ROW_KEY2) + self.assertEqual(row3[0], ROW_KEY3) + + # Drop the keys now that we have checked. + _, row1 = row1 + _, row2 = row2 + _, row3 = row3 + + # These are numbered in order of insertion, **not** in + # the order of the values. + ts1 = row3[COL4][1] + ts2 = row2[COL3][1] + ts3 = row2[COL2][1] + ts4 = row1[COL2][1] + ts5 = row3[COL3][1] + ts6 = row1[COL1][1] + + self.assertEqual(row1, {COL1: (value1, ts6), COL2: (value2, ts4)}) + self.assertEqual(row2, {COL2: (value3, ts3), COL3: (value4, ts2)}) + self.assertEqual(row3, {COL3: (value5, ts5), COL4: (value6, ts1)}) + + # All cells before ts1 (exclusive) + scan_result_before_ts1 = list(table.scan(timestamp=ts1, + include_timestamp=True)) + self.assertEqual(scan_result_before_ts1, []) + + # All cells before ts2 (inclusive) + scan_result_before_ts2 = list(table.scan(timestamp=ts2 + 1, + include_timestamp=True)) + self.assertEqual(scan_result_before_ts2, [ + (ROW_KEY2, {COL3: (value4, ts2)}), + (ROW_KEY3, {COL4: (value6, ts1)}), + ]) + + # All cells before ts6 (exclusive) + scan_result_before_ts6 = list(table.scan(timestamp=ts6, + include_timestamp=True)) + self.assertEqual(scan_result_before_ts6, [ + (ROW_KEY1, {COL2: (value2, ts4)}), + (ROW_KEY2, {COL2: (value3, ts3), COL3: (value4, ts2)}), + (ROW_KEY3, {COL3: (value5, ts5), COL4: (value6, ts1)}), + ]) + + class TestTableCounterMethods(BaseTableTest): def test_counter_get(self):