Skip to content

Commit

Permalink
Merge pull request #135 from ARGOeu/devel
Browse files Browse the repository at this point in the history
Version 0.5.6
  • Loading branch information
themiszamani authored Jun 21, 2022
2 parents c679cd8 + d8092c1 commit 7be4d7c
Show file tree
Hide file tree
Showing 13 changed files with 723 additions and 80 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## [0.5.6] - 2022-06-21

### Added

AM-233 ams-library: support for project_member_get api call
AM-230 ams-library: support for project_member_add api call
AM-229 ams-library: support for user_get api call
AM-226 ams-library: support for user_create api call

## [0.5.5] - 2021-04-15

### Added
Expand Down
5 changes: 2 additions & 3 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@ pipeline {
echo 'Building Rpm...'
sh '''
cd ${WORKSPACE}/$PROJECT_DIR
coverage run -m unittest2 discover -v
scl enable python27 rh-python36 'tox'
scl enable rh-python36 'coverage xml --omit=*usr* --omit=*.tox*'
coverage run -m unittest discover -v
coverage xml --omit=*usr* --omit=*.tox*
'''
cobertura coberturaReportFile: '**/coverage.xml'
}
Expand Down
7 changes: 6 additions & 1 deletion argo-ams-library.spec
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

Name: argo-ams-library
Summary: %{sum}
Version: 0.5.5
Version: 0.5.6
Release: 1%{?dist}

Group: Development/Libraries
Expand Down Expand Up @@ -95,6 +95,11 @@ rm -rf %{buildroot}


%changelog
* Tue Jun 21 2022 agelostsal <[email protected]> - 0.5.6-1%{?dist}
- AM-233 ams-library: support for project_member_get api call
- AM-230 ams-library: support for project_member_add api call
- AM-229 ams-library: support for user_get api call
- AM-226 ams-library: support for user_create api call
* Thu Apr 15 2021 agelostsal <[email protected]> - 0.5.5-1%{?dist}
- ARGO-2768 ams-library: support for AMS authorization header
* Thu Oct 8 2020 Daniel Vrcic <[email protected]> - 0.5.4-1%{?dist}
Expand Down
2 changes: 2 additions & 0 deletions pymod/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging

try:
from logging import NullHandler
except ImportError:
Expand All @@ -14,3 +15,4 @@ def emit(self, record):
from .amsmsg import AmsMessage
from .amstopic import AmsTopic
from .amssubscription import AmsSubscription
from .amsuser import AmsUser, AmsUserProject
238 changes: 178 additions & 60 deletions pymod/ams.py

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion pymod/amsmsg.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
import json
import inspect
from base64 import b64encode, b64decode
from collections import Callable
try:
from collections.abc import Callable
except ImportError:
from collections import Callable
from .amsexceptions import AmsMessageException

class AmsMessage(Callable):
Expand Down
5 changes: 3 additions & 2 deletions pymod/amstopic.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .amsexceptions import AmsException


class AmsTopic(object):
"""Abstraction of AMS Topic
Expand All @@ -18,10 +19,10 @@ def __init__(self, fullname, init):
self.name = self._build_name(self.fullname)

def delete(self):
"""Delete subscription
"""Delete topic
Return:
True: succesfull topic deletion
True: successfull topic deletion
"""

return self.init.delete_topic(self.name)
Expand Down
209 changes: 209 additions & 0 deletions pymod/amsuser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import json


class AmsUserProject(object):

def __init__(self, project="", roles=None, topics=None, subscriptions=None):
"""
Initialises a new User-Project object.
NOTE:
When using a new AmsUserProject object during the creation of a new user in ams,
you can only affect the project and roles fields.You cannot add a user to a topic
or subscription through the create functionality.The topics and subscriptions fields
are present only for view purposes.
:param project: (str) name of the project
:param roles: (str[]) roles the user has under the given project
:param topics: (str[]) topics that the user belongs to under the given project
:param subscriptions: (str[]) subscriptions that the user belongs to under the given project
"""
if subscriptions is None or not isinstance(subscriptions, list):
subscriptions = []
if topics is None or not isinstance(topics, list):
topics = []
if roles is None or not isinstance(roles, list):
roles = []
else:
for r in roles:
if not isinstance(r, str):
raise ValueError("role has to be of type str")
self.project = project
self.roles = roles
self.topics = topics
self.subscriptions = subscriptions

