def test_valid_create(app, db, es, test_data, search_url, search_class, content_type): """Test VALID record creation request (POST .../records/).""" with app.test_client() as client: HEADERS = [ ('Accept', 'application/json'), ('Content-Type', content_type) ] HEADERS.append(('Content-Type', content_type)) # Create record res = client.post( search_url, data=json.dumps(test_data[0]), headers=HEADERS) assert res.status_code == 201 # Check that the returned record matches the given data data = get_json(res) for k in test_data[0].keys(): assert data['metadata'][k] == test_data[0][k] # Recid has been added in control number assert data['metadata']['control_number'] # Check location header assert res.headers['Location'] == data['links']['self'] # Record can be retrieved. assert client.get(record_url(data['id'])).status_code == 200 IndexFlusher(search_class).flush_and_wait() # Record shows up in search res = client.get(search_url, query_string={"control_number": data['metadata']['control_number']}) assert_hits_len(res, 1)
def test_valid_put_etag(app, es, test_records, content_type, search_url, search_class): """Test concurrency control with etags.""" HEADERS = [ ('Accept', 'application/json'), ('Content-Type', content_type) ] pid, record = test_records[0] record['year'] = 1234 with app.test_client() as client: url = record_url(pid) res = client.put( url, data=json.dumps(record.dumps()), headers={ 'Content-Type': 'application/json', 'If-Match': '"{0}"'.format(record.revision_id) }) assert res.status_code == 200 assert get_json(client.get(url))['metadata']['year'] == 1234 IndexFlusher(search_class).flush_and_wait() res = client.get(search_url, query_string={"year": 1234}) assert_hits_len(res, 1)
def test_page_size_without_size_in_request_with_five_as_default( app, indexed_records, search_url): """Test custom default page parameter.""" config = {'RECORDS_REST_DEFAULT_RESULTS_SIZE': 2} with app.test_client() as client, patch.dict(app.config, config): res = client.get(search_url, query_string=dict(page=1)) assert_hits_len(res, 2)
def test_invalid_patch(app, es, test_records, test_patch, charset, search_url, search_class): """Test INVALID record put request (PUT .../records/<record_id>).""" HEADERS = [('Accept', 'application/json'), ('Content-Type', 'application/json-patch+json{0}'.format(charset))] pid, record = test_records[0] with app.test_client() as client: url = record_url(pid) # Non-existing record res = client.patch(record_url('0'), data=json.dumps(test_patch), headers=HEADERS) assert res.status_code == 404 IndexFlusher(search_class).flush_and_wait() res = client.get(search_url) assert_hits_len(res, 0) # Invalid accept mime type. headers = [('Content-Type', 'application/json-patch+json{0}'.format(charset)), ('Accept', 'video/mp4')] res = client.patch(url, data=json.dumps(test_patch), headers=headers) assert res.status_code == 406 # Invalid content type headers = [('Content-Type', 'video/mp4{0}'.format(charset)), ('Accept', 'application/json')] res = client.patch(url, data=json.dumps(test_patch), headers=headers) assert res.status_code == 415 # Invalid Patch res = client.patch(url, data=json.dumps([{ 'invalid': 'json-patch{0}'.format(charset) }]), headers=HEADERS) assert res.status_code == 400 # Invalid JSON res = client.patch(url, data='{', headers=HEADERS) assert res.status_code == 400 # Invalid ETag res = client.patch( url, data=json.dumps(test_patch), headers={ 'Content-Type': 'application/json-patch+json{0}'.format(charset), 'If-Match': '"2"' }) assert res.status_code == 412
def test_videos_search(api_app, indexed_videos): """Test that searching for videos returns correct number of results.""" with api_app.test_client() as client: search_url = url_for('invenio_records_rest.recid_list') # Get a query with only one record res = client.get(search_url, query_string={'q': 'video'}) assert_hits_len(res, 3) assert res.status_code == 200 # Also make sure that there is no "Project" in the results res = client.get(search_url, query_string={'q': 'Project'}) assert_hits_len(res, 0) assert res.status_code == 200
def test_page_size(app, indexed_records, search_url): """Test page and size parameters.""" with app.test_client() as client: # Limit records res = client.get(search_url, query_string=dict(page=1, size=2)) assert_hits_len(res, 2) # All records res = client.get(search_url, query_string=dict(page=1, size=10)) assert_hits_len(res, len(indexed_records)) # Exceed max result window res = client.get(search_url, query_string=dict(page=100, size=100)) assert res.status_code == 400 assert 'message' in get_json(res)
def test_invalid_put(app, es, test_records, charset, search_url): """Test INVALID record put request (PUT .../records/<record_id>).""" HEADERS = [ ('Accept', 'application/json'), ('Content-Type', 'application/json{0}'.format(charset)), ] pid, record = test_records[0] record['year'] = 1234 test_data = record.dumps() with app.test_client() as client: url = record_url(pid) # Non-existing record res = client.put(record_url('0'), data=json.dumps(test_data), headers=HEADERS) assert res.status_code == 404 res = client.get(search_url, query_string={"year": 1234}) assert_hits_len(res, 0) # Invalid accept mime type. headers = [('Content-Type', 'application/json{0}'.format(charset)), ('Accept', 'video/mp4')] res = client.put(url, data=json.dumps(test_data), headers=headers) assert res.status_code == 406 # Invalid content type headers = [('Content-Type', 'video/mp4{0}'.format(charset)), ('Accept', 'application/json')] res = client.put(url, data=json.dumps(test_data), headers=headers) assert res.status_code == 415 # Invalid JSON res = client.put(url, data='{invalid-json', headers=HEADERS) assert res.status_code == 400 # Invalid ETag res = client.put(url, data=json.dumps(test_data), headers={ 'Content-Type': 'application/json{0}'.format(charset), 'If-Match': '"2"' }) assert res.status_code == 412
def test_from_parameter_edges(app, indexed_records, search_url): """Test first and last values for "from" parameter pagination.""" with app.test_client() as client: res = client.get(search_url, query_string={'size': 1, 'from': 1}) assert_hits_len(res, 1) data = get_json(res) assert 'self' in data['links'] assert 'next' in data['links'] assert 'prev' not in data['links'] res = client.get(search_url, query_string={'size': 1, 'from': 4}) assert_hits_len(res, 1) data = get_json(res) assert 'self' in data['links'] assert 'next' not in data['links'] assert 'prev' in data['links']
def test_invalid_put(app, es, test_records, charset, search_url): """Test INVALID record put request (PUT .../records/<record_id>).""" HEADERS = [ ('Accept', 'application/json'), ('Content-Type', 'application/json{0}'.format(charset)), ] pid, record = test_records[0] record['year'] = 1234 test_data = record.dumps() with app.test_client() as client: url = record_url(pid) # Non-existing record res = client.put( record_url('0'), data=json.dumps(test_data), headers=HEADERS) assert res.status_code == 404 res = client.get(search_url, query_string={"year": 1234}) assert_hits_len(res, 0) # Invalid accept mime type. headers = [('Content-Type', 'application/json{0}'.format(charset)), ('Accept', 'video/mp4')] res = client.put(url, data=json.dumps(test_data), headers=headers) assert res.status_code == 406 # Invalid content type headers = [('Content-Type', 'video/mp4{0}'.format(charset)), ('Accept', 'application/json')] res = client.put(url, data=json.dumps(test_data), headers=headers) assert res.status_code == 415 # Invalid JSON res = client.put(url, data='{invalid-json', headers=HEADERS) assert res.status_code == 400 # Invalid ETag res = client.put( url, data=json.dumps(test_data), headers={'Content-Type': 'application/json{0}'.format(charset), 'If-Match': '"2"'} ) assert res.status_code == 412
def test_json_result_serializer(app, indexed_records, test_records, search_url): """JSON result.""" with app.test_client() as client: # Get a query with only one record res = client.get(search_url, query_string={"q": "year:2015"}) assert_hits_len(res, 1) assert res.status_code == 200 # Check serialization of record record = get_json(res)["hits"]["hits"][0] for k in ["id", "created", "updated", "metadata", "links"]: assert k in record pid, db_record = test_records[0] assert record["id"] == int(pid.pid_value) assert record["metadata"] == db_record.dumps()
def test_invalid_create(app, db, es, test_data, search_url, content_type): """Test INVALID record creation request (POST .../records/).""" with app.test_client() as client: HEADERS = [('Accept', 'application/json'), ('Content-Type', content_type)] # Invalid accept type headers = [('Content-Type', 'application/json'), ('Accept', 'video/mp4')] res = client.post(search_url, data=json.dumps(test_data[0]), headers=headers) assert res.status_code == 406 # check that nothing is indexed res = client.get(search_url, query_string=dict(page=1, size=2)) assert_hits_len(res, 0) # Invalid content-type headers = [('Content-Type', 'video/mp4'), ('Accept', 'application/json')] res = client.post(search_url, data=json.dumps(test_data[0]), headers=headers) assert res.status_code == 415 res = client.get(search_url, query_string=dict(page=1, size=2)) assert_hits_len(res, 0) # Invalid JSON res = client.post(search_url, data='{fdssfd', headers=HEADERS) assert res.status_code == 400 res = client.get(search_url, query_string=dict(page=1, size=2)) assert_hits_len(res, 0) # No data res = client.post(search_url, headers=HEADERS) assert res.status_code == 400 res = client.get(search_url, query_string=dict(page=1, size=2)) assert_hits_len(res, 0) # Posting a list instead of dictionary pytest.raises(TypeError, client.post, search_url, data='[]', headers=HEADERS) # Bad internal error: with patch('invenio_records_rest.views.db.session.commit') as m: m.side_effect = SQLAlchemyError() pytest.raises(SQLAlchemyError, client.post, search_url, data=json.dumps(test_data[0]), headers=HEADERS)
def test_json_result_serializer(app, indexed_records, test_records, search_url): """JSON result.""" with app.test_client() as client: # Get a query with only one record res = client.get(search_url, query_string={'q': 'year:2015'}) assert_hits_len(res, 1) assert res.status_code == 200 # Check serialization of record record = get_json(res)['hits']['hits'][0] for k in ['id', 'created', 'updated', 'metadata', 'links']: assert k in record pid, db_record = test_records[0] assert record['id'] == int(pid.pid_value) assert record['metadata'] == db_record.dumps()
def test_api_views(app, prefixed_es, db, test_data, search_url, search_class): """Test REST API views behavior.""" suffix = current_search.current_suffix with app.test_client() as client: HEADERS = [ ('Accept', 'application/json'), ('Content-Type', 'application/json'), ] # Create record res = client.post( search_url, data=json.dumps(test_data[0]), headers=HEADERS) recid = get_json(res)['id'] assert res.status_code == 201 # Flush and check indices IndexFlusher(search_class).flush_and_wait() result = prefixed_es.search(index='test-invenio-records-rest') assert len(result['hits']['hits']) == 1 record_doc = result['hits']['hits'][0] assert record_doc['_index'] == \ 'test-invenio-records-rest-testrecord' + suffix assert record_doc['_type'] == 'testrecord' if lt_es7 else '_doc' # Fetch the record assert client.get(record_url(recid)).status_code == 200 # Record shows up in search res = client.get(search_url) assert_hits_len(res, 1) # Delete the record res = client.delete(record_url(recid)) IndexFlusher(search_class).flush_and_wait() result = prefixed_es.search(index='test-invenio-records-rest') assert len(result['hits']['hits']) == 0 # Deleted record should return 410 assert client.get(record_url(recid)).status_code == 410 # Record doesn't show up in search res = client.get(search_url) assert_hits_len(res, 0)
def test_page_links(app, indexed_records, search_url): """Test Link HTTP header on multi-page searches.""" with app.test_client() as client: # Limit records res = client.get(search_url, query_string=dict(size=1, page=1)) assert_hits_len(res, 1) def parse_link_header(response): """Parses the links from a REST response's HTTP header.""" return { k: v for (k, v) in map( lambda s: re.findall(r'<(.*)>; rel="(.*)"', s)[0][::-1], [x for x in res.headers['Link'].split(', ')]) } links = parse_link_header(res) data = get_json(res)['links'] assert 'self' in data \ and 'self' in links \ and data['self'] == links['self'] assert 'next' in data \ and 'next' in links \ and data['next'] == links['next'] assert 'prev' not in data \ and 'prev' not in links # Assert next URL before calling it first_url = links['self'] next_url = links['next'] parsed_url = parse_url(next_url) assert parsed_url['qs']['size'] == ['1'] assert parsed_url['qs']['page'] == ['2'] # Access next URL res = client.get(to_relative_url(next_url)) assert_hits_len(res, 1) links = parse_link_header(res) assert links['self'] == next_url assert 'next' in links assert 'prev' in links and links['prev'] == first_url
def test_invalid_create(app, db, es, test_data, search_url, content_type): """Test INVALID record creation request (POST .../records/).""" with app.test_client() as client: HEADERS = [ ('Accept', 'application/json'), ('Content-Type', content_type) ] # Invalid accept type headers = [('Content-Type', 'application/json'), ('Accept', 'video/mp4')] res = client.post( search_url, data=json.dumps(test_data[0]), headers=headers) assert res.status_code == 406 # check that nothing is indexed res = client.get(search_url, query_string=dict(page=1, size=2)) assert_hits_len(res, 0) # Invalid content-type headers = [('Content-Type', 'video/mp4'), ('Accept', 'application/json')] res = client.post( search_url, data=json.dumps(test_data[0]), headers=headers) assert res.status_code == 415 res = client.get(search_url, query_string=dict(page=1, size=2)) assert_hits_len(res, 0) # Invalid JSON res = client.post(search_url, data='{fdssfd', headers=HEADERS) assert res.status_code == 400 res = client.get(search_url, query_string=dict(page=1, size=2)) assert_hits_len(res, 0) # No data res = client.post(search_url, headers=HEADERS) assert res.status_code == 400 res = client.get(search_url, query_string=dict(page=1, size=2)) assert_hits_len(res, 0) # Posting a list instead of dictionary pytest.raises( TypeError, client.post, search_url, data='[]', headers=HEADERS) # Bad internal error: with patch('invenio_records_rest.views.db.session.commit') as m: m.side_effect = SQLAlchemyError() pytest.raises( SQLAlchemyError, client.post, search_url, data=json.dumps(test_data[0]), headers=HEADERS)
def test_valid_put(app, es, test_records, content_type, search_url, search_class): """Test VALID record patch request (PATCH .../records/<record_id>).""" HEADERS = [('Accept', 'application/json'), ('Content-Type', content_type)] pid, record = test_records[0] record['year'] = 1234 with app.test_client() as client: url = record_url(pid) res = client.put(url, data=json.dumps(record.dumps()), headers=HEADERS) assert res.status_code == 200 # Check that the returned record matches the given data assert get_json(res)['metadata']['year'] == 1234 IndexFlusher(search_class).flush_and_wait() res = client.get(search_url, query_string={"year": 1234}) assert_hits_len(res, 1) # Retrieve record via get request assert get_json(client.get(url))['metadata']['year'] == 1234
def test_page_links(app, indexed_records, search_url): """Test Link HTTP header on multi-page searches.""" with app.test_client() as client: # Limit records res = client.get(search_url, query_string=dict(size=1, page=1)) assert_hits_len(res, 1) def parse_link_header(response): """Parse the links from a REST response's HTTP header.""" return { k: v for (k, v) in map(lambda s: re.findall(r'<(.*)>; rel="(.*)"', s)[0][::-1], [x for x in res.headers['Link'].split(', ')]) } links = parse_link_header(res) data = get_json(res)['links'] assert 'self' in data \ and 'self' in links \ and data['self'] == links['self'] assert 'next' in data \ and 'next' in links \ and data['next'] == links['next'] assert 'prev' not in data \ and 'prev' not in links # Assert next URL before calling it first_url = links['self'] next_url = links['next'] parsed_url = parse_url(next_url) assert parsed_url['qs']['size'] == ['1'] assert parsed_url['qs']['page'] == ['2'] # Access next URL res = client.get(to_relative_url(next_url)) assert_hits_len(res, 1) links = parse_link_header(res) assert links['self'] == next_url assert 'next' in links assert 'prev' in links and links['prev'] == first_url
def test_from_parameter_pagination(app, indexed_records, search_url): """Test "from" parameter pagination.""" with app.test_client() as client: res = client.get(search_url, query_string={'size': 1, 'from': 1}) assert_hits_len(res, 1) data = get_json(res) assert 'self' in data['links'] assert 'next' in data['links'] assert 'prev' not in data['links'] next_url = get_json(res)['links']['next'] parsed_url = parse_url(next_url) assert parsed_url['qs']['size'] == ['1'] assert parsed_url['qs']['from'] == ['2'] assert 'page' not in parsed_url['qs'] self_url = get_json(res)['links']['self'] parsed_url = parse_url(self_url) assert parsed_url['qs']['size'] == ['1'] assert parsed_url['qs']['from'] == ['1'] assert 'page' not in parsed_url['qs'] res = client.get(next_url) assert_hits_len(res, 1) data = get_json(res) assert data['links']['self'] == next_url assert 'next' in data['links'] assert 'prev' in data['links'] next_url = get_json(res)['links']['next'] parsed_url = parse_url(next_url) assert parsed_url['qs']['size'] == ['1'] assert parsed_url['qs']['from'] == ['3'] assert 'page' not in parsed_url['qs']
def test_put_on_deleted(app, db, es, test_data, content_type, search_url, search_class): """Test putting to a deleted record.""" with app.test_client() as client: HEADERS = [('Accept', 'application/json'), ('Content-Type', content_type)] HEADERS.append(('Content-Type', content_type)) # Create record res = client.post(search_url, data=json.dumps(test_data[0]), headers=HEADERS) assert res.status_code == 201 url = record_url(get_json(res)['id']) assert client.delete(url).status_code == 204 IndexFlusher(search_class).flush_and_wait() res = client.get(search_url, query_string={'title': test_data[0]['title']}) assert_hits_len(res, 0) res = client.put(url, data='{}', headers=HEADERS) assert res.status_code == 410
def test_patch_deleted(app, db, es, test_data, test_patch, content_type, search_url, search_class): """Test patching deleted record.""" HEADERS = [('Accept', 'application/json'), ('Content-Type', content_type)] with app.test_client() as client: # Create record res = client.post(search_url, data=json.dumps(test_data[0]), headers=HEADERS) assert res.status_code == 201 _id = get_json(res)['id'] # Delete record. url = record_url(_id) assert client.delete(url).status_code == 204 # check patch response for deleted resource res = client.patch(url, data=json.dumps(test_patch), headers=HEADERS) assert res.status_code == 410 IndexFlusher(search_class).flush_and_wait() res = client.get(search_url, query_string={'title': test_data[0]['title']}) assert_hits_len(res, 0)
def test_page_links(app, indexed_records, search_url): """Test Link HTTP header on multi-page searches.""" with app.test_client() as client: # Limit records res = client.get(search_url, query_string=dict(size=1, page=1)) assert_hits_len(res, 1) def parse_link_header(response): """Parses the links from a REST response's HTTP header.""" return { k: v for (k, v) in map( lambda s: re.findall(r'<(.*)>; rel="(.*)"', s)[0][::-1], [x for x in res.headers["Link"].split(", ")], ) } links = parse_link_header(res) data = get_json(res)["links"] assert "self" in data and "self" in links and data["self"] == links["self"] assert "next" in data and "next" in links and data["next"] == links["next"] assert "prev" not in data and "prev" not in links # Assert next URL before calling it first_url = links["self"] next_url = links["next"] parsed_url = parse_url(next_url) assert parsed_url["qs"]["size"] == ["1"] assert parsed_url["qs"]["page"] == ["2"] # Access next URL res = client.get(to_relative_url(next_url)) assert_hits_len(res, 1) links = parse_link_header(res) assert links["self"] == next_url assert "next" in links assert "prev" in links and links["prev"] == first_url
def test_valid_patch(app, es, test_records, test_patch, content_type, search_url, search_class): """Test VALID record patch request (PATCH .../records/<record_id>).""" HEADERS = [('Accept', 'application/json'), ('Content-Type', content_type)] pid, record = test_records[0] # Check that assert record.patch(test_patch) with app.test_client() as client: # Check that patch and record is not the same value for year. url = record_url(pid) previous_year = get_json(client.get(url))['metadata']['year'] # Patch record res = client.patch(url, data=json.dumps(test_patch), headers=HEADERS) assert res.status_code == 200 # Check that year changed. new_year = get_json(client.get(url))['metadata']['year'] assert previous_year != new_year IndexFlusher(search_class).flush_and_wait() res = client.get(search_url, query_string={'year': new_year}) assert_hits_len(res, 1)
def test_pagination(app, indexed_records, search_url): """Test pagination.""" with app.test_client() as client: # Limit records res = client.get(search_url, query_string=dict(size=1, page=1)) assert_hits_len(res, 1) data = get_json(res) assert 'self' in data['links'] assert 'next' in data['links'] assert 'prev' not in data['links'] # Assert next URL before calling it next_url = get_json(res)['links']['next'] parsed_url = parse_url(next_url) assert parsed_url['qs']['size'] == ['1'] assert parsed_url['qs']['page'] == ['2'] # Access next URL res = client.get(to_relative_url(next_url)) assert_hits_len(res, 1) data = get_json(res) assert data['links']['self'] == next_url assert 'next' in data['links'] assert 'prev' in data['links']
def test_valid_put(app, es, test_records, content_type, search_url, search_class): """Test VALID record patch request (PATCH .../records/<record_id>).""" HEADERS = [ ('Accept', 'application/json'), ('Content-Type', content_type) ] pid, record = test_records[0] record['year'] = 1234 with app.test_client() as client: url = record_url(pid) res = client.put(url, data=json.dumps(record.dumps()), headers=HEADERS) assert res.status_code == 200 # Check that the returned record matches the given data assert get_json(res)['metadata']['year'] == 1234 IndexFlusher(search_class).flush_and_wait() res = client.get(search_url, query_string={"year": 1234}) assert_hits_len(res, 1) # Retrieve record via get request assert get_json(client.get(url))['metadata']['year'] == 1234
def test_put_on_deleted(app, db, es, test_data, content_type, search_url, search_class): """Test putting to a deleted record.""" with app.test_client() as client: HEADERS = [ ('Accept', 'application/json'), ('Content-Type', content_type) ] HEADERS.append(('Content-Type', content_type)) # Create record res = client.post( search_url, data=json.dumps(test_data[0]), headers=HEADERS) assert res.status_code == 201 url = record_url(get_json(res)['id']) assert client.delete(url).status_code == 204 IndexFlusher(search_class).flush_and_wait() res = client.get(search_url, query_string={'title': test_data[0]['title']}) assert_hits_len(res, 0) res = client.put(url, data='{}', headers=HEADERS) assert res.status_code == 410
def test_pagination(app, indexed_records, search_url): """Test pagination.""" with app.test_client() as client: # Limit records res = client.get(search_url, query_string=dict(size=1, page=1)) assert_hits_len(res, 1) data = get_json(res) assert "self" in data["links"] assert "next" in data["links"] assert "prev" not in data["links"] # Assert next URL before calling it next_url = get_json(res)["links"]["next"] parsed_url = parse_url(next_url) assert parsed_url["qs"]["size"] == ["1"] assert parsed_url["qs"]["page"] == ["2"] # Access next URL res = client.get(to_relative_url(next_url)) assert_hits_len(res, 1) data = get_json(res) assert data["links"]["self"] == next_url assert "next" in data["links"] assert "prev" in data["links"]
def test_max_result_window_valid_params(app, indexed_records, search_url): """Test max_result_window with a valid page/from/size parameters.""" with app.test_client() as client: res = client.get(search_url, query_string={'size': 3}) assert_hits_len(res, 3) res = client.get(search_url, query_string={'page': 1, 'size': 3}) assert_hits_len(res, 3) data = get_json(res) res = client.get(search_url, query_string={'from': 3, 'size': 1}) assert_hits_len(res, 1) data = get_json(res) assert 'self' in data['links'] assert 'next' in data['links'] assert 'prev' in data['links']
def test_filters(app, indexed_records, search_url): """Test aggregations.""" with app.test_client() as client: res = client.get(search_url, query_string=dict(stars='4')) assert_hits_len(res, 2)
def test_page_size_without_size_in_request( app, indexed_records, search_url): """Test default size parameter.""" with app.test_client() as client: res = client.get(search_url, query_string=dict(page=1)) assert_hits_len(res, len(indexed_records))