Skip to content

Commit

Permalink
feat: omit an empty 'transaction' field from write/txn reflected context
Browse files Browse the repository at this point in the history
  • Loading branch information
edaniszewski committed Mar 11, 2020
1 parent 5b9cdde commit 44c8515
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 25 deletions.
6 changes: 3 additions & 3 deletions synse_server/cmd/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import synse_grpc.utils
from structlog import get_logger

from synse_server import cache, errors, plugin
from synse_server import cache, errors, plugin, utils

logger = get_logger()

Expand Down Expand Up @@ -54,8 +54,8 @@ async def transaction(transaction_id: str) -> Dict[str, Any]:

status = synse_grpc.utils.to_dict(response)
status['device'] = device
if status.get('context', {}).get('data'):
status['context']['data'] = status['context']['data'].decode('utf-8')
utils.normalize_write_ctx(status)

return status


Expand Down
14 changes: 6 additions & 8 deletions synse_server/cmd/write.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
from typing import Any, Dict, List, Union

from structlog import get_logger
from synse_grpc import utils
from synse_grpc import utils as grpc_utils

from synse_server import cache, errors
from synse_server import cache, errors, utils

logger = get_logger()

Expand Down Expand Up @@ -36,9 +36,8 @@ async def write_async(device_id: str, payload: Union[Dict, List[Dict]]) -> List[
for txn in client.write_async(device_id=device_id, data=payload):
# Add the transaction to the cache
await cache.add_transaction(txn.id, txn.device, plugin.id)
rsp = utils.to_dict(txn)
if rsp.get('context', {}).get('data'):
rsp['context']['data'] = rsp['context']['data'].decode('utf-8')
rsp = grpc_utils.to_dict(txn)
utils.normalize_write_ctx(rsp)
response.append(rsp)
except Exception as e:
raise errors.ServerError(
Expand Down Expand Up @@ -75,10 +74,9 @@ async def write_sync(device_id: str, payload: Union[Dict, List[Dict]]) -> List[D
for status in client.write_sync(device_id=device_id, data=payload):
# Add the transaction to the cache
await cache.add_transaction(status.id, device_id, plugin.id)
s = utils.to_dict(status)
s = grpc_utils.to_dict(status)
s['device'] = device_id
if s.get('context', {}).get('data'):
s['context']['data'] = s['context']['data'].decode('utf-8')
utils.normalize_write_ctx(s)
response.append(s)
except Exception as e:
raise errors.ServerError(
Expand Down
24 changes: 24 additions & 0 deletions synse_server/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,30 @@
from synse_server import config


def normalize_write_ctx(data: Dict) -> None:
"""Normalize the given write context for consistent response formatting.
The write context is the dictionary under the 'context' key which contains
the reflected write data (action, data, transaction) which is included as
part of the API write and transaction responses.
The normalization process includes:
* Ensuring the "data" field is encoded as utf-8
* Ensuring that an empty "transaction" field is omitted from the response.
"""
if 'context' not in data:
return

# Ensure the 'data' field is encoded as utf-8
if 'data' in data['context']:
if isinstance(data['context']['data'], bytes):
data['context']['data'] = data['context']['data'].decode('utf-8')

# Ensure an empty 'transaction' field is omitted
if 'transaction' in data['context'] and not data['context']['transaction']:
del data['context']['transaction']


def rfc3339now() -> str:
"""Create an RFC3339 formatted timestamp for the current UTC time.
Expand Down
3 changes: 1 addition & 2 deletions tests/unit/cmd/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,7 @@ async def test_transaction_client_ok(mocker, simple_plugin):
'timeout': '',
'context': {
'action': 'test',
'data': b'',
'transaction': '',
'data': '',
},
}

Expand Down
18 changes: 6 additions & 12 deletions tests/unit/cmd/test_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,7 @@ async def test_write_async_ok(mocker, simple_plugin):
'timeout': '5s',
'context': {
'action': 'foo',
'data': b'',
'transaction': '',
'data': '',
},
},
{
Expand All @@ -164,8 +163,7 @@ async def test_write_async_ok(mocker, simple_plugin):
'timeout': '5s',
'context': {
'action': 'bar',
'data': b'',
'transaction': '',
'data': '',
},
},
{
Expand All @@ -174,8 +172,7 @@ async def test_write_async_ok(mocker, simple_plugin):
'timeout': '5s',
'context': {
'action': 'baz',
'data': b'',
'transaction': '',
'data': '',
},
},
]
Expand Down Expand Up @@ -354,8 +351,7 @@ async def test_write_sync_ok(mocker, simple_plugin):
'status': 'DONE',
'context': {
'action': 'foo',
'data': b'',
'transaction': '',
'data': '',
},
},
{
Expand All @@ -368,8 +364,7 @@ async def test_write_sync_ok(mocker, simple_plugin):
'status': 'DONE',
'context': {
'action': 'bar',
'data': b'',
'transaction': '',
'data': '',
},
},
{
Expand All @@ -382,8 +377,7 @@ async def test_write_sync_ok(mocker, simple_plugin):
'status': 'DONE',
'context': {
'action': 'baz',
'data': b'',
'transaction': '',
'data': '',
},
},
]
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@
from synse_server import utils


@pytest.mark.parametrize(
'data,expected', [
({}, {}),
({'foo': 'bar'}, {'foo': 'bar'}),
({'context': {'data': 'abc'}}, {'context': {'data': 'abc'}}),
({'context': {'data': b'abc'}}, {'context': {'data': 'abc'}}),
({'context': {'transaction': None}}, {'context': {}}),
({'context': {'transaction': ''}}, {'context': {}}),
({'context': {'transaction': '123'}}, {'context': {'transaction': '123'}}),
(
{'context': {'data': b'10', 'transaction': '', 'action': 'a'}},
{'context': {'data': '10', 'action': 'a'}},
),
],
)
def test_normalize_write_ctx(data, expected):
utils.normalize_write_ctx(data)
assert data == expected


@pytest.mark.usefixtures('patch_datetime_utcnow')
def test_rfc3339now():
actual = utils.rfc3339now()
Expand Down

0 comments on commit 44c8515

Please sign in to comment.