Skip to content

Commit 7eba32c

Browse files
authored
Allow specifying the basepath in the engine settings. (#447)
Added new primitive 'restler_basepath; and a new engine setting 'basepath'. If the engine settings do not specify the base path, the one from the specification is used. Updated test baselines.
1 parent ab77840 commit 7eba32c

21 files changed

+168
-98
lines changed

docs/user-guide/SettingsFile.md

+5
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ Example: `management.web.com`
102102

103103
(Note: do NOT include https:// or slashes here!)
104104

105+
### basepath: string (default None)
106+
Set to override the basepath that is specified in the grammar.
107+
108+
Example: `/api/v2`
109+
105110
### include_user_agent: bool (default True)
106111
Set to false to disable sending user agent with requests
107112

restler/engine/core/requests.py

+45
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,22 @@ def get_host_index(self):
568568
pass
569569
return -1
570570

571+
def get_basepath_index(self):
572+
""" Gets the index of the basepath custom payload line, if it exists in the grammar.
573+
574+
@return: The index of the basepath parameter or -1 if not found
575+
@rtype : Int
576+
577+
"""
578+
for i, line in enumerate(self._definition):
579+
try:
580+
if line[0] == "restler_basepath":
581+
return i
582+
except:
583+
# ignore line parsing exceptions
584+
pass
585+
return -1
586+
571587
def update_host(self):
572588
""" Updates the Host field for every request with the one specified in Settings
573589
@@ -586,6 +602,24 @@ def update_host(self):
586602
raise InvalidGrammarException
587603
self._definition.insert(header_idx, new_host_line)
588604

605+
def update_basepath(self):
606+
""" Updates the basepath custom payload for every request with the one specified in Settings
607+
608+
@return: None
609+
@rtype : None
610+
611+
"""
612+
basepath_idx = self.get_basepath_index()
613+
if basepath_idx >= 0:
614+
basepath = self._definition[basepath_idx][1]
615+
if Settings().basepath is not None:
616+
basepath = Settings().basepath
617+
self._definition[basepath_idx] = primitives.restler_static_string(basepath)
618+
else:
619+
# No basepath custom payload in the grammar - this is possible for older grammar versions.
620+
# Do nothing
621+
pass
622+
589623
def header_start_index(self):
590624
""" Gets the index of the first header line in the definition
591625
@@ -1298,6 +1332,17 @@ def update_hosts(self):
12981332
for req in self._requests:
12991333
req.update_host()
13001334

1335+
1336+
def update_basepaths(self):
1337+
""" Updates the basepaths in each request of the grammar file
1338+
1339+
@return: None
1340+
@rtype : None
1341+
1342+
"""
1343+
for req in self._requests:
1344+
req.update_basepath()
1345+
13011346
def get_host_from_grammar(self):
13021347
""" Gets the hostname from the grammar
13031348

restler/engine/primitives.py

+24
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class InvalidDictPrimitiveException(Exception):
4444
CUSTOM_PAYLOAD_QUERY = "restler_custom_payload_query"
4545
CUSTOM_PAYLOAD_UUID4_SUFFIX = "restler_custom_payload_uuid4_suffix"
4646
REFRESHABLE_AUTHENTICATION_TOKEN = "restler_refreshable_authentication_token"
47+
BASEPATH = "restler_basepath"
4748
SHADOW_VALUES = "shadow_values"
4849

4950
# Optional argument passed to grammar function definition functions
@@ -126,6 +127,7 @@ def __init__(self):
126127
CUSTOM_PAYLOAD_QUERY,
127128
CUSTOM_PAYLOAD_UUID4_SUFFIX,
128129
REFRESHABLE_AUTHENTICATION_TOKEN,
130+
BASEPATH,
129131
SHADOW_VALUES
130132
]
131133
self.supported_primitive_dict_types = [
@@ -847,3 +849,25 @@ def restler_refreshable_authentication_token(*args, **kwargs):
847849
examples = None
848850
param_name = None
849851
return sys._getframe().f_code.co_name, field_name, quoted, examples, param_name
852+
853+
def restler_basepath(*args, **kwargs):
854+
""" The basepath.
855+
856+
@param args: The argument with which the primitive is defined in the block
857+
of the request to which it belongs to. This is a custom
858+
payload which means that the user should have provided its
859+
exact value (to be rendered with).
860+
@type args: Tuple
861+
@param kwargs: Optional keyword arguments.
862+
@type kwargs: Dict
863+
864+
@return: A tuple of the primitive's name and its default value or its tag
865+
both passed as arguments via the restler grammar.
866+
@rtype : Tuple
867+
868+
"""
869+
basepath_value = args[0]
870+
quoted = False
871+
examples = None
872+
param_name = None
873+
return sys._getframe().f_code.co_name, basepath_value, quoted, examples, param_name

restler/restler.py

+5
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,11 @@ def signal_handler(sig, frame):
461461
)
462462
sys.exit(-1)
463463

464+
try:
465+
req_collection.update_basepaths()
466+
except requests.InvalidGrammarException:
467+
sys.exit(-1)
468+
464469
# Filter and get the requests to be used for fuzzing
465470
fuzzing_requests = preprocessing.create_fuzzing_req_collection(args.path_regex)
466471

restler/restler_settings.py

+6
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ def convert_wildcards_to_regex(str_value):
399399
self._grammar_schema = SettingsArg('grammar_schema', str, None, user_args)
400400
## Set to override the Host that's specified in the grammar
401401
self._host = SettingsArg('host', str, None, user_args)
402+
## Set to override the basepath that's specified in the grammar
403+
self._basepath = SettingsArg('basepath', str, None, user_args)
402404
## Ignore request dependencies
403405
self._ignore_dependencies = SettingsArg('ignore_dependencies', bool, False, user_args)
404406
## Ignore server-side feedback
@@ -532,6 +534,10 @@ def grammar_schema(self):
532534
def host(self):
533535
return self._host.val
534536

537+
@property
538+
def basepath(self):
539+
return self._basepath.val
540+
535541
@property
536542
def ignore_dependencies(self):
537543
return self._ignore_dependencies.val

src/compiler/Restler.Compiler.Test/CodeGeneratorTests.fs

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ module CodeGenerator =
7272

7373
method = OperationMethod.Get
7474
path = pathPayload
75+
basePath = ""
7576
queryParameters = [(ParameterPayloadSource.Examples, ParameterList [{ name = "page"; payload = q1; serialization = None}
7677
{ name = "payload"; payload = q2; serialization = None}])]
7778
bodyParameters = [ParameterPayloadSource.Examples, (ParameterList [{ name = "thebody"; payload = b1; serialization = None}]) ]

src/compiler/Restler.Compiler.Test/baselines/dependencyTests/header_deps_grammar.py

+7-11
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ def parse_serviceuserpost(data, **kwargs):
3131

3232
try:
3333
temp_7262 = str(headers["user-id"])
34-
34+
3535
except Exception as error:
3636
# This is not an error, since some properties are not always returned
3737
pass
3838

3939
pass
40-
40+
4141
# If no dynamic objects were extracted, throw.
4242
if not (temp_7262):
4343
raise ResponseParsingException("Error: all of the expected dynamic objects were not present in the response.")
@@ -50,8 +50,7 @@ def parse_serviceuserpost(data, **kwargs):
5050
# Endpoint: /service/user, method: Post
5151
request = requests.Request([
5252
primitives.restler_static_string("POST "),
53-
primitives.restler_static_string("/"),
54-
primitives.restler_static_string("api"),
53+
primitives.restler_basepath("/api"),
5554
primitives.restler_static_string("/"),
5655
primitives.restler_static_string("service"),
5756
primitives.restler_static_string("/"),
@@ -61,7 +60,7 @@ def parse_serviceuserpost(data, **kwargs):
6160
primitives.restler_static_string("Host: localhost:8888\r\n"),
6261
primitives.restler_refreshable_authentication_token("authentication_token_tag"),
6362
primitives.restler_static_string("\r\n"),
64-
63+
6564
{
6665
'post_send':
6766
{
@@ -81,8 +80,7 @@ def parse_serviceuserpost(data, **kwargs):
8180
# Endpoint: /service/user, method: Get
8281
request = requests.Request([
8382
primitives.restler_static_string("GET "),
84-
primitives.restler_static_string("/"),
85-
primitives.restler_static_string("api"),
83+
primitives.restler_basepath("/api"),
8684
primitives.restler_static_string("/"),
8785
primitives.restler_static_string("service"),
8886
primitives.restler_static_string("/"),
@@ -104,8 +102,7 @@ def parse_serviceuserpost(data, **kwargs):
104102
# Endpoint: /service/user, method: Put
105103
request = requests.Request([
106104
primitives.restler_static_string("PUT "),
107-
primitives.restler_static_string("/"),
108-
primitives.restler_static_string("api"),
105+
primitives.restler_basepath("/api"),
109106
primitives.restler_static_string("/"),
110107
primitives.restler_static_string("service"),
111108
primitives.restler_static_string("/"),
@@ -127,8 +124,7 @@ def parse_serviceuserpost(data, **kwargs):
127124
# Endpoint: /service/user, method: Delete
128125
request = requests.Request([
129126
primitives.restler_static_string("DELETE "),
130-
primitives.restler_static_string("/"),
131-
primitives.restler_static_string("api"),
127+
primitives.restler_basepath("/api"),
132128
primitives.restler_static_string("/"),
133129
primitives.restler_static_string("service"),
134130
primitives.restler_static_string("/"),

src/compiler/Restler.Compiler.Test/baselines/dependencyTests/header_response_writer_annotation_grammar.py

+7-11
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ def parse_serviceuserpost(data, **kwargs):
3131

3232
try:
3333
temp_7262 = str(headers["Location"])
34-
34+
3535
except Exception as error:
3636
# This is not an error, since some properties are not always returned
3737
pass
3838

3939
pass
40-
40+
4141
# If no dynamic objects were extracted, throw.
4242
if not (temp_7262):
4343
raise ResponseParsingException("Error: all of the expected dynamic objects were not present in the response.")
@@ -50,8 +50,7 @@ def parse_serviceuserpost(data, **kwargs):
5050
# Endpoint: /service/user, method: Post
5151
request = requests.Request([
5252
primitives.restler_static_string("POST "),
53-
primitives.restler_static_string("/"),
54-
primitives.restler_static_string("api"),
53+
primitives.restler_basepath("/api"),
5554
primitives.restler_static_string("/"),
5655
primitives.restler_static_string("service"),
5756
primitives.restler_static_string("/"),
@@ -61,7 +60,7 @@ def parse_serviceuserpost(data, **kwargs):
6160
primitives.restler_static_string("Host: localhost:8888\r\n"),
6261
primitives.restler_refreshable_authentication_token("authentication_token_tag"),
6362
primitives.restler_static_string("\r\n"),
64-
63+
6564
{
6665
'post_send':
6766
{
@@ -81,8 +80,7 @@ def parse_serviceuserpost(data, **kwargs):
8180
# Endpoint: /service/user/{userId}, method: Get
8281
request = requests.Request([
8382
primitives.restler_static_string("GET "),
84-
primitives.restler_static_string("/"),
85-
primitives.restler_static_string("api"),
83+
primitives.restler_basepath("/api"),
8684
primitives.restler_static_string("/"),
8785
primitives.restler_static_string("service"),
8886
primitives.restler_static_string("/"),
@@ -103,8 +101,7 @@ def parse_serviceuserpost(data, **kwargs):
103101
# Endpoint: /service/user/{userId}, method: Put
104102
request = requests.Request([
105103
primitives.restler_static_string("PUT "),
106-
primitives.restler_static_string("/"),
107-
primitives.restler_static_string("api"),
104+
primitives.restler_basepath("/api"),
108105
primitives.restler_static_string("/"),
109106
primitives.restler_static_string("service"),
110107
primitives.restler_static_string("/"),
@@ -125,8 +122,7 @@ def parse_serviceuserpost(data, **kwargs):
125122
# Endpoint: /service/user/{userId}, method: Delete
126123
request = requests.Request([
127124
primitives.restler_static_string("DELETE "),
128-
primitives.restler_static_string("/"),
129-
primitives.restler_static_string("api"),
125+
primitives.restler_basepath("/api"),
130126
primitives.restler_static_string("/"),
131127
primitives.restler_static_string("service"),
132128
primitives.restler_static_string("/"),

src/compiler/Restler.Compiler.Test/baselines/dependencyTests/header_response_writer_grammar.py

+7-11
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ def parse_serviceuserpost(data, **kwargs):
3131

3232
try:
3333
temp_7262 = str(headers["userId"])
34-
34+
3535
except Exception as error:
3636
# This is not an error, since some properties are not always returned
3737
pass
3838

3939
pass
40-
40+
4141
# If no dynamic objects were extracted, throw.
4242
if not (temp_7262):
4343
raise ResponseParsingException("Error: all of the expected dynamic objects were not present in the response.")
@@ -50,8 +50,7 @@ def parse_serviceuserpost(data, **kwargs):
5050
# Endpoint: /service/user, method: Post
5151
request = requests.Request([
5252
primitives.restler_static_string("POST "),
53-
primitives.restler_static_string("/"),
54-
primitives.restler_static_string("api"),
53+
primitives.restler_basepath("/api"),
5554
primitives.restler_static_string("/"),
5655
primitives.restler_static_string("service"),
5756
primitives.restler_static_string("/"),
@@ -61,7 +60,7 @@ def parse_serviceuserpost(data, **kwargs):
6160
primitives.restler_static_string("Host: localhost:8888\r\n"),
6261
primitives.restler_refreshable_authentication_token("authentication_token_tag"),
6362
primitives.restler_static_string("\r\n"),
64-
63+
6564
{
6665
'post_send':
6766
{
@@ -81,8 +80,7 @@ def parse_serviceuserpost(data, **kwargs):
8180
# Endpoint: /service/user/{userId}, method: Get
8281
request = requests.Request([
8382
primitives.restler_static_string("GET "),
84-
primitives.restler_static_string("/"),
85-
primitives.restler_static_string("api"),
83+
primitives.restler_basepath("/api"),
8684
primitives.restler_static_string("/"),
8785
primitives.restler_static_string("service"),
8886
primitives.restler_static_string("/"),
@@ -103,8 +101,7 @@ def parse_serviceuserpost(data, **kwargs):
103101
# Endpoint: /service/user/{userId}, method: Put
104102
request = requests.Request([
105103
primitives.restler_static_string("PUT "),
106-
primitives.restler_static_string("/"),
107-
primitives.restler_static_string("api"),
104+
primitives.restler_basepath("/api"),
108105
primitives.restler_static_string("/"),
109106
primitives.restler_static_string("service"),
110107
primitives.restler_static_string("/"),
@@ -125,8 +122,7 @@ def parse_serviceuserpost(data, **kwargs):
125122
# Endpoint: /service/user/{userId}, method: Delete
126123
request = requests.Request([
127124
primitives.restler_static_string("DELETE "),
128-
primitives.restler_static_string("/"),
129-
primitives.restler_static_string("api"),
125+
primitives.restler_basepath("/api"),
130126
primitives.restler_static_string("/"),
131127
primitives.restler_static_string("service"),
132128
primitives.restler_static_string("/"),

0 commit comments

Comments
 (0)