summaryrefslogtreecommitdiffstats
path: root/pceplib/test/pcep_session_logic_states_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'pceplib/test/pcep_session_logic_states_test.c')
-rw-r--r--pceplib/test/pcep_session_logic_states_test.c933
1 files changed, 933 insertions, 0 deletions
diff --git a/pceplib/test/pcep_session_logic_states_test.c b/pceplib/test/pcep_session_logic_states_test.c
new file mode 100644
index 0000000..17ddae6
--- /dev/null
+++ b/pceplib/test/pcep_session_logic_states_test.c
@@ -0,0 +1,933 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_socket_comm_mock.h"
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_timers.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_memory.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tools.h"
+#include "pcep_session_logic_states_test.h"
+
+/* Functions being tested */
+extern pcep_session_logic_handle *session_logic_handle_;
+extern pcep_event_queue *session_logic_event_queue_;
+
+static pcep_session_event event;
+static pcep_session session;
+/* A message list is a dll of struct pcep_messages_list_node items */
+static double_linked_list *msg_list;
+struct pcep_message *message;
+static bool free_msg_list;
+static bool msg_enqueued;
+/* Forward declaration */
+void destroy_message_for_test(void);
+void create_message_for_test(uint8_t msg_type, bool free_msg_list_at_teardown,
+ bool was_msg_enqueued);
+void test_handle_timer_event_open_keep_alive(void);
+
+/*
+ * Test suite setup and teardown called before AND after the test suite.
+ */
+
+int pcep_session_logic_states_test_suite_setup(void)
+{
+ pceplib_memory_reset();
+ return 0;
+}
+
+int pcep_session_logic_states_test_suite_teardown(void)
+{
+ printf("\n");
+ pceplib_memory_dump();
+ return 0;
+}
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+
+void pcep_session_logic_states_test_setup()
+{
+ session_logic_handle_ = pceplib_malloc(
+ PCEPLIB_INFRA, sizeof(pcep_session_logic_handle));
+ memset(session_logic_handle_, 0, sizeof(pcep_session_logic_handle));
+
+ session_logic_event_queue_ =
+ pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event_queue));
+ memset(session_logic_event_queue_, 0, sizeof(pcep_event_queue));
+ session_logic_event_queue_->event_queue = queue_initialize();
+
+ memset(&session, 0, sizeof(pcep_session));
+ session.pcc_config.keep_alive_seconds = 5;
+ session.pcc_config.keep_alive_pce_negotiated_timer_seconds = 5;
+ session.pcc_config.min_keep_alive_seconds = 1;
+ session.pcc_config.max_keep_alive_seconds = 10;
+ session.pcc_config.dead_timer_seconds = 5;
+ session.pcc_config.dead_timer_pce_negotiated_seconds = 5;
+ session.pcc_config.min_dead_timer_seconds = 1;
+ session.pcc_config.max_dead_timer_seconds = 10;
+ session.pcc_config.max_unknown_messages = 2;
+ memcpy(&session.pce_config, &session.pcc_config,
+ sizeof(pcep_configuration));
+ session.num_unknown_messages_time_queue = queue_initialize();
+
+ memset(&event, 0, sizeof(pcep_session_event));
+ event.socket_closed = false;
+ event.session = &session;
+
+ setup_mock_socket_comm_info();
+ free_msg_list = false;
+ msg_enqueued = false;
+}
+
+
+void pcep_session_logic_states_test_teardown()
+{
+ destroy_message_for_test();
+ pceplib_free(PCEPLIB_INFRA, session_logic_handle_);
+ queue_destroy(session_logic_event_queue_->event_queue);
+ pceplib_free(PCEPLIB_INFRA, session_logic_event_queue_);
+ session_logic_handle_ = NULL;
+ session_logic_event_queue_ = NULL;
+ queue_destroy_with_data(session.num_unknown_messages_time_queue);
+ teardown_mock_socket_comm_info();
+}
+
+void create_message_for_test(uint8_t msg_type, bool free_msg_list_at_teardown,
+ bool was_msg_enqueued)
+{
+ /* See the comments in destroy_message_for_test() about these 2
+ * variables */
+ free_msg_list = free_msg_list_at_teardown;
+ msg_enqueued = was_msg_enqueued;
+
+ message = pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message));
+ memset(message, 0, sizeof(struct pcep_message));
+
+ message->msg_header = pceplib_malloc(
+ PCEPLIB_MESSAGES, sizeof(struct pcep_message_header));
+ memset(message->msg_header, 0, sizeof(struct pcep_message_header));
+ message->obj_list = dll_initialize();
+ message->msg_header->type = msg_type;
+
+ msg_list = dll_initialize();
+ dll_append(msg_list, message);
+ event.received_msg_list = msg_list;
+}
+
+void destroy_message_for_test()
+{
+ /* Some test cases internally free the message list, so we dont
+ * want to double free it */
+ if (free_msg_list == true) {
+ /* This will destroy both the msg_list and the obj_list */
+ pcep_msg_free_message_list(msg_list);
+ }
+
+ /* Some tests cause the message to be enqueued and dont delete it,
+ * so we have to delete it here */
+ if (msg_enqueued == true) {
+ pcep_msg_free_message(message);
+ }
+}
+
+/*
+ * Test cases
+ */
+
+void test_handle_timer_event_dead_timer()
+{
+ /* Dead Timer expired */
+ event.expired_timer_id = session.timer_id_dead_timer = 100;
+
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_dead_timer, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCE_DEAD_TIMER_EXPIRED, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+
+ /* verify_socket_comm_times_called(
+ * initialized, teardown, connect, send_message, close_after_write,
+ * close, destroy); */
+ verify_socket_comm_times_called(0, 0, 0, 1, 1, 0, 0);
+}
+
+
+void test_handle_timer_event_keep_alive()
+{
+ /* Keep Alive timer expired */
+ event.expired_timer_id = session.timer_id_keep_alive = 200;
+
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_keep_alive, TIMER_ID_NOT_SET);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+}
+
+
+void test_handle_timer_event_open_keep_wait()
+{
+ /* Open Keep Wait timer expired */
+ event.expired_timer_id = session.timer_id_open_keep_wait = 300;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 1, 0, 0);
+
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+
+ /* If the state is not SESSION_STATE_PCEP_CONNECTED, then nothing should
+ * happen */
+ reset_mock_socket_comm_info();
+ session.session_state = SESSION_STATE_UNKNOWN;
+ event.expired_timer_id = session.timer_id_open_keep_wait = 300;
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, 300);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_UNKNOWN);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+}
+
+
+void test_handle_timer_event_open_keep_alive()
+{
+ /* Open Keep Alive timer expired, but the Keep Alive should not be sent
+ * since the PCE Open has not been received yet */
+ event.expired_timer_id = session.timer_id_open_keep_alive = 300;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ session.pce_open_keep_alive_sent = false;
+ session.pce_open_received = false;
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_alive, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+
+ /* Open Keep Alive timer expired, the Keep Alive should be sent,
+ * but the session should not be connected, since the PCC Open
+ * has not been accepted yet */
+ event.expired_timer_id = session.timer_id_open_keep_alive = 300;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ session.pce_open_keep_alive_sent = false;
+ session.pce_open_received = true;
+ session.pce_open_rejected = false;
+ session.pcc_open_accepted = false;
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_alive, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ CU_ASSERT_TRUE(session.pce_open_keep_alive_sent);
+
+ /* Open Keep Alive timer expired, the Keep Alive should be sent,
+ * and the session is connected */
+ event.expired_timer_id = session.timer_id_open_keep_alive = 300;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ session.pce_open_keep_alive_sent = false;
+ session.pce_open_received = true;
+ session.pce_open_rejected = false;
+ session.pcc_open_accepted = true;
+ handle_timer_event(&event);
+
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_alive, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTED);
+ CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+}
+
+
+void test_handle_socket_comm_event_null_params()
+{
+ /* Verify it doesn't core dump */
+ handle_socket_comm_event(NULL);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ reset_mock_socket_comm_info();
+
+ event.received_msg_list = NULL;
+ handle_socket_comm_event(&event);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+}
+
+
+void test_handle_socket_comm_event_close()
+{
+ event.socket_closed = true;
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 1, 0);
+
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCE_CLOSED_SOCKET, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_open()
+{
+ /*
+ * Test when a PCE Open is received, but the PCC Open has not been
+ * accepted yet
+ */
+ create_message_for_test(PCEP_TYPE_OPEN, false, true);
+ struct pcep_object_open *open_object =
+ pcep_obj_create_open(1, 1, 1, NULL);
+ dll_append(message->obj_list, open_object);
+ session.pcc_open_accepted = false;
+ session.pce_open_received = false;
+ session.pce_open_accepted = false;
+ session.timer_id_open_keep_alive = 100;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pce_open_received);
+ CU_ASSERT_TRUE(session.pce_open_accepted);
+ CU_ASSERT_FALSE(session.pce_open_rejected);
+ CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ CU_ASSERT_NOT_EQUAL(session.timer_id_open_keep_alive, 100);
+ /* A keep alive response should NOT be sent yet */
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_OPEN, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ destroy_message_for_test();
+
+ /*
+ * Test when a PCE Open is received, and the PCC Open has been accepted
+ */
+ create_message_for_test(PCEP_TYPE_OPEN, false, true);
+ reset_mock_socket_comm_info();
+ open_object = pcep_obj_create_open(1, 1, 1, NULL);
+ dll_append(message->obj_list, open_object);
+ session.pcc_open_accepted = true;
+ session.pce_open_received = false;
+ session.pce_open_accepted = false;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pce_open_received);
+ CU_ASSERT_TRUE(session.pce_open_accepted);
+ CU_ASSERT_FALSE(session.pce_open_rejected);
+ CU_ASSERT_TRUE(session.pce_open_keep_alive_sent);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTED);
+ /* A keep alive response should be sent, accepting the Open */
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 2);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_OPEN, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_CONNECTED_TO_PCE, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ destroy_message_for_test();
+
+ /*
+ * Send a 2nd Open, an error should be sent
+ */
+ create_message_for_test(PCEP_TYPE_OPEN, false, false);
+ reset_mock_socket_comm_info();
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 0);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ /* What gets saved in the mock is the msg byte buffer. The msg struct
+ * was deleted when it was sent. Instead of inspecting the msg byte
+ * buffer, lets just decode it. */
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(msg);
+ assert(msg != NULL);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, msg->msg_header->type);
+ /* Verify the error object */
+ CU_ASSERT_EQUAL(1, msg->obj_list->num_entries);
+ struct pcep_object_error *error_obj = msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, error_obj->header.object_class);
+ CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, error_obj->header.object_type);
+ CU_ASSERT_EQUAL(PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION,
+ error_obj->error_type);
+ CU_ASSERT_EQUAL(PCEP_ERRV_RECVD_INVALID_OPEN_MSG,
+ error_obj->error_value);
+ pcep_msg_free_message(msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_handle_socket_comm_event_open_error()
+{
+ /* Test when the PCE rejects the PCC Open with an Error
+ * that a "corrected" Open message is sent. */
+
+ create_message_for_test(PCEP_TYPE_ERROR, false, true);
+ struct pcep_object_error *error_object = pcep_obj_create_error(
+ PCEP_ERRT_SESSION_FAILURE, PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG);
+ struct pcep_object_open *error_open_object =
+ pcep_obj_create_open(1, 1, 1, NULL);
+ /* The configured [Keep-alive, Dead-timer] values are [5, 5],
+ * this error open object will request they be changed to [10, 10] */
+ error_open_object->open_keepalive = 10;
+ error_open_object->open_deadtimer = 10;
+ dll_append(message->obj_list, error_object);
+ dll_append(message->obj_list, error_open_object);
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pcc_open_rejected);
+ CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ /* Another Open should be sent */
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 2);
+
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_SENT_INVALID_OPEN, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+
+ /* Check the Corrected Open Message */
+
+ /* What gets saved in the mock is the msg byte buffer. The msg struct
+ * was deleted when it was sent. Instead of inspecting the msg byte
+ * buffer, lets just decode it. */
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ assert(encoded_msg != NULL);
+ struct pcep_message *open_msg_corrected =
+ pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(open_msg_corrected);
+ struct pcep_object_open *open_object_corrected =
+ (struct pcep_object_open *)pcep_obj_get(
+ open_msg_corrected->obj_list, PCEP_OBJ_CLASS_OPEN);
+ CU_ASSERT_PTR_NOT_NULL(open_object_corrected);
+ assert(open_object_corrected != NULL);
+ /* Verify the Keep-alive and Dead timers have been negotiated */
+ CU_ASSERT_EQUAL(error_open_object->open_keepalive,
+ open_object_corrected->open_keepalive);
+ CU_ASSERT_EQUAL(error_open_object->open_deadtimer,
+ open_object_corrected->open_deadtimer);
+ CU_ASSERT_EQUAL(session.pcc_config.dead_timer_pce_negotiated_seconds,
+ open_object_corrected->open_deadtimer);
+ CU_ASSERT_EQUAL(
+ session.pcc_config.keep_alive_pce_negotiated_timer_seconds,
+ open_object_corrected->open_keepalive);
+ CU_ASSERT_NOT_EQUAL(
+ session.pcc_config.dead_timer_pce_negotiated_seconds,
+ session.pcc_config.dead_timer_seconds);
+ CU_ASSERT_NOT_EQUAL(
+ session.pcc_config.keep_alive_pce_negotiated_timer_seconds,
+ session.pcc_config.keep_alive_seconds);
+
+ pcep_msg_free_message(open_msg_corrected);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_handle_socket_comm_event_keep_alive()
+{
+ /* Test when a Keep Alive is received, but the PCE Open has not been
+ * received yet */
+ create_message_for_test(PCEP_TYPE_KEEPALIVE, false, false);
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ session.timer_id_dead_timer = 100;
+ session.timer_id_open_keep_wait = 200;
+ session.pce_open_accepted = false;
+ session.pce_open_received = false;
+ session.pcc_open_accepted = false;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pcc_open_accepted);
+ CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+ CU_ASSERT_FALSE(session.pcc_open_rejected);
+ CU_ASSERT_FALSE(session.pce_open_accepted);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.timer_id_dead_timer, 100);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 0);
+
+ /* Test when a Keep Alive is received, and the PCE Open has been
+ * received and accepted */
+ create_message_for_test(PCEP_TYPE_KEEPALIVE, false, false);
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ session.timer_id_dead_timer = 100;
+ session.timer_id_open_keep_wait = 200;
+ session.pce_open_received = true;
+ session.pce_open_accepted = true;
+ session.pcc_open_accepted = false;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pcc_open_accepted);
+ CU_ASSERT_TRUE(session.pce_open_keep_alive_sent);
+ CU_ASSERT_FALSE(session.pcc_open_rejected);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTED);
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.timer_id_dead_timer, 100);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+
+ /* Test when a Keep Alive is received, and the PCE Open has been
+ * received and rejected */
+ create_message_for_test(PCEP_TYPE_KEEPALIVE, false, false);
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+ session.timer_id_dead_timer = 100;
+ session.timer_id_open_keep_wait = 200;
+ session.pce_open_received = true;
+ session.pce_open_accepted = false;
+ session.pce_open_rejected = true;
+ session.pce_open_keep_alive_sent = false;
+ session.pcc_open_accepted = true;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pcc_open_accepted);
+ CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+ CU_ASSERT_FALSE(session.pcc_open_rejected);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET);
+ CU_ASSERT_EQUAL(session.timer_id_dead_timer, 100);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+
+ /* The session is considered connected, when both the
+ * PCE and PCC Open messages have been accepted */
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_CONNECTED_TO_PCE, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_pcrep()
+{
+ create_message_for_test(PCEP_TYPE_PCREP, false, true);
+ struct pcep_object_rp *rp =
+ pcep_obj_create_rp(1, true, true, true, true, 1, NULL);
+ dll_append(message->obj_list, rp);
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_pcreq()
+{
+ create_message_for_test(PCEP_TYPE_PCREQ, false, false);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ /* The PCC does not support receiving PcReq messages, so an error should
+ * be sent */
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 0);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *error_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(error_msg);
+ assert(error_msg != NULL);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, error_msg->msg_header->type);
+ /* Verify the error object */
+ CU_ASSERT_EQUAL(1, error_msg->obj_list->num_entries);
+ struct pcep_object_error *obj = error_msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, obj->header.object_class);
+ CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, obj->header.object_type);
+ CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, obj->error_type);
+ CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, obj->error_value);
+ pcep_msg_free_message(error_msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_handle_socket_comm_event_report()
+{
+ create_message_for_test(PCEP_TYPE_REPORT, false, false);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ /* The PCC does not support receiving Report messages, so an error
+ * should be sent */
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 0);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *error_msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(error_msg);
+ assert(error_msg != NULL);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, error_msg->msg_header->type);
+ /* Verify the error object */
+ CU_ASSERT_EQUAL(1, error_msg->obj_list->num_entries);
+ struct pcep_object_error *obj = error_msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, obj->header.object_class);
+ CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, obj->header.object_type);
+ CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, obj->error_type);
+ CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, obj->error_value);
+ pcep_msg_free_message(error_msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_handle_socket_comm_event_update()
+{
+ create_message_for_test(PCEP_TYPE_UPDATE, false, true);
+ struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL);
+ struct pcep_object_lsp *lsp =
+ pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true,
+ true, true, true, NULL);
+ double_linked_list *ero_subobj_list = dll_initialize();
+ dll_append(ero_subobj_list, pcep_obj_create_ro_subobj_asn(0x0102));
+ struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list);
+ struct pcep_object_metric *metric =
+ pcep_obj_create_metric(PCEP_METRIC_TE, false, true, 16.0);
+ dll_append(message->obj_list, srp);
+ dll_append(message->obj_list, lsp);
+ dll_append(message->obj_list, ero);
+ dll_append(message->obj_list, metric);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_UPDATE, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_initiate()
+{
+ create_message_for_test(PCEP_TYPE_INITIATE, false, true);
+ struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL);
+ struct pcep_object_lsp *lsp =
+ pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true,
+ true, true, true, NULL);
+ dll_append(message->obj_list, srp);
+ dll_append(message->obj_list, lsp);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_INITIATE, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_notify()
+{
+ create_message_for_test(PCEP_TYPE_PCNOTF, false, true);
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_PCNOTF, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_error()
+{
+ create_message_for_test(PCEP_TYPE_ERROR, false, true);
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_unknown_msg()
+{
+ create_message_for_test(13, false, false);
+ mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ /* Sending an unsupported message type, so an error should be sent,
+ * but the connection should remain open, since max_unknown_messages = 2
+ */
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 0);
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ uint8_t *encoded_msg =
+ dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ struct pcep_message *msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(msg);
+ assert(msg != NULL);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, msg->msg_header->type);
+ /* Verify the error object */
+ CU_ASSERT_EQUAL(1, msg->obj_list->num_entries);
+ struct pcep_object_error *error_obj = msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, error_obj->header.object_class);
+ CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, error_obj->header.object_type);
+ CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
+ error_obj->error_type);
+ CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, error_obj->error_value);
+ pcep_msg_free_message(msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+ destroy_message_for_test();
+
+ /* Send another unsupported message type, an error should be sent and
+ * the connection should be closed, since max_unknown_messages = 2 */
+ create_message_for_test(13, false, false);
+ reset_mock_socket_comm_info();
+ mock_info = get_mock_socket_comm_info();
+ mock_info->send_message_save_message = true;
+
+ handle_socket_comm_event(&event);
+
+ verify_socket_comm_times_called(0, 0, 0, 2, 1, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_RCVD_MAX_UNKOWN_MSGS, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+
+ /* Verify the error message */
+ encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ assert(encoded_msg != NULL);
+ msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(msg);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, msg->msg_header->type);
+ /* Verify the error object */
+ CU_ASSERT_EQUAL(1, msg->obj_list->num_entries);
+ error_obj = msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, error_obj->header.object_class);
+ CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, error_obj->header.object_type);
+ CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
+ error_obj->error_type);
+ CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, error_obj->error_value);
+ pcep_msg_free_message(msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+ /* Verify the Close message */
+ encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+ CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+ assert(encoded_msg != NULL);
+ msg = pcep_decode_message(encoded_msg);
+ CU_ASSERT_PTR_NOT_NULL(msg);
+ assert(msg != NULL);
+ CU_ASSERT_EQUAL(PCEP_TYPE_CLOSE, msg->msg_header->type);
+ /* Verify the error object */
+ CU_ASSERT_EQUAL(1, msg->obj_list->num_entries);
+ struct pcep_object_close *close_obj = msg->obj_list->head->data;
+ CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_CLOSE, close_obj->header.object_class);
+ CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_CLOSE, close_obj->header.object_type);
+ CU_ASSERT_EQUAL(PCEP_CLOSE_REASON_UNREC_MSG, close_obj->reason);
+ pcep_msg_free_message(msg);
+ pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_connection_failure(void)
+{
+ /*
+ * Test when 2 invalid Open messages are received that a
+ * PCC_CONNECTION_FAILURE event is generated.
+ */
+ create_message_for_test(PCEP_TYPE_OPEN, false, false);
+ reset_mock_socket_comm_info();
+ struct pcep_object_open *open_object =
+ pcep_obj_create_open(1, 1, 1, NULL);
+ /* Make the Open message invalid */
+ open_object->open_deadtimer =
+ session.pcc_config.max_dead_timer_seconds + 1;
+ dll_append(message->obj_list, open_object);
+ session.pce_open_received = false;
+ session.pce_open_accepted = false;
+ session.pce_open_rejected = false;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pce_open_received);
+ CU_ASSERT_TRUE(session.pce_open_rejected);
+ CU_ASSERT_FALSE(session.pce_open_accepted);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ /* An error response should be sent, rejecting the Open */
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 1);
+ pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_RCVD_INVALID_OPEN, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ destroy_message_for_test();
+
+ /* Send the same erroneous Open again */
+ create_message_for_test(PCEP_TYPE_OPEN, false, false);
+ reset_mock_socket_comm_info();
+ open_object = pcep_obj_create_open(1, 1, 1, NULL);
+ /* Make the Open message invalid */
+ open_object->open_deadtimer =
+ session.pcc_config.max_dead_timer_seconds + 1;
+ dll_append(message->obj_list, open_object);
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pce_open_received);
+ CU_ASSERT_TRUE(session.pce_open_rejected);
+ CU_ASSERT_FALSE(session.pce_open_accepted);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+ /* An error response should be sent, rejecting the Open */
+ verify_socket_comm_times_called(0, 0, 0, 1, 1, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 2);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_RCVD_INVALID_OPEN, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_CONNECTION_FAILURE, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+
+ destroy_message_for_test();
+
+ /*
+ * Test when 2 invalid Open messages are sent that a
+ * PCC_CONNECTION_FAILURE event is generated.
+ */
+ create_message_for_test(PCEP_TYPE_ERROR, false, false);
+ reset_mock_socket_comm_info();
+ struct pcep_object_error *error_object = pcep_obj_create_error(
+ PCEP_ERRT_SESSION_FAILURE, PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG);
+ dll_append(message->obj_list, error_object);
+ session.pcc_open_accepted = false;
+ session.pcc_open_rejected = false;
+ session.session_state = SESSION_STATE_PCEP_CONNECTING;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pcc_open_rejected);
+ CU_ASSERT_FALSE(session.pcc_open_accepted);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+ /* Another Open should be sent */
+ verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 2);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_SENT_INVALID_OPEN, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+ CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, e->message->msg_header->type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ destroy_message_for_test();
+
+ /* Send a socket close while connecting, which should
+ * generate a PCC_CONNECTION_FAILURE event */
+ reset_mock_socket_comm_info();
+ event.socket_closed = true;
+ event.received_msg_list = NULL;
+
+ handle_socket_comm_event(&event);
+
+ CU_ASSERT_TRUE(session.pcc_open_rejected);
+ CU_ASSERT_FALSE(session.pcc_open_accepted);
+ CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+ verify_socket_comm_times_called(0, 0, 0, 0, 0, 1, 0);
+ CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+ 2);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCE_CLOSED_SOCKET, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+ e = queue_dequeue(session_logic_event_queue_->event_queue);
+ CU_ASSERT_EQUAL(PCC_CONNECTION_FAILURE, e->event_type);
+ pceplib_free(PCEPLIB_INFRA, e);
+}