MatrixBerryCore
MUnitRemoteTestRunner.m
Go to the documentation of this file.
1 classdef MUnitRemoteTestRunner<handle
2  properties
3  emailLogger
4  fTempDirGetter
5  isConsoleOutputCollected
6  end
7  methods
8  %
9  function self=MUnitRemoteTestRunner(emailLogger,fTempDirGetter,varargin)
10  import mxberry.core.parseparext;
11  self.emailLogger=emailLogger;
12  self.fTempDirGetter=fTempDirGetter;
13  [~,~,self.isConsoleOutputCollected]=parseparext(varargin,...
14  {'isConsoleOutputCollected';...
15  true;...
16  'islogical(x)&&isscalar(x)'},0);
17  end
18  %
19  function resultVec=runTestPack(self,topPackageName,varargin)
20  import mxberry.core.throwerror;
22  %
23  [testPackArgList,~,isJUnitXMLReportEnabled,jUnitXMLReportDir,...
24  isJUnitReportEnabledSpec,isJUnitXMLReportDirSpec]=...
25  mxberry.core.parseparext(varargin,...
26  {'isJUnitXMLReportEnabled','jUnitXMLReportDir';...
27  false,'';...
28  'islogical(x)','isstring(x)'});
29  if isJUnitReportEnabledSpec&&~isJUnitXMLReportDirSpec
30  throwerror('wrongInput',['jUnitXMLReportDir property',...
31  'is obligatory when isJUnitXMLReportEnabled=true']);
32  end
33  %
34  self.emailLogger.sendMessage('STARTED','');
35  tmpDirName=self.fTempDirGetter(topPackageName);
36  resultVec=[];
37  logger=Log4jConfigurator.getLogger();
38  isConsoleOutputCollected=self.isConsoleOutputCollected; %#ok<*PROPLC>
39  try
40  suite=testsuite(topPackageName,'IncludeSubpackages',true);
41  runner=matlab.unittest.TestRunner.withNoPlugins;
42  %
43  if isJUnitXMLReportEnabled
44  if ~mxberry.io.isdir(jUnitXMLReportDir)
45  mxberry.io.mkdir(jUnitXMLReportDir);
46  end
47  %
48  xmlFile = [jUnitXMLReportDir,filesep,'test_results.xml'];
49  p=matlab.unittest.plugins.XMLPlugin.producingJUnitFormat(xmlFile);
50  runner.addPlugin(p);
51  end
52  %
53  fRun=@()runner.run(suite);
54  %
55  if isConsoleOutputCollected
56  consoleOutStr=evalc(...
57  'resultVec=feval(fRun,testPackArgList{:});');
58  else
59  resultVec=feval(fRun,testPackArgList{:});
60  end
61  %
62  errorFailStr=getErrorFailMessage(resultVec);
63  errorHyperStr=errorFailStr;
64  isFailed=~getIsPassed(resultVec);
65  %
66  subjectStr=getMinimalReport(resultVec);
67  %
68  if isConsoleOutputCollected
69  consoleOutFileName=writeMessageToFile('console_output',...
70  consoleOutStr);
71  consoleOutZipFileName=[tmpDirName,filesep,'cosoleOutput.zip'];
72  zip(consoleOutZipFileName,consoleOutFileName);
73  attachFileNameList={consoleOutZipFileName};
74  else
75  attachFileNameList={};
76  end
77  %
78  catch meObj
79  subjectStr='ERROR';
80  errorFailStr=...
81  mxberry.core.MExceptionUtils.me2PlainString(meObj);
82  errorHyperStr=...
83  mxberry.core.MExceptionUtils.me2HyperString(meObj);
84  attachFileNameList={};
85  isFailed=true;
86  end
87  if isFailed
88  errorFailFileName=writeMessageToFile('error_fail_list',...
89  errorFailStr);
90  attachFileNameList=[attachFileNameList,{errorFailFileName}];
91  logger.error(errorHyperStr);
92  end
93  %
94  self.emailLogger.sendMessage(subjectStr,...
95  'emailAttachmentNameList',attachFileNameList);
96  %
97  function fullFileName=getFullFileName(shortFileName,extName)
98  if nargin<2
99  extName='.txt';
100  end
101  fullFileName=[tmpDirName,filesep,shortFileName,extName];
102  end
103  function fullFileName=writeMessageToFile(shortFileName,msgStr)
104  fullFileName=getFullFileName(shortFileName);
105  [fid,errMsg] = fopen(fullFileName, 'w');
106  if fid<0
107  throwerror('cantOpenFile',errMsg);
108  end
109  try
110  fprintf(fid,'%s',msgStr);
111  catch meObj
112  fclose(fid);
113  rethrow(meObj);
114  end
115  fclose(fid);
116  end
117  end
118  end
119  %
120  methods (Static)
121  function resultVec=runTestsWithConf(inpArgList,confRepoMgr,log4jConfiguratorName,emailSubjSuffixName,runnerName,fTempDirGetter,topPackageName,varargin)
122  import mxberry.core.throwerror;
123  import mxberry.core.struct.strucdisp;
125  import(log4jConfiguratorName);
126  %
127  try
128  %% Configure Log4j
129  confName=confRepoMgr.getCurConfName(); %#ok<NASGU>
130  Log4jConfigurator.unlockConfiguration();
131  Log4jConfigurator.configure(confRepoMgr);
132  Log4jConfigurator.lockConfiguration();
133  %% Log configuration
134  logger=Log4jConfigurator.getLogger();
135  logger.info(sprintf('Test configuration:\n%s',...
136  evalc('strucdisp(confRepoMgr.getConf(confName))')));
137  %
138  emailLogger=...
140  confRepoMgr,runnerName,emailSubjSuffixName,....
141  Log4jConfigurator.getMainLogFileName(),fTempDirGetter);
142  %
143  try
144  testRunner=MUnitRemoteTestRunner(emailLogger,...
145  fTempDirGetter,varargin{:});
146  %
147  isJUnitXMLReportEnabled=confRepoMgr.getParam(...
148  'reporting.JUnitXMLReport.isEnabled');
149  dirNameByTheFollowingFile=confRepoMgr.getParam(...
150  'reporting.JUnitXMLReport.dirNameByTheFollowingFile');
151  dirNameSuffix=confRepoMgr.getParam(...
152  'reporting.JUnitXMLReport.dirNameSuffix');
153  jUnitXMLReportRootDir=fileparts(which(dirNameByTheFollowingFile));
154  %
155  if isempty(jUnitXMLReportRootDir)
156  throwerror('notExistentRefFile',['file %s by which the ',...
157  'directory for JUnit XML reports is build doesn''t exist'],...
158  dirNameByTheFollowingFile);
159  end
160  %
161  jUnitXMLReportDir=[fileparts(which(...
162  dirNameByTheFollowingFile)),filesep,...
163  dirNameSuffix];
164  %
165  inpArgList=[inpArgList,{'isJUnitXMLReportEnabled',...
166  isJUnitXMLReportEnabled,...
167  'jUnitXMLReportDir',jUnitXMLReportDir}];
168  %
169  resultVec=testRunner.runTestPack(topPackageName,...
170  inpArgList{:});
171  catch meObj
172  emailLogger.sendMessage('ERROR',...
173  mxberry.core.MExceptionUtils.me2PlainString(meObj));
174  rethrow(meObj);
175  end
176  catch meObj
177  disp(mxberry.core.MExceptionUtils.me2PlainString(meObj));
178  rethrow(meObj);
179  end
180  end
181  end
182 end
183 function reportStr=getErrorFailMessage(testResVec)
184 isEmptyVec=arrayfun(@(x)~isfield(x.Details,'DiagnosticRecord')||...
185  isfield(x.Details,'DiagnosticRecord')&&...
186  isempty(x.Details.DiagnosticRecord),testResVec);
187 reportStrList=arrayfun(@(x)x.Details.DiagnosticRecord.Report,...
188  testResVec(~isEmptyVec),'UniformOutput',false);
189 reportStr=sprintf('%s\n',reportStrList{:});
190 end
191 function isPassed=getIsPassed(testResVec)
192 isPassed=(sum([testResVec.Failed])+sum([testResVec.Incomplete]))==0;
193 end
194 function reportStr=getMinimalReport(testResVec)
195 nTests=numel(testResVec);
196 runTime=sum([testResVec.Duration]);
197 nFails=sum([testResVec.Failed]);
198 nIncomplete=sum([testResVec.Incomplete]);
199 %
200 msgFormatStr='<< %s >> || TESTS: %d';
201 suffixStr=', RUN TIME(sec.): %.5g';
202 %
203 if (nFails==0)&&(nIncomplete)==0
204  prefixStr='PASSED';
205  addArgList={};
206 else
207  prefixStr='FAILED';
208  msgFormatStr=[msgFormatStr,...
209  ', FAILURES: %d, INCOMPLETE: %d'];
210  addArgList={nFails,nIncomplete};
211 end
212 msgFormatStr=[msgFormatStr,suffixStr];
213 reportStr=sprintf(msgFormatStr,prefixStr,...
214  nTests,addArgList{:},runTime);
215 end
LOG4JCONFIGURATOR simplifies log4j configuration, especially when Parallel Computing Toolbox is used...
function filesep()
function throwerror(in msgTag, in varargin)
THROWERROR works similarly to built-in ERROR function in case when there is no output arguments but s...
function parseparext(in args, in propNameValMat, in varargin)
PARSEPAREXT behaves in the same way as mxberry.core.parseparams but returns property values in a more...
static function fromConfRepoMgr(in confRepoMgr, in appName, in inpSubjSuffName, in mainLogFileName, in fTempDirGetter, in varargin)