forked from DonDebonair/slack-machine
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
60f58ed
commit 63b3934
Showing
6 changed files
with
124 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
from datetime import datetime, timedelta | ||
|
||
from happybase import Connection | ||
from machine.storage.backends.base import MachineBaseStorage | ||
|
||
|
||
def bytes_to_float(byte_arr): | ||
s = byte_arr.decode('utf-8') | ||
return float(s) | ||
|
||
|
||
def float_to_bytes(i): | ||
return bytes(str(i), 'utf-8') | ||
|
||
|
||
class HBaseStorage(MachineBaseStorage): | ||
|
||
_VAL = b'values:value' | ||
_EXP = b'values:expires_at' | ||
_COLS = [_VAL, _EXP] | ||
|
||
def __init__(self, settings): | ||
super().__init__(settings) | ||
hbase_host = settings['HBASE_HOST'] | ||
hbase_table = settings['HBASE_TABLE'] | ||
self._connection = Connection(hbase_host) | ||
self._table = self._connection.table(hbase_table) | ||
|
||
def _get_value(self, key): | ||
row = self._table.row(key, self._COLS) | ||
val = row.get(self._VAL) | ||
if val: | ||
exp = row.get(self._EXP) | ||
if not exp: | ||
return val | ||
elif datetime.fromtimestamp(bytes_to_float(exp)) > datetime.utcnow(): | ||
return val | ||
else: | ||
self.delete(key) | ||
return None | ||
return None | ||
|
||
def has(self, key): | ||
val = self._get_value(key) | ||
return bool(val) | ||
|
||
def get(self, key): | ||
return self._get_value(key) | ||
|
||
def set(self, key, value, expires=None): | ||
data = {self._VAL: value} | ||
if expires: | ||
expires_at = datetime.utcnow() + timedelta(seconds=expires) | ||
data[self._EXP] = float_to_bytes(expires_at.timestamp()) | ||
self._table.put(key, data) | ||
|
||
def delete(self, key): | ||
self._table.delete(key) | ||
|
||
def size(self): | ||
return 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import pytest | ||
from happybase import Table | ||
|
||
from machine.storage.backends.hbase import bytes_to_float, float_to_bytes, HBaseStorage | ||
|
||
_VAL = b'values:value' | ||
_EXP = b'values:expires_at' | ||
_COLS = [_VAL, _EXP] | ||
|
||
|
||
@pytest.fixture | ||
def table(mocker): | ||
table = mocker.MagicMock(spec=Table) | ||
ConnectionCls = mocker.patch('machine.storage.backends.hbase.Connection', autospec=True) | ||
instance = ConnectionCls.return_value | ||
instance.table.return_value = table | ||
return table | ||
|
||
|
||
@pytest.fixture | ||
def hbase_storage(table): | ||
return HBaseStorage({'HBASE_HOST': 'foo', 'HBASE_TABLE': 'bar'}) | ||
|
||
|
||
def test_float_conversion(): | ||
assert bytes_to_float(float_to_bytes(3.14159265359)) == 3.14159265359 | ||
|
||
|
||
def test_get(table, hbase_storage): | ||
hbase_storage.get('key1') | ||
table.row.assert_called_with('key1', _COLS) | ||
|
||
|
||
def test_has(table, hbase_storage): | ||
hbase_storage.has('key1') | ||
table.row.assert_called_with('key1', _COLS) | ||
|
||
|
||
def test_delete(table, hbase_storage): | ||
hbase_storage.delete('key1') | ||
table.delete.assert_called_with('key1') | ||
|
||
|
||
def test_set(table, hbase_storage): | ||
hbase_storage.set('key1', 'val1') | ||
table.put.assert_called_with('key1', {b'values:value': 'val1'}) |