Browse Source

Merge pull request #1387 from open62541/feature/unit_test_appveyor

Unit Tests for Windows/Appveyor
Stefan Profanter 6 years ago
parent
commit
abe27b43bd

+ 5 - 2
CMakeLists.txt

@@ -370,7 +370,8 @@ set(default_plugin_headers ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.h
                            ${PROJECT_SOURCE_DIR}/plugins/ua_log_stdout.h
                            ${PROJECT_SOURCE_DIR}/plugins/ua_nodestore_default.h
                            ${PROJECT_SOURCE_DIR}/plugins/ua_config_default.h
-                           ${PROJECT_SOURCE_DIR}/plugins/ua_securitypolicy_none.h)
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_securitypolicy_none.h
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_log_socket_error.h)
 
 set(default_plugin_sources ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.c
                            ${PROJECT_SOURCE_DIR}/plugins/ua_clock.c
@@ -540,7 +541,9 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_namespace0.c
                            ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541_datatypes.py)
 
 # stack protector needs to be disabled for the huge ns0 file, otherwise it may take many minutes to compile the file.
-set_source_files_properties(${PROJECT_BINARY_DIR}/src_generated/ua_namespace0.c PROPERTIES COMPILE_FLAGS -fno-stack-protector)
+if(NOT MSVC)
+    set_source_files_properties(${PROJECT_BINARY_DIR}/src_generated/ua_namespace0.c PROPERTIES COMPILE_FLAGS -fno-stack-protector)
+endif()
 
 # we need a custom target to avoid that the generator is called concurrently and thus overwriting files while the other thread is compiling
 add_custom_target(open62541-generator-namespace DEPENDS

+ 17 - 3
appveyor.yml

@@ -3,6 +3,9 @@ version: '{build}'
 clone_folder: c:\projects\open62541
 clone_depth: 20
 
+# Avoid building branch if it is part of a PR and built anyways
+skip_branch_with_pr: true
+
 environment:
     global:
         APPVEYOR_CACHE_ENTRY_ZIP_ARGS: -t7z -m0=lzma -mx=9
@@ -34,8 +37,8 @@ environment:
           FORCE_CXX: OFF
           OUT_DIR_LIB: bin\Debug
           OUT_DIR_EXAMPLES: bin\examples\Debug
-        - CC_NAME: Visual Studio 12 2013 Win64
-          CC_SHORTNAME: vs2013-x64
+        - CC_NAME: Visual Studio 14 2015
+          CC_SHORTNAME: vs2015
           # Do not build in parallel, project dependencies are not solved correctly and thus appveyor may randomly fail
           MAKE: msbuild /m:1 /p:BuildInParallel=false /p:ContinueOnError=false /p:StopOnFirstFailure=true open62541.sln
           FORCE_CXX: OFF
@@ -45,7 +48,6 @@ environment:
 cache:
   - '%CYG_CACHE%'
   - 'c:\miktex'
-  #- 'c:\python27'
 
 init:
   - git config --global core.autocrlf input # Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail
@@ -70,6 +72,9 @@ install:
   - if exist c:\miktex\texmfs\install\miktex\bin\a5toa4.exe rd /s /q c:\miktex\texmfs\install\miktex\bin\a5toa4.exe
   - pip install --user sphinx sphinx_rtd_theme
   - cinst graphviz.portable
+  # Download and build libcheck
+  - appveyor DownloadFile https://github.com/Pro/check/releases/download/0.12.0_win/check.zip
+  - 7z x check.zip -oc:\ >NUL
 
 before_build:
   # use MinGW64
@@ -148,6 +153,15 @@ build_script:
   - if not "%CC_SHORTNAME%" == "mingw" move "%APPVEYOR_BUILD_FOLDER%\build\%OUT_DIR_LIB%\open62541.pdb" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
   - cd ..
   - 7z a -tzip open62541-%CC_SHORTNAME%-dynamic.zip "%APPVEYOR_BUILD_FOLDER%\pack\*" "%APPVEYOR_BUILD_FOLDER%\pack_tmp\*"
+  - rd /s /q pack_tmp
+  - rd /s /q build
+  # Only execute unit tests on vs2015 to save compilation time
+  - if "%CC_SHORTNAME%" == "vs2015" md build
+  - if "%CC_SHORTNAME%" == "vs2015" cd build
+  - if "%CC_SHORTNAME%" == "vs2015" echo. && echo "##### Testing %CC_NAME% with unit tests #####" && echo.
+  - if "%CC_SHORTNAME%" == "vs2015" cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=OFF -DUA_ENABLE_DISCOVERY=ON -DUA_ENABLE_DISCOVERY_MULTICAST=ON -DUA_BUILD_UNIT_TESTS=ON -DCMAKE_LIBRARY_PATH=c:\check\lib -DCMAKE_INCLUDE_PATH=c:\check\include -DUA_COMPILE_AS_CXX:BOOL=%FORCE_CXX% -G"%CC_NAME%" ..
+  - if "%CC_SHORTNAME%" == "vs2015" %MAKE%
+  - if "%CC_SHORTNAME%" == "vs2015" cmake --build . --target test-verbose --config debug
   # do not cache log
   - rd /s /q c:\miktex\texmfs\data\miktex\log
 

+ 1 - 1
deps/mdnsd

@@ -1 +1 @@
-Subproject commit 9c11048aefc2a47b78230491931c8346fb6c6b98
+Subproject commit f4aee59d4bbed766a9a8ef3c44492e98edfdd654

+ 1 - 0
include/ua_plugin_log.h

@@ -114,6 +114,7 @@ UA_LOG_FATAL(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
 #define UA_PRINTF_STRING_FORMAT "\"%.*s\""
 #define UA_PRINTF_STRING_DATA(STRING) (int)(STRING).length, (STRING).data
 
+
 #ifdef __cplusplus
 } // extern "C"
 #endif

+ 34 - 0
plugins/ua_log_socket_error.h

@@ -0,0 +1,34 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#ifndef UA_LOG_SOCKET_ERROR_H_
+#define UA_LOG_SOCKET_ERROR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef _WIN32
+#include <winsock2.h>
+#define UA_LOG_SOCKET_ERRNO_WRAP(LOG) { \
+    char *errno_str = NULL; \
+    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
+    NULL, WSAGetLastError(), \
+    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), \
+    (LPSTR)&errno_str, 0, NULL); \
+    LOG; \
+    LocalFree(errno_str); \
+}
+#else
+#define UA_LOG_SOCKET_ERRNO_WRAP(LOG) { \
+    char *errno_str = strerror(errno); \
+    LOG; \
+}
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* UA_LOG_SOCKET_ERROR_H_ */

