def test_get_all(self): client = TestClient(PiccoloCRUD(table=TopSecret, exclude_secrets=True)) response = client.get("/") self.assertEqual( response.json(), {"rows": [{ "id": 1, "name": "My secret", "confidential": None }]}, ) client = TestClient(PiccoloCRUD(table=TopSecret, exclude_secrets=False)) response = client.get("/") self.assertEqual( response.json(), { "rows": [{ "id": 1, "name": "My secret", "confidential": "secret123" }] }, )
def test_visible_fields_with_join(self): """ Make sure that GETs with the ``__visible_fields`` parameter return the correct data, when using joins. """ # Test 1 - should be rejected, as by default `max_joins` is 0: client = TestClient(PiccoloCRUD(table=Role, read_only=False)) response = client.get( "/", params={"__visible_fields": "name,movie.name", "__order": "id"}, ) self.assertEqual(response.status_code, 400) self.assertEqual(response.content, b"Max join depth exceeded") # Test 2 - should work as `max_joins` is set: client = TestClient( PiccoloCRUD(table=Role, read_only=False, max_joins=1) ) response = client.get( "/", params={"__visible_fields": "name,movie.name", "__order": "id"}, ) self.assertEqual(response.status_code, 200) self.assertEqual( response.json(), { "rows": [ {"movie": {"name": "Star Wars"}, "name": "Luke Skywalker"} ] }, )
def test_pre_patch_hook(self): """ Make sure pre_patch hook executes successfully """ client = TestClient( PiccoloCRUD( table=Movie, read_only=False, hooks=[ Hook(hook_type=HookType.pre_patch, callable=remove_spaces) ], )) movie = Movie(name="Star Wars", rating=93) movie.save().run_sync() new_name = "Star Wars: A New Hope" new_name_modified = new_name.replace(" ", "") response = client.patch(f"/{movie.id}/", json={"name": new_name}) self.assertTrue(response.status_code == 200) # Make sure the row is returned: response_json = json.loads(response.json()) self.assertTrue(response_json["name"] == new_name_modified) # Make sure the underlying database row was changed: movies = Movie.select().run_sync() self.assertTrue(movies[0]["name"] == new_name_modified)
def test_get_visible_fields(self): """ Make sure a get can return a row successfully with the ``__visible_fields`` parameter. """ client = TestClient(PiccoloCRUD(table=Role, read_only=False)) movie = Movie(name="Star Wars", rating=93) movie.save().run_sync() role = Role(name="Luke Skywalker", movie=movie.id) role.save().run_sync() response = client.get(f"/{role.id}/", params={"__visible_fields": "name"}) self.assertEqual(response.status_code, 200) self.assertEqual( response.json(), { "name": "Luke Skywalker", }, ) # Test with unrecognised columns response = client.get(f"/{role.id}/", params={"__visible_fields": "foobar"}) self.assertEqual(response.status_code, 400) self.assertEqual( response.content, (b"No matching column found with name == foobar - the column " b"options are ('id', 'movie', 'name')."), )
def test_visible_fields_with_readable(self): """ Make sure that GETs with the ``__visible_fields`` parameter return the correct data, when also used wit the ``__readable`` parameter. """ client = TestClient(PiccoloCRUD(table=Role, read_only=False)) response = client.get( "/", params={ "__visible_fields": "name,movie", "__readable": "true", "__order": "id", }, ) self.assertEqual(response.status_code, 200) self.assertEqual( response.json(), { "rows": [ { "name": "Luke Skywalker", "movie_readable": "Star Wars", "movie": 1, } ] }, )
def test_readable(self): """ Make sure that bulk GETs with the ``__readable`` parameter return the correct data. """ client = TestClient(PiccoloCRUD(table=Role, read_only=False)) response = client.get("/", params={"__readable": "true"}) self.assertEqual(response.status_code, 200) self.assertEqual( response.json(), { "rows": [ { "id": 1, "name": "Luke Skywalker", "movie": 1, "movie_readable": "Star Wars", } ] }, ) response = client.get("/", params={}) self.assertEqual(response.status_code, 200) self.assertEqual( response.json(), {"rows": [{"id": 1, "name": "Luke Skywalker", "movie": 1}]}, )
def test_get(self): """ Make sure a get can return a row successfully. """ client = TestClient(PiccoloCRUD(table=Role, read_only=False)) movie = Movie(name="Star Wars", rating=93) movie.save().run_sync() role = Role(name="Luke Skywalker", movie=movie.id) role.save().run_sync() response = client.get(f"/{role.id}/") self.assertEqual(response.status_code, 200) self.assertEqual( response.json(), {"id": role.id, "name": "Luke Skywalker", "movie": movie.id}, ) response = client.get(f"/{role.id}/", params={"__readable": "true"}) self.assertEqual(response.status_code, 200) self.assertEqual( response.json(), { "id": role.id, "name": "Luke Skywalker", "movie": movie.id, "movie_readable": "Star Wars", }, ) response = client.get("/123/") self.assertEqual(response.status_code, 404)
def test_get_ids_with_limit_offset(self): """ Test the limit and offset parameter. """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) Movie.insert( Movie(name="Star Wars", rating=93), Movie(name="Lord of the Rings", rating=90), ).run_sync() response = client.get("/ids/?limit=1") self.assertTrue(response.status_code == 200) self.assertEqual(response.json(), {"1": "Star Wars"}) # Make sure only valid limit values are accepted. response = client.get("/ids/?limit=abc") self.assertEqual(response.status_code, 400) # Make sure only valid offset values are accepted. response = client.get("/ids/?offset=abc") self.assertEqual(response.status_code, 400) # Test with offset response = client.get("/ids/?limit=1&offset=1") self.assertTrue(response.status_code == 200) self.assertEqual(response.json(), {"2": "Lord of the Rings"})
def test_page_sized_results(self): """ Make sure the content-range header responds correctly requests with page_size """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) movie = Movie(name="Star Wars", rating=93) movie.save().run_sync() movie2 = Movie(name="Blade Runner", rating=94) movie2.save().run_sync() movie3 = Movie(name="The Godfather", rating=95) movie3.save().run_sync() response = client.get("/?__page_size=1&__range_header=true") self.assertEqual(response.headers.get("Content-Range"), "movie 0-0/3") response = client.get("/?__page_size=1&__page=2&__range_header=true") self.assertEqual(response.headers.get("Content-Range"), "movie 1-1/3") response = client.get("/?__page_size=1&__page=2&__range_header=true") self.assertEqual(response.headers.get("Content-Range"), "movie 1-1/3") response = client.get("/?__page_size=99&__page=1&__range_header=true") self.assertEqual(response.headers.get("Content-Range"), "movie 0-2/3")
def test_incorrect_verbs(self): client = TestClient( PiccoloCRUD(table=Movie, read_only=False, allow_bulk_delete=True) ) response = client.patch("/", params={}) self.assertEqual(response.status_code, 405)
def test_parsing(self): app = PiccoloCRUD(table=Movie) parsed_1 = app._parse_params( QueryParams("tags=horror&tags=scifi&rating=90") ) self.assertEqual( parsed_1, {"tags": ["horror", "scifi"], "rating": "90"} ) parsed_2 = app._parse_params( QueryParams("tags[]=horror&tags[]=scifi&rating=90") ) self.assertEqual( parsed_2, {"tags": ["horror", "scifi"], "rating": "90"} )
def test_patch_succeeds(self): """ Make sure a patch modifies the underlying database, and returns the new row data. """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) rating = 93 movie = Movie(name="Star Wars", rating=rating) movie.save().run_sync() new_name = "Star Wars: A New Hope" response = client.patch(f"/{movie.id}/", json={"name": new_name}) self.assertTrue(response.status_code == 200) self.assertIsInstance(response.json(), dict) # Make sure the row is returned: response_json = response.json() self.assertTrue(response_json["name"] == new_name) self.assertTrue(response_json["rating"] == rating) # Make sure the underlying database row was changed: movies = Movie.select().run_sync() self.assertTrue(len(movies) == 1) self.assertTrue(movies[0]["name"] == new_name)
def test_pre_patch_hook_db_lookup(self): """ Make sure pre_patch hook can perform db lookups (function will always reset "name" to the original name) """ client = TestClient( PiccoloCRUD( table=Movie, read_only=False, hooks=[ Hook(hook_type=HookType.pre_patch, callable=look_up_existing) ], )) original_name = "Star Wars" movie = Movie(name="Star Wars", rating=93) movie.save().run_sync() new_name = "Star Wars: A New Hope" response = client.patch(f"/{movie.id}/", json={"name": new_name}) self.assertTrue(response.status_code == 200) response_json = json.loads(response.json()) self.assertTrue(response_json["name"] == original_name) movies = Movie.select().run_sync() self.assertTrue(movies[0]["name"] == original_name)
def test_get_visible_fields_with_join_readable(self): """ Make sure a get can return a row successfully with the ``__visible_fields`` parameter, when using joins and readable. """ client = TestClient( PiccoloCRUD(table=Role, read_only=False, max_joins=1) ) movie = Movie(name="Star Wars", rating=93) movie.save().run_sync() role = Role(name="Luke Skywalker", movie=movie.id) role.save().run_sync() response = client.get( f"/{role.id}/", params={ "__visible_fields": "id,name,movie.name", "__readable": "true", }, ) self.assertEqual(response.status_code, 200) self.assertEqual( response.json(), { "id": 1, "name": "Luke Skywalker", "movie_readable": "Star Wars", "movie": { "name": "Star Wars", }, }, )
def test_visible_fields(self): """ Make sure that GETs with the ``__visible_fields`` parameter return the correct data. """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) # Test a simple query response = client.get( "/", params={"__visible_fields": "id,name", "__order": "id"} ) self.assertEqual(response.status_code, 200) self.assertEqual( response.json(), { "rows": [ {"id": 1, "name": "Star Wars"}, {"id": 2, "name": "Lord of the Rings"}, ] }, ) # Test with unrecognised columns response = client.get( "/", params={"__visible_fields": "foobar", "__order": "id"} ) self.assertEqual(response.status_code, 400) self.assertEqual( response.content, ( b"No matching column found with name == foobar - the column " b"options are ('id', 'name', 'rating')." ), )
def test_get_schema_with_choices(self): """ Make sure that if a Table has columns with choices specified, they appear in the schema. """ class Review(Table): class Rating(Enum): bad = 1 average = 2 good = 3 great = 4 score = Integer(choices=Rating) client = TestClient(PiccoloCRUD(table=Review, read_only=False)) response = client.get("/schema/") self.assertTrue(response.status_code == 200) self.assertEqual( response.json(), { "title": "ReviewIn", "type": "object", "properties": { "score": { "title": "Score", "extra": { "help_text": None, "choices": { "bad": { "display_name": "Bad", "value": 1 }, "average": { "display_name": "Average", "value": 2, }, "good": { "display_name": "Good", "value": 3 }, "great": { "display_name": "Great", "value": 4 }, }, }, "nullable": False, "type": "integer", } }, "help_text": None, "visible_fields_options": [ "id", "score", ], }, )
def test_delete_404(self): """ Should get a 404 if a matching row doesn't exist. """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) response = client.delete("/123/") self.assertTrue(response.status_code == 404)
def test_offset_limit_pagination(self): """ If the page size is greater than one, offset and limit is applied """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) response = client.get("/", params={"__page": 2}) self.assertTrue(response.status_code, 403) self.assertEqual(response.json(), {"rows": []})
def test_put_new(self): """ We expect a 404 - we don't allow PUT requests to create new resources. """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) response = client.put("/123/") self.assertTrue(response.status_code == 404)
def test_page_size_limit(self): """ If the page size limit is exceeded, the request should be rejected. """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) response = client.get( "/", params={"__page_size": PiccoloCRUD.max_page_size + 1}) self.assertTrue(response.status_code, 403) self.assertEqual(response.json(), {"error": "The page size limit has been exceeded"})
def test_reverse_order(self): """ Make sure that descending ordering works, e.g. ``__order=-id``. """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) rows = Movie.select().order_by(Movie.id, ascending=False).run_sync() response = client.get("/", params={"__order": "-id"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"rows": rows})
def test_get_404(self): """ A 404 should be returned if there's no matching row. """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) json = {"name": "Star Wars", "rating": "hello world"} response = client.post("/", json=json) self.assertEqual(response.status_code, 400) self.assertTrue(Movie.count().run_sync() == 0)
def test_patch_fails(self): """ Make sure a patch containing the wrong columns is rejected. """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) movie = Movie(name="Star Wars", rating=93) movie.save().run_sync() response = client.patch(f"/{movie.id}/", json={"foo": "bar"}) self.assertTrue(response.status_code == 400)
def test_basic(self): """ Make sure that bulk GETs return the correct data. """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) rows = Movie.select().order_by(Movie.id).run_sync() response = client.get("/", params={"__order": "id"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"rows": rows})
def test_empty_list(self): """ Make sure the content-range header responds correctly for empty rows """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) response = client.get("/?__range_header=true") self.assertTrue(response.status_code == 200) # Make sure the content is correct: response_json = response.json() self.assertEqual(0, len(response_json["rows"])) self.assertEqual(response.headers.get("Content-Range"), "movie 0-0/0")
def test_post_error(self): """ Make sure a post returns a validation error with incorrect or missing data. """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) json = {"name": "Star Wars", "rating": "hello world"} response = client.post("/", json=json) self.assertEqual(response.status_code, 400) self.assertTrue(Movie.count().run_sync() == 0)
def test_false_range_header_param(self): """ Make sure that __range_header=false is supported """ client = TestClient(PiccoloCRUD( table=Movie, read_only=False, )) response = client.get("/?__range_header=false") self.assertTrue(response.status_code == 200) self.assertEqual(response.headers.get("Content-Range"), None)
def test_get_schema_with_joins(self): """ Make sure that if a Table has columns with joins specified, they appear in the schema. """ client = TestClient( PiccoloCRUD(table=Role, read_only=False, max_joins=1)) response = client.get("/schema/") self.assertTrue(response.status_code == 200) self.assertEqual( response.json(), { "title": "RoleIn", "type": "object", "properties": { "movie": { "title": "Movie", "extra": { "foreign_key": True, "to": "movie", "help_text": None, "choices": None, }, "nullable": True, "type": "integer", }, "name": { "title": "Name", "extra": { "help_text": None, "choices": None }, "nullable": False, "maxLength": 100, "type": "string", }, }, "help_text": None, "visible_fields_options": [ "id", "movie", "movie.id", "movie.name", "movie.rating", "name", ], }, )
def test_delete_single(self): """ Make sure an existing row is deleted successfully. """ client = TestClient(PiccoloCRUD(table=Movie, read_only=False)) movie = Movie(name="Star Wars", rating=93) movie.save().run_sync() response = client.delete(f"/{movie.id}/") self.assertTrue(response.status_code == 204) self.assertTrue(Movie.count().run_sync() == 0)
def test_get_visible_fields_with_join(self): """ Make sure a get can return a row successfully with the ``__visible_fields`` parameter, when using joins. """ movie = Movie(name="Star Wars", rating=93) movie.save().run_sync() role = Role(name="Luke Skywalker", movie=movie.id) role.save().run_sync() # Test 1 - should be rejected, as by default `max_joins` is 0: client = TestClient(PiccoloCRUD(table=Role, read_only=False)) response = client.get( f"/{role.id}/", params={"__visible_fields": "name,movie.name"}, ) self.assertEqual(response.status_code, 400) self.assertEqual(response.content, b"Max join depth exceeded") # Test 2 - should work as `max_joins` is set: client = TestClient( PiccoloCRUD(table=Role, read_only=False, max_joins=1) ) response = client.get( f"/{role.id}/", params={"__visible_fields": "name,movie.name"} ) self.assertEqual(response.status_code, 200) self.assertEqual( response.json(), { "name": "Luke Skywalker", "movie": { "name": "Star Wars", }, }, )