Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HPCC-30310 esdl ecl output to stdout #17971

Merged
merged 1 commit into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 138 additions & 1 deletion testing/esp/esdlcmd/esdlcmd-test.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def __init__(self, stats, exe_path, output_base, test_path):
self.test_path = test_path
self.stats = stats

# This class is base for commands related to services: wsdl, xsd, cpp and java.
class TestCaseBase:
"""Settings for a specific test case."""

Expand Down Expand Up @@ -103,6 +104,110 @@ def validate_results(self):
logging.debug('TestCaseBase implementation called, no comparison run')
return False

# This class is the base for the 'transform' commands: ecl and xml.
# In a future update, investigate refactoring the base classes so there is a single
# parent with any shared capabilities.
#
# When writing to stdout, the key directory should contain a file named 'from-stdout.ecl'
# that contains the expected output.
class TestCaseTransformBase:
def __init__(self, run_settings, name, command, esdl_file, xsl_path, use_stdout, expected_err=None, options=None):
self.run_settings = run_settings
self.name = name
self.command = command
self.esdl_path = (self.run_settings.test_path / 'inputs' / esdl_file)
self.xsl_path = xsl_path
self.options = options
self.output_path = Path(self.run_settings.output_base) / name
self.stdout = use_stdout
self.expected_err = expected_err
if self.stdout:
self.args = [
str(run_settings.exe_path),
self.command,
self.esdl_path,
'-cde',
self.xsl_path,
]
else:
self.args = [
str(run_settings.exe_path),
self.command,
self.esdl_path,
self.output_path,
'-cde',
self.xsl_path,
]

if options:
self.args.extend(options)

self.result = None

def run_test(self):
safe_mkdir(self.output_path)
logging.debug("Test %s args: %s", self.name, str(self.args))
self.result = subprocess.run(self.args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

if self.expected_err != None and self.expected_err == self.result.stderr:
success = True
elif self.result.returncode != 0:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this check be done first before the expected_err != None check (in Line 153)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in this case. The check on 153 captures any tests that are expected to return an error by making sure the error message printed matches what is expected. Then any other test returning an error return code is a failure. I can't make an analogous check of stderr, because the esdl command prints some non-failure messages to stderr.

logging.error('Error running "esdl %s" for test "%s": %s', self.command, self.name, self.result.stderr)
success = False
else:
success = self.validate_results()

self.run_settings.stats.add_count(success)

def is_same(self, dir1, dir2):
"""
Compare two directory trees content.
Return False if they differ, True is they are the same.
"""
compared = DirectoryCompare(dir1, dir2)
if (compared.left_only or compared.right_only or compared.diff_files
or compared.funny_files):
return False
for subdir in compared.common_dirs:
if not self.is_same(os.path.join(dir1, subdir), os.path.join(dir2, subdir)):
return False
return True

def validate_results(self):
"""Compare test case results to the known key.

Return True if the two are identical or False otherwise.
"""
outName = self.output_path
key = (self.run_settings.test_path / 'key' / self.name)

# When output was stdout, write the captured stdout text to a file named 'from-stdout.ecl'
# in the output directory. This allows us to use the same method of comparing the key
# and result.
if self.stdout:
if self.result.stdout != None and len(self.result.stdout) > 0:
with open((outName / 'from-stdout.ecl'), 'w', encoding='utf-8') as f:
f.write(self.result.stdout)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should probably be do an "else return False" here after line 192. Otherwise, the tests in the next few lines will compare with previously created "from-stdout.ecl" from previous test runs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

else:
logging.error('Missing stdout output for test %s', self.name)
return False

if (not key.exists()):
logging.error('Missing key file %s', str(key))
return False

if (not outName.exists()):
logging.error('Missing output for test %s', self.name)
return False

if (not self.is_same(str(key), str(outName))):
logging.debug('Comparing key %s to output %s', str(key), str(outName))
logging.error('Test failed: %s', self.name)
return False
else:
logging.debug('Passed: %s', self.name)
return True


class TestCaseXSD(TestCaseBase):
"""Test case for the wsdl or xsd commands.
Expand Down Expand Up @@ -212,6 +317,8 @@ def parse_options():
the parsed options and arguments.
"""

command_values = ['all', 'cpp', 'ecl', 'java', 'wsdl', 'xsd']

parser = argparse.ArgumentParser(description=DESC)
parser.add_argument('testroot',
help='Path of the root folder of the esdlcmd testing project')
Expand All @@ -231,7 +338,15 @@ def parse_options():
help='Enable debug logging of test cases',
action='store_true', default=False)

parser.add_argument('-c', '--commands',
help='esdl commands to run tests for, use once for each command or pass "all" to test all commands. Defaults to "all".',
action="append", choices=command_values)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to use "default" parameter rather than the extra code in 345.

Copy link
Contributor Author

