moto/tests/test_lakeformation/test_lakeformation.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

624 lines
19 KiB
Python
Raw Normal View History

2023-04-04 09:36:48 +00:00
"""Unit tests for lakeformation-supported APIs."""
from typing import Dict, Optional
2023-04-04 09:36:48 +00:00
import boto3
import pytest
from botocore.exceptions import ClientError
2024-01-07 12:03:33 +00:00
from moto import mock_aws
2023-04-04 09:36:48 +00:00
# See our Development Tips on writing tests for hints on how to write good tests:
# http://docs.getmoto.org/en/latest/docs/contributing/development_tips/tests.html
2024-01-07 12:03:33 +00:00
@mock_aws
2023-04-04 09:36:48 +00:00
def test_register_resource():
client = boto3.client("lakeformation", region_name="us-east-2")
resp = client.register_resource(ResourceArn="some arn", RoleArn="another arn")
2023-04-04 09:36:48 +00:00
del resp["ResponseMetadata"]
assert resp == {}
with pytest.raises(client.exceptions.AlreadyExistsException):
client.register_resource(ResourceArn="some arn", RoleArn="another arn")
2023-04-04 09:36:48 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
2023-04-04 09:36:48 +00:00
def test_describe_resource():
client = boto3.client("lakeformation", region_name="us-east-2")
client.register_resource(ResourceArn="some arn", RoleArn="role arn")
resp = client.describe_resource(ResourceArn="some arn")
assert resp["ResourceInfo"] == {"ResourceArn": "some arn", "RoleArn": "role arn"}
2024-01-07 12:03:33 +00:00
@mock_aws
2023-04-04 09:36:48 +00:00
def test_deregister_resource():
client = boto3.client("lakeformation", region_name="us-east-2")
client.register_resource(ResourceArn="some arn")
client.deregister_resource(ResourceArn="some arn")
with pytest.raises(ClientError) as exc:
client.describe_resource(ResourceArn="some arn")
err = exc.value.response["Error"]
assert err["Code"] == "EntityNotFoundException"
with pytest.raises(ClientError) as exc:
client.deregister_resource(ResourceArn="some arn")
err = exc.value.response["Error"]
assert err["Code"] == "EntityNotFoundException"
2023-04-04 09:36:48 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
2023-04-04 09:36:48 +00:00
def test_list_resources():
client = boto3.client("lakeformation", region_name="us-east-2")
resp = client.list_resources()
assert resp["ResourceInfoList"] == []
client.register_resource(ResourceArn="some arn")
client.register_resource(ResourceArn="another arn")
resp = client.list_resources()
assert len(resp["ResourceInfoList"]) == 2
2024-01-07 12:03:33 +00:00
@mock_aws
2023-04-04 09:36:48 +00:00
def test_data_lake_settings():
client = boto3.client("lakeformation", region_name="us-east-2")
resp = client.get_data_lake_settings()
assert resp["DataLakeSettings"] == {
"DataLakeAdmins": [],
"CreateDatabaseDefaultPermissions": [
{
"Principal": {"DataLakePrincipalIdentifier": "IAM_ALLOWED_PRINCIPALS"},
"Permissions": ["ALL"],
}
],
"CreateTableDefaultPermissions": [
{
"Principal": {"DataLakePrincipalIdentifier": "IAM_ALLOWED_PRINCIPALS"},
"Permissions": ["ALL"],
}
],
"TrustedResourceOwners": [],
"AllowExternalDataFiltering": False,
"ExternalDataFilteringAllowList": [],
}
settings = {"DataLakeAdmins": [{"DataLakePrincipalIdentifier": "dlpi"}]}
client.put_data_lake_settings(DataLakeSettings=settings)
resp = client.get_data_lake_settings()
assert resp["DataLakeSettings"] == settings
2024-01-07 12:03:33 +00:00
@mock_aws
def test_grant_permissions():
client = boto3.client("lakeformation", region_name="us-east-2")
resp = client.grant_permissions(
Principal={"DataLakePrincipalIdentifier": "asdf"},
Resource={"Database": {"Name": "db"}},
Permissions=["ALL"],
)
del resp["ResponseMetadata"]
assert resp == {}
resp = client.list_permissions()
assert resp["PrincipalResourcePermissions"] == [
{
"Principal": {"DataLakePrincipalIdentifier": "asdf"},
"Resource": {"Database": {"Name": "db"}},
"Permissions": ["ALL"],
"PermissionsWithGrantOption": [],
}
]
2024-01-07 12:03:33 +00:00
@mock_aws
def test_grant_permissions_idempotent():
client = boto3.client("lakeformation", region_name="us-east-2")
for _ in range(2):
resp = client.grant_permissions(
Principal={"DataLakePrincipalIdentifier": "asdf"},
Resource={"Database": {"Name": "db"}},
Permissions=["ALL"],
)
del resp["ResponseMetadata"]
assert resp == {}
resp = client.list_permissions()
assert resp["PrincipalResourcePermissions"] == [
{
"Principal": {"DataLakePrincipalIdentifier": "asdf"},
"Resource": {"Database": {"Name": "db"}},
"Permissions": ["ALL"],
"PermissionsWithGrantOption": [],
}
]
2024-01-07 12:03:33 +00:00
@mock_aws
def test_grant_permissions_staggered():
client = boto3.client("lakeformation", region_name="us-east-2")
client.grant_permissions(
Principal={"DataLakePrincipalIdentifier": "asdf"},
Resource={"Database": {"Name": "db"}},
Permissions=["DESCRIBE"],
)
client.grant_permissions(
Principal={"DataLakePrincipalIdentifier": "asdf"},
Resource={"Database": {"Name": "db"}},
Permissions=["CREATE_TABLE"],
)
resp = client.list_permissions()
assert len(resp["PrincipalResourcePermissions"]) == 1
assert set(resp["PrincipalResourcePermissions"][0]["Permissions"]) == set(
["DESCRIBE", "CREATE_TABLE"]
)
2024-01-07 12:03:33 +00:00
@mock_aws
2023-04-04 09:36:48 +00:00
def test_list_permissions():
client = boto3.client("lakeformation", region_name="eu-west-2")
resp = client.grant_permissions(
Principal={"DataLakePrincipalIdentifier": "asdf"},
Resource={"Database": {"Name": "db"}},
Permissions=["ALL"],
PermissionsWithGrantOption=["SELECT"],
)
del resp["ResponseMetadata"]
assert resp == {}
# list all
resp = client.list_permissions()
assert resp["PrincipalResourcePermissions"] == [
{
"Principal": {"DataLakePrincipalIdentifier": "asdf"},
"Resource": {"Database": {"Name": "db"}},
"Permissions": ["ALL"],
"PermissionsWithGrantOption": ["SELECT"],
}
]
2024-01-07 12:03:33 +00:00
@mock_aws
def test_list_permissions_invalid_input():
client = boto3.client("lakeformation", region_name="eu-west-2")
client.grant_permissions(
Principal={"DataLakePrincipalIdentifier": "asdf"},
Resource={"Database": {"Name": "db"}},
Permissions=["ALL"],
PermissionsWithGrantOption=["SELECT"],
)
with pytest.raises(client.exceptions.InvalidInputException):
client.list_permissions(Principal={"DataLakePrincipalIdentifier": "asdf"})
with pytest.raises(client.exceptions.InvalidInputException):
client.list_permissions(Resource={})
def grant_table_permissions(
client: boto3.client, catalog_id: str, principal: str, db: str, table: str
):
client.grant_permissions(
CatalogId=catalog_id,
Principal={"DataLakePrincipalIdentifier": principal},
Resource={
"Table": {
"DatabaseName": db,
"Name": table,
"CatalogId": catalog_id,
"TableWildcard": {},
}
},
Permissions=["ALL"],
PermissionsWithGrantOption=["SELECT"],
)
def grant_db_permissions(
client: boto3.client, catalog_id: str, principal: str, db: str
):
client.grant_permissions(
CatalogId=catalog_id,
Principal={"DataLakePrincipalIdentifier": principal},
Resource={"Database": {"Name": db, "CatalogId": catalog_id}},
Permissions=["ALL"],
PermissionsWithGrantOption=["SELECT"],
)
def grant_catalog_permissions(client: boto3.client, catalog_id: str, principal: str):
client.grant_permissions(
CatalogId=catalog_id,
Principal={"DataLakePrincipalIdentifier": principal},
Resource={"Catalog": {}},
Permissions=["CREATE_DATABASE"],
PermissionsWithGrantOption=[],
)
def grant_data_location_permissions(
client: boto3.client, resource_arn: str, catalog_id: str, principal: str
):
client.grant_permissions(
CatalogId=catalog_id,
Principal={"DataLakePrincipalIdentifier": principal},
Resource={"DataLocation": {"ResourceArn": resource_arn}},
Permissions=["DATA_LOCATION_ACCESS"],
PermissionsWithGrantOption=[],
)
def db_response(principal: str, catalog_id: str, db: str) -> Dict:
return {
"Principal": {"DataLakePrincipalIdentifier": principal},
"Resource": {
"Database": {
"CatalogId": catalog_id,
"Name": db,
}
},
"Permissions": ["ALL"],
"PermissionsWithGrantOption": ["SELECT"],
}
def table_response(principal: str, catalog_id: str, db: str, table: str) -> Dict:
return {
"Principal": {"DataLakePrincipalIdentifier": principal},
"Resource": {
"Table": {
"CatalogId": catalog_id,
"DatabaseName": db,
"Name": table,
"TableWildcard": {},
}
},
"Permissions": ["ALL"],
"PermissionsWithGrantOption": ["SELECT"],
}
def catalog_response(principal: str) -> Dict:
return {
"Principal": {"DataLakePrincipalIdentifier": principal},
"Resource": {"Catalog": {}},
"Permissions": ["CREATE_DATABASE"],
"PermissionsWithGrantOption": [],
}
def data_location_response(
principal: str, resource_arn: str, catalog_id: Optional[str] = None
) -> Dict:
response = {
"Principal": {"DataLakePrincipalIdentifier": principal},
"Resource": {"DataLocation": {"ResourceArn": resource_arn}},
"Permissions": ["DATA_LOCATION_ACCESS"],
"PermissionsWithGrantOption": [],
}
if catalog_id is not None:
response["Resource"]["CatalogId"] = catalog_id
return response
2024-01-07 12:03:33 +00:00
@mock_aws
def test_list_permissions_filtered_for_catalog_id():
client = boto3.client("lakeformation", region_name="eu-west-2")
catalog_id_1 = "000000000000"
catalog_id_2 = "000000000001"
principal_1 = "principal_1"
principal_2 = "principal_2"
grant_catalog_permissions(
client=client, catalog_id=catalog_id_1, principal=principal_1
)
grant_catalog_permissions(
client=client, catalog_id=catalog_id_2, principal=principal_2
)
permissions = client.list_permissions(CatalogId=catalog_id_1)[
"PrincipalResourcePermissions"
]
assert permissions == [catalog_response(principal=principal_1)]
permissions = client.list_permissions(CatalogId=catalog_id_2)[
"PrincipalResourcePermissions"
]
assert permissions == [catalog_response(principal=principal_2)]
2024-01-07 12:03:33 +00:00
@mock_aws
def test_list_permissions_filtered_for_resource_type():
client = boto3.client("lakeformation", region_name="eu-west-2")
catalog_id = "000000000000"
principal_1 = "principal_1"
db_1 = "db_1"
table_1 = "table_1"
grant_db_permissions(
client=client, catalog_id=catalog_id, principal=principal_1, db=db_1
)
grant_table_permissions(
client=client,
catalog_id=catalog_id,
principal=principal_1,
db=db_1,
table=table_1,
)
grant_catalog_permissions(
client=client, catalog_id=catalog_id, principal=principal_1
)
res = client.list_permissions(CatalogId=catalog_id, ResourceType="DATABASE")
assert res["PrincipalResourcePermissions"] == [
db_response(principal=principal_1, catalog_id=catalog_id, db=db_1),
]
res = client.list_permissions(CatalogId=catalog_id, ResourceType="TABLE")
assert res["PrincipalResourcePermissions"] == [
table_response(
principal=principal_1, catalog_id=catalog_id, db=db_1, table=table_1
),
]
res = client.list_permissions(CatalogId=catalog_id, ResourceType="CATALOG")
assert res["PrincipalResourcePermissions"] == [
catalog_response(principal=principal_1),
]
2024-01-07 12:03:33 +00:00
@mock_aws
def test_list_permissions_filtered_for_resource_db():
client = boto3.client("lakeformation", region_name="eu-west-2")
catalog_id = "000000000000"
principal_1 = "principal_1"
db_1 = "db_1"
db_2 = "db_2"
grant_db_permissions(
client=client, catalog_id=catalog_id, principal=principal_1, db=db_1
)
grant_db_permissions(
client=client, catalog_id=catalog_id, principal=principal_1, db=db_2
)
res = client.list_permissions(
CatalogId=catalog_id, Resource={"Database": {"Name": db_1}}
)
assert res["PrincipalResourcePermissions"] == [
db_response(principal=principal_1, catalog_id=catalog_id, db=db_1),
]
res = client.list_permissions(
CatalogId=catalog_id, Resource={"Database": {"Name": db_2}}
)
assert res["PrincipalResourcePermissions"] == [
db_response(principal=principal_1, catalog_id=catalog_id, db=db_2),
]
2024-01-07 12:03:33 +00:00
@mock_aws
def test_list_permissions_filtered_for_resource_table():
client = boto3.client("lakeformation", region_name="eu-west-2")
catalog_id = "000000000000"
principal_1 = "principal_1"
db_1 = "db_1"
table_1 = "table_1"
table_2 = "table_2"
grant_table_permissions(
client=client,
catalog_id=catalog_id,
principal=principal_1,
db=db_1,
table=table_1,
)
grant_table_permissions(
client=client,
catalog_id=catalog_id,
principal=principal_1,
db=db_1,
table=table_2,
)
res = client.list_permissions(
CatalogId=catalog_id,
Resource={"Table": {"DatabaseName": db_1, "Name": table_1}},
)
assert res["PrincipalResourcePermissions"] == [
table_response(
principal=principal_1, catalog_id=catalog_id, db=db_1, table=table_1
),
]
res = client.list_permissions(
CatalogId=catalog_id,
Resource={"Table": {"DatabaseName": db_1, "Name": table_2}},
)
assert res["PrincipalResourcePermissions"] == [
table_response(
principal=principal_1, catalog_id=catalog_id, db=db_1, table=table_2
),
]
2024-01-07 12:03:33 +00:00
@mock_aws
def test_list_permissions_filtered_for_resource_data_location():
client = boto3.client("lakeformation", region_name="eu-west-2")
catalog_id = "000000000000"
principal = "principal"
data_location_resource_arn_1 = "resource_arn_1"
data_location_resource_arn_2 = "resource_arn_2"
grant_data_location_permissions(
catalog_id=catalog_id,
client=client,
resource_arn=data_location_resource_arn_1,
principal=principal,
)
grant_data_location_permissions(
catalog_id=catalog_id,
client=client,
resource_arn=data_location_resource_arn_2,
principal=principal,
)
res = client.list_permissions(
CatalogId=catalog_id,
Resource={"DataLocation": {"ResourceArn": data_location_resource_arn_1}},
)
assert res["PrincipalResourcePermissions"] == [
data_location_response(principal, resource_arn=data_location_resource_arn_1)
]
res = client.list_permissions(
CatalogId=catalog_id,
Resource={"DataLocation": {"ResourceArn": data_location_resource_arn_2}},
)
assert res["PrincipalResourcePermissions"] == [
data_location_response(principal, resource_arn=data_location_resource_arn_2)
]
2024-01-07 12:03:33 +00:00
@mock_aws
2023-04-04 09:36:48 +00:00
def test_revoke_permissions():
client = boto3.client("lakeformation", region_name="eu-west-2")
client.grant_permissions(
Principal={"DataLakePrincipalIdentifier": "asdf"},
Resource={"Database": {"Name": "db"}},
Permissions=["SELECT", "ALTER", "DROP"],
PermissionsWithGrantOption=["SELECT", "DROP"],
)
resp = client.revoke_permissions(
Principal={"DataLakePrincipalIdentifier": "asdf"},
Resource={"Database": {"Name": "db"}},
Permissions=["DROP"],
)
del resp["ResponseMetadata"]
assert resp == {}
# list all
resp = client.list_permissions()
assert resp["PrincipalResourcePermissions"][0]["Principal"] == {
"DataLakePrincipalIdentifier": "asdf"
}
assert resp["PrincipalResourcePermissions"][0]["Resource"] == {
"Database": {"Name": "db"}
}
# compare as sets to be order independent
assert set(resp["PrincipalResourcePermissions"][0]["Permissions"]) == set(
["SELECT", "ALTER"]
)
assert set(
resp["PrincipalResourcePermissions"][0]["PermissionsWithGrantOption"]
) == set(
[
"SELECT",
"DROP",
]
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_revoke_permissions_unknown_catalog_id():
client = boto3.client("lakeformation", region_name="eu-west-2")
client.grant_permissions(
CatalogId="valid_id",
Principal={"DataLakePrincipalIdentifier": "asdf"},
Resource={"Database": {"Name": "db"}},
Permissions=["SELECT"],
)
resp = client.revoke_permissions(
CatalogId="different_id",
Principal={"DataLakePrincipalIdentifier": "asdf"},
Resource={"Database": {"Name": "db"}},
Permissions=["SELECT"],
)
del resp["ResponseMetadata"]
assert resp == {}
resp = client.list_permissions()
assert len(["PrincipalResourcePermissions"]) == 1
2023-04-04 09:36:48 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
2023-04-04 09:36:48 +00:00
def test_list_data_cells_filter():
client = boto3.client("lakeformation", region_name="eu-west-2")
resp = client.list_data_cells_filter()
assert resp["DataCellsFilters"] == []
2024-01-07 12:03:33 +00:00
@mock_aws
2023-04-04 09:36:48 +00:00
def test_batch_revoke_permissions():
client = boto3.client("lakeformation", region_name="eu-west-2")
client.batch_grant_permissions(
Entries=[
{
"Id": "id1",
"Principal": {"DataLakePrincipalIdentifier": "id1"},
"Resource": {"Database": {"Name": "db"}},
"Permissions": ["SELECT", "ALTER", "DROP"],
"PermissionsWithGrantOption": ["SELECT", "DROP"],
},
{
"Id": "id2",
"Principal": {"DataLakePrincipalIdentifier": "id2"},
"Resource": {"Database": {"Name": "db"}},
"Permissions": ["SELECT", "ALTER", "DROP"],
"PermissionsWithGrantOption": ["SELECT", "DROP"],
},
{
"Id": "id3",
"Principal": {"DataLakePrincipalIdentifier": "id3"},
"Resource": {"Database": {"Name": "db"}},
"Permissions": ["SELECT", "ALTER", "DROP"],
"PermissionsWithGrantOption": ["SELECT", "DROP"],
},
]
)
resp = client.list_permissions()
assert len(resp["PrincipalResourcePermissions"]) == 3
client.batch_revoke_permissions(
Entries=[
{
"Id": "id1",
"Principal": {"DataLakePrincipalIdentifier": "id2"},
"Resource": {"Database": {"Name": "db"}},
"Permissions": ["SELECT", "ALTER", "DROP"],
"PermissionsWithGrantOption": ["SELECT", "DROP"],
},
{
"Id": "id2",
"Principal": {"DataLakePrincipalIdentifier": "id3"},
"Resource": {"Database": {"Name": "db"}},
"Permissions": ["SELECT", "ALTER", "DROP"],
"PermissionsWithGrantOption": ["SELECT", "DROP"],
},
]
)
resp = client.list_permissions()
assert len(resp["PrincipalResourcePermissions"]) == 1