+ 31 - 18
plugins/ua_network_tcp.c

@@ -109,6 +109,8 @@
 # define AGAIN EAGAIN
 #endif
 
+#include "ua_log_socket_error.h"
+
 /****************************/
 /* Generic Socket Functions */
 /****************************/
@@ -290,9 +292,10 @@ ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd,
     int dummy = 1;
     if(setsockopt(newsockfd, IPPROTO_TCP, TCP_NODELAY,
                (const char *)&dummy, sizeof(dummy)) < 0) {
-        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
-                     "Cannot set socket option TCP_NODELAY. Error: %s",
-                     strerror(errno));
+        UA_LOG_SOCKET_ERRNO_WRAP(
+                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
+                             "Cannot set socket option TCP_NODELAY. Error: %s",
+                             errno_str));
         return UA_STATUSCODE_BADUNEXPECTEDERROR;
     }
 
@@ -307,10 +310,10 @@ ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd,
                     "Connection %i | New connection over TCP from %s",
                     (int)newsockfd, remote_name);
     } else {
-        UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
-                       "Connection %i | New connection over TCP, "
-                       "getnameinfo failed with errno %i",
-                       (int)newsockfd, errno__);
+        UA_LOG_SOCKET_ERRNO_WRAP(UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
+                                                "Connection %i | New connection over TCP, "
+                                                        "getnameinfo failed with error: %s",
+                                                (int)newsockfd, errno_str));
     }
 
     /* Allocate and initialize the connection */
@@ -382,16 +385,18 @@ addServerSocket(ServerNetworkLayerTCP *layer, struct addrinfo *ai) {
 
     /* Bind socket to address */
     if(bind(newsock, ai->ai_addr, WIN32_INT ai->ai_addrlen) < 0) {
-        UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
-                       "Error binding a server socket: %i", errno__);
+        UA_LOG_SOCKET_ERRNO_WRAP(
+            UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
+                           "Error binding a server socket: %s", errno_str));
         CLOSESOCKET(newsock);
         return;
     }
 
     /* Start listening */
     if(listen(newsock, MAXBACKLOG) < 0) {
-        UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
-                       "Error listening on server socket");
+        UA_LOG_SOCKET_ERRNO_WRAP(
+                UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
+                       "Error listening on server socket: %s", errno_str));
         CLOSESOCKET(newsock);
         return;
     }
@@ -501,14 +506,20 @@ ServerNetworkLayerTCP_listen(UA_ServerNetworkLayer *nl, UA_Server *server,
     /* Every open socket can generate two jobs */
     ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP *)nl->handle;
 
+    if (layer->serverSocketsSize == 0)
+        return UA_STATUSCODE_GOOD;
+
     /* Listen on open sockets (including the server) */
     fd_set fdset, errset;
     UA_Int32 highestfd = setFDSet(layer, &fdset);
     setFDSet(layer, &errset);
     struct timeval tmptv = {0, timeout * 1000};
     if (select(highestfd+1, &fdset, NULL, &errset, &tmptv) < 0) {
-        UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
-                       "Socket select failed with %s", strerror(errno));
+        UA_LOG_SOCKET_ERRNO_WRAP(
+            UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
+                                  "Socket select failed with %s", errno_str));
+        // we will retry, so do not return bad
+        return UA_STATUSCODE_GOOD;
     }
 
     /* Accept new connections via the server sockets */
@@ -732,8 +743,9 @@ UA_ClientConnectionTCP(UA_ConnectionConfig conf,
     #else
         if(clientsockfd < 0) {
     #endif
-            UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
-                           "Could not create client socket: %s", strerror(errno__));
+            UA_LOG_SOCKET_ERRNO_WRAP(
+                    UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
+                                          "Could not create client socket: %s", errno_str));
             freeaddrinfo(server);
             return connection;
         }
@@ -756,9 +768,10 @@ UA_ClientConnectionTCP(UA_ConnectionConfig conf,
 
         if ((error == -1) && (errno__ != ERR_CONNECTION_PROGRESS)) {
             ClientNetworkLayerTCP_close(&connection);
-            UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
-                           "Connection to %s failed with error: %s",
-                           endpointUrl, strerror(errno__));
+            UA_LOG_SOCKET_ERRNO_WRAP(
+                    UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_NETWORK,
+                                          "Connection to %s failed with error: %s",
+                                          endpointUrl, errno_str));
             freeaddrinfo(server);
             return connection;
         }

