Sfoglia il codice sorgente

Add unit test for windows

Stefan Profanter 7 anni fa
parent
commit
3619afb6bd

+ 3 - 1
CMakeLists.txt

@@ -540,7 +540,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

+ 1 - 1
deps/mdnsd

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

+ 22 - 0
include/ua_plugin_log.h

@@ -114,6 +114,28 @@ 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 _WIN32
+#include <windows.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(s); \
+}
+
+#else
+#define UA_LOG_SOCKET_ERRNO_WRAP(LOG) { \
+    char *errno_str = strerror(errno); \
+    LOG; \
+}
+#endif
+
+
 #ifdef __cplusplus
 } // extern "C"
 #endif

+ 29 - 18
plugins/ua_network_tcp.c

@@ -290,9 +290,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 +308,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 +383,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 +504,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 +741,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 +766,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] = ',';
         }

+ 9 - 22
src/server/ua_services_discovery_multicast.c

@@ -40,22 +40,6 @@
 # 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
-
 #ifdef UA_ENABLE_MULTITHREADING
 
 static void *
@@ -342,8 +326,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 +588,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;
     }
 

+ 7 - 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"))

+ 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}" )