Skip to content
This repository has been archived by the owner on Mar 28, 2019. It is now read-only.

Commit

Permalink
Pass User-Agent header to sync (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
leplatrem committed Nov 11, 2015
1 parent 48b34ca commit 321a8f8
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 16 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Expand Up @@ -7,7 +7,7 @@ This document describes changes between each past release.
1.4.0 (unreleased)
------------------

- Nothing changed yet.
- Pass User-Agent header to sync (#68)


1.3.0 (2015-10-27)
Expand Down
12 changes: 12 additions & 0 deletions syncto/headers.py
@@ -1,12 +1,24 @@
from cliquet import utils
from cliquet.errors import raise_invalid

from syncto import __version__


def import_headers(syncto_request, sync_request_headers=None):
"""Convert incoming Kinto headers into Sync headers."""
request_headers = syncto_request.headers
headers = sync_request_headers or {}

# For server-side analytics, keep original User-Agent.

ua = "Syncto/%s" % __version__
original_ua = request_headers.get('User-Agent')
if original_ua:
ua += " (on behalf of %s)" % original_ua
headers['User-Agent'] = ua

# Handle concurrency control.

if 'If-Match' in request_headers:
if_match = request_headers['If-Match']
try:
Expand Down
56 changes: 41 additions & 15 deletions syncto/tests/test_functional.py
Expand Up @@ -5,6 +5,8 @@
from cliquet.errors import ERRORS
from cliquet.tests.support import FormattedErrorMixin
from requests.exceptions import HTTPError, ConnectionError

from syncto import __version__
from syncto import AUTHORIZATION_HEADER, CLIENT_STATE_HEADER
from syncto import main as testapp
from syncto.heartbeat import ping_sync_cluster
Expand All @@ -21,6 +23,9 @@
}
}

_USER_AGENT = 'Syncto/%s' % __version__
_DEFAULT_SYNC_HEADERS = {'User-Agent': _USER_AGENT}


class SettingsMissingTest(unittest.TestCase):
MANDATORY_SETTINGS = {
Expand All @@ -34,14 +39,16 @@ def test_syncto_cache_hmac_secret_missing(self):
self.assertRaises(ValueError, testapp, {}, **settings)


class ErrorsTest(FormattedErrorMixin, BaseWebTest, unittest.TestCase):
class KintoJsCompatTest(BaseWebTest, unittest.TestCase):

def test_public_settings_are_shown_in_view_prefixed_with_cliquet(self):
response = self.app.get('/')
settings = response.json['settings']
expected = {'batch_max_requests': 25,
'cliquet.batch_max_requests': 25}
self.assertEqual(expected, settings)
self.assertEqual(settings['batch_max_requests'], 25)
self.assertEqual(settings['cliquet.batch_max_requests'], 25)


class ErrorsTest(FormattedErrorMixin, BaseWebTest, unittest.TestCase):

def test_authorization_header_is_required_for_collection(self):
resp = self.app.get(COLLECTION_URL, headers=self.headers, status=401)
Expand Down Expand Up @@ -190,14 +197,24 @@ def test_collection_handle_cache_control_headers(self):
headers=self.headers, status=200)
self.assertIn('Cache-Control', resp.headers)

def test_original_user_agent_is_passed_to_sync(self):
headers = self.headers.copy()
headers['User-Agent'] = 'HTTPie/0.9.2'
self.app.get(COLLECTION_URL, headers=headers)

expected = '%s (on behalf of HTTPie/0.9.2)' % _USER_AGENT
self.sync_client.return_value.get_records.assert_called_with(
"tabs", full=True, headers={'User-Agent': expected})

def test_collection_handle_since_parameter(self):
self.app.get(COLLECTION_URL,
params={'_since': '14377478425700',
'_sort': 'newest'},
headers=self.headers, status=200)

self.sync_client.return_value.get_records.assert_called_with(
"tabs", full=True, newer='14377478425.70', sort='newest',
headers={})
headers=_DEFAULT_SYNC_HEADERS)

def test_collection_handles_if_none_match_headers(self):
headers = self.headers.copy()
Expand All @@ -206,9 +223,12 @@ def test_collection_handles_if_none_match_headers(self):
params={'_since': '14377478425700',
'_sort': 'newest'},
headers=headers, status=200)

expected = {'X-If-Modified-Since': '14377478425.70'}
expected.update(_DEFAULT_SYNC_HEADERS)
self.sync_client.return_value.get_records.assert_called_with(
"tabs", full=True, newer='14377478425.70', sort='newest',
headers={'X-If-Modified-Since': '14377478425.70'})
headers=expected)

def test_collection_handle_if_match_headers(self):
headers = self.headers.copy()
Expand All @@ -217,9 +237,12 @@ def test_collection_handle_if_match_headers(self):
params={'_since': '14377478425700',
'_sort': 'newest'},
headers=headers, status=200)

expected = {'X-If-Unmodified-Since': '14377478425.70'}
expected.update(_DEFAULT_SYNC_HEADERS)
self.sync_client.return_value.get_records.assert_called_with(
"tabs", full=True, newer='14377478425.70', sort='newest',
headers={'X-If-Unmodified-Since': '14377478425.70'})
headers=expected)

def test_collection_raises_on_wrong_if_none_match_header_value(self):
headers = self.headers.copy()
Expand Down Expand Up @@ -255,14 +278,14 @@ def test_collection_handle_limit_and_token_parameters(self):
headers=self.headers, status=200)
self.sync_client.return_value.get_records.assert_called_with(
"tabs", full=True, limit='2', offset='12345', sort='index',
headers={})
headers=_DEFAULT_SYNC_HEADERS)

def test_collection_handles_oldest_sort(self):
self.app.get(COLLECTION_URL,
params={'_sort': 'oldest'},
headers=self.headers, status=200)
self.sync_client.return_value.get_records.assert_called_with(
"tabs", full=True, sort='oldest', headers={})
"tabs", full=True, sort='oldest', headers=_DEFAULT_SYNC_HEADERS)

def test_collection_raises_with_invalid_sort_parameter(self):
resp = self.app.get(COLLECTION_URL,
Expand Down Expand Up @@ -340,11 +363,13 @@ def test_can_delete_record_handles_if_match_headers(self):

headers = self.headers.copy()
headers['If-Match'] = '"14377478425700"'

self.app.delete(RECORD_URL, headers=headers, status=204)

expected = {'X-If-Unmodified-Since': '14377478425.70'}
expected.update(_DEFAULT_SYNC_HEADERS)
self.sync_client.return_value.delete_record.assert_called_with(
"tabs", RECORD_URL.split('/')[-1],
headers={'X-If-Unmodified-Since': '14377478425.70'})
headers=expected)

def test_delete_return_a_503_in_case_of_unknown_error(self):
response = mock.MagicMock()
Expand Down Expand Up @@ -384,10 +409,11 @@ def test_put_record_handles_if_none_match_headers(self):

self.app.put_json(RECORD_URL, RECORD_EXAMPLE,
headers=headers, status=200)
put_record_mock = self.sync_client.return_value.put_record
self.assertDictEqual(
put_record_mock.mock_calls[0][2]['headers'],
{'X-If-Unmodified-Since': 0})

expected = {'X-If-Unmodified-Since': 0}
expected.update(_DEFAULT_SYNC_HEADERS)
put_record_arg = self.sync_client.return_value.put_record.mock_calls[0]
self.assertDictEqual(put_record_arg[2]['headers'], expected)

def test_put_record_reject_invalid_record(self):
invalid = {"payload": "foobar"}
Expand Down

0 comments on commit 321a8f8

Please sign in to comment.