+ 9 - 3
src/server/ua_mdns.c

@@ -242,8 +242,14 @@ setSrv(UA_Server *server, const struct resource *r,
 
     // todo: malloc may fail: return a statuscode
     char *newUrl = (char*)UA_malloc(10 + srvNameLen + 8);
-    sprintf(newUrl, "opc.tcp://%.*s:%d/", (int) srvNameLen,
-            r->known.srv.name, r->known.srv.port);
+    #ifndef _MSC_VER
+    snprintf(newUrl, 10 + srvNameLen + 8, "opc.tcp://%.*s:%d/", (int) srvNameLen,
+             r->known.srv.name, r->known.srv.port);
+    #else
+    _snprintf_s(newUrl, 10 + srvNameLen + 8, _TRUNCATE, "opc.tcp://%.*s:%d/", (int) srvNameLen,
+             r->known.srv.name, r->known.srv.port);
+    #endif
+
     UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
                 "Multicast DNS: found server: %s", newUrl);
     entry->serverOnNetwork.discoveryUrl = UA_String_fromChars(newUrl);
@@ -349,7 +355,7 @@ void mdns_create_txt(UA_Server *server, const char *fullServiceDomain, const cha
         caps = (char*)UA_malloc(sizeof(char) * capsLen);
         size_t idx = 0;
         for (size_t i = 0; i < *capabilitiesSize; i++) {
-            strncpy(caps + idx, (const char *) capabilites[i].data, capabilites[i].length);
+            memcpy(caps + idx, (const char *) capabilites[i].data, capabilites[i].length);
             idx += capabilites[i].length + 1;
             caps[idx - 1] = ',';
         }

+ 39 - 39
src/server/ua_nodes.c

@@ -220,45 +220,45 @@ UA_Node_copy(const UA_Node *src, UA_Node *dst) {
 
 UA_Node *
 UA_Node_copy_alloc(const UA_Node *src) {
-	// use dstPtr to trick static code analysis in accepting dirty cast
-	void *dstPtr;
-	switch(src->nodeClass) {
-		case UA_NODECLASS_OBJECT:
-			dstPtr = UA_malloc(sizeof(UA_ObjectNode));
-			break;
-		case UA_NODECLASS_VARIABLE:
-			dstPtr =UA_malloc(sizeof(UA_VariableNode));
-			break;
-		case UA_NODECLASS_METHOD:
-			dstPtr = UA_malloc(sizeof(UA_MethodNode));
-			break;
-		case UA_NODECLASS_OBJECTTYPE:
-			dstPtr = UA_malloc(sizeof(UA_ObjectTypeNode));
-			break;
-		case UA_NODECLASS_VARIABLETYPE:
-			dstPtr = UA_malloc(sizeof(UA_VariableTypeNode));
-			break;
-		case UA_NODECLASS_REFERENCETYPE:
-			dstPtr = UA_malloc(sizeof(UA_ReferenceTypeNode));
-			break;
-		case UA_NODECLASS_DATATYPE:
-			dstPtr = UA_malloc(sizeof(UA_DataTypeNode));
-			break;
-		case UA_NODECLASS_VIEW:
-			dstPtr = UA_malloc(sizeof(UA_ViewNode));
-			break;
-		default:
-			return NULL;
-	}
-	UA_Node *dst = (UA_Node*)dstPtr;
-	dst->nodeClass = src->nodeClass;
-
-	UA_StatusCode retval = UA_Node_copy(src, dst);
-	if (retval != UA_STATUSCODE_GOOD){
-		UA_free(dst);
-		return NULL;
-	}
-	return dst;
+    // use dstPtr to trick static code analysis in accepting dirty cast
+    void *dstPtr;
+    switch(src->nodeClass) {
+        case UA_NODECLASS_OBJECT:
+            dstPtr = UA_malloc(sizeof(UA_ObjectNode));
+            break;
+        case UA_NODECLASS_VARIABLE:
+            dstPtr =UA_malloc(sizeof(UA_VariableNode));
+            break;
+        case UA_NODECLASS_METHOD:
+            dstPtr = UA_malloc(sizeof(UA_MethodNode));
+            break;
+        case UA_NODECLASS_OBJECTTYPE:
+            dstPtr = UA_malloc(sizeof(UA_ObjectTypeNode));
+            break;
+        case UA_NODECLASS_VARIABLETYPE:
+            dstPtr = UA_malloc(sizeof(UA_VariableTypeNode));
+            break;
+        case UA_NODECLASS_REFERENCETYPE:
+            dstPtr = UA_malloc(sizeof(UA_ReferenceTypeNode));
+            break;
+        case UA_NODECLASS_DATATYPE:
+            dstPtr = UA_malloc(sizeof(UA_DataTypeNode));
+            break;
+        case UA_NODECLASS_VIEW:
+            dstPtr = UA_malloc(sizeof(UA_ViewNode));
+            break;
+        default:
+            return NULL;
+    }
+    UA_Node *dst = (UA_Node*)dstPtr;
+    dst->nodeClass = src->nodeClass;
+
+    UA_StatusCode retval = UA_Node_copy(src, dst);
+    if (retval != UA_STATUSCODE_GOOD){
+        UA_free(dst);
+        return NULL;
+    }
+    return dst;
 }
 /******************************/
 /* Copy Attributes into Nodes */

+ 16 - 25
src/server/ua_services_discovery_multicast.c

@@ -40,21 +40,7 @@
 # define errno__ errno
 #endif
 
-#ifdef __WIN32
-#define UA_LOG_ERROR_SOCKET(LOGGER, CATEGORY, DESCRIPTION) { \
-    char *s = NULL; \
-    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
-    NULL, WSAGetLastError(), \
-    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), \
-    (LPSTR)&s, 0, NULL); \
-    UA_LOG_ERROR(LOGGER, CATEGORY, DESCRIPTION, s); \
-    LocalFree(s); \
-}
-#else
-#define UA_LOG_ERROR_SOCKET(LOGGER, CATEGORY, DESCRIPTION) { \
-    UA_LOG_ERROR(LOGGER, CATEGORY, DESCRIPTION, strerror(errno)); \
-}
-#endif
+#include "ua_log_socket_error.h"
 
 #ifdef UA_ENABLE_MULTITHREADING
 
