Ver código fonte

fix select test timing

StalderT 7 anos atrás
pai
commit
6941fe4708

+ 1 - 4
src/client/ua_client.c

@@ -289,10 +289,7 @@ receiveServiceResponse(UA_Client *client, void *response, const UA_DataType *res
         retval = UA_Connection_receiveChunksBlocking(&client->connection, &rd,
                                                      client_processChunk, timeout);
 
-        if (retval == UA_STATUSCODE_GOODNONCRITICALTIMEOUT)
-            break;
-
-        if(retval != UA_STATUSCODE_GOOD) {
+        if(retval != UA_STATUSCODE_GOOD && retval != UA_STATUSCODE_GOODNONCRITICALTIMEOUT) {
             if(retval == UA_STATUSCODE_BADCONNECTIONCLOSED)
                 client->state = UA_CLIENTSTATE_DISCONNECTED;
             else

+ 41 - 13
tests/client/check_client_securechannel.c

@@ -10,6 +10,7 @@
 #include "ua_client_highlevel.h"
 #include "ua_network_tcp.h"
 #include "testing_clock.h"
+#include "testing_networklayers.h"
 #include "check.h"
 #include "thread_wrapper.h"
 
@@ -84,11 +85,6 @@ START_TEST(SecureChannel_timeout_fail) {
 }
 END_TEST
 
-static void
-read_cb(UA_Client *client, void *userdata,
-        UA_UInt32 requestId, const void *response) {
-}
-
 /* Send an async message and receive the response when the securechannel timed out */
 START_TEST(SecureChannel_networkfail) {
     UA_Client *client = UA_Client_new(UA_ClientConfig_default);
@@ -104,15 +100,16 @@ START_TEST(SecureChannel_networkfail) {
     rq.nodesToRead = &rvi;
     rq.nodesToReadSize = 1;
 
-    UA_UInt32 rqId;
-    __UA_Client_AsyncService(client, &rq, &UA_TYPES[UA_TYPES_READREQUEST],
-                             read_cb, &UA_TYPES[UA_TYPES_READRESPONSE], NULL, &rqId);
-
-    UA_fakeSleep(UA_ClientConfig_default.secureChannelLifeTime+1);
-    UA_realSleep(100); // UA_MAXTIMEOUT+1 wait to be sure UA_Server_run_iterate can be completely executed
+    /* Forward the clock after recv in the client */
+    UA_Client_recv = client->connection.recv;
+    client->connection.recv = UA_Client_recvTesting;
+    UA_Client_recvSleepDuration = UA_ClientConfig_default.secureChannelLifeTime+1;
 
-    retval = UA_Client_runAsync(client, 50);
-    ck_assert_msg(retval != UA_STATUSCODE_GOOD, UA_StatusCode_name(retval));
+    UA_Variant val;
+    UA_Variant_init(&val);
+    UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE);
+    retval = UA_Client_readValueAttribute(client, nodeId, &val);
+    ck_assert_msg(retval == UA_STATUSCODE_BADSECURECHANNELCLOSED);
 
     UA_Client_disconnect(client);
     UA_Client_delete(client);
@@ -139,6 +136,36 @@ START_TEST(SecureChannel_reconnect) {
 }
 END_TEST
 
+START_TEST(SecureChannel_cableunplugged) {
+    UA_Client *client = UA_Client_new(UA_ClientConfig_default);
+    UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+    UA_Variant val;
+    UA_Variant_init(&val);
+    UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE);
+    retval = UA_Client_readValueAttribute(client, nodeId, &val);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+    UA_Variant_deleteMembers(&val);
+
+    UA_Client_recv = client->connection.recv;
+    client->connection.recv = UA_Client_recvTesting;
+
+    /* Simulate network cable unplugged (no response from server) */
+    UA_Client_recvTesting_result = UA_STATUSCODE_GOODNONCRITICALTIMEOUT;
+
+    UA_Variant_init(&val);
+    retval = UA_Client_readValueAttribute(client, nodeId, &val);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_BADCONNECTIONCLOSED);
+
+    ck_assert_msg(UA_Client_getState(client) == UA_CLIENTSTATE_DISCONNECTED);
+
+    UA_Client_recvTesting_result = UA_STATUSCODE_GOOD;
+
+    UA_Client_delete(client);
+}
+END_TEST
+
 int main(void) {
     TCase *tc_sc = tcase_create("Client SecureChannel");
     tcase_add_checked_fixture(tc_sc, setup, teardown);
@@ -146,6 +173,7 @@ int main(void) {
     tcase_add_test(tc_sc, SecureChannel_timeout_fail);
     tcase_add_test(tc_sc, SecureChannel_networkfail);
     tcase_add_test(tc_sc, SecureChannel_reconnect);
+    tcase_add_test(tc_sc, SecureChannel_cableunplugged);
 
     Suite *s = suite_create("Client");
     suite_add_tcase(s, tc_sc);

+ 4 - 0
tests/testing-plugins/testing_clock.h

@@ -7,6 +7,10 @@
 
 #include "ua_types.h"
 
+/**
+ * Simulate the system clock
+ * ------------------------- */
+
 /* The testing clock is used for reproducible unit tests that require precise
  * timings. It implements the following functions from ua_types.h. They return a
  * deterministic time that can be advanced manually with UA_sleep.

+ 27 - 0
tests/testing-plugins/testing_networklayers.c

@@ -5,10 +5,13 @@
 #include <stdlib.h>
 #include <assert.h>
 #include "testing_networklayers.h"
+#include "testing_clock.h"
 #include "ua_config_default.h"
 
 UA_ByteString *vBuffer;
 
+UA_StatusCode UA_Client_recvTesting_result = UA_STATUSCODE_GOOD;
+
 static UA_StatusCode
 dummyGetSendBuffer(UA_Connection *connection, size_t length, UA_ByteString *buf) {
     buf->data = (length == 0) ? NULL : (UA_Byte*)UA_malloc(length);
@@ -61,3 +64,27 @@ UA_Connection createDummyConnection(UA_ByteString *verificationBuffer) {
     c.close = dummyClose;
     return c;
 }
+
+UA_UInt32 UA_Client_recvSleepDuration;
+UA_StatusCode (*UA_Client_recv)(UA_Connection *connection, UA_ByteString *response,
+                                UA_UInt32 timeout);
+
+UA_StatusCode
+UA_Client_recvTesting(UA_Connection *connection, UA_ByteString *response,
+                    UA_UInt32 timeout) {
+
+    if(UA_Client_recvTesting_result != UA_STATUSCODE_GOOD) {
+        UA_StatusCode temp = UA_Client_recvTesting_result;
+        UA_Client_recvTesting_result = UA_STATUSCODE_GOOD;
+        UA_fakeSleep(timeout);
+        return temp;
+    }
+
+    UA_StatusCode res = UA_Client_recv(connection, response, timeout);
+    if(res == UA_STATUSCODE_GOODNONCRITICALTIMEOUT)
+        UA_fakeSleep(timeout);
+    else
+        UA_fakeSleep(UA_Client_recvSleepDuration);
+    UA_Client_recvSleepDuration = 0;
+    return res;
+}

+ 17 - 0
tests/testing-plugins/testing_networklayers.h

@@ -18,6 +18,23 @@ extern "C" {
  */
 UA_Connection createDummyConnection(UA_ByteString *verificationBuffer);
 
+/**
+ * Simulate network timing conditions
+ * ---------------------------------- */
+
+extern UA_UInt32 UA_Client_recvSleepDuration;
+extern UA_StatusCode (*UA_Client_recv)(UA_Connection *connection, UA_ByteString *response,
+                                       UA_UInt32 timeout);
+
+extern UA_StatusCode UA_Client_recvTesting_result;
+
+/* Override the client recv method to increase the simulated clock after the first recv.
+ * UA_Client_recvSleepDuration is set to zero after the first recv.
+ * UA_Client_recvTesting_result can be used to simulate an error */
+UA_StatusCode
+UA_Client_recvTesting(UA_Connection *connection, UA_ByteString *response,
+                    UA_UInt32 timeout);
+
 #ifdef __cplusplus
 }
 #endif