Skip to content

Commit 7628372

Browse files
nesiesnesies
authored andcommitted
src/SnowLibrary/keywords/rest_api.py RESTClient and lazy authentication
1 parent 6493140 commit 7628372

1 file changed

Lines changed: 154 additions & 49 deletions

File tree

src/SnowLibrary/keywords/rest_api.py

Lines changed: 154 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,149 @@
1313
from SnowLibrary.exceptions import QueryNotExecuted
1414

1515

16+
class Singleton:
17+
def __init__(self, cls):
18+
self._cls = cls
19+
20+
def Instance(self, **kwargs):
21+
try:
22+
return self._instance
23+
except AttributeError:
24+
self._instance = self._cls(**kwargs)
25+
return self._instance
26+
27+
def __call__(self):
28+
raise TypeError('Singletons must be accessed through `Instance()`.')
29+
30+
def __instancecheck__(self, inst):
31+
return isinstance(inst, self._cls)
32+
33+
34+
@Singleton
35+
class RESTClientImpl:
36+
"""
37+
client to ServiceNow
38+
"""
39+
def __init__(self, host=None, user=None, password=None, is_admin=None):
40+
self.__is_admin_default = True
41+
42+
self.reset()
43+
self.__is_admin = is_admin
44+
self.__host = host
45+
self.__user = user
46+
self.__password = password
47+
48+
def reset(self):
49+
self.__is_admin = None
50+
self.__host = None
51+
self.__user = None
52+
self.__password = None
53+
self.__client = None
54+
self.__instance = None
55+
56+
@property
57+
def is_admin(self):
58+
if self.__is_admin is None:
59+
if "SNOW_REST_IS_ADMIN" not in os.environ:
60+
raise Exception("not is_admin argument nor "
61+
"SNOW_REST_IS_ADMIN found in environ")
62+
self.__is_admin = True \
63+
if os.environ.get("SNOW_REST_IS_ADMIN") == "1" \
64+
else False
65+
return self.__is_admin
66+
67+
@property
68+
def host(self):
69+
if self.__host is None:
70+
if "SNOW_TEST_URL" not in os.environ:
71+
raise Exception("not host argument nor SNOW_TEST_URL "
72+
"found in environ")
73+
self.__host = os.environ.get("SNOW_TEST_URL").strip()
74+
return self.__host
75+
76+
@property
77+
def user(self):
78+
if self.__user is None:
79+
if "SNOW_REST_USER" not in os.environ:
80+
raise Exception("not user argument nor SNOW_REST_USER "
81+
"found in environ")
82+
self.__user = os.environ.get("SNOW_REST_USER")
83+
return self.__user
84+
85+
@property
86+
def password(self):
87+
if self.__password is None:
88+
if "SNOW_REST_PASS" not in os.environ:
89+
raise Exception("not password argument nor SNOW_REST_PASS "
90+
"found in environ")
91+
self.__password = os.environ.get("SNOW_REST_PASS")
92+
return self.__password
93+
94+
@property
95+
def user(self):
96+
if self.__user is None:
97+
if "SNOW_REST_USER" not in os.environ:
98+
raise Exception("not user argument nor SNOW_REST_USER "
99+
"found in environ")
100+
self.__user = os.environ.get("SNOW_REST_USER")
101+
return self.__user
102+
103+
@property
104+
def instance(self):
105+
if self.__instance is None:
106+
if "http" not in self.host:
107+
self.__instance = urlparse(self.host).path.split(".")[0]
108+
else:
109+
self.__instance = urlparse(self.host).netloc.split(".")[0]
110+
111+
if self.__instance == "":
112+
raise AssertionError(
113+
"Unable to determine SNOW Instance. Verify that the "
114+
"SNOW_TEST_URL environment variable been set.")
115+
return self.__instance
116+
117+
@property
118+
def client(self):
119+
if self.__client is None:
120+
logger.debug("init new client instance:{} user:{}".format(
121+
self.instance,
122+
self.user))
123+
self.__client = pysnow.Client(
124+
instance=self.instance,
125+
user=self.user,
126+
password=self.password)
127+
return self.__client
128+
129+
130+
class RESTClient:
131+
"""
132+
robotframework keywords
133+
"""
134+
def __init__(self, host=None, user=None, password=None, is_admin=None):
135+
RESTClientImpl.Instance(host=host, user=user, password=password, is_admin=is_admin)
136+
137+
def get(self):
138+
RESTClientImpl.Instance()
139+
return RESTClientImpl.Instance()
140+
141+
@keyword
142+
def get_snow_instance(self):
143+
return RESTClientImpl.Instance().instance
144+
145+
@keyword
146+
def get_snow_user(self):
147+
return RESTClientImpl.Instance().user
148+
149+
@keyword
150+
def get_snow_is_admin(self):
151+
return RESTClientImpl.Instance().is_admin
152+
153+
@keyword
154+
def snow_reset_client(self):
155+
logger.info("snow_reset_client")
156+
RESTClientImpl.Instance().reset()
157+
158+
16159
class RESTQuery:
17160
"""
18161
This library implements keywords for retrieving current data for testing from ServiceNow. It leverages the
@@ -43,6 +186,7 @@ class RESTQuery:
43186
VALID_OPERANDS = ["AND", "OR", "NQ"]
44187

45188
def __init__(self, host=None, user=None, password=None, query_table=None, response=None):
189+
RESTClientImpl.Instance(host=host, user=user, password=password)
46190
"""
47191
The following arguments can be optionally provided when importing this library:
48192
- ``host``: The URL to your target ServiceNow instance (e.g. https://iceuat.service-now.com/). If none is provided,
@@ -55,31 +199,12 @@ def __init__(self, host=None, user=None, password=None, query_table=None, respon
55199
- ``response``: Set the response object from the ServiceNow REST API (intended to be used for testing).
56200
57201
"""
58-
if host is None:
59-
self.host = os.environ.get("SNOW_TEST_URL").strip()
60-
else:
61-
self.host = host.strip()
62-
if user is None:
63-
self.user = os.environ.get("SNOW_REST_USER")
64-
else:
65-
self.user = user
66-
if password is None:
67-
self.password = os.environ.get("SNOW_REST_PASS")
68-
else:
69-
self.password = password
70-
if "http" not in self.host:
71-
self.instance = urlparse(self.host).path.split(".")[0]
72-
else:
73-
self.instance = urlparse(self.host).netloc.split(".")[0]
74-
if self.instance == "":
75-
raise AssertionError(
76-
"Unable to determine SNOW Instance. Verify that the SNOW_TEST_URL environment variable been set.")
77-
self.client = pysnow.Client(instance=self.instance, user=self.user, password=self.password)
78202
self.query_table = query_table
79203
self.query = pysnow.QueryBuilder()
80204
self.response = response
81205
self.record_count = None
82206
self.desired_response_fields = list()
207+
83208

84209
@staticmethod
85210
def _parse_datetime(date):
@@ -263,7 +388,8 @@ def execute_query(self, multiple=False):
263388
or no table has been defined, an error is thrown.
264389
"""
265390
assert self.query_table is not None, "Query table must already be specified in this test case, but is not."
266-
query_resource = self.client.resource(api_path="/table/{query_table}".format(query_table=self.query_table))
391+
query_resource = RESTClientImpl.Instance().client.resource(
392+
api_path="/table/{query_table}".format(query_table=self.query_table))
267393
try: # Catch empty queries or errors making the request
268394
if self.desired_response_fields:
269395
logger.info("Response fields specified in query parameters.")
@@ -431,7 +557,8 @@ def get_records_created_in_date_range(self, start, end):
431557
start_dt = self._parse_datetime(start)
432558
end_dt = self._parse_datetime(end)
433559

434-
query_resource = self.client.resource(api_path="/table/{query_table}".format(query_table=self.query_table))
560+
query_resource = RESTClientImpl.Instance().client.resource(
561+
api_path="/table/{query_table}".format(query_table=self.query_table))
435562
fields = ['sys_id']
436563
content = query_resource.get(
437564
query="sys_created_onBETWEENjavascript:gs.dateGenerate('{start}')@javascript:gs.dateGenerate('{end}')".format(
@@ -449,6 +576,7 @@ class RESTInsert:
449576
ROBOT_LIBRARY_SCOPE = "TEST CASE"
450577

451578
def __init__(self, host=None, user=None, password=None, insert_table=None, response=None):
579+
RESTClientImpl.Instance(host=host, user=user, password=password)
452580

453581
"""The following arguments can be optionally provided when importing this library:
454582
- ``host``: The URL to your target ServiceNow instance (e.g. https://iceuat.service-now.com/).
@@ -462,34 +590,10 @@ def __init__(self, host=None, user=None, password=None, insert_table=None, respo
462590
- ``response``: Set the response object from the ServiceNow REST API (intended to be used for testing).
463591
"""
464592

465-
if host is None:
466-
self.host = os.environ.get("SNOW_TEST_URL").strip()
467-
else:
468-
self.host = host.strip()
469-
470-
if user is None:
471-
self.user = os.environ.get("SNOW_REST_USER")
472-
else:
473-
self.user = user
474-
475-
if password is None:
476-
self.password = os.environ.get("SNOW_REST_PASS")
477-
else:
478-
self.password = password
479-
480-
if "http" not in self.host:
481-
self.instance = urlparse(self.host).path.split(".")[0]
482-
else:
483-
self.instance = urlparse(self.host).netloc.split(".")[0]
484-
485-
if self.instance == "":
486-
raise AssertionError(
487-
"Unable to determine SNOW Instance. Verify that the SNOW_TEST_URL environment variable been set.")
488-
489-
self.client = pysnow.Client(instance=self.instance, user=self.user, password=self.password)
593+
490594
self.insert_table = insert_table
491595
self.response = response
492-
596+
493597
@keyword
494598
def insert_table_is(self, insert_table):
495599
"""
@@ -530,7 +634,8 @@ def insert_record_parameters(self, new_record_payload):
530634
def insert_record(self):
531635
"""This keyword inserts the record in Servicenow by calling Create function from pysnow. It returns the sysid
532636
of the newly created record."""
533-
insert_resource = self.client.resource(api_path="/table/{insert_table}".format(insert_table=self.insert_table))
637+
insert_resource = RESTClientImpl.Instance().client.resource(
638+
api_path="/table/{insert_table}".format(insert_table=self.insert_table))
534639
result = insert_resource.create(payload=self.new_record_payload)
535640
sys_id = result['sys_id']
536641
return sys_id

0 commit comments

Comments
 (0)