@@ -76,12 +62,14 @@ multicastWorkerLoop(UA_Server *server) {
             mdnsd_step(server->mdnsDaemon, server->mdnsSocket,
                        FD_ISSET(server->mdnsSocket, &fds), true, &next_sleep);
         if (retVal == 1) {
-            UA_LOG_ERROR_SOCKET(server->config.logger, UA_LOGCATEGORY_SERVER,
-                         "Multicast error: Can not read from socket. %s");
+            UA_LOG_SOCKET_ERRNO_WRAP(
+                UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                          "Multicast error: Can not read from socket. %s", errno_str));
             break;
         } else if (retVal == 2) {
-            UA_LOG_ERROR_SOCKET(server->config.logger, UA_LOGCATEGORY_SERVER,
-                         "Multicast error: Can not write to socket. %s");
+            UA_LOG_SOCKET_ERRNO_WRAP(
+                UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                         "Multicast error: Can not write to socket. %s", errno_str));
             break;
         }
     }
@@ -342,8 +330,9 @@ initMulticastDiscoveryServer(UA_Server* server) {
 #endif
 
     if((server->mdnsSocket = discovery_createMulticastSocket()) == 0) {
-        UA_LOG_ERROR_SOCKET(server->config.logger, UA_LOGCATEGORY_SERVER,
-                     "Could not create multicast socket. Error: %s");
+        UA_LOG_SOCKET_ERRNO_WRAP(
+                UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                     "Could not create multicast socket. Error: %s", errno_str));
         return UA_STATUSCODE_BADUNEXPECTEDERROR;
     }
     mdnsd_register_receive_callback(server->mdnsDaemon,
@@ -603,12 +592,14 @@ iterateMulticastDiscoveryServer(UA_Server* server, UA_DateTime *nextRepeat,
     unsigned short retval = mdnsd_step(server->mdnsDaemon, server->mdnsSocket,
                                        processIn, true, &next_sleep);
     if(retval == 1) {
-        UA_LOG_ERROR_SOCKET(server->config.logger, UA_LOGCATEGORY_SERVER,
-                     "Multicast error: Can not read from socket. %s");
+        UA_LOG_SOCKET_ERRNO_WRAP(
+                UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                     "Multicast error: Can not read from socket. %s", errno_str));
         return UA_STATUSCODE_BADNOCOMMUNICATION;
     } else if(retval == 2) {
-        UA_LOG_ERROR_SOCKET(server->config.logger, UA_LOGCATEGORY_SERVER,
-                     "Multicast error: Can not write to socket. %s");
+        UA_LOG_SOCKET_ERRNO_WRAP(
+                UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                     "Multicast error: Can not write to socket. %s", errno_str));
         return UA_STATUSCODE_BADNOCOMMUNICATION;
     }
 

+ 12 - 12
src/server/ua_services_nodemanagement.c

@@ -649,9 +649,9 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
             referenceTypeId = &hasSubtype;
         const UA_Node *parentNode = UA_Nodestore_get(server, parentNodeId);
         if (parentNode) {
-			if (parentNode->nodeClass == node->nodeClass)
-				typeDefinitionId = parentNodeId;
-			UA_Nodestore_release(server, parentNode);
+            if (parentNode->nodeClass == node->nodeClass)
+                typeDefinitionId = parentNodeId;
+            UA_Nodestore_release(server, parentNode);
         }
     }
 
