test(macros): cover mpe_dirlist and mpe_writecheck directly
The service tests exercise the actions through a child session; these call the
macros in place, so the guard and the answers are covered without a request:
mpe_dirlist 7 assertions - iftrue=0 does nothing, one level, files
excluded, three levels, the depth cap, the maxobs cap with
TRUNCATED=Y, and a blank parent returning a root path
mpe_writecheck 5 assertions - iftrue=0 does nothing, a writable folder, a
file, a missing path with a reason, and the probe leaving an
existing file that already had its old name alone
They live in sasjs/macros beside the macros they test, which works: a test file
in a declared macro folder compiles to sasjsbuild/tests/macros/ and sasjs test
runs it from there.
Two traps, both hit before this passed:
- these macros write JSON to _webout, so the test has to point _webout at a
temp file while they run and put it back before the term program writes the
results - the first attempt redirected without restoring and the runner
reported "No webout was returned by job";
- descriptions in mp_assert must not contain a comma: an unquoted comma splits
the parameter list and the assertion fails to compile with "All positional
parameters must precede keyword parameters", which names the call rather than
the comma.
This commit is contained in:
1 parent
be58be379a
commit
f1b9484463
2 files changed
+308
No files matched your search
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
@file
|
||||
@brief Testing mpe_dirlist macro
|
||||
@details Covers the guard, the listing shape and the cap. The abort paths
|
||||
(a relative parent, one carrying macro triggers) are covered by
|
||||
services/admin/makedata.test.sas, because mp_abort cannot be exercised
|
||||
inside the test session itself.
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mf_mkdir.sas
|
||||
@li mp_assert.sas
|
||||
@li mpe_dirlist.sas
|
||||
|
||||
@author 4GL Apps Ltd
|
||||
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
|
||||
and may not be re-distributed or re-sold without the express permission of
|
||||
4GL Apps Ltd.
|
||||
|
||||
@sasjslint {"maxLineLength": 80}
|
||||
|
||||
**/
|
||||
|
||||
%macro countfolders(libds,outmac);
|
||||
%global &outmac;
|
||||
proc sql noprint;
|
||||
select count(*) into:&outmac from &libds
|
||||
where filepath is not null and filepath ne '';
|
||||
quit;
|
||||
%mend countfolders;
|
||||
|
||||
/*
|
||||
These macros write their JSON answer to _webout. Point it at a temporary
|
||||
file while they run and put it back afterwards, so the test's own result -
|
||||
which the term program writes to _webout - still reaches the caller. The
|
||||
assertions read the work datasets the macros build, not the JSON.
|
||||
*/
|
||||
%let _webout_path=%sysfunc(pathname(_webout));
|
||||
filename _webout temp;
|
||||
|
||||
%let root=%sysfunc(pathname(work))/dirlist%mf_getuniquefileref();
|
||||
%mf_mkdir(&root)
|
||||
%mf_mkdir(&root/aa)
|
||||
%mf_mkdir(&root/aa/bb)
|
||||
%mf_mkdir(&root/aa/bb/cc)
|
||||
data _null_;
|
||||
file "&root/plain.txt";
|
||||
put 'x';
|
||||
run;
|
||||
|
||||
/**
|
||||
* Test 1 - the iftrue guard: nothing happens, and nothing is created
|
||||
*/
|
||||
%mpe_dirlist(iftrue=0)
|
||||
%mp_assert(
|
||||
iftrue=(%sysfunc(exist(work.dirlist))=0),
|
||||
desc=The listing does nothing when iftrue is false,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/**
|
||||
* Test 2 - one level: folders only, the file beside them is not offered
|
||||
*/
|
||||
data work.fromjs;
|
||||
length parent $1000;
|
||||
parent="&root";
|
||||
depth=1;
|
||||
maxobs=2000;
|
||||
run;
|
||||
%mpe_dirlist(iftrue=1)
|
||||
%countfolders(work.dirlist,c2)
|
||||
%mp_assert(
|
||||
iftrue=(&c2=1),
|
||||
desc=One level returns the immediate folder only,
|
||||
outds=work.test_results
|
||||
)
|
||||
data _null_;
|
||||
set work.dirlist;
|
||||
call symputx('name2',filename,'l');
|
||||
call symputx('type2',file_or_folder,'l');
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=("%upcase(&name2)"="AA" and "%upcase(&type2)"="FOLDER"),
|
||||
desc=The file beside it is not offered,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/**
|
||||
* Test 3 - depth and its cap
|
||||
*/
|
||||
data work.fromjs;
|
||||
length parent $1000;
|
||||
parent="&root";
|
||||
depth=3;
|
||||
maxobs=2000;
|
||||
run;
|
||||
%mpe_dirlist(iftrue=1)
|
||||
%countfolders(work.dirlist,c3)
|
||||
%mp_assert(
|
||||
iftrue=(&c3=3),
|
||||
desc=Three levels are returned,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
data work.fromjs;
|
||||
length parent $1000;
|
||||
parent="&root";
|
||||
depth=9;
|
||||
maxobs=2000;
|
||||
run;
|
||||
%mpe_dirlist(iftrue=1)
|
||||
%countfolders(work.dirlist,c4)
|
||||
%mp_assert(
|
||||
iftrue=(&c4=3),
|
||||
desc=Depth above three is capped at three,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/**
|
||||
* Test 5 - the row cap, and the flag that says it was hit
|
||||
*/
|
||||
data work.fromjs;
|
||||
length parent $1000;
|
||||
parent="&root";
|
||||
depth=3;
|
||||
maxobs=2;
|
||||
run;
|
||||
%mpe_dirlist(iftrue=1)
|
||||
%countfolders(work.dirlist,c5)
|
||||
data _null_;
|
||||
set work.dirinfo;
|
||||
call symputx('trunc5',truncated,'l');
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=(&c5=2 and "%upcase(&trunc5)"="Y"),
|
||||
desc=Rows are capped by maxobs and dirinfo says so,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/**
|
||||
* Test 6 - a blank parent is the platform roots
|
||||
*/
|
||||
data work.fromjs;
|
||||
length parent $1000;
|
||||
parent='';
|
||||
depth=1;
|
||||
maxobs=50;
|
||||
run;
|
||||
%mpe_dirlist(iftrue=1)
|
||||
%countfolders(work.dirlist,c6)
|
||||
data _null_;
|
||||
set work.dirlist(obs=1);
|
||||
call symputx('rootpath6',filepath,'l');
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=(&c6>=1 and "%trim(&rootpath6)" ne ""),
|
||||
desc=A blank parent returns a root entry with a path,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/*
|
||||
hand _webout back before the results are dumped
|
||||
*/
|
||||
filename _webout "&_webout_path" mod;
|
||||
|
||||
/**
|
||||
* dump results to the log for offline inspection
|
||||
*/
|
||||
data _null_;
|
||||
set work.test_results;
|
||||
putlog 'TEST_RESULT_LINE: ' test_result ' - ' test_description;
|
||||
run;
|
||||
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
@file
|
||||
@brief Testing mpe_writecheck macro
|
||||
@details Covers the guard, the three answers, and the probe: it must not
|
||||
destroy a file that happens to carry a name it used to use. The abort paths
|
||||
are covered by services/admin/makedata.test.sas, because mp_abort cannot be
|
||||
exercised inside the test session itself.
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mf_mkdir.sas
|
||||
@li mp_assert.sas
|
||||
@li mpe_writecheck.sas
|
||||
|
||||
@author 4GL Apps Ltd
|
||||
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
|
||||
and may not be re-distributed or re-sold without the express permission of
|
||||
4GL Apps Ltd.
|
||||
|
||||
@sasjslint {"maxLineLength": 80}
|
||||
|
||||
**/
|
||||
|
||||
/*
|
||||
These macros write their JSON answer to _webout. Point it at a temporary
|
||||
file while they run and put it back afterwards, so the test's own result -
|
||||
which the term program writes to _webout - still reaches the caller. The
|
||||
assertions read the work datasets the macros build, not the JSON.
|
||||
*/
|
||||
%let _webout_path=%sysfunc(pathname(_webout));
|
||||
filename _webout temp;
|
||||
|
||||
%let root=%sysfunc(pathname(work))/checkwrite%mf_getuniquefileref();
|
||||
%mf_mkdir(&root)
|
||||
data _null_;
|
||||
file "&root/plain.txt";
|
||||
put 'x';
|
||||
run;
|
||||
|
||||
/* a file whose name the macro used to pick, which must survive the probe */
|
||||
data _null_;
|
||||
file "&root/.dcprobe_&sysprocessid";
|
||||
put 'do not delete me';
|
||||
run;
|
||||
|
||||
/**
|
||||
* Test 1 - the iftrue guard
|
||||
*/
|
||||
%mpe_writecheck(iftrue=0)
|
||||
%mp_assert(
|
||||
iftrue=(%sysfunc(exist(work.checkwrite))=0),
|
||||
desc=The check does nothing when iftrue is false,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/**
|
||||
* Test 2 - a folder the deployment user can write to
|
||||
*/
|
||||
data work.fromjs;
|
||||
length path $1000;
|
||||
path="&root";
|
||||
run;
|
||||
%mpe_writecheck(iftrue=1)
|
||||
data _null_;
|
||||
set work.checkwrite;
|
||||
if upcase(path_exists)='Y' and upcase(is_folder)='Y'
|
||||
and upcase(writeable)='Y' then call symputx('ok2',1,'l');
|
||||
else call symputx('ok2',0,'l');
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=(&ok2=1),
|
||||
desc=A writable folder is reported as writeable,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/**
|
||||
* Test 3 - a file is not a folder you can write a control library into
|
||||
*/
|
||||
data work.fromjs;
|
||||
length path $1000;
|
||||
path="&root/plain.txt";
|
||||
run;
|
||||
%mpe_writecheck(iftrue=1)
|
||||
data _null_;
|
||||
set work.checkwrite;
|
||||
if upcase(path_exists)='Y' and upcase(is_folder)='N'
|
||||
and upcase(writeable)='N' then call symputx('ok3',1,'l');
|
||||
else call symputx('ok3',0,'l');
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=(&ok3=1),
|
||||
desc=A file is not reported as a writeable folder,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/**
|
||||
* Test 4 - a path that is not there is a negative answer, with a reason
|
||||
*/
|
||||
data work.fromjs;
|
||||
length path $1000;
|
||||
path="&root/nothing_here";
|
||||
run;
|
||||
%mpe_writecheck(iftrue=1)
|
||||
data _null_;
|
||||
set work.checkwrite;
|
||||
if upcase(path_exists)='N' and upcase(writeable)='N'
|
||||
and length(trim(msg))>0 then call symputx('ok4',1,'l');
|
||||
else call symputx('ok4',0,'l');
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=(&ok4=1),
|
||||
desc=A missing path is reported as missing and carries a reason,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/**
|
||||
* Test 5 - the probe leaves an existing file alone
|
||||
*/
|
||||
%mp_assert(
|
||||
iftrue=(%sysfunc(fileexist("&root/.dcprobe_&sysprocessid"))=1),
|
||||
desc=The write probe does not delete a file that already had its old name,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/*
|
||||
hand _webout back before the results are dumped
|
||||
*/
|
||||
filename _webout "&_webout_path" mod;
|
||||
|
||||
/**
|
||||
* dump results to the log for offline inspection
|
||||
*/
|
||||
data _null_;
|
||||
set work.test_results;
|
||||
putlog 'TEST_RESULT_LINE: ' test_result ' - ' test_description;
|
||||
run;
|
||||
Reference in new issue
Block a user