Medical Imaging Interaction Toolkit  2018.4.99-b20efe7f
Medical Imaging Interaction Toolkit
mitkLogTest.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include "mitkCommon.h"
14 #include "mitkTestingMacros.h"
15 #include <itkMultiThreader.h>
16 #include <itksys/SystemTools.hxx>
17 #include <mitkLog.h>
18 #include <mitkNumericTypes.h>
20 
27 class TestBackendCout : public mbilog::BackendCout
28 {
29 public:
30  TestBackendCout()
31  {
32  m_Called = false;
34  }
35 
36  void ProcessMessage(const mbilog::LogMessage &l) override
37  {
38  m_Called = true;
40  }
41 
42  bool WasCalled() { return m_Called; }
43 private:
44  bool m_Called;
45 };
53 class mitkTestLoggingThread : public itk::Object
54 {
55 public:
56  mitkClassMacroItkParent(mitkTestLoggingThread, itk::Object);
57  mitkNewMacro1Param(mitkTestLoggingThread, itk::MultiThreader::Pointer);
58 
59  int NumberOfMessages;
60 
61 protected:
62  mitkTestLoggingThread(itk::MultiThreader::Pointer MultiThreader)
63  {
64  ThreadID = -1;
65  NumberOfMessages = 0;
66  m_MultiThreader = MultiThreader;
67  LoggingRunning = true;
68  }
69 
70  bool LoggingRunning;
71 
72  int ThreadID;
73 
74  itk::MultiThreader::Pointer m_MultiThreader;
75 
76  void LogMessages()
77  {
78  while (LoggingRunning)
79  {
80  MITK_INFO << "Test info stream in thread" << ThreadID << "\n even with newlines";
81  MITK_WARN << "Test warning stream in thread " << ThreadID << ". "
82  << "Even with a very long text, even without meaning or implied meaning or content, just a long "
83  "sentence to see whether something has problems with long sentences or output in files or into "
84  "windows or commandlines or whatever.";
85  MITK_DEBUG << "Test debugging stream in thread " << ThreadID;
86  MITK_ERROR << "Test error stream in thread " << ThreadID;
87  MITK_FATAL << "Test fatal stream in thread " << ThreadID;
88 
89  NumberOfMessages += 5;
90  }
91  }
92 
93  static ITK_THREAD_RETURN_TYPE ThreadStartTracking(void *pInfoStruct)
94  {
95  /* extract this pointer from Thread Info structure */
96  auto *pInfo = (struct itk::MultiThreader::ThreadInfoStruct *)pInfoStruct;
97  if (pInfo == nullptr)
98  {
99  return ITK_THREAD_RETURN_VALUE;
100  }
101  if (pInfo->UserData == nullptr)
102  {
103  return ITK_THREAD_RETURN_VALUE;
104  }
105  auto *thisthread = (mitkTestLoggingThread *)pInfo->UserData;
106 
107  if (thisthread != nullptr)
108  thisthread->LogMessages();
109 
110  return ITK_THREAD_RETURN_VALUE;
111  }
112 
113 public:
114  int Start()
115  {
116  LoggingRunning = true;
117  this->ThreadID = m_MultiThreader->SpawnThread(this->ThreadStartTracking, this);
118  return ThreadID;
119  }
120 
121  void Stop() { LoggingRunning = false; }
122 };
123 
128 class mitkLogTestClass
129 {
130 public:
131  static void TestSimpleLog()
132  {
133  bool testSucceded = true;
134  try
135  {
136  MITK_INFO << "Test info stream.";
137  MITK_WARN << "Test warning stream.";
138  MITK_DEBUG << "Test debugging stream."; // only activated if cmake variable is on!
139  // so no worries if you see no output for this line
140  MITK_ERROR << "Test error stream.";
141  MITK_FATAL << "Test fatal stream.";
142  }
143  catch (const mitk::Exception &)
144  {
145  testSucceded = false;
146  }
147  MITK_TEST_CONDITION_REQUIRED(testSucceded, "Test logging streams.");
148  }
149 
150  static void TestObjectInfoLogging()
151  {
152  bool testSucceded = true;
153  try
154  {
155  int i = 123;
156  float f = .32234;
157  double d = 123123;
158  std::string testString = "testString";
159  std::stringstream testStringStream;
160  testStringStream << "test"
161  << "String"
162  << "Stream";
163  mitk::Point3D testMitkPoint;
164  testMitkPoint.Fill(2);
165 
166  MITK_INFO << i;
167  MITK_INFO << f;
168  MITK_INFO << d;
169  MITK_INFO << testString;
170  MITK_INFO << testStringStream.str();
171  MITK_INFO << testMitkPoint;
172  }
173  catch (const mitk::Exception &)
174  {
175  testSucceded = false;
176  }
177  MITK_TEST_CONDITION_REQUIRED(testSucceded, "Test logging of object information.");
178  }
179 
180  static void TestThreadSaveLog(bool toFile)
181  {
182  bool testSucceded = true;
183 
184  try
185  {
186  if (toFile)
187  {
188  std::string filename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory() + "/testthreadlog.log";
189  itksys::SystemTools::RemoveFile(filename.c_str()); // remove old file, we do not want to append to large files
190  mitk::LoggingBackend::SetLogFile(filename.c_str());
191  }
192 
193  unsigned int numberOfThreads = 20;
194  unsigned int threadRuntimeInMilliseconds = 2000;
195 
196  std::vector<unsigned int> threadIDs;
197  std::vector<mitkTestLoggingThread::Pointer> threads;
198 
199  itk::MultiThreader::Pointer multiThreader = itk::MultiThreader::New();
200  for (unsigned int threadIdx = 0; threadIdx < numberOfThreads; ++threadIdx)
201  {
202  // initialize threads...
203  mitkTestLoggingThread::Pointer newThread = mitkTestLoggingThread::New(multiThreader);
204  threads.push_back(newThread);
205  std::cout << "Created " << threadIdx << ". thread." << std::endl;
206  }
207 
208  for (unsigned int threadIdx = 0; threadIdx < numberOfThreads; ++threadIdx)
209  {
210  // start them
211  std::cout << "Start " << threadIdx << ". thread." << std::endl;
212  threadIDs.push_back(threads[threadIdx]->Start());
213  std::cout << threadIdx << ". thread has ID " << threadIDs[threadIdx] << std::endl;
214  }
215 
216  // wait for some time (milliseconds)
217  itksys::SystemTools::Delay(threadRuntimeInMilliseconds);
218 
219  for (unsigned int threadIdx = 0; threadIdx < numberOfThreads; ++threadIdx)
220  {
221  // stop them
222  std::cout << "Stop " << threadIdx << ". thread." << std::endl;
223  threads[threadIdx]->Stop();
224  }
225 
226  for (unsigned int threadIdx = 0; threadIdx < numberOfThreads; ++threadIdx)
227  {
228  // Wait for all threads to end
229  multiThreader->TerminateThread(threadIDs[threadIdx]);
230  std::cout << "Terminated " << threadIdx << ". thread (" << threads[threadIdx]->NumberOfMessages << " messages)."
231  << std::endl;
232  }
233  }
234  catch (std::exception &e)
235  {
236  MITK_ERROR << "exception during 'TestThreadSaveLog': " << e.what();
237  testSucceded = false;
238  }
239  catch (...)
240  {
241  MITK_ERROR << "unknown exception during 'TestThreadSaveLog'";
242  testSucceded = false;
243  }
244 
245  // if no error occured until now, everything is ok
246  MITK_TEST_CONDITION_REQUIRED(testSucceded, "Test logging in different threads.");
247  }
248 
249  static void TestLoggingToFile()
250  {
251  std::string filename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory() + "/testlog.log";
252  mitk::LoggingBackend::SetLogFile(filename.c_str());
253  MITK_INFO << "Test logging to default filename: " << mitk::LoggingBackend::GetLogFile();
254  MITK_TEST_CONDITION_REQUIRED(itksys::SystemTools::FileExists(filename.c_str()), "Testing if log file exists.");
255  // TODO delete log file?
256  }
257 
258  static void TestAddAndRemoveBackends()
259  {
261  mbilog::RegisterBackend(&myBackend);
262  MITK_INFO << "Test logging";
263  mbilog::UnregisterBackend(&myBackend);
264 
265  // if no error occured until now, everything is ok
266  MITK_TEST_CONDITION_REQUIRED(true, "Test add/remove logging backend.");
267  }
268 
269  static void TestDefaultBackend()
270  {
271  // not possible now, because we cannot unregister the mitk logging backend in the moment. If such a method is added
272  // to mbilog utility one may add this test.
273  }
274 
275  static void TestEnableDisableBackends()
276  {
277  TestBackendCout myCoutBackend = TestBackendCout();
278  mbilog::RegisterBackend(&myCoutBackend);
279 
281  MITK_INFO << "There should be no output!";
282  bool success = !myCoutBackend.WasCalled();
283 
285  MITK_INFO << "Now there should be an output.";
286  success &= myCoutBackend.WasCalled();
287 
288  mbilog::UnregisterBackend(&myCoutBackend);
289  MITK_TEST_CONDITION_REQUIRED(success, "Test disable / enable logging backends.")
290  }
291 };
292 
293 int mitkLogTest(int /* argc */, char * /*argv*/ [])
294 {
295  // always start with this!
296  MITK_TEST_BEGIN("Log")
297 
298  MITK_TEST_OUTPUT(<< "TESTING ALL LOGGING OUTPUTS, ERROR MESSAGES ARE ALSO TESTED AND NOT MEANING AN ERROR OCCURED!")
299 
300  mitkLogTestClass::TestSimpleLog();
301  mitkLogTestClass::TestObjectInfoLogging();
302 
303  mitkLogTestClass::TestLoggingToFile();
304  mitkLogTestClass::TestAddAndRemoveBackends();
305  mitkLogTestClass::TestThreadSaveLog(false); // false = to console
306  mitkLogTestClass::TestThreadSaveLog(true); // true = to file
307  mitkLogTestClass::TestEnableDisableBackends();
308  // TODO actually test file somehow?
309 
310  // always end with this!
311  MITK_TEST_END()
312 }
#define MITK_FATAL
Definition: mitkLogMacros.h:21
void MBILOG_EXPORT UnregisterBackend(BackendBase *backend)
Unregisters a backend.
Definition: mbilog.cpp:31
#define mitkNewMacro1Param(classname, type)
Definition: mitkCommon.h:72
#define MITK_INFO
Definition: mitkLogMacros.h:18
void MBILOG_EXPORT EnableBackends(OutputType type)
Definition: mbilog.cpp:70
#define MITK_ERROR
Definition: mitkLogMacros.h:20
void LogMessages(unsigned int threadID, unsigned int numberOfTimes)
#define MITK_TEST_CONDITION_REQUIRED(COND, MSG)
void MBILOG_EXPORT DisableBackends(OutputType type)
Definition: mbilog.cpp:75
Default backend of the mbi logging mechanism. This backend is used if no other backend is registered...
#define MITK_DEBUG
Definition: mitkLogMacros.h:22
section GeneralTestsDeprecatedOldTestingStyle Deprecated macros All tests with MITK_TEST_BEGIN()
static void TestThreadSaveLog(bool toFile)
Test logging from Qt threads.
An object of this class represents a single logging message (logging event) of the mbi logging mechan...
#define MITK_TEST_OUTPUT(x)
Output some text.
std::string GetOptionDirectory()
Return directory of/for option files.
#define MITK_WARN
Definition: mitkLogMacros.h:19
An object of this class represents an exception of MITK. Please don&#39;t instantiate exceptions manually...
Definition: mitkException.h:45
#define mitkClassMacroItkParent(className, SuperClassName)
Definition: mitkCommon.h:49
void MBILOG_EXPORT RegisterBackend(BackendBase *backend)
Registeres a backend to the mbi logging mechanism. If a backend is registered here, all mbilog messages are relayed to this backend through the method ProcessMessage. If no backend is registered the default backend is used.
Definition: mbilog.cpp:26
static void SetLogFile(const char *file)
Sets extra log file path (additionally to the console log)
Definition: mitkLog.cpp:90
int mitkLogTest(int, char *[])
void ProcessMessage(const mbilog::LogMessage &l) override
This method is called by the mbi logging mechanism if the object is registered in the mbi logging mec...
static std::string GetLogFile()
Definition: mitkLog.cpp:141
and MITK_TEST_END()
static StandardFileLocations * GetInstance()