def load_from_dict(self, project_dict):
"""
Accepts a dictionary that contains project data in order to fill the instance's fields
:param (dict) project_dict: dict that contains project data
:return: (AmsUserProject) the ams user project object filled with any data provided to its respective fields
"""
if "project" in project_dict:
self.project = project_dict["project"]

if "roles" in project_dict:
self.roles = project_dict["roles"]
else:
self.roles = []

if "topics" in project_dict:
self.topics = project_dict["topics"]
else:
self.topics = []

if "subscriptions" in project_dict:
self.subscriptions = project_dict["subscriptions"]
else:
self.subscriptions = []

return self


class AmsUser(object):

def __init__(self, uuid="", name="", projects=None, firstname="", lastname="", organization="", description="",
token="", email="", service_roles=None, created_on="", created_by="", modified_on=""):
"""
Initialise a new user object.
NOTE:
When using a new AmsUser object during the create functionality, the fields that will affect
the user creation are name, projects, firstname, lastname, organisation, description, email and
service_roles.You cannot control the values for the rest of the fields through the create functionality.
The rest of the fields are present for view purposes.
:param uuid: (str) the uuid of the user
:param name: (str) the username
:param projects: (AmsUserProject[]) list of projects the user belongs to in AMS
:param firstname: (str) firstname of the user
:param lastname: (str) lastname of the user
:param organization: (str) organisation of the user
:param description: (str) description of the user
:param token: (str) user access token for the AMS
:param email: (str) user email
:param service_roles: (str[]) possible service roles the user might have in AMS
:param created_on: (str) user creation date
:param created_by: (str) user creator
:param modified_on: (str) timestamp of the latest modification
"""

if service_roles is None or not isinstance(service_roles, list):
service_roles = []
else:
for s in service_roles:
if not isinstance(s, str):
raise ValueError("service role has to be of type str")

if projects is None or not isinstance(projects, list):
projects = []
else:
for p in projects:
if not isinstance(p, AmsUserProject):
raise ValueError("project has to be of type AmsUserProject")

self.uuid = uuid
self.name = name
self.projects = projects
self.firstname = firstname
self.lastname = lastname
self.organization = organization
self.description = description
self.token = token
self.email = email
self.service_roles = service_roles
self.created_on = created_on
self.created_by = created_by
self.modified_on = modified_on

def to_json(self):
"""
Utility function that helps convert the AmsUser object to its json string representation
using json.dumps().
:return: (str) the json string representation of the object
"""
user_dict = {}
if len(self.projects) > 0:
projects_body = []
for p in self.projects:
projects_body.append(
{
"project": p.project,
"roles": p.roles,
"topics": p.topics,
"subscriptions": p.subscriptions
}
)
user_dict["projects"] = projects_body

if self.firstname != "":
user_dict["first_name"] = self.firstname

if self.lastname != "":
user_dict["last_name"] = self.lastname

if self.description != "":
user_dict["description"] = self.description

if self.organization != "":
user_dict["organization"] = self.organization

if self.email != "":
user_dict["email"] = self.email

if len(self.service_roles) > 0:
user_dict["service_roles"] = self.service_roles

return json.dumps(user_dict)

def load_from_dict(self, user_dict):
"""
Accepts a dictionary that contains user data in order to fill the instance's fields
:param (dict) user_dict: dict that contains user data
:return: (AmsUser) the user object filled with any data provided to its respective fields
"""

if "uuid" in user_dict:
self.uuid = user_dict["uuid"]

if "projects" in user_dict:
user_projects = []
for p in user_dict["projects"]:
user_projects.append(AmsUserProject().load_from_dict(p))
self.projects = user_projects

if "name" in user_dict:
self.name = user_dict["name"]

if "token" in user_dict:
self.token = user_dict["token"]

if "email" in user_dict:
self.email = user_dict["email"]

if "service_roles" in user_dict:
self.service_roles = user_dict["service_roles"]

if "created_on" in user_dict:
self.created_on = user_dict["created_on"]

if "modified_on" in user_dict:
self.modified_on = user_dict["modified_on"]

if "created_by" in user_dict:
self.created_by = user_dict["created_by"]

