def test_post_cached_with_id(self): response = post_through_spectre( '/post_id_cache/', data='{"request_id":123, "vary_id":"abc"}', extra_headers={'content-type': 'application/json'}) assert response.status_code == 200 assert response.headers['Spectre-Cache-Status'] == 'miss' # When calling with different data, we will see a cache miss. response = post_through_spectre( '/post_id_cache/', data='{"request_id":234, "vary_id":"abc"}', extra_headers={'content-type': 'application/json'}) assert response.status_code == 200 assert response.headers['Spectre-Cache-Status'] == 'miss' # When calling with different data with same id, we will see a cache miss. response = post_through_spectre( '/post_id_cache/', data='{"request_id":234, "vary_id":"def"}', extra_headers={'content-type': 'application/json'}) assert response.status_code == 200 assert response.headers['Spectre-Cache-Status'] == 'miss' # Calling again with same request_id should be a cache hit assert_is_in_spectre_cache( '/post_id_cache/', data='{"request_id":234, "vary_id":"abc"}', extra_headers={'content-type': 'application/json'})
def test_default_vary_headers(self): assert get_through_spectre('/long_ttl/vary').headers['Spectre-Cache-Status'] == 'miss' assert assert_is_in_spectre_cache('/long_ttl/vary') # namespace vary_headers do not contain X-Mode assert assert_is_in_spectre_cache('/long_ttl/vary', {'x-mode': 'ro'}) assert get_through_spectre('/long_ttl/vary', {'accept-encoding': 'text'}).headers['Spectre-Cache-Status'] == 'miss'
def test_purge_cassandra_by_id(self): get_through_spectre('/bulk_requester?ids=1') assert_is_in_spectre_cache('/bulk_requester?ids=1') # Purge id 1 purge_resource({'namespace': 'backend.main', 'cache_name': 'bulk_requester_does_not_cache_missing_ids', 'id': '1'}) get_resp_3 = get_through_spectre('/bulk_requester?ids=1') # resp 3 was no longer cached. assert get_resp_3.headers['Spectre-Cache-Status'] == 'miss'
def test_post_always_cached_for_extended_json_content_type(self): response = post_through_spectre( '/post_always_cache/', data={}, extra_headers={'content-type': 'application/json; charset=utf-8'}) assert response.status_code == 200 assert response.headers['Spectre-Cache-Status'] == 'miss' # When calling again the result should be cached assert_is_in_spectre_cache( '/post_always_cache/', data={}, extra_headers={'content-type': 'application/json; charset=utf-8'})
def test_post_cache_hit_even_if_body_doesnt_match_without_vary(self): response = post_through_spectre( '/post_always_cache/', data='{"field1":"key1"}', extra_headers={'content-type': 'application/json'}) assert response.status_code == 200 assert response.headers['Spectre-Cache-Status'] == 'miss' # When calling again the result should be cached assert_is_in_spectre_cache( '/post_always_cache/', data='{"field1":"key2"}', extra_headers={'content-type': 'application/json'})
def test_post_cached_with_id_ignore_fields(self): response = post_through_spectre( '/post_id_cache_variable_body/', data='{"request_id":234, "ignore_field1":"abc"}', extra_headers={'content-type': 'application/json'}) assert response.status_code == 200 assert response.headers['Spectre-Cache-Status'] == 'miss' # Calling again with more fields in body which are ignored would also be a cache hit assert_is_in_spectre_cache( '/post_id_cache_variable_body/', data= '{"request_id":234, "ignore_field1":"xyz", "ignore_field3":"21"}', extra_headers={'content-type': 'application/json'})
def test_spectre_status_response_header(self): response = get_through_spectre('/not_cacheable') assert response.headers['Spectre-Cache-Status'] == 'non-cacheable-uri (backend.main)' response = get_through_spectre('/timestamp/spectre_status_header') assert response.headers['Spectre-Cache-Status'] == 'miss' assert_is_in_spectre_cache('/timestamp/spectre_status_header') response = get_through_spectre('/timestamp/spectre_status_header', extra_headers={'Pragma': 'no-cache'}) assert response.headers['Spectre-Cache-Status'] == 'no-cache-header' response = post_through_spectre('/timestamp/spectre_status_header') assert response.headers['Spectre-Cache-Status'] == 'non-cacheable-method'
def test_different_vary_headers(self): # same vary header val1 = get_through_spectre('/timestamp/cached', {'accept-encoding': 'testzip, deflate, custom'}) assert val1.headers['Spectre-Cache-Status'] == 'miss' assert_is_in_spectre_cache('/timestamp/cached', {'accept-encoding': 'testzip, deflate, custom'}) # different vary headers --> val3 is a miss val3 = get_through_spectre('/timestamp/cached', {'accept-encoding': 'none'}) assert val3.headers['Spectre-Cache-Status'] == 'miss' # contains x-mode --> miss val4 = get_through_spectre('/timestamp/cached', {'X-Mode': 'ro'}) assert val4.headers['Spectre-Cache-Status'] == 'miss' # Host is not a Vary header --> hit assert_is_in_spectre_cache('/timestamp/cached', {'X-Mode': 'ro', 'Host': 'localhost'})
def test_caching_works_with_id_extraction(self): response = get_through_spectre('/biz?foo=bar&business_id=1234') assert response.headers['Spectre-Cache-Status'] == 'miss' # ensure extracting the id is not messing up the caching logic assert_is_in_spectre_cache('/biz?foo=bar&business_id=1234') # check that invalidation is actually supported purge_resource({ 'namespace': 'backend.main', 'cache_name': 'url_with_id_extraction', 'id': '1234', }) # now this should be a cache miss response = get_through_spectre('/biz?foo=bar&business_id=1234') assert response.headers['Spectre-Cache-Status'] == 'miss'
def test_post_cached_with_id_can_be_purged(self): response = post_through_spectre( '/post_id_cache/', data='{"request_id":123, "vary_id":"abc"}', extra_headers={'content-type': 'application/json'}) assert response.status_code == 200 assert response.headers['Spectre-Cache-Status'] == 'miss' # When calling with different data with same id, we will see a cache miss. response = post_through_spectre( '/post_id_cache/', data='{"request_id":123, "vary_id":"def"}', extra_headers={'content-type': 'application/json'}) assert response.status_code == 200 assert response.headers['Spectre-Cache-Status'] == 'miss' # Calling again with same request_id should be a cache hit assert_is_in_spectre_cache( '/post_id_cache/', data='{"request_id":123, "vary_id":"abc"}', extra_headers={'content-type': 'application/json'}) # Purge all resources with same id. purge_resource({ 'namespace': 'backend.main', 'cache_name': 'post_with_id', 'id': '123' }) # All resources with same id should be a miss now. response = post_through_spectre( '/post_id_cache/', data='{"request_id":123, "vary_id":"def"}', extra_headers={'content-type': 'application/json'}) assert response.status_code == 200 assert response.headers['Spectre-Cache-Status'] == 'miss' response = post_through_spectre( '/post_id_cache/', data='{"request_id":123, "vary_id":"abc"}', extra_headers={'content-type': 'application/json'}) assert response.status_code == 200 assert response.headers['Spectre-Cache-Status'] == 'miss'
def test_response_headers_passed_back(self): response = get_through_spectre('/not_cacheable') assert response.headers['Some-Header'] == 'abc' assert response.headers['Spectre-Cache-Status'] == 'non-cacheable-uri (backend.main)' response = get_through_spectre('/timestamp/response_header') assert response.headers['Spectre-Cache-Status'] == 'miss' assert response.headers['Some-Header'] == 'abc' response = assert_is_in_spectre_cache('/timestamp/response_header') assert response.headers['Some-Header'] == 'abc'
def test_with_invalid_id_when_cache_missing_ids_is_true(self): path = '/bulk_requester_2/{ids}/v1?k1=v1' # 0 < ids < 1000 are valid response = get_through_spectre(path.format(ids='10,5000,11')) assert len(response.json()) == 2 assert response.headers['Spectre-Cache-Status'] == 'miss' # "5000" is an invalid id; but by default cache_missing_ids is set to true, so the # empty response would've been cached from the above request hit_response = assert_is_in_spectre_cache(path.format(ids='5000')) assert hit_response.json() == []
def test_with_invalid_id_when_cache_missing_ids_is_true(self): base_path = '/bulk_requester_2' # 0 < ids < 1000 are valid resp1 = get_through_spectre("{}/{}/v1?k1=v2".format(base_path, '10,5000,11')) headers1, body1 = resp1.headers, resp1.json() assert len(body1) == 2 assert headers1['Spectre-Cache-Status'] == 'miss' # "5000" is an invalid id; but by default cache_missing_ids is set to true, so the # empty response would've been cached from the above request resp2 = assert_is_in_spectre_cache("{}/{}/v1?k1=v2".format(base_path, '5000')) resp2.json() == []
def test_bulk_ids_in_path(self): base_path = '/bulk_requester_2' resp_1 = get_through_spectre("{}/{}/v1?k1=v2".format(base_path, '1,2,3')) # Bulk was a miss bulk_headers, bulk_body = resp_1.headers, resp_1.json() assert bulk_headers['Spectre-Cache-Status'] == 'miss' resp_2 = assert_is_in_spectre_cache("{}/{}/v1?k1=v2".format(base_path, '2')) _, body = resp_2.headers, resp_2.json() # Check for correctness assert len(body) == 1 assert bulk_body[1] == body[0]
def test_purge_cassandra_by_id_backward_compatible(self): # Delete after PERF-2453 is done get_through_spectre('/bulk_requester?ids=1') assert_is_in_spectre_cache('/bulk_requester?ids=1') # Purge id 1 res = requests.request( 'PURGE', util.SPECTRE_BASE_URL + '?cache_name=bulk_requester_does_not_cache_missing_ids&id=1', headers=util.HAPROXY_ADDED_HEADERS) assert res.status_code == 200 get_resp_3 = get_through_spectre('/bulk_requester?ids=1') # resp 3 was no longer cached. assert get_resp_3.headers['Spectre-Cache-Status'] == 'miss' res = requests.request( 'PURGE', util.SPECTRE_BASE_URL + '?cache_name=bulk_requester_does_not_cache_missing_ids', headers=util.HAPROXY_ADDED_HEADERS) assert res.status_code == 200
def test_uncacheable_headers_not_passed_back(self): """Spectre doesn't store uncacheable headers in the cache, but it always passes back all response headers in the uncached (or uncacheable) case. """ response = get_through_spectre('/not_cacheable') assert response.headers['Spectre-Cache-Status'] == 'non-cacheable-uri (backend.main)' assert 'Uncacheable-Header' in response.headers response = get_through_spectre('/timestamp/uncacheable_header') assert response.headers['Spectre-Cache-Status'] == 'miss' assert 'Uncacheable-Header' in response.headers # This is the cached case, where the uncacheable header isn't expected # in the response. response = assert_is_in_spectre_cache('/timestamp/uncacheable_header') assert 'Uncacheable-Header' not in response.headers
def make_request(self, ids, cache=True, extra_headers=None, assert_hit=False): base_path = '/bulk_requester' ids = [str(i) for i in ids] ids = "%2C".join(ids) if not cache: cache_headers = {'Cache-Control': 'no-cache'} if extra_headers is None: extra_headers = {} extra_headers.update(cache_headers) if assert_hit: resp = assert_is_in_spectre_cache("{}?ids={}".format(base_path, ids), extra_headers) else: resp = get_through_spectre("{}?ids={}".format(base_path, ids), extra_headers) return resp.headers, resp.json()
def test_different_params_same_id(self): base_path = '/bulk_requester' resp1 = get_through_spectre("{}?ids={}&data=false".format(base_path, '5%2C6')) assert resp1.headers['Spectre-Cache-Status'] == 'miss' resp2 = get_through_spectre("{}?ids={}&data=true".format(base_path, '5')) assert resp2.headers['Spectre-Cache-Status'] == 'miss' assert_is_in_spectre_cache("{}?data=false&ids={}".format(base_path, '5')) assert_is_in_spectre_cache("{}?data=false&ids={}".format(base_path, '6')) assert_is_in_spectre_cache("{}?ids={}&data=false".format(base_path, '6'))
def test_gzipped_responses_work(self): assert get_through_spectre( '/gzipped').headers['Spectre-Cache-Status'] == 'miss' assert_is_in_spectre_cache('/gzipped')
def test_query_params_ordering(self): val1 = get_through_spectre('/happy/?k1=v1&k2=v2') assert val1.headers['Spectre-Cache-Status'] == 'miss' assert_is_in_spectre_cache('/happy/?k1=v1&k2=v2') assert_is_in_spectre_cache('/happy/?k2=v2&k1=v1')