diff --git a/itext.tests/itext.barcodes.tests/Properties/AssemblyInfo.cs b/itext.tests/itext.barcodes.tests/Properties/AssemblyInfo.cs
index 7bf66bb33..7bacbaa8f 100644
--- a/itext.tests/itext.barcodes.tests/Properties/AssemblyInfo.cs
+++ b/itext.tests/itext.barcodes.tests/Properties/AssemblyInfo.cs
@@ -1,3 +1,4 @@
+using NUnit.Framework;
using System.Reflection;
using System.Runtime.InteropServices;
@@ -18,6 +19,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyFileVersion("9.2.0.0")]
[assembly: AssemblyInformationalVersion("9.2.0-SNAPSHOT")]
+[assembly: Parallelizable(ParallelScope.ContextMask)]
+
#if !NETSTANDARD2_0
[assembly: NUnit.Framework.Timeout(300000)]
#endif
diff --git a/itext.tests/itext.layout.tests/Properties/AssemblyInfo.cs b/itext.tests/itext.layout.tests/Properties/AssemblyInfo.cs
index 953ff2056..a13f0e934 100644
--- a/itext.tests/itext.layout.tests/Properties/AssemblyInfo.cs
+++ b/itext.tests/itext.layout.tests/Properties/AssemblyInfo.cs
@@ -1,3 +1,4 @@
+using NUnit.Framework;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -19,6 +20,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyFileVersion("9.2.0.0")]
[assembly: AssemblyInformationalVersion("9.2.0-SNAPSHOT")]
+[assembly: Parallelizable(ParallelScope.ContextMask)]
+
#if !NETSTANDARD2_0
[assembly: NUnit.Framework.Timeout(600000)]
#endif
diff --git a/itext/itext.pdftest/itext/test/ITextTestLoggerFactory.cs b/itext/itext.pdftest/itext/test/ITextTestLoggerFactory.cs
index 7d693b2a5..336c4b6a7 100644
--- a/itext/itext.pdftest/itext/test/ITextTestLoggerFactory.cs
+++ b/itext/itext.pdftest/itext/test/ITextTestLoggerFactory.cs
@@ -21,39 +21,63 @@
along with this program. If not, see .
*/
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading;
using Microsoft.Extensions.Logging;
+using NUnit.Framework;
namespace iText.Test
{
internal class ITextTestLoggerFactory : ILoggerFactory
{
- private readonly Dictionary expectedTemplates = new Dictionary();
+ private readonly IDictionary> expectedTemplates = new ConcurrentDictionary>();
- private readonly IList logEvents = new List();
-
- public void SetExpectedTemplates(Dictionary expectedTemplates) {
- this.expectedTemplates.Clear();
- foreach (KeyValuePair item in expectedTemplates)
+ private readonly IDictionary> logEvents = new ConcurrentDictionary>();
+
+ private static readonly int DEFAULT_THREAD_ID = 1;
+ private static bool threadsAware = false;
+
+ public ITextTestLoggerFactory()
+ {
+ InitThreadAwareness();
+ }
+
+ public void SetExpectedTemplates(Dictionary expectedTemplates) {
+ var threadId = GetThreadID();
+
+ if (!this.expectedTemplates.ContainsKey(threadId))
{
- this.expectedTemplates[item.Key] = item.Value;
+ this.expectedTemplates.Add(threadId, new Dictionary());
}
+ this.expectedTemplates[threadId] = expectedTemplates;
}
public IList GetLogEvents()
{
- return logEvents;
+ var threadId = GetThreadID();
+
+ return logEvents.ContainsKey(threadId) ? logEvents[threadId] : new List();
}
public void Dispose()
{
- expectedTemplates.Clear();
- logEvents.Clear();
+ var threadId = GetThreadID();
+ if (expectedTemplates.ContainsKey(threadId))
+ {
+ expectedTemplates[threadId].Clear();
+ }
+
+ if (logEvents.ContainsKey(threadId))
+ {
+ logEvents[threadId].Clear();
+ }
}
public ILogger CreateLogger(string categoryName)
{
-
return new ITextTestLogger(categoryName, this);
}
@@ -64,10 +88,10 @@ namespace iText.Test
throw new NotImplementedException();
}
- private bool IsExpectedMessage(String message) {
- if (message != null) {
- foreach (var template in expectedTemplates) {
- if (LogListenerHelper.EqualsMessageByTemplate(message, template.Key)) {
+ private bool IsExpectedMessage(string message, int threadId) {
+ if (message != null && expectedTemplates.ContainsKey(threadId)) {
+ foreach (var template in expectedTemplates[threadId].Keys) {
+ if (LogListenerHelper.EqualsMessageByTemplate(message, template)) {
return true;
}
}
@@ -75,10 +99,10 @@ namespace iText.Test
return false;
}
- private bool IsExpectedMessageQuiet(String message) {
- if (message != null) {
- foreach (String template in expectedTemplates.Keys) {
- if (LogListenerHelper.EqualsMessageByTemplate(message, template) && expectedTemplates[template]) {
+ private bool IsExpectedMessageQuiet(string message, int threadId) {
+ if (message != null && expectedTemplates.ContainsKey(threadId)) {
+ foreach (var template in expectedTemplates[threadId].Keys) {
+ if (LogListenerHelper.EqualsMessageByTemplate(message, template) && expectedTemplates[threadId][template]) {
return true;
}
}
@@ -88,7 +112,46 @@ namespace iText.Test
private void AddLogEvent(ITextTestLogEvent testLogEvent)
{
- logEvents.Add(testLogEvent);
+ var threadId = GetThreadID();
+
+ if (!logEvents.ContainsKey(threadId))
+ {
+ logEvents.Add(threadId, new List());
+ }
+
+ logEvents[threadId].Add(testLogEvent);
+ }
+
+ private static void InitThreadAwareness()
+ {
+ var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
+ foreach (var asm in loadedAssemblies)
+ {
+ if (asm.IsDynamic || !asm.CodeBase.ToLower().EndsWith("tests.dll"))
+ {
+ continue;
+ }
+
+ var attrs = asm.GetCustomAttributes(true);
+ int parallel = attrs.Count(t => t is ParallelizableAttribute);
+ if (parallel > 0)
+ {
+ threadsAware = true;
+ return;
+ }
+ }
+ }
+
+ private static int GetThreadID()
+ {
+ if (threadsAware)
+ {
+ return Thread.CurrentThread.ManagedThreadId;
+ }
+ else
+ {
+ return DEFAULT_THREAD_ID;
+ }
}
public class ITextTestLogEvent
@@ -102,35 +165,34 @@ namespace iText.Test
this.message = message;
}
}
-
- private class ITextTestLogger : ILogger
+
+ internal class ITextTestLogger : ILogger
{
private readonly string categoryName;
private readonly ITextTestLoggerFactory factory;
- private bool runInSilentMode = false;
+ private bool runInSilentMode;
private static readonly string TOKEN_ITEXT_SILENT_MODE = "ITEXT_SILENT_MODE";
private static readonly string ITEXT_LICENCING_PACKAGE = "iText.Licensing";
private static readonly string ITEXT_ACTIONS_PACKAGE = "iText.Commons.Actions.Processors";
-
+
public ITextTestLogger(string categoryName, ITextTestLoggerFactory factory)
{
this.categoryName = categoryName;
this.factory = factory;
SetupRunInSilentMode();
}
-
-
+
public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
{
- if (!factory.IsExpectedMessageQuiet(state.ToString()))
+ if (!factory.IsExpectedMessageQuiet(state.ToString(), GetThreadID()))
{
if (ShouldPrintMessage(categoryName))
{
Console.WriteLine( categoryName + ": " + state);
}
}
- if (logLevel >= LogLevel.Warning || factory.IsExpectedMessage(state.ToString()))
+ if (logLevel >= LogLevel.Warning || factory.IsExpectedMessage(state.ToString(), GetThreadID()))
{
factory.AddLogEvent(new ITextTestLogEvent(logLevel, state.ToString()));
}
@@ -161,7 +223,7 @@ namespace iText.Test
}
private void SetupRunInSilentMode() {
- string envIsSilentModeEnabled = Environment.GetEnvironmentVariable(TOKEN_ITEXT_SILENT_MODE);
+ var envIsSilentModeEnabled = Environment.GetEnvironmentVariable(TOKEN_ITEXT_SILENT_MODE);
if (string.IsNullOrEmpty(envIsSilentModeEnabled)) {
runInSilentMode = false;
return;
diff --git a/itext/itext.pdftest/itext/test/LogListener.cs b/itext/itext.pdftest/itext/test/LogListener.cs
index ec4ab82c4..3836777d9 100644
--- a/itext/itext.pdftest/itext/test/LogListener.cs
+++ b/itext/itext.pdftest/itext/test/LogListener.cs
@@ -20,77 +20,92 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
+
using System;
using System.Collections.Generic;
using iText.Commons;
-using iText.IO;
using iText.Test.Attributes;
using Microsoft.Extensions.Logging;
using NUnit.Framework;
using NUnit.Framework.Interfaces;
-namespace iText.Test {
+namespace iText.Test
+{
[AttributeUsage(AttributeTargets.Class)]
- public class LogListener : TestActionAttribute {
-
+ public class LogListener : TestActionAttribute
+ {
private static readonly ITextTestLoggerFactory TEST_LOGGER_FACTORY;
-
- private ILoggerFactory defaultLoggerFactory;
- static LogListener() {
+ static LogListener()
+ {
TEST_LOGGER_FACTORY = new ITextTestLoggerFactory();
+ ITextLogManager.SetLoggerFactory(TEST_LOGGER_FACTORY);
}
public override void BeforeTest(ITest testDetails)
{
- defaultLoggerFactory = ITextLogManager.GetLoggerFactory();
- ITextLogManager.SetLoggerFactory(TEST_LOGGER_FACTORY);
Init(testDetails);
}
- public override void AfterTest(ITest testDetails) {
+ public override void AfterTest(ITest testDetails)
+ {
CheckLogMessages(testDetails);
- ITextLogManager.SetLoggerFactory(defaultLoggerFactory);
}
- public override ActionTargets Targets {
+ public override ActionTargets Targets
+ {
get { return ActionTargets.Test; }
}
- private void CheckLogMessages(ITest testDetails) {
- int checkedMessages = 0;
- LogMessageAttribute[] attributes = LogListenerHelper.GetTestAttributes(testDetails);
- if (attributes.Length > 0) {
- for (int i = 0; i < attributes.Length; i++) {
- LogMessageAttribute logMessage = attributes[i];
- int foundCount = Contains(logMessage);
- if (foundCount != logMessage.Count && !logMessage.Ignore) {
- LogListenerHelper.FailWrongMessageCount(logMessage.Count, foundCount, logMessage.GetMessageTemplate(), testDetails);
- } else {
- checkedMessages += foundCount;
+ private void CheckLogMessages(ITest testDetails)
+ {
+ var checkedMessagesCount = 0;
+ var attributes = LogListenerHelper.GetTestAttributes(testDetails);
+ if (attributes.Length > 0)
+ {
+ for (var i = 0; i < attributes.Length; i++)
+ {
+ var logMessage = attributes[i];
+ var foundCount = Contains(logMessage);
+ if (foundCount != logMessage.Count && !logMessage.Ignore)
+ {
+ LogListenerHelper.FailWrongMessageCount(logMessage.Count, foundCount,
+ logMessage.GetMessageTemplate(), testDetails);
+ }
+ else
+ {
+ checkedMessagesCount += foundCount;
}
}
}
- if (GetSize() > checkedMessages) {
- LogListenerHelper.FailWrongTotalCount(GetSize(), checkedMessages, testDetails);
+ if (GetLogEventsSize() > checkedMessagesCount)
+ {
+ LogListenerHelper.FailWrongTotalCount(GetLogEventsSize(), checkedMessagesCount, testDetails);
}
}
- private int Contains(LogMessageAttribute loggingStatement) {
- IList eventList = TEST_LOGGER_FACTORY.GetLogEvents();
- int index = 0;
- for (int i = 0; i < eventList.Count; i++) {
- if (IsLevelCompatible(loggingStatement.LogLevel, eventList[i].logLevel)
- && LogListenerHelper.EqualsMessageByTemplate(eventList[i].message, loggingStatement.GetMessageTemplate())) {
+ private int Contains(LogMessageAttribute loggingStatement)
+ {
+ var eventList = TEST_LOGGER_FACTORY.GetLogEvents();
+ var index = 0;
+ for (var i = 0; i < eventList.Count; i++)
+ {
+ if (IsLevelCompatible(loggingStatement.LogLevel, eventList[i].logLevel)
+ && LogListenerHelper.EqualsMessageByTemplate(eventList[i].message,
+ loggingStatement.GetMessageTemplate()))
+ {
index++;
}
}
+
return index;
}
-
- private bool IsLevelCompatible(int logMessageLevel, LogLevel eventLevel) {
- switch (logMessageLevel) {
+
+ private bool IsLevelCompatible(int logMessageLevel, LogLevel eventLevel)
+ {
+ switch (logMessageLevel)
+ {
case LogLevelConstants.UNKNOWN:
return eventLevel >= LogLevel.Warning;
case LogLevelConstants.ERROR:
@@ -106,22 +121,27 @@ namespace iText.Test {
}
}
- private void Init(ITest testDetails) {
+ private void Init(ITest testDetails)
+ {
+ // Cleanup on Init. We can cleanup when finishing but there some exception may be thrown on checking messages.
TEST_LOGGER_FACTORY.Dispose();
- LogMessageAttribute[] attributes = LogListenerHelper.GetTestAttributes(testDetails);
+
+ var attributes = LogListenerHelper.GetTestAttributes(testDetails);
if (attributes.Length > 0)
{
- Dictionary expectedTemplates = new Dictionary();
-
- for (int i = 0; i < attributes.Length; i++) {
- LogMessageAttribute logMessage = attributes[i];
+ var expectedTemplates = new Dictionary();
+ for (var i = 0; i < attributes.Length; i++)
+ {
+ var logMessage = attributes[i];
expectedTemplates.Add(logMessage.GetMessageTemplate(), logMessage.QuietMode);
}
+
TEST_LOGGER_FACTORY.SetExpectedTemplates(expectedTemplates);
}
}
- private int GetSize() {
+ private int GetLogEventsSize()
+ {
return TEST_LOGGER_FACTORY.GetLogEvents().Count;
}
}