@asselitx asselitx Nov 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my first approach, but I saw that using action="append" with a default always results in the list containing the default in addition to any values supplied on the command line. The behavior was counter-intuitive, but the append action documentation does mention it: https://docs.python.org/3.12/library/argparse.html?highlight=argparse#action


args = parser.parse_args()

if args.commands == None:
args.commands = ['all']

return args


Expand Down Expand Up @@ -278,6 +393,11 @@ def main():
stats = Statistics()
run_settings = TestRun(stats, exe_path, args.outdir, test_path)

esdl_includes_path = str(test_path / 'inputs')

expected_err_multi_file_incl = '\nOutput to stdout is not supported for multiple files. Either add the Rollup\noption or specify an output directory.\n'
expected_err_multi_file_expanded = '\nOutput to stdout is not supported for multiple files. Remove the Output expanded\n XML option or specify an output directory.\n'

test_cases = [
# wsdl
TestCaseXSD(run_settings, 'wstest-wsdl-default', 'wsdl', 'ws_test.ecm', 'WsTest',
Expand Down Expand Up @@ -390,10 +510,27 @@ def main():
# A single element is created for each request structure defined. This is default behavior.
TestCaseXSD(run_settings, 'use-request-name', 'wsdl', 'ws_userequestname.ecm', 'WsUseRequestName',
xsl_base_path),

# ecl
TestCaseTransformBase(run_settings, 'ecl-stdout-single', 'ecl', 'ws_test.ecm', xsl_base_path, use_stdout=True),

TestCaseTransformBase(run_settings, 'ecl-stdout-incl-err', 'ecl', 'ws_test.ecm', xsl_base_path, use_stdout=True,
expected_err=expected_err_multi_file_incl, options=['-I', esdl_includes_path, '--includes']),

TestCaseTransformBase(run_settings, 'ecl-stdout-expanded-err', 'ecl', 'ws_test.ecm', xsl_base_path, use_stdout=True,
expected_err=expected_err_multi_file_expanded, options=['-x']),

TestCaseTransformBase(run_settings, 'ecl-stdout-incl-rollup', 'ecl', 'ws_test.ecm', xsl_base_path, use_stdout=True,
options=['-I', esdl_includes_path, '--includes', '--rollup']),

TestCaseTransformBase(run_settings, 'ecl-incl', 'ecl', 'ws_test.ecm', xsl_base_path, use_stdout=False,
options=['-I', esdl_includes_path, '--includes'])

]

for case in test_cases:
case.run_test()
if 'all' in args.commands or case.command in args.commands:
case.run_test()

logging.info('Success count: %d', stats.successCount)
logging.info('Failure count: %d', stats.failureCount)
Expand Down
37 changes: 37 additions & 0 deletions testing/esp/esdlcmd/key/ecl-incl/allversionreport.ecl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*** Not to be hand edited (changes will be lost on re-generation) ***/
/*** ECL Interface generated by esdl2ecl version 1.0 from allversionreport.xml. ***/
/*===================================================*/


EXPORT allversionreport := MODULE

EXPORT t_FooBar := RECORD
UTF8 Foo {XPATH('Foo')};
UTF8 Bar {XPATH('Bar')};
END;

EXPORT t_AllVersionArrays := RECORD
SET OF UTF8 StringArray {XPATH('StringArray/Item'), MAXCOUNT(1)}; // max_count must be specified in ESDL defintion!
DATASET(t_FooBar) FooBarArray {XPATH('FooBarArray/FooBar'), MAXCOUNT(1)}; // max_count must be specified in ESDL defintion!
DATASET(t_FooBar) NamedItemFooBarArray {XPATH('NamedItemFooBarArray/NamedItem'), MAXCOUNT(1)}; // max_count must be specified in ESDL defintion!
END;

EXPORT t_AllVersionReportRequest := RECORD
UTF8 OptionalDeveloperStringVal {XPATH('OptionalDeveloperStringVal')};//hidden[developer]
INTEGER Annotate20ColsIntVal {XPATH('Annotate20ColsIntVal')};
t_AllVersionArrays Arrays {XPATH('Arrays')};
UTF8 UnrelentingForce {XPATH('UnrelentingForce')}; //values['1','2','3','']
END;

EXPORT t_AllVersionReportResponse := RECORD
UTF8 ResultVal {XPATH('ResultVal')};
t_AllVersionArrays ResultArrays {XPATH('ResultArrays')};
END;


END;

/*** Not to be hand edited (changes will be lost on re-generation) ***/
/*** ECL Interface generated by esdl2ecl version 1.0 from allversionreport.xml. ***/
/*===================================================*/

40 changes: 40 additions & 0 deletions testing/esp/esdlcmd/key/ecl-incl/ws_test.ecl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*** Not to be hand edited (changes will be lost on re-generation) ***/
/*** ECL Interface generated by esdl2ecl version 1.0 from ws_test.xml. ***/
/*===================================================*/


EXPORT ws_test := MODULE

EXPORT t_MinVersionReportRequest := RECORD
UTF8 RequestString {XPATH('RequestString')};
END;

EXPORT t_VersionRangeReportRequest := RECORD
UTF8 RequestString {XPATH('RequestString')};
END;

EXPORT t_VersionRangeReportResponse := RECORD
UTF8 ResponseString {XPATH('ResponseString')};
END;

/*Empty record generated from empty EsdlRequest
EXPORT t_WsTestPingRequest := RECORD
END;
*/

EXPORT t_MinVersionReportResponse := RECORD
UTF8 ResponseString {XPATH('ResponseString')};
END;

/*Empty record generated from empty EsdlResponse
EXPORT t_WsTestPingResponse := RECORD
END;
*/


END;

/*** Not to be hand edited (changes will be lost on re-generation) ***/
/*** ECL Interface generated by esdl2ecl version 1.0 from ws_test.xml. ***/
/*===================================================*/

63 changes: 63 additions & 0 deletions testing/esp/esdlcmd/key/ecl-stdout-incl-rollup/from-stdout.ecl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*** Not to be hand edited (changes will be lost on re-generation) ***/
/*** ECL Interface generated by esdl2ecl version 1.0 from ws_test.xml. ***/
/*===================================================*/


EXPORT ws_test := MODULE

EXPORT t_FooBar := RECORD
UTF8 Foo {XPATH('Foo')};
UTF8 Bar {XPATH('Bar')};
END;

EXPORT t_AllVersionArrays := RECORD
SET OF UTF8 StringArray {XPATH('StringArray/Item'), MAXCOUNT(1)}; // max_count must be specified in ESDL defintion!
DATASET(t_FooBar) FooBarArray {XPATH('FooBarArray/FooBar'), MAXCOUNT(1)}; // max_count must be specified in ESDL defintion!
DATASET(t_FooBar) NamedItemFooBarArray {XPATH('NamedItemFooBarArray/NamedItem'), MAXCOUNT(1)}; // max_count must be specified in ESDL defintion!
END;

EXPORT t_AllVersionReportRequest := RECORD
UTF8 OptionalDeveloperStringVal {XPATH('OptionalDeveloperStringVal')};//hidden[developer]
INTEGER Annotate20ColsIntVal {XPATH('Annotate20ColsIntVal')};
t_AllVersionArrays Arrays {XPATH('Arrays')};
UTF8 UnrelentingForce {XPATH('UnrelentingForce')}; //values['1','2','3','']
END;

EXPORT t_MinVersionReportRequest := RECORD
UTF8 RequestString {XPATH('RequestString')};
END;

EXPORT t_VersionRangeReportRequest := RECORD
UTF8 RequestString {XPATH('RequestString')};
END;

EXPORT t_VersionRangeReportResponse := RECORD
UTF8 ResponseString {XPATH('ResponseString')};
END;

/*Empty record generated from empty EsdlRequest
EXPORT t_WsTestPingRequest := RECORD
END;
*/

EXPORT t_AllVersionReportResponse := RECORD
UTF8 ResultVal {XPATH('ResultVal')};
t_AllVersionArrays ResultArrays {XPATH('ResultArrays')};
END;

EXPORT t_MinVersionReportResponse := RECORD
UTF8 ResponseString {XPATH('ResponseString')};
END;

/*Empty record generated from empty EsdlResponse
EXPORT t_WsTestPingResponse := RECORD
END;
*/


END;

/*** Not to be hand edited (changes will be lost on re-generation) ***/
/*** ECL Interface generated by esdl2ecl version 1.0 from ws_test.xml. ***/
/*===================================================*/

40 changes: 40 additions & 0 deletions testing/esp/esdlcmd/key/ecl-stdout-single/from-stdout.ecl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*** Not to be hand edited (changes will be lost on re-generation) ***/
/*** ECL Interface generated by esdl2ecl version 1.0 from ws_test.xml. ***/
/*===================================================*/


EXPORT ws_test := MODULE

EXPORT t_MinVersionReportRequest := RECORD
UTF8 RequestString {XPATH('RequestString')};
END;

EXPORT t_VersionRangeReportRequest := RECORD
UTF8 RequestString {XPATH('RequestString')};
END;

EXPORT t_VersionRangeReportResponse := RECORD
UTF8 ResponseString {XPATH('ResponseString')};
END;

/*Empty record generated from empty EsdlRequest
EXPORT t_WsTestPingRequest := RECORD
END;
*/

EXPORT t_MinVersionReportResponse := RECORD
UTF8 ResponseString {XPATH('ResponseString')};
END;

/*Empty record generated from empty EsdlResponse
EXPORT t_WsTestPingResponse := RECORD
END;
*/


END;

/*** Not to be hand edited (changes will be lost on re-generation) ***/
/*** ECL Interface generated by esdl2ecl version 1.0 from ws_test.xml. ***/
/*===================================================*/

Loading
Loading