if "description" in user_dict:
self.description = user_dict["description"]

if "first_name" in user_dict:
self.firstname = user_dict["first_name"]

if "last_name" in user_dict:
self.lastname = user_dict["last_name"]

if "organization" in user_dict:
self.organization = user_dict["organization"]

return self
25 changes: 14 additions & 11 deletions tests/amsmocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ class SubMocks(object):
path="/v1/projects/TEST/subscriptions/subscription1:modifyOffset",
method="POST")
get_sub_timeTooffet_urlmatch = dict(netloc="localhost",
path="/v1/projects/TEST/subscriptions/subscription1:timeToOffset",
method="GET")
path="/v1/projects/TEST/subscriptions/subscription1:timeToOffset",
method="GET")

# Mock response for GET subscription request
@urlmatch(**get_sub_urlmatch)
Expand Down Expand Up @@ -112,38 +112,41 @@ def modifyacl_subscription_mock(self, url, request):

class ErrorMocks(object):
create_topic_urlmatch = dict(netloc="localhost",
path="/v1/projects/TEST/topics/topic1",
method='PUT')
path="/v1/projects/TEST/topics/topic1",
method='PUT')
create_subscription_urlmatch = dict(netloc="localhost",
path="/v1/projects/TEST/subscriptions/subscription1",
method="PUT")
delete_topic_urlmatch = dict(netloc="localhost",
path="/v1/projects/TEST/topics/topic1",
method='DELETE')
path="/v1/projects/TEST/topics/topic1",
method='DELETE')

# Mock ALREADY_EXIST error response for PUT topic request
@urlmatch(**create_topic_urlmatch)
def create_topic_alreadyexist_mock(self, url, request):
return response(409, '{"error":{"code": 409,"message":"Topic already exists","status":"ALREADY_EXIST"}}', None, None, 5, request)
return response(409, '{"error":{"code": 409,"message":"Topic already exists","status":"ALREADY_EXIST"}}', None,
None, 5, request)

# Mock NOT_FOUND error response for DELETE topic request
@urlmatch(**delete_topic_urlmatch)
def delete_topic_notfound_mock(self, url, request):
return response(404, '{"error":{"code": 404,"message":"Topic does not exist","status":"NOT_FOUND"}}', None, None, 5, request)
return response(404, '{"error":{"code": 404,"message":"Topic does not exist","status":"NOT_FOUND"}}', None,
None, 5, request)

# Mock ALREADY_EXIST error response for PUT subscription request
@urlmatch(**create_subscription_urlmatch)
def create_subscription_alreadyexist_mock(self, url, request):
return response(409, '{"error":{"code": 409,"message":"Subscription already exists","status":"ALREADY_EXIST"}}', None, None, 5, request)
return response(409, '{"error":{"code": 409,"message":"Subscription already exists","status":"ALREADY_EXIST"}}',
None, None, 5, request)


class TopicMocks(object):
get_topic_urlmatch = dict(netloc="localhost",
path="/v1/projects/TEST/topics/topic1",
method='GET')
create_topic_urlmatch = dict(netloc="localhost",
path="/v1/projects/TEST/topics/topic1",
method='PUT')
path="/v1/projects/TEST/topics/topic1",
method='PUT')
has_topic_urlmatch = dict(netloc="localhost",
path="/v1/projects/TEST/topics/topic1",
method="GET")
Expand Down
2 changes: 1 addition & 1 deletion tests/test_authenticate.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ def get_sub_offsets(url, request):
assert request.headers["x-api-key"] == "success_token"
return response(200, '{"max": 79, "min": 0, "current": 78}', None, None, 5, request)


# Execute ams client with mocked response
with HTTMock(auth_via_cert_success, get_sub_offsets):
ams = ArgoMessagingService(endpoint="localhost", project="TEST", cert="/path/cert", key="/path/key")
Expand Down Expand Up @@ -109,5 +108,6 @@ def auth_via_cert_missing_field(url, request):
response_dict = "{'other_field': 'success_token'}"
self.assertEqual(e.msg, "While trying the [auth_x509]: Token was not found in the response. Response: " + response_dict)


if __name__ == "__main__":
unittest.main()
Loading

0 comments on commit 7be4d7c

Please sign in to comment.