Skip to content

Commit

Permalink
Merge pull request #75 from keboola/AIS-44
Browse files Browse the repository at this point in the history
add verify token & branch metadata methods
  • Loading branch information
odinuv authored Jun 1, 2023
2 parents e491a19 + c466048 commit 59c8daa
Show file tree
Hide file tree
Showing 11 changed files with 343 additions and 8 deletions.
2 changes: 0 additions & 2 deletions kbcstorage/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ def __init__(self, root_url, path_component, token):
"""
if not root_url:
raise ValueError("Root URL is required.")
if not path_component:
raise ValueError("Path component is required.")
if not token:
raise ValueError("Token is required.")
self.root_url = root_url
Expand Down
43 changes: 43 additions & 0 deletions kbcstorage/branches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
Manages calls to the Storage API relating to development branches
Full documentation https://keboola.docs.apiary.io/#reference/development-branches
"""
from kbcstorage.base import Endpoint


class Branches(Endpoint):
"""
Tokens Endpoint
"""
def __init__(self, root_url, token):
"""
Create a Tokens endpoint.
Args:
root_url (:obj:`str`): The base url for the API.
token (:obj:`str`): A storage API key.
"""
# Branches have inconsistent endpoint naming - it's either dev-branches or branch, so it need to be resolved
# endpoint by endpoint.
super().__init__(root_url, "", token)

def metadata(self, branch_id="default"):
"""
Get branch metadata
Args:
branch_id (str): The id of the branch or "default" to get metadata for the main branch (production).
Returns:
response_body: The parsed json from the HTTP response.
Raises:
requests.HTTPError: If the API request fails.
"""
if not isinstance(branch_id, str) or branch_id == "":
raise ValueError(f"Invalid branch_id '{branch_id}'")

url = f"{self.base_url}branch/{branch_id}/metadata"
return self._get(url)
5 changes: 4 additions & 1 deletion kbcstorage/client.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
""""
Entry point for the Storage API client.
"""

from kbcstorage.branches import Branches
from kbcstorage.buckets import Buckets
from kbcstorage.components import Components
from kbcstorage.configurations import Configurations
from kbcstorage.tokens import Tokens
from kbcstorage.workspaces import Workspaces
from kbcstorage.jobs import Jobs
from kbcstorage.tables import Tables
Expand Down Expand Up @@ -37,6 +38,8 @@ def __init__(self, api_domain, token, branch_id='default'):
self.workspaces = Workspaces(self.root_url, self.token)
self.components = Components(self.root_url, self.token, self.branch_id)
self.configurations = Configurations(self.root_url, self.token, self.branch_id)
self.tokens = Tokens(self.root_url, self.token)
self.branches = Branches(self.root_url, self.token)

@property
def token(self):
Expand Down
35 changes: 35 additions & 0 deletions kbcstorage/tokens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
Manages calls to the Storage API relating to tokens
Full documentation https://keboola.docs.apiary.io/#reference/tokens-and-permissions/.
"""
from kbcstorage.base import Endpoint


class Tokens(Endpoint):
"""
Tokens Endpoint
"""
def __init__(self, root_url, token):
"""
Create a Tokens endpoint.
Args:
root_url (:obj:`str`): The base url for the API.
token (:obj:`str`): A storage API key.
"""
super().__init__(root_url, 'tokens', token)

def verify(self):
"""
Verify token.
Returns:
response_body: The parsed json from the HTTP response.
Raises:
requests.HTTPError: If the API request fails.
"""
url = '{}/verify'.format(self.base_url)
return self._get(url)
5 changes: 0 additions & 5 deletions tests/functional/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,6 @@ def test_missing_url(self):
with self.assertRaisesRegex(ValueError, "Root URL is required."):
Endpoint(None, '', None)

def test_missing_part(self):
with self.assertRaisesRegex(ValueError,
"Path component is required."):
Endpoint('https://connection.keboola.com/', '', None)

def test_missing_token(self):
with self.assertRaisesRegex(ValueError, "Token is required."):
Endpoint('https://connection.keboola.com/', 'tables', None)
13 changes: 13 additions & 0 deletions tests/functional/test_branches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import os

from kbcstorage.branches import Branches
from tests.base_test_case import BaseTestCase


class TestEndpoint(BaseTestCase):
def setUp(self):
self.branches = Branches(os.getenv('KBC_TEST_API_URL'), os.getenv('KBC_TEST_TOKEN'))

def test_metadata(self):
metadata = self.branches.metadata('default')
self.assertTrue(isinstance(metadata, list))
16 changes: 16 additions & 0 deletions tests/functional/test_tokens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import os
from kbcstorage.tokens import Tokens
from tests.base_test_case import BaseTestCase


class TestEndpoint(BaseTestCase):
def setUp(self):
self.tokens = Tokens(os.getenv('KBC_TEST_API_URL'),
os.getenv('KBC_TEST_TOKEN'))

def test_verify(self):
token_info = self.tokens.verify()
self.assertTrue('id' in token_info)
self.assertTrue('description' in token_info)
self.assertTrue('canManageBuckets' in token_info)
self.assertTrue('owner' in token_info)
8 changes: 8 additions & 0 deletions tests/mocks/branches_responses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
branches_metadata_response = [
{
"id": "93670",
"key": "KBC.projectDescription",
"value": "Testing project one",
"timestamp": "2023-05-31T17:52:18+0200"
}
]
49 changes: 49 additions & 0 deletions tests/mocks/test_branches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""
Test basic functionality of the Branches endpoint
"""
import unittest

import responses

