mirror of
https://github.com/sasjs/core.git
synced 2026-01-15 12:30:06 +00:00
feat: ms_testservice.sas macro for testing services on sasjs/server
This commit is contained in:
@@ -42,6 +42,7 @@
|
|||||||
@li mp_binarycopy.sas
|
@li mp_binarycopy.sas
|
||||||
@li mp_chop.sas
|
@li mp_chop.sas
|
||||||
@li mp_ds2csv.sas
|
@li mp_ds2csv.sas
|
||||||
|
@li ms_testservice.sas
|
||||||
@li mv_getjobresult.sas
|
@li mv_getjobresult.sas
|
||||||
@li mv_jobflow.sas
|
@li mv_jobflow.sas
|
||||||
|
|
||||||
@@ -270,95 +271,16 @@ filename &webref "&webrefpath";
|
|||||||
%end;
|
%end;
|
||||||
%else %if &platform=SASJS %then %do;
|
%else %if &platform=SASJS %then %do;
|
||||||
|
|
||||||
/* avoid sending bom marker to API */
|
%ms_testservice(&program
|
||||||
%local optval;
|
,inputfiles=&inputfiles
|
||||||
%let optval=%sysfunc(getoption(bomfile));
|
,inputdatasets=&inputdatasets
|
||||||
options nobomfile;
|
,inputparams=&inputparams
|
||||||
|
,debug=&debug
|
||||||
data _null_;
|
|
||||||
file &fname0 termstr=crlf;
|
|
||||||
infile &inref end=eof;
|
|
||||||
if _n_ = 1 then do;
|
|
||||||
put "--&boundary.";
|
|
||||||
put 'Content-Disposition: form-data; name="filePath"';
|
|
||||||
put ;
|
|
||||||
put "&driveloc";
|
|
||||||
put "--&boundary";
|
|
||||||
put 'Content-Disposition: form-data; name="file"; filename="ignore.sas"';
|
|
||||||
put "Content-Type: text/plain";
|
|
||||||
put ;
|
|
||||||
end;
|
|
||||||
input;
|
|
||||||
put _infile_; /* add the actual file to be sent */
|
|
||||||
if eof then do;
|
|
||||||
put ;
|
|
||||||
put "--&boundary--";
|
|
||||||
end;
|
|
||||||
run;
|
|
||||||
|
|
||||||
data _null_;
|
|
||||||
file &fname1 lrecl=1000;
|
|
||||||
infile "&_sasjs_tokenfile" lrecl=1000;
|
|
||||||
input;
|
|
||||||
put "Content-Type: multipart/form-data; boundary=&boundary";
|
|
||||||
put "Authorization: Bearer " _infile_;
|
|
||||||
run;
|
|
||||||
|
|
||||||
%if &mdebug=1 %then %do;
|
|
||||||
data _null_;
|
|
||||||
infile &fname0;
|
|
||||||
input;
|
|
||||||
put _infile_;
|
|
||||||
data _null_;
|
|
||||||
infile &fname1;
|
|
||||||
input;
|
|
||||||
put _infile_;
|
|
||||||
run;
|
|
||||||
%end;
|
|
||||||
|
|
||||||
proc http method='POST' in=&fname0 headerin=&fname1 out=&webref
|
|
||||||
url="&_sasjs_apiserverurl/SASjsApi/drive/file";
|
|
||||||
%if &mdebug=1 %then %do;
|
|
||||||
debug level=1;
|
|
||||||
%end;
|
|
||||||
run;
|
|
||||||
|
|
||||||
/* reset options */
|
|
||||||
options &optval;
|
|
||||||
|
|
||||||
/* SASjs services have the _webout embedded in wrapper JSON */
|
|
||||||
/* Files can also be very large - so use a dedicated macro to chop it out */
|
|
||||||
%local matchstr1 matchstr2 chopout1 chopout2;
|
|
||||||
%let matchstr1={"status":"success","_webout":{;
|
|
||||||
%let matchst2=},"log":[{;
|
|
||||||
%let chopout1=&webrefpath._1;
|
|
||||||
%let chopout2=&webrefpath._2;
|
|
||||||
|
|
||||||
%mp_chop("&webrefpath"
|
|
||||||
,matchvar=matchstr1
|
|
||||||
,keep=LAST
|
|
||||||
,matchpoint=END
|
|
||||||
,offset=-1
|
|
||||||
,outfile="&chopout1"
|
|
||||||
,mdebug=&mdebug
|
,mdebug=&mdebug
|
||||||
|
,outlib=&outlib
|
||||||
|
,outref=&outref
|
||||||
)
|
)
|
||||||
|
|
||||||
%mp_chop("&chopout1"
|
|
||||||
,matchvar=matchstr2
|
|
||||||
,keep=FIRST
|
|
||||||
,matchpoint=START
|
|
||||||
,offset=1
|
|
||||||
,outfile="&chopout2"
|
|
||||||
,mdebug=&mdebug
|
|
||||||
)
|
|
||||||
|
|
||||||
%if &outlib ne 0 %then %do;
|
|
||||||
libname &outlib json ("&chopout2");
|
|
||||||
%end;
|
|
||||||
%if &outref ne 0 %then %do;
|
|
||||||
filename &outref "&chopout2";
|
|
||||||
%end;
|
|
||||||
|
|
||||||
%end;
|
%end;
|
||||||
%else %do;
|
%else %do;
|
||||||
%put %str(ERR)OR: Unrecognised platform: &platform;
|
%put %str(ERR)OR: Unrecognised platform: &platform;
|
||||||
|
|||||||
152
server/ms_testservice.sas
Normal file
152
server/ms_testservice.sas
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Will execute a SASjs web service on SASjs Server
|
||||||
|
@details Prepares the input files and retrieves the resulting datasets from
|
||||||
|
the response JSON.
|
||||||
|
|
||||||
|
@param [in] program The Stored Program endpoint to test
|
||||||
|
@param [in] inputfiles=(0) A list of space seperated fileref:filename pairs as
|
||||||
|
follows:
|
||||||
|
inputfiles=inref:filename inref2:filename2
|
||||||
|
@param [in] inputdatasets= (0) All datasets in this space seperated list are
|
||||||
|
converted into SASJS-formatted CSVs (see mp_ds2csv.sas) files and added to
|
||||||
|
the list of `inputfiles` for ingestion. The dataset will be sent with the
|
||||||
|
same name (no need for a colon modifier).
|
||||||
|
@param [in] inputparams=(0) A dataset containing name/value pairs in the
|
||||||
|
following format:
|
||||||
|
|name:$32|value:$1000|
|
||||||
|
|---|---|
|
||||||
|
|stpmacname|some value|
|
||||||
|
|mustbevalidname|can be anything, oops, %abort!!|
|
||||||
|
|
||||||
|
@param [in] debug= (131) Provide the _debug value to pass to the STP
|
||||||
|
@param [in] mdebug= (0) Set to 1 to provide macro debugging (this macro)
|
||||||
|
@param [out] outlib= (0) Output libref to contain the final tables. Set to
|
||||||
|
0 if the service output is not in JSON format.
|
||||||
|
@param [out] outref= (0) Output fileref to create, to contain the full _webout
|
||||||
|
response.
|
||||||
|
@param [out] outlogds= (_null_) Set to the name of a dataset to contain the
|
||||||
|
log. Table format:
|
||||||
|
|line:$2000|
|
||||||
|
|---|
|
||||||
|
|log line 1|
|
||||||
|
|log line 2|
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
@li mf_getuniquename.sas
|
||||||
|
@li mp_abort.sas
|
||||||
|
@li mp_binarycopy.sas
|
||||||
|
@li mp_chop.sas
|
||||||
|
@li mp_ds2csv.sas
|
||||||
|
@li ms_runstp.sas
|
||||||
|
|
||||||
|
<h4> Related Programs </h4>
|
||||||
|
@li mp_testservice.test.sas
|
||||||
|
|
||||||
|
@version 9.4
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro ms_testservice(program,
|
||||||
|
inputfiles=0,
|
||||||
|
inputdatasets=0,
|
||||||
|
inputparams=0,
|
||||||
|
debug=0,
|
||||||
|
mdebug=0,
|
||||||
|
outlib=0,
|
||||||
|
outref=0,
|
||||||
|
outlogds=_null_
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
%local dbg fref1 chopout1 chopout2;
|
||||||
|
%if &mdebug=1 %then %do;
|
||||||
|
%put &sysmacroname entry vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
%else %let dbg=*;
|
||||||
|
|
||||||
|
/* convert inputdatasets to filerefs */
|
||||||
|
%if "&inputdatasets" ne "0" %then %do;
|
||||||
|
%if %quote(&inputfiles)=0 %then %let inputfiles=;
|
||||||
|
%do i=1 %to %sysfunc(countw(&inputdatasets,%str( )));
|
||||||
|
%let var=%scan(&inputdatasets,&i,%str( ));
|
||||||
|
%local dsref&i;
|
||||||
|
%let dsref&i=%mf_getuniquefileref();
|
||||||
|
%mp_ds2csv(&var,outref=&&dsref&i,headerformat=SASJS)
|
||||||
|
%let inputfiles=&inputfiles &&dsref&i:%scan(&var,-1,.);
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
/* parse the filerefs - convert to a dataset */
|
||||||
|
%let ds1=%mf_getuniquename();
|
||||||
|
data &ds1;
|
||||||
|
length fileref $8 name $32 filename $256 var $300;
|
||||||
|
webcount=countw("&inputfiles");
|
||||||
|
do i=1 to webcount;
|
||||||
|
var=scan("&inputfiles",i,' ');
|
||||||
|
fileref=scan(var,1,':');
|
||||||
|
name=scan(var,2,':');
|
||||||
|
filename=cats(name,'.csv');
|
||||||
|
output;
|
||||||
|
end;
|
||||||
|
run;
|
||||||
|
|
||||||
|
|
||||||
|
/* execute the STP */
|
||||||
|
%let fref1=%mf_getuniquefileref();
|
||||||
|
|
||||||
|
%ms_runstp(&program
|
||||||
|
,debug=&debug
|
||||||
|
,inputparams=&inputparams
|
||||||
|
,inputfiles=&ds1
|
||||||
|
,outref=&fref1
|
||||||
|
,mdebug=&mdebug
|
||||||
|
,outlogds=&outlogds
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
/* SASjs services have the _webout embedded in wrapper JSON */
|
||||||
|
/* Files can also be very large - so use a dedicated macro to chop it out */
|
||||||
|
%local matchstr1 matchstr2 ;
|
||||||
|
%let matchstr1={"status":"success","_webout":{;
|
||||||
|
%let matchstr2=},"log":[{;
|
||||||
|
%let chopout1=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop1);
|
||||||
|
%let chopout2=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop2);
|
||||||
|
|
||||||
|
%mp_chop("%sysfunc(pathname(&fref1,F))"
|
||||||
|
,matchvar=matchstr1
|
||||||
|
,keep=LAST
|
||||||
|
,matchpoint=END
|
||||||
|
,offset=-1
|
||||||
|
,outfile="&chopout1"
|
||||||
|
,mdebug=&mdebug
|
||||||
|
)
|
||||||
|
|
||||||
|
%mp_chop("&chopout1"
|
||||||
|
,matchvar=matchstr2
|
||||||
|
,keep=FIRST
|
||||||
|
,matchpoint=START
|
||||||
|
,offset=1
|
||||||
|
,outfile="&chopout2"
|
||||||
|
,mdebug=&mdebug
|
||||||
|
)
|
||||||
|
|
||||||
|
%if &outlib ne 0 %then %do;
|
||||||
|
libname &outlib json "&chopout2";
|
||||||
|
%end;
|
||||||
|
%if &outref ne 0 %then %do;
|
||||||
|
filename &outref "&chopout2";
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%if &mdebug=0 %then %do;
|
||||||
|
filename &webref clear;
|
||||||
|
filename &fref1 clear;
|
||||||
|
filename &fref2 clear;
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
%put &sysmacroname exit vars:;
|
||||||
|
%put _local_;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%mend ms_testservice;
|
||||||
@@ -55,37 +55,28 @@ run;
|
|||||||
outlib=testlib1,
|
outlib=testlib1,
|
||||||
outref=test1
|
outref=test1
|
||||||
)
|
)
|
||||||
|
%let test1=FAIL;
|
||||||
%global test1a test1b test1c test1d;
|
|
||||||
data _null_;
|
data _null_;
|
||||||
infile test1;
|
set testlib1.somedata1;
|
||||||
input;
|
if x=1 and y=' t"w"o' and z="Z" then call symputx('test1','PASS');
|
||||||
putlog _n_ _infile_;
|
putlog (_all_)(=);
|
||||||
if _infile_=', "somedata1":' then call symputx('test1a','PASS');
|
|
||||||
if _infile_='{"X":1 ,"Y":" t\"w\"o" ,"Z":"Z" }' then
|
|
||||||
call symputx('test1b','PASS');
|
|
||||||
if _infile_='], "somedata2":' then call symputx('test1c','PASS');
|
|
||||||
if _infile_='{"X":1 ,"Y":" t\"w\"o" ,"Z":"Z" }' then
|
|
||||||
call symputx('test1d','PASS');
|
|
||||||
run;
|
run;
|
||||||
|
|
||||||
|
%let test2=FAIL;
|
||||||
|
data _null_;
|
||||||
|
set testlib1.somedata2;
|
||||||
|
if x=1 and y=' t"w"o' and z="Z" then call symputx('test2','PASS');
|
||||||
|
putlog (_all_)(=);
|
||||||
|
run;
|
||||||
|
|
||||||
|
|
||||||
%mp_assert(
|
%mp_assert(
|
||||||
iftrue=(&test1a=PASS),
|
iftrue=(&test1=PASS),
|
||||||
desc=Test 1 table 1 name,
|
desc=somedata1 created correctly,
|
||||||
outds=work.test_results
|
outds=work.test_results
|
||||||
)
|
)
|
||||||
%mp_assert(
|
%mp_assert(
|
||||||
iftrue=(&test1b=PASS),
|
iftrue=(&test2=PASS),
|
||||||
desc=Test 1 table 1 values,
|
desc=somedata2 created correctly,
|
||||||
outds=work.test_results
|
|
||||||
)
|
|
||||||
%mp_assert(
|
|
||||||
iftrue=(&test1c=PASS),
|
|
||||||
desc=Test 1 table 2 name,
|
|
||||||
outds=work.test_results
|
|
||||||
)
|
|
||||||
%mp_assert(
|
|
||||||
iftrue=(&test1d=PASS),
|
|
||||||
desc=Test 1 table 2 values,
|
|
||||||
outds=work.test_results
|
outds=work.test_results
|
||||||
)
|
)
|
||||||
87
tests/serveronly/ms_testservice.test.sas
Normal file
87
tests/serveronly/ms_testservice.test.sas
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Testing ms_testservice.sas macro
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li ms_createwebservice.sas
|
||||||
|
@li ms_testservice.sas
|
||||||
|
@li mp_assert.sas
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
filename ft15f001 temp;
|
||||||
|
parmcards4;
|
||||||
|
%put Initialising sendObj: ;
|
||||||
|
%put _all_;
|
||||||
|
%webout(FETCH)
|
||||||
|
%webout(OPEN)
|
||||||
|
%macro x();
|
||||||
|
%if (%symexist(sasjs_tables) and %length(&sasjs_tables)>0)
|
||||||
|
%then %do i=1 %to %sysfunc(countw(&sasjs_tables));
|
||||||
|
%let table=%scan(&sasjs_tables,&i);
|
||||||
|
%webout(OBJ,&table,missing=STRING)
|
||||||
|
%end;
|
||||||
|
%else %do i=1 %to &_webin_file_count;
|
||||||
|
%webout(OBJ,&&_webin_name&i,missing=STRING)
|
||||||
|
%end;
|
||||||
|
%mend x; %x()
|
||||||
|
%webout(CLOSE)
|
||||||
|
;;;;
|
||||||
|
%put creating web service: &mcTestAppLoc/services;
|
||||||
|
%ms_createwebservice(
|
||||||
|
path=&mcTestAppLoc/services,
|
||||||
|
name=sendObj,
|
||||||
|
mdebug=&sasjs_mdebug
|
||||||
|
)
|
||||||
|
%put created web service: &mcTestAppLoc/services;
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&syscc=0),
|
||||||
|
desc=No errors after service creation,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test 1 - send a dataset
|
||||||
|
*/
|
||||||
|
data work.somedata1 work.somedata2;
|
||||||
|
x=1;
|
||||||
|
y=' t"w"o';
|
||||||
|
z=.z;
|
||||||
|
label x='x factor';
|
||||||
|
output;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%ms_testservice(&mcTestAppLoc/services/sendObj,
|
||||||
|
inputdatasets=work.somedata1 work.somedata2,
|
||||||
|
debug=log,
|
||||||
|
mdebug=1,
|
||||||
|
outlib=testlib1,
|
||||||
|
outref=test1
|
||||||
|
)
|
||||||
|
|
||||||
|
%let test1=FAIL;
|
||||||
|
data _null_;
|
||||||
|
set testlib1.somedata1;
|
||||||
|
if x=1 and y=' t"w"o' and z="Z" then call symputx('test1','PASS');
|
||||||
|
putlog (_all_)(=);
|
||||||
|
run;
|
||||||
|
|
||||||
|
%let test2=FAIL;
|
||||||
|
data _null_;
|
||||||
|
set testlib1.somedata2;
|
||||||
|
if x=1 and y=' t"w"o' and z="Z" then call symputx('test2','PASS');
|
||||||
|
putlog (_all_)(=);
|
||||||
|
run;
|
||||||
|
|
||||||
|
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&test1=PASS),
|
||||||
|
desc=somedata1 created correctly,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
|
%mp_assert(
|
||||||
|
iftrue=(&test2=PASS),
|
||||||
|
desc=somedata2 created correctly,
|
||||||
|
outds=work.test_results
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user