@@ -794,15 +794,15 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
        node->nodeClass == UA_NODECLASS_OBJECT) {
         UA_assert(type != NULL); /* see above */
         /* Add (mandatory) child nodes from the type definition */
-		if (!server->bootstrapNS0) {
-			retval = addChildren(server, session, node, type);
-			if(retval != UA_STATUSCODE_GOOD) {
-				UA_LOG_INFO_SESSION(server->config.logger, session,
-									"AddNodes: Adding child nodes failed with error code %s",
-									UA_StatusCode_name(retval));
-				goto cleanup;
-			}
-		}
+        if (!server->bootstrapNS0) {
+            retval = addChildren(server, session, node, type);
+            if(retval != UA_STATUSCODE_GOOD) {
+                UA_LOG_INFO_SESSION(server->config.logger, session,
+                                    "AddNodes: Adding child nodes failed with error code %s",
+                                    UA_StatusCode_name(retval));
+                goto cleanup;
+            }
+        }
 
         /* Add a hasTypeDefinition reference */
         retval = addTypeDefRef(server, session, node, type);

+ 9 - 1
tests/CMakeLists.txt

@@ -21,7 +21,11 @@ if(UA_ENABLE_VALGRIND_UNIT_TESTS)
     find_package(Valgrind REQUIRED)
 endif()
 
-set(LIBS subunit ${CHECK_LIBRARIES} ${open62541_LIBRARIES})
+set(LIBS ${CHECK_LIBRARIES} ${open62541_LIBRARIES})
+if(NOT MSVC)
+    LIST(APPEND LIBS subunit)
+endif()
+include_directories(${CHECK_INCLUDE_DIRS})
 
 # Use different plugins for testing
 set(test_plugin_sources ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.c
@@ -35,6 +39,8 @@ set(test_plugin_sources ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.c
 
 add_library(open62541-testplugins OBJECT ${test_plugin_sources})
 add_dependencies(open62541-testplugins open62541)
+target_compile_definitions(open62541-testplugins PRIVATE -DUA_DYNAMIC_LINKING_EXPORT)
+
 
 # Workaround some clang warnings in the uni tests
 if((NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") AND (CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang"))
@@ -53,6 +59,8 @@ macro(add_test_valgrind TEST_NAME)
     endif()
 endmacro()
 
+add_custom_target(test-verbose COMMAND ${CMAKE_CTEST_COMMAND} --verbose)
+
 # the unit test are built directly on the open62541 object files. so they can
 # access symbols that are hidden/not exported to the shared library
 

+ 5 - 1
tests/check_types_builtin.c

@@ -804,12 +804,16 @@ START_TEST(UA_Float_encodeShallWorkOnExample) {
         {0x00, 0x00, 0xD0, 0xC0}, // -6.5
         {0x00, 0x00, 0x00, 0x00}, // 0.0
         {0x00, 0x00, 0x00, 0x80}, // -0.0
-        {0x00, 0x00, 0xC0, 0xFF}, // NAN
+        {0x00, 0x00, 0xC0, 0xFF}, // -NAN
         {0xFF, 0xFF, 0x7F, 0x7F}, // FLT_MAX
         {0x00, 0x00, 0x80, 0x00}, // FLT_MIN
         {0x00, 0x00, 0x80, 0x7F}, // INF
         {0x00, 0x00, 0x80, 0xFF} // -INF
     };
+#ifdef _WIN32
+    // on WIN32 -NAN is encoded differently
+    result[4][3] = 127;
+#endif
 
     UA_Byte data[] = {0x55, 0x55, 0x55,  0x55};
     UA_ByteString dst = {4, data};

+ 6 - 6
tests/client/check_client.c

@@ -4,7 +4,6 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <pthread.h>
 
 #include "ua_types.h"
 #include "ua_server.h"
@@ -14,12 +13,13 @@
 #include "ua_network_tcp.h"
 #include "testing_clock.h"
 #include "check.h"
+#include "thread_wrapper.h"
 
 UA_Server *server;
 UA_ServerConfig *config;
 UA_Boolean *running;
 UA_ServerNetworkLayer nl;
-pthread_t server_thread;
+THREAD_HANDLE server_thread;
 
 static void
 addVariable(size_t size) {
@@ -47,10 +47,10 @@ addVariable(size_t size) {
     UA_free(array);
 }
 
-static void * serverloop(void *_) {
+THREAD_CALLBACK(serverloop) {
     while(*running)
         UA_Server_run_iterate(server, true);
-    return NULL;
+    return 0;
 }
 
 static void setup(void) {
@@ -60,12 +60,12 @@ static void setup(void) {
     server = UA_Server_new(config);
     UA_Server_run_startup(server);
     addVariable(16366);
-    pthread_create(&server_thread, NULL, serverloop, NULL);
+    THREAD_CREATE(server_thread, serverloop);
 }
 
 static void teardown(void) {
     *running = false;
-    pthread_join(server_thread, NULL);
+    THREAD_JOIN(server_thread);
     UA_Server_run_shutdown(server);
     UA_Boolean_delete(running);
     UA_Server_delete(server);

+ 10 - 6
tests/client/check_client_async.c

@@ -4,8 +4,10 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <pthread.h>
+
+#ifndef WIN32
 #include <unistd.h>
+#endif
 
 #include "ua_types.h"
 #include "ua_server.h"
@@ -15,16 +17,18 @@
 #include "check.h"
 #include "testing_clock.h"
 
+#include "thread_wrapper.h"
+
 UA_Server *server;
 UA_ServerConfig *config;
 UA_Boolean running;
 UA_ServerNetworkLayer nl;
-pthread_t server_thread;
+THREAD_HANDLE server_thread;
 
-static void * serverloop(void *_) {
+THREAD_CALLBACK(serverloop) {
     while(running)
         UA_Server_run_iterate(server, true);
-    return NULL;
+    return 0;
 }
 
 static void setup(void) {
@@ -32,12 +36,12 @@ static void setup(void) {
     config = UA_ServerConfig_new_default();
     server = UA_Server_new(config);
     UA_Server_run_startup(server);
-    pthread_create(&server_thread, NULL, serverloop, NULL);
+    THREAD_CREATE(server_thread, serverloop);
 }
 
 static void teardown(void) {
     running = false;
-    pthread_join(server_thread, NULL);
+    THREAD_JOIN(server_thread);
     UA_Server_run_shutdown(server);
     UA_Server_delete(server);
     UA_ServerConfig_delete(config);

+ 6 - 7
tests/client/check_client_highlevel.c

@@ -4,8 +4,6 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <pthread.h>
-#include <ua_types.h>
 
 #include "ua_server.h"
 #include "ua_client.h"
@@ -13,22 +11,23 @@
 #include "ua_client_highlevel.h"
 #include "ua_network_tcp.h"
 #include "check.h"
+#include "thread_wrapper.h"
 
 UA_Server *server;
 UA_ServerConfig *config;
 UA_Boolean running;
 UA_ServerNetworkLayer nl;
-pthread_t server_thread;
+THREAD_HANDLE server_thread;
 
 UA_Client *client;
 
 #define CUSTOM_NS "http://open62541.org/ns/test"
 #define CUSTOM_NS_UPPER "http://open62541.org/ns/Test"
 
-static void *serverloop(void *_) {
+THREAD_CALLBACK(serverloop) {
     while (running)
         UA_Server_run_iterate(server, true);
-    return NULL;
+    return 0;
 }
 
 static void setup(void) {
@@ -39,7 +38,7 @@ static void setup(void) {
     ck_assert_uint_eq(2, UA_Server_addNamespace(server, CUSTOM_NS));
 
     UA_Server_run_startup(server);
-    pthread_create(&server_thread, NULL, serverloop, NULL);
+    THREAD_CREATE(server_thread, serverloop);
 
     client = UA_Client_new(UA_ClientConfig_default);
     UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
@@ -50,7 +49,7 @@ static void teardown(void) {
     UA_Client_disconnect(client);
     UA_Client_delete(client);
     running = false;
-    pthread_join(server_thread, NULL);
+    THREAD_JOIN(server_thread);
     UA_Server_run_shutdown(server);
     UA_Server_delete(server);
     UA_ServerConfig_delete(config);

+ 6 - 6
tests/client/check_client_securechannel.c

@@ -2,7 +2,6 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include <pthread.h>
 
 #include "ua_types.h"
 #include "ua_server.h"
@@ -12,16 +11,17 @@
 #include "ua_network_tcp.h"
 #include "testing_clock.h"
 #include "check.h"
+#include "thread_wrapper.h"
 
 UA_Server *server;
 UA_ServerConfig *config;
 UA_Boolean *running;
-pthread_t server_thread;
+THREAD_HANDLE server_thread;
 
-static void * serverloop(void *_) {
+THREAD_CALLBACK(serverloop) {
     while(*running)
         UA_Server_run_iterate(server, true);
-    return NULL;
+    return 0;
 }
 
 static void setup(void) {
@@ -30,13 +30,13 @@ static void setup(void) {
     config = UA_ServerConfig_new_default();
     server = UA_Server_new(config);
     UA_Server_run_startup(server);
-    pthread_create(&server_thread, NULL, serverloop, NULL);
+    THREAD_CREATE(server_thread, serverloop);
     UA_realSleep(100);
 }
 
 static void teardown(void) {
     *running = false;
-    pthread_join(server_thread, NULL);
+    THREAD_JOIN(server_thread);
     UA_Server_run_shutdown(server);
     UA_Boolean_delete(running);
     UA_Server_delete(server);

+ 7 - 7
tests/client/check_client_subscriptions.c

@@ -4,8 +4,6 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <pthread.h>
-
 #include "ua_types.h"
 #include "ua_server.h"
 #include "ua_client.h"
@@ -15,17 +13,19 @@
 
 #include "check.h"
 #include "testing_clock.h"
+#include "thread_wrapper.h"
+
 
 UA_Server *server;
 UA_ServerConfig *config;
 UA_Boolean *running;
 UA_ServerNetworkLayer nl;
-pthread_t server_thread;
+THREAD_HANDLE server_thread;
 
-static void * serverloop(void *_) {
+THREAD_CALLBACK(serverloop) {
     while(*running)
         UA_Server_run_iterate(server, true);
-    return NULL;
+    return 0;
 }
 
 static void setup(void) {
@@ -34,12 +34,12 @@ static void setup(void) {
     config = UA_ServerConfig_new_default();
     server = UA_Server_new(config);
     UA_Server_run_startup(server);
-    pthread_create(&server_thread, NULL, serverloop, NULL);
+    THREAD_CREATE(server_thread, serverloop);
 }
 
 static void teardown(void) {
     *running = false;
-    pthread_join(server_thread, NULL);
+    THREAD_JOIN(server_thread);
     UA_Server_run_shutdown(server);
     UA_Boolean_delete(running);
     UA_Server_delete(server);

+ 7 - 6
tests/server/check_accesscontrol.c

@@ -3,7 +3,6 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdlib.h>
-#include <pthread.h>
 
 #include "ua_types.h"
 #include "ua_server.h"
@@ -11,16 +10,18 @@
 #include "ua_config_default.h"
 #include "check.h"
 
+#include "thread_wrapper.h"
+
 UA_Server *server;
 UA_ServerConfig *config;
 UA_Boolean *running;
 UA_ServerNetworkLayer nl;
-pthread_t server_thread;
+THREAD_HANDLE server_thread;
 
-static void * serverloop(void *_) {
+THREAD_CALLBACK(serverloop) {
     while(*running)
         UA_Server_run_iterate(server, true);
-    return NULL;
+    return 0;
 }
 
 static void setup(void) {
@@ -29,12 +30,12 @@ static void setup(void) {
     config = UA_ServerConfig_new_default();
     server = UA_Server_new(config);
     UA_Server_run_startup(server);
-    pthread_create(&server_thread, NULL, serverloop, NULL);
+    THREAD_CREATE(server_thread, serverloop);
 }
 
 static void teardown(void) {
     *running = false;
-    pthread_join(server_thread, NULL);
+    THREAD_JOIN(server_thread);
     UA_Server_run_shutdown(server);
     UA_Boolean_delete(running);
     UA_Server_delete(server);

+ 30 - 15
tests/server/check_discovery.c

@@ -16,16 +16,18 @@
 #endif
 
 #include <stdio.h>
-#include <unistd.h>
-#include <pthread.h>
 #include <fcntl.h>
 #include <check.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
 
 #include "server/ua_server_internal.h"
 #include "ua_client.h"
 #include "ua_config_default.h"
 #include "ua_network_tcp.h"
 #include "testing_clock.h"
+#include "thread_wrapper.h"
 
 // set register timeout to 1 second so we are able to test it.
 #define registerTimeout 1
@@ -35,12 +37,12 @@
 UA_Server *server_lds;
 UA_ServerConfig *config_lds;
 UA_Boolean *running_lds;
-pthread_t server_thread_lds;
+THREAD_HANDLE server_thread_lds;
 
-static void * serverloop_lds(void *_) {
+THREAD_CALLBACK(serverloop_lds) {
     while(*running_lds)
         UA_Server_run_iterate(server_lds, true);
-    return NULL;
+    return 0;
 }
 
 static void setup_lds(void) {
@@ -63,7 +65,7 @@ static void setup_lds(void) {
     config_lds->discoveryCleanupTimeout = registerTimeout;
     server_lds = UA_Server_new(config_lds);
     UA_Server_run_startup(server_lds);
-    pthread_create(&server_thread_lds, NULL, serverloop_lds, NULL);
+    THREAD_CREATE(server_thread_lds, serverloop_lds);
 
     // wait until LDS started
     UA_fakeSleep(1000);
@@ -72,7 +74,7 @@ static void setup_lds(void) {
 
 static void teardown_lds(void) {
     *running_lds = false;
-    pthread_join(server_thread_lds, NULL);
+    THREAD_JOIN(server_thread_lds);
     UA_Server_run_shutdown(server_lds);
     UA_Boolean_delete(running_lds);
     UA_Server_delete(server_lds);
@@ -82,14 +84,14 @@ static void teardown_lds(void) {
 UA_Server *server_register;
 UA_ServerConfig *config_register;
 UA_Boolean *running_register;
-pthread_t server_thread_register;
+THREAD_HANDLE server_thread_register;
 
 UA_UInt64 periodicRegisterCallbackId;
 
-static void * serverloop_register(void *_) {
+THREAD_CALLBACK(serverloop_register) {
     while(*running_register)
         UA_Server_run_iterate(server_register, true);
-    return NULL;
+    return 0;
 }
 
 static void setup_register(void) {
@@ -106,12 +108,12 @@ static void setup_register(void) {
     config_register->mdnsServerName = UA_String_fromChars("Register_test");
     server_register = UA_Server_new(config_register);
     UA_Server_run_startup(server_register);
-    pthread_create(&server_thread_register, NULL, serverloop_register, NULL);
+    THREAD_CREATE(server_thread_register, serverloop_register);
 }
 
 static void teardown_register(void) {
     *running_register = false;
-    pthread_join(server_thread_register, NULL);
+    THREAD_JOIN(server_thread_register);
     UA_Server_run_shutdown(server_register);
     UA_Boolean_delete(running_register);
     UA_Server_delete(server_register);
@@ -132,22 +134,35 @@ START_TEST(Server_unregister) {
 }
 END_TEST
 
+#ifndef WIN32
+#define SEMAPHORE_PATH "/tmp/open62541-unit-test-semaphore"
+#else
+#define SEMAPHORE_PATH ".\\open62541-unit-test-semaphore"
+#endif
+
 START_TEST(Server_register_semaphore) {
     // create the semaphore
-    int fd = open("/tmp/open62541-unit-test-semaphore", O_RDWR|O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
+#ifndef WIN32
+    int fd = open(SEMAPHORE_PATH, O_RDWR|O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
     ck_assert_int_ne(fd, -1);
     close(fd);
+#else
+    FILE *fp;
+    fopen_s(&fp, SEMAPHORE_PATH, "ab+");
+    ck_assert_ptr_ne(fp, NULL);
+    fclose(fp);
+#endif
 
     UA_StatusCode retval =
         UA_Server_register_discovery(server_register, "opc.tcp://localhost:4840",
-                                     "/tmp/open62541-unit-test-semaphore");
+                                     SEMAPHORE_PATH);
     ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
 }
 END_TEST
 
 START_TEST(Server_unregister_semaphore) {
     // delete the semaphore, this should remove the registration automatically on next check
-    ck_assert_int_eq(remove("/tmp/open62541-unit-test-semaphore"), 0);
+    ck_assert_int_eq(remove(SEMAPHORE_PATH), 0);
 }
 END_TEST
 

+ 6 - 1
tests/server/check_server_binary_messages.c

@@ -18,7 +18,12 @@ char **filenames;
 static UA_ByteString readFile(char *filename) {
     UA_ByteString buf = UA_BYTESTRING_NULL;
     size_t length;
-    FILE *f = fopen(filename,"r");
+    FILE *f = NULL;
+#ifdef WIN32
+    fopen_s(&f, filename,"r");
+#else
+    f = fopen(filename,"r");
+#endif
 
     if(f) {
         fseek(f, 0, SEEK_END);

+ 6 - 6
tests/server/check_services_view.c

@@ -4,23 +4,23 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <pthread.h>
 #include <server/ua_server_internal.h>
 
 #include "check.h"
 #include "ua_server.h"
 #include "ua_config_default.h"
 #include "ua_network_tcp.h"
+#include "thread_wrapper.h"
 
 UA_Server *server_translate_browse;
 UA_ServerConfig *server_translate_config;
 UA_Boolean *running_translate_browse;
-pthread_t server_thread_translate_browse;
+THREAD_HANDLE server_thread_translate_browse;
 
-static void *serverloop_register(void *_) {
+THREAD_CALLBACK(serverloop_register) {
     while (*running_translate_browse)
         UA_Server_run_iterate(server_translate_browse, true);
-    return NULL;
+    return 0;
 }
 
 static void setup_server(void) {
@@ -33,12 +33,12 @@ static void setup_server(void) {
         UA_String_fromChars("urn:open62541.test.server_translate_browse");
     server_translate_browse = UA_Server_new(server_translate_config);
     UA_Server_run_startup(server_translate_browse);
-    pthread_create(&server_thread_translate_browse, NULL, serverloop_register, NULL);
+    THREAD_CREATE(server_thread_translate_browse, serverloop_register);
 }
 
 static void teardown_server(void) {
     *running_translate_browse = false;
-    pthread_join(server_thread_translate_browse, NULL);
+    THREAD_JOIN(server_thread_translate_browse);
     UA_Server_run_shutdown(server_translate_browse);
     UA_Boolean_delete(running_translate_browse);
     UA_Server_delete(server_translate_browse);

+ 13 - 0
tests/testing-plugins/testing_clock.c

@@ -18,6 +18,10 @@
 #include <time.h>
 #include "testing_clock.h"
 
+#ifdef _WIN32
+#include <windows.h>	/* WinAPI */
+#endif
+
 UA_DateTime testingClock = 0;
 
 UA_DateTime UA_DateTime_now(void) {
@@ -36,6 +40,14 @@ UA_fakeSleep(UA_UInt32 duration) {
 /* 1 millisecond = 1,000,000 Nanoseconds */
 #define NANO_SECOND_MULTIPLIER 1000000
 
+#ifdef _WIN32
+
+void
+UA_realSleep(UA_UInt32 duration) {
+    Sleep(duration);
+}
+
+#else
 void
 UA_realSleep(UA_UInt32 duration) {
     UA_UInt32 sec = duration / 1000;
@@ -45,3 +57,4 @@ UA_realSleep(UA_UInt32 duration) {
     sleepValue.tv_nsec = ns;
     nanosleep(&sleepValue, NULL);
 }
+#endif

+ 25 - 0
tests/testing-plugins/thread_wrapper.h

@@ -0,0 +1,25 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Simple wrapper for unit test threads */
+
+
+#ifndef WIN32
+#include <pthread.h>
+#define THREAD_HANDLE pthread_t
+#define THREAD_CREATE(handle, callback) pthread_create(&handle, NULL, callback, NULL)
+#define THREAD_JOIN(handle) pthread_join(handle, NULL)
+#define THREAD_CALLBACK(name) static void * name(void *_)
+
+#else
+
+#include <windows.h>
+#define THREAD_HANDLE HANDLE
+#define THREAD_CREATE(handle, callback) { handle = CreateThread( NULL, 0, callback, NULL, 0, NULL); }
+#define THREAD_JOIN(handle) WaitForSingleObject(handle, INFINITE)
+
+
+#define THREAD_CALLBACK(name) DWORD WINAPI name( LPVOID lpParam )
+
+#endif

+ 15 - 5
tools/cmake/FindCheck.cmake

@@ -21,11 +21,13 @@ ELSE( Check_FIND_REQUIRED )
 	SET( _pkgconfig_REQUIRED "" )	
 ENDIF ( Check_FIND_REQUIRED )
 
-IF ( CHECK_MIN_VERSION )
-	PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check>=${CHECK_MIN_VERSION} )
-ELSE ( CHECK_MIN_VERSION )
-	PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check )
-ENDIF ( CHECK_MIN_VERSION )
+if(NOT MSVC)
+	IF ( CHECK_MIN_VERSION )
+		PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check>=${CHECK_MIN_VERSION} )
+	ELSE ( CHECK_MIN_VERSION )
+		PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check )
+	ENDIF ( CHECK_MIN_VERSION )
+endif()
 
 # Look for CHECK include dir and libraries
 IF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND )
@@ -34,7 +36,15 @@ IF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND )
 
 	FIND_LIBRARY( CHECK_LIBRARIES NAMES check )
 
+	if (MSVC)
+		FIND_LIBRARY( CHECK_COMPAT_LIBRARIES NAMES compat )
+	endif()
+
+
 	IF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
+		if ( CHECK_COMPAT_LIBRARIES )
+			LIST(APPEND CHECK_LIBRARIES "${CHECK_COMPAT_LIBRARIES}")
+		endif()
 		SET( CHECK_FOUND 1 )
 		IF ( NOT Check_FIND_QUIETLY )
 			MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" )