from kbcstorage.branches import Branches
from tests.mocks.branches_responses import branches_metadata_response


class TestBranchesEndpointWithMocks(unittest.TestCase):
"""
Test the methods of a Branches endpoint instance with mock HTTP responses
"""
def setUp(self):
token = 'dummy_token'
base_url = 'https://connection.keboola.com/'
self.branches = Branches(base_url, token)

@responses.activate
def test_metadata_no_branch(self):
"""
Branches lists metadata correctly
"""
responses.add(
responses.Response(
method='GET',
url='https://connection.keboola.com/v2/storage/branch/default/metadata',
json=branches_metadata_response
)
)
branch_metadata = self.branches.metadata()
self.assertEqual(branches_metadata_response, branch_metadata)

@responses.activate
def test_metadata_some_branch(self):
"""
Branches lists metadata correctly
"""
responses.add(
responses.Response(
method='GET',
url='https://connection.keboola.com/v2/storage/branch/1234/metadata',
json=branches_metadata_response
)
)
branch_metadata = self.branches.metadata('1234')
self.assertEqual(branches_metadata_response, branch_metadata)
34 changes: 34 additions & 0 deletions tests/mocks/test_tokens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""
Test basic functionality of the Tokens endpoint
"""
import unittest

import responses

from kbcstorage.tokens import Tokens
from tests.mocks.token_responses import verify_token_response


class TestTokensEndpointWithMocks(unittest.TestCase):
"""
Test the methods of a Tokens endpoint instance with mock HTTP responses
"""
def setUp(self):
token = 'dummy_token'
base_url = 'https://connection.keboola.com/'
self.tokens = Tokens(base_url, token)

@responses.activate
def test_verify(self):
"""
Verify token returns correctly
"""
responses.add(
responses.Response(
method='GET',
url='https://connection.keboola.com/v2/storage/tokens/verify',
json=verify_token_response
)
)
token_info = self.tokens.verify()
self.assertEqual(verify_token_response, token_info)
141 changes: 141 additions & 0 deletions tests/mocks/token_responses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
verify_token_response = {
"id": "373115",
"created": "2021-06-23T09:33:36+0200",
"refreshed": "2021-06-23T09:33:36+0200",
"description": "[email protected]",
"uri": "https://connection.keboola.com/v2/storage/tokens/373115",
"isMasterToken": True,
"canManageBuckets": True,
"canManageTokens": True,
"canReadAllFileUploads": True,
"canPurgeTrash": True,
"expires": None,
"isExpired": False,
"isDisabled": False,
"dailyCapacity": 0,
"token": "8625-373115-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"bucketPermissions": {
"out.c-test2": "manage",
"in.c-test3": "manage",
"out.c-test": "manage",
"out.c-some-other": "manage"
},
"owner": {
"id": 8625,
"name": "Test Project",
"type": "production",
"region": "us-east-1",
"created": "2021-06-23T09:33:32+0200",
"expires": None,
"features": [
"syrup-jobs-limit-10",
"oauth-v3",
"queuev2",
"storage-types",
"allow-ai",
"alternat",
],
"dataSizeBytes": 31474176,
"rowsCount": 797,
"hasMysql": False,
"hasSynapse": False,
"hasRedshift": True,
"hasSnowflake": True,
"hasExasol": False,
"hasTeradata": False,
"hasBigquery": False,
"defaultBackend": "snowflake",
"hasTryModeOn": "0",
"limits": {
"components.jobsParallelism": {
"name": "components.jobsParallelism",
"value": 10
},
"goodData.dataSizeBytes": {
"name": "goodData.dataSizeBytes",
"value": 1000000000
},
"goodData.demoTokenEnabled": {
"name": "goodData.demoTokenEnabled",
"value": 1
},
"goodData.prodTokenEnabled": {
"name": "goodData.prodTokenEnabled",
"value": 0
},
"goodData.usersCount": {
"name": "goodData.usersCount",
"value": 30
},
"kbc.adminsCount": {
"name": "kbc.adminsCount",
"value": 10
},
"kbc.extractorsCount": {
"name": "kbc.extractorsCount",
"value": 0
},
"kbc.monthlyProjectPowerLimit": {
"name": "kbc.monthlyProjectPowerLimit",
"value": 50
},
"kbc.writersCount": {
"name": "kbc.writersCount",
"value": 0
},
"orchestrations.count": {
"name": "orchestrations.count",
"value": 10
},
"storage.dataSizeBytes": {
"name": "storage.dataSizeBytes",
"value": 50000000000
},
"storage.jobsParallelism": {
"name": "storage.jobsParallelism",
"value": 10
}
},
"metrics": {
"kbc.adminsCount": {
"name": "kbc.adminsCount",
"value": 1
},
"orchestrations.count": {
"name": "orchestrations.count",
"value": 0
},
"storage.dataSizeBytes": {
"name": "storage.dataSizeBytes",
"value": 31474176
},
"storage.rowsCount": {
"name": "storage.rowsCount",
"value": 797
}
},
"isDisabled": False,
"billedMonthlyPrice": None,
"dataRetentionTimeInDays": 7,
"fileStorageProvider": "aws",
"redshift": {
"connectionId": 365,
"databaseName": "sapi_8625"
}
},
"organization": {
"id": "111111"
},
"admin": {
"name": "Devel",
"id": 59,
"features": [
"ui-devel-preview",
"manage-try-mode",
"validate-sql",
"early-adopter-preview"
],
"isOrganizationMember": True,
"role": "admin"
}
}

0 comments on commit 59c8daa

Please sign in to comment.