diff options
author | Javier Garcia <javier.garcia@voltanet.io> | 2021-01-22 10:38:12 +0100 |
---|---|---|
committer | Javier Garcia <javier.garcia@voltanet.io> | 2021-03-05 12:12:47 +0100 |
commit | 749714731ee9a59ae39be77e7db3915ce3ad0bd8 (patch) | |
tree | 2a50fcd5ce5c2f01ac381ba769c3d8f145768f9d /pceplib/test | |
parent | Merge pull request #8091 from mjstapp/fix_config_icc_diag (diff) | |
download | frr-749714731ee9a59ae39be77e7db3915ce3ad0bd8.tar.xz frr-749714731ee9a59ae39be77e7db3915ce3ad0bd8.zip |
pceplib: Integrate pcelib into frr
Signed-off-by: Brady Johnson <brady@voltanet.io>
Co-authored-by: Javier Garcia <javier.garcia@voltanet.io>
Signed-off-by: Javier Garcia <javier.garcia@voltanet.io>
Diffstat (limited to 'pceplib/test')
50 files changed, 9395 insertions, 0 deletions
diff --git a/pceplib/test/pcep_msg_messages_test.c b/pceplib/test/pcep_msg_messages_test.c new file mode 100644 index 000000000..10b678bce --- /dev/null +++ b/pceplib/test/pcep_msg_messages_test.c @@ -0,0 +1,498 @@ +/* + * 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> + * + */ + + +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "pcep_msg_encoding.h" +#include "pcep_msg_messages.h" +#include "pcep_msg_objects.h" +#include "pcep_msg_tools.h" +#include "pcep_utils_double_linked_list.h" +#include "pcep_utils_memory.h" +#include "pcep_msg_messages_test.h" + +/* + * Notice: + * All of these message Unit Tests encode the created messages by explicitly + * calling pcep_encode_message() thus testing the message creation and the + * message encoding. + */ + +static struct pcep_versioning *versioning = NULL; + +int pcep_messages_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_messages_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +void pcep_messages_test_setup() +{ + versioning = create_default_pcep_versioning(); +} + +void pcep_messages_test_teardown() +{ + destroy_pcep_versioning(versioning); +} + +void test_pcep_msg_create_open() +{ + uint8_t keepalive = 30; + uint8_t deadtimer = 60; + uint8_t sid = 255; + + struct pcep_message *message = + pcep_msg_create_open(keepalive, deadtimer, sid); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length(PCEP_OBJ_CLASS_OPEN, + PCEP_OBJ_TYPE_OPEN)); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_OPEN); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + /* Just check the class and type, the rest of the hdr fields + * are verified in pcep-objects-test.c */ + struct pcep_object_open *open_obj = + (struct pcep_object_open *)message->obj_list->head->data; + CU_ASSERT_EQUAL(open_obj->header.object_class, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_EQUAL(open_obj->header.object_type, PCEP_OBJ_TYPE_OPEN); + + CU_ASSERT_EQUAL(open_obj->open_deadtimer, deadtimer); + CU_ASSERT_EQUAL(open_obj->open_keepalive, keepalive); + CU_ASSERT_EQUAL(open_obj->open_sid, sid); + CU_ASSERT_EQUAL(open_obj->open_version, PCEP_OBJECT_OPEN_VERSION); + pcep_msg_free_message(message); +} + + +void test_pcep_msg_create_request() +{ + /* First test with NULL objects */ + struct pcep_message *message = + pcep_msg_create_request(NULL, NULL, NULL); + CU_ASSERT_PTR_NULL(message); + + /* Test IPv4 */ + struct pcep_object_rp *rp_obj = + pcep_obj_create_rp(0, false, false, false, false, 10, NULL); + struct in_addr src_addr, dst_addr; + struct pcep_object_endpoints_ipv4 *ipv4_obj = + pcep_obj_create_endpoint_ipv4(&src_addr, &dst_addr); + message = pcep_msg_create_request(rp_obj, ipv4_obj, NULL); + + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 2); + CU_ASSERT_EQUAL( + message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length_by_hdr(&rp_obj->header) + + pcep_object_get_length_by_hdr(&ipv4_obj->header)); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREQ); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); + + /* Test IPv6 */ + rp_obj = pcep_obj_create_rp(0, false, false, false, false, 10, NULL); + struct in6_addr src_addr_ipv6, dst_addr_ipv6; + struct pcep_object_endpoints_ipv6 *ipv6_obj = + pcep_obj_create_endpoint_ipv6(&src_addr_ipv6, &dst_addr_ipv6); + message = pcep_msg_create_request_ipv6(rp_obj, ipv6_obj, NULL); + + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 2); + CU_ASSERT_EQUAL( + message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length_by_hdr(&rp_obj->header) + + pcep_object_get_length_by_hdr(&ipv6_obj->header)); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREQ); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); + + /* The objects get deleted with the message, so they need to be created + * again */ + rp_obj = pcep_obj_create_rp(0, false, false, false, false, 10, NULL); + ipv4_obj = pcep_obj_create_endpoint_ipv4(&src_addr, &dst_addr); + struct pcep_object_bandwidth *bandwidth_obj = + pcep_obj_create_bandwidth(4.2); + double_linked_list *obj_list = dll_initialize(); + dll_append(obj_list, bandwidth_obj); + message = pcep_msg_create_request(rp_obj, ipv4_obj, obj_list); + + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 3); + CU_ASSERT_EQUAL( + message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length_by_hdr(&rp_obj->header) + + pcep_object_get_length_by_hdr(&ipv4_obj->header) + + pcep_object_get_length_by_hdr( + &bandwidth_obj->header)); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREQ); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); +} + + +void test_pcep_msg_create_request_svec() +{ +} + + +void test_pcep_msg_create_reply_nopath() +{ + struct pcep_object_rp *rp_obj = + pcep_obj_create_rp(0, false, false, false, false, 10, NULL); + struct pcep_object_nopath *nopath_obj = pcep_obj_create_nopath( + false, false, PCEP_NOPATH_TLV_ERR_NO_TLV); + double_linked_list *obj_list = dll_initialize(); + dll_append(obj_list, nopath_obj); + + struct pcep_message *message = pcep_msg_create_reply(rp_obj, obj_list); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 2); + CU_ASSERT_EQUAL(message->encoded_message_length, + (MESSAGE_HEADER_LENGTH + + pcep_object_get_length_by_hdr(&rp_obj->header) + + pcep_object_get_length_by_hdr(&nopath_obj->header))); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREP); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); +} + + +void test_pcep_msg_create_reply() +{ + /* First test with NULL ero and rp objects */ + struct pcep_message *message = pcep_msg_create_reply(NULL, NULL); + + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 0); + CU_ASSERT_EQUAL(message->encoded_message_length, MESSAGE_HEADER_LENGTH); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREP); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); + + double_linked_list *ero_subobj_list = dll_initialize(); + struct pcep_object_ro_subobj *ero_subobj = + (struct pcep_object_ro_subobj *) + pcep_obj_create_ro_subobj_32label(true, 1, 10); + dll_append(ero_subobj_list, ero_subobj); + struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list); + + double_linked_list *object_list = dll_initialize(); + dll_append(object_list, ero); + struct pcep_object_rp *rp_obj = + pcep_obj_create_rp(0, false, false, false, false, 10, NULL); + message = pcep_msg_create_reply(rp_obj, object_list); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 2); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length_by_hdr(&rp_obj->header) + + OBJECT_HEADER_LENGTH + + OBJECT_RO_SUBOBJ_HEADER_LENGTH + + 6 /* size of the 32label */); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREP); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); +} + + +void test_pcep_msg_create_close() +{ + uint8_t reason = PCEP_CLOSE_REASON_UNREC_MSG; + + struct pcep_message *message = pcep_msg_create_close(reason); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length(PCEP_OBJ_CLASS_CLOSE, + PCEP_OBJ_TYPE_CLOSE)); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_CLOSE); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + /* Just check the class and type, the rest of the hdr fields + * are verified in pcep-objects-test.c */ + struct pcep_object_close *close_obj = + (struct pcep_object_close *)message->obj_list->head->data; + CU_ASSERT_EQUAL(close_obj->header.object_class, PCEP_OBJ_CLASS_CLOSE); + CU_ASSERT_EQUAL(close_obj->header.object_type, PCEP_OBJ_TYPE_CLOSE); + CU_ASSERT_EQUAL(close_obj->reason, reason); + pcep_msg_free_message(message); +} + + +void test_pcep_msg_create_error() +{ + uint8_t error_type = PCEP_ERRT_RECEPTION_OF_INV_OBJECT; + uint8_t error_value = PCEP_ERRV_KEEPALIVEWAIT_TIMED_OUT; + + struct pcep_message *message = + pcep_msg_create_error(error_type, error_value); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length(PCEP_OBJ_CLASS_ERROR, + PCEP_OBJ_TYPE_ERROR)); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_ERROR); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + /* Just check the class and type, the rest of the hdr fields + * are verified in pcep-objects-test.c */ + struct pcep_object_error *error_obj = + (struct pcep_object_error *)message->obj_list->head->data; + CU_ASSERT_EQUAL(error_obj->header.object_class, PCEP_OBJ_CLASS_ERROR); + CU_ASSERT_EQUAL(error_obj->header.object_type, PCEP_OBJ_TYPE_ERROR); + + CU_ASSERT_EQUAL(error_obj->error_type, error_type); + CU_ASSERT_EQUAL(error_obj->error_value, error_value); + pcep_msg_free_message(message); +} + + +void test_pcep_msg_create_keepalive() +{ + struct pcep_message *message = pcep_msg_create_keepalive(); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 0); + CU_ASSERT_EQUAL(message->encoded_message_length, MESSAGE_HEADER_LENGTH); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_KEEPALIVE); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); +} + +void test_pcep_msg_create_report() +{ + double_linked_list *obj_list = dll_initialize(); + + /* Should return NULL if obj_list is empty */ + struct pcep_message *message = pcep_msg_create_report(NULL); + CU_ASSERT_PTR_NULL(message); + + struct pcep_object_lsp *lsp = + pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true, + true, true, true, NULL); + dll_append(obj_list, lsp); + message = pcep_msg_create_report(obj_list); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + lsp->header.encoded_object_length); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_REPORT); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + pcep_msg_free_message(message); +} + +void test_pcep_msg_create_update() +{ + double_linked_list *obj_list = dll_initialize(); + double_linked_list *ero_subobj_list = dll_initialize(); + + struct pcep_message *message = pcep_msg_create_update(NULL); + CU_ASSERT_PTR_NULL(message); + + /* Should return NULL if obj_list is empty */ + message = pcep_msg_create_update(obj_list); + CU_ASSERT_PTR_NULL(message); + + 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(ero_subobj_list, pcep_obj_create_ro_subobj_asn(0x0102)); + struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list); + + /* Should return NULL if obj_list does not have 3 entries */ + dll_append(obj_list, srp); + dll_append(obj_list, lsp); + message = pcep_msg_create_update(obj_list); + CU_ASSERT_PTR_NULL(message); + + dll_append(obj_list, ero); + message = pcep_msg_create_update(obj_list); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 3); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + srp->header.encoded_object_length + + lsp->header.encoded_object_length + + ero->header.encoded_object_length); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_UPDATE); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + pcep_msg_free_message(message); +} + +void test_pcep_msg_create_initiate() +{ + double_linked_list *obj_list = dll_initialize(); + double_linked_list *ero_subobj_list = dll_initialize(); + + /* Should return NULL if obj_list is empty */ + struct pcep_message *message = pcep_msg_create_initiate(NULL); + CU_ASSERT_PTR_NULL(message); + + 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(ero_subobj_list, pcep_obj_create_ro_subobj_asn(0x0102)); + struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list); + + /* Should return NULL if obj_list does not have 2 entries */ + dll_append(obj_list, srp); + message = pcep_msg_create_initiate(obj_list); + CU_ASSERT_PTR_NULL(message); + + dll_append(obj_list, lsp); + dll_append(obj_list, ero); + message = pcep_msg_create_initiate(obj_list); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 3); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + srp->header.encoded_object_length + + lsp->header.encoded_object_length + + ero->header.encoded_object_length); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_INITIATE); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + pcep_msg_free_message(message); +} + +void test_pcep_msg_create_notify(void) +{ + struct pcep_object_notify *notify_obj = pcep_obj_create_notify( + PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED, + PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST); + + /* Should return NULL if the notify obj is empty */ + struct pcep_message *message = pcep_msg_create_notify(NULL, NULL); + CU_ASSERT_PTR_NULL(message); + + message = pcep_msg_create_notify(notify_obj, NULL); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + notify_obj->header.encoded_object_length); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCNOTF); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + pcep_msg_free_message(message); + + struct pcep_object_rp *rp_obj = + pcep_obj_create_rp(0, false, false, false, false, 10, NULL); + double_linked_list *obj_list = dll_initialize(); + dll_append(obj_list, rp_obj); + notify_obj = pcep_obj_create_notify( + PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED, + PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST); + + message = pcep_msg_create_notify(notify_obj, obj_list); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 2); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + notify_obj->header.encoded_object_length + + rp_obj->header.encoded_object_length); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCNOTF); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + pcep_msg_free_message(message); +} diff --git a/pceplib/test/pcep_msg_messages_test.h b/pceplib/test/pcep_msg_messages_test.h new file mode 100644 index 000000000..a3295c74e --- /dev/null +++ b/pceplib/test/pcep_msg_messages_test.h @@ -0,0 +1,48 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_MSG_MSG_TEST_H_ +#define PCEP_MSG_MSG_TEST_H_ + +/* functions to be tested from pcep-messages.c */ +int pcep_messages_test_suite_setup(void); +int pcep_messages_test_suite_teardown(void); +void pcep_messages_test_setup(void); +void pcep_messages_test_teardown(void); +void test_pcep_msg_create_open(void); +void test_pcep_msg_create_request(void); +void test_pcep_msg_create_request_svec(void); +void test_pcep_msg_create_reply_nopath(void); +void test_pcep_msg_create_reply(void); +void test_pcep_msg_create_close(void); +void test_pcep_msg_create_error(void); +void test_pcep_msg_create_keepalive(void); +void test_pcep_msg_create_report(void); +void test_pcep_msg_create_update(void); +void test_pcep_msg_create_initiate(void); +void test_pcep_msg_create_notify(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_msg_messages_tests.c b/pceplib/test/pcep_msg_messages_tests.c new file mode 100644 index 000000000..bd85a1653 --- /dev/null +++ b/pceplib/test/pcep_msg_messages_tests.c @@ -0,0 +1,256 @@ +/* + * 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> + * + */ + + +#include <CUnit/Basic.h> +#include <CUnit/CUnit.h> +#include <CUnit/TestDB.h> + +#include "pcep_msg_messages_test.h" +#include "pcep_msg_tools_test.h" +#include "pcep_msg_object_error_types.h" +#include "pcep_msg_object_error_types_test.h" +#include "pcep_msg_tlvs_test.h" +#include "pcep_msg_objects_test.h" + + +int main(int argc, char **argv) +{ + /* Unused parameters cause compilation warnings */ + (void)argc; + (void)argv; + + CU_initialize_registry(); + + CU_pSuite messages_suite = CU_add_suite_with_setup_and_teardown( + "PCEP Messages Test Suite", pcep_messages_test_suite_setup, + pcep_messages_test_suite_teardown, /* suite setup and cleanup + function pointers */ + pcep_messages_test_setup, pcep_messages_test_teardown); + CU_add_test(messages_suite, "test_pcep_msg_create_open", + test_pcep_msg_create_open); + CU_add_test(messages_suite, "test_pcep_msg_create_request", + test_pcep_msg_create_request); + CU_add_test(messages_suite, "test_pcep_msg_create_request_svec", + test_pcep_msg_create_request_svec); + CU_add_test(messages_suite, "test_pcep_msg_create_reply_nopath", + test_pcep_msg_create_reply_nopath); + CU_add_test(messages_suite, "test_pcep_msg_create_reply", + test_pcep_msg_create_reply); + CU_add_test(messages_suite, "test_pcep_msg_create_close", + test_pcep_msg_create_close); + CU_add_test(messages_suite, "test_pcep_msg_create_error", + test_pcep_msg_create_error); + CU_add_test(messages_suite, "test_pcep_msg_create_keepalive", + test_pcep_msg_create_keepalive); + CU_add_test(messages_suite, "test_pcep_msg_create_report", + test_pcep_msg_create_report); + CU_add_test(messages_suite, "test_pcep_msg_create_update", + test_pcep_msg_create_update); + CU_add_test(messages_suite, "test_pcep_msg_create_initiate", + test_pcep_msg_create_initiate); + CU_add_test(messages_suite, "test_pcep_msg_create_notify", + test_pcep_msg_create_notify); + + CU_pSuite tlvs_suite = CU_add_suite_with_setup_and_teardown( + "PCEP TLVs Test Suite", pcep_tlvs_test_suite_setup, + pcep_tlvs_test_suite_teardown, /* suite setup and cleanup + function pointers */ + pcep_tlvs_test_setup, pcep_tlvs_test_teardown); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_stateful_pce_capability", + test_pcep_tlv_create_stateful_pce_capability); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_speaker_entity_id", + test_pcep_tlv_create_speaker_entity_id); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_lsp_db_version", + test_pcep_tlv_create_lsp_db_version); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_path_setup_type", + test_pcep_tlv_create_path_setup_type); + CU_add_test(tlvs_suite, + "test_pcep_tlv_create_path_setup_type_capability", + test_pcep_tlv_create_path_setup_type_capability); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_sr_pce_capability", + test_pcep_tlv_create_sr_pce_capability); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_symbolic_path_name", + test_pcep_tlv_create_symbolic_path_name); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_ipv4_lsp_identifiers", + test_pcep_tlv_create_ipv4_lsp_identifiers); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_ipv6_lsp_identifiers", + test_pcep_tlv_create_ipv6_lsp_identifiers); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_pol_id_ipv4", + test_pcep_tlv_create_srpag_pol_id_ipv4); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_pol_id_ipv6", + test_pcep_tlv_create_srpag_pol_id_ipv6); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_pol_name", + test_pcep_tlv_create_srpag_pol_name); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_cp_id", + test_pcep_tlv_create_srpag_cp_id); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_cp_pref", + test_pcep_tlv_create_srpag_cp_pref); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_lsp_error_code", + test_pcep_tlv_create_lsp_error_code); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_rsvp_ipv4_error_spec", + test_pcep_tlv_create_rsvp_ipv4_error_spec); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_rsvp_ipv6_error_spec", + test_pcep_tlv_create_rsvp_ipv6_error_spec); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_nopath_vector", + test_pcep_tlv_create_nopath_vector); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_arbitrary", + test_pcep_tlv_create_arbitrary); + + CU_pSuite objects_suite = CU_add_suite_with_setup_and_teardown( + "PCEP Objects Test Suite", pcep_objects_test_suite_setup, + pcep_objects_test_suite_teardown, /* suite setup and cleanup + function pointers */ + pcep_objects_test_setup, pcep_objects_test_teardown); + CU_add_test(objects_suite, "test_pcep_obj_create_open", + test_pcep_obj_create_open); + CU_add_test(objects_suite, "test_pcep_obj_create_open", + test_pcep_obj_create_open_with_tlvs); + CU_add_test(objects_suite, "test_pcep_obj_create_rp", + test_pcep_obj_create_rp); + CU_add_test(objects_suite, "test_pcep_obj_create_nopath", + test_pcep_obj_create_nopath); + CU_add_test(objects_suite, "test_pcep_obj_create_enpoint_ipv4", + test_pcep_obj_create_endpoint_ipv4); + CU_add_test(objects_suite, "test_pcep_obj_create_enpoint_ipv6", + test_pcep_obj_create_endpoint_ipv6); + CU_add_test(objects_suite, "test_pcep_obj_create_association_ipv4", + test_pcep_obj_create_association_ipv4); + CU_add_test(objects_suite, "test_pcep_obj_create_association_ipv6", + test_pcep_obj_create_association_ipv6); + CU_add_test(objects_suite, "test_pcep_obj_create_bandwidth", + test_pcep_obj_create_bandwidth); + CU_add_test(objects_suite, "test_pcep_obj_create_metric", + test_pcep_obj_create_metric); + CU_add_test(objects_suite, "test_pcep_obj_create_lspa", + test_pcep_obj_create_lspa); + CU_add_test(objects_suite, "test_pcep_obj_create_svec", + test_pcep_obj_create_svec); + CU_add_test(objects_suite, "test_pcep_obj_create_error", + test_pcep_obj_create_error); + CU_add_test(objects_suite, "test_pcep_obj_create_close", + test_pcep_obj_create_close); + CU_add_test(objects_suite, "test_pcep_obj_create_srp", + test_pcep_obj_create_srp); + CU_add_test(objects_suite, "test_pcep_obj_create_lsp", + test_pcep_obj_create_lsp); + CU_add_test(objects_suite, "test_pcep_obj_create_vendor_info", + test_pcep_obj_create_vendor_info); + + CU_add_test(objects_suite, "test_pcep_obj_create_ero", + test_pcep_obj_create_ero); + CU_add_test(objects_suite, "test_pcep_obj_create_rro", + test_pcep_obj_create_rro); + CU_add_test(objects_suite, "test_pcep_obj_create_iro", + test_pcep_obj_create_iro); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_ipv4", + test_pcep_obj_create_ro_subobj_ipv4); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_ipv6", + test_pcep_obj_create_ro_subobj_ipv6); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_unnum", + test_pcep_obj_create_ro_subobj_unnum); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_32label", + test_pcep_obj_create_ro_subobj_32label); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_asn", + test_pcep_obj_create_ro_subobj_asn); + + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_sr_nonai", + test_pcep_obj_create_ro_subobj_sr_nonai); + CU_add_test(objects_suite, + "test_pcep_obj_create_ro_subobj_sr_ipv4_node", + test_pcep_obj_create_ro_subobj_sr_ipv4_node); + CU_add_test(objects_suite, + "test_pcep_obj_create_ro_subobj_sr_ipv6_node", + test_pcep_obj_create_ro_subobj_sr_ipv6_node); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_sr_ipv4_adj", + test_pcep_obj_create_ro_subobj_sr_ipv4_adj); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_sr_ipv6_adj", + test_pcep_obj_create_ro_subobj_sr_ipv6_adj); + CU_add_test(objects_suite, + "test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj", + test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj); + CU_add_test(objects_suite, + "test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj", + test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj); + + CU_pSuite tools_suite = CU_add_suite_with_setup_and_teardown( + "PCEP Tools Test Suite", pcep_tools_test_suite_setup, + pcep_tools_test_suite_teardown, pcep_tools_test_setup, + pcep_tools_test_teardown); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate", + test_pcep_msg_read_pcep_initiate); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate2", + test_pcep_msg_read_pcep_initiate2); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_update", + test_pcep_msg_read_pcep_update); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open", + test_pcep_msg_read_pcep_open); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open_initiate", + test_pcep_msg_read_pcep_open_initiate); + CU_add_test(tools_suite, "test_validate_message_header", + test_validate_message_header); + CU_add_test(tools_suite, "test_validate_message_objects", + test_validate_message_objects); + CU_add_test(tools_suite, "test_validate_message_objects_invalid", + test_validate_message_objects_invalid); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open_cisco_pce", + test_pcep_msg_read_pcep_open_cisco_pce); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_update_cisco_pce", + test_pcep_msg_read_pcep_update_cisco_pce); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_report_cisco_pcc", + test_pcep_msg_read_pcep_report_cisco_pcc); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate_cisco_pcc", + test_pcep_msg_read_pcep_initiate_cisco_pcc); + + CU_pSuite obj_errors_suite = CU_add_suite_with_setup_and_teardown( + "PCEP Object Error Types Test Suite", + pcep_object_error_types_test_suite_setup, + pcep_object_error_types_test_suite_teardown, + pcep_object_error_types_test_setup, + pcep_object_error_types_test_teardown); + CU_add_test(obj_errors_suite, "test_get_error_type_str", + test_get_error_type_str); + CU_add_test(obj_errors_suite, "test_get_error_value_str", + test_get_error_value_str); + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_FailureRecord *failure_record = CU_get_failure_list(); + if (failure_record != NULL) { + printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n"); + do { + printf("\t [%s] [%s] [%s:%d]\n", + failure_record->pSuite->pName, + failure_record->pTest->pName, + failure_record->strFileName, + failure_record->uiLineNumber); + failure_record = failure_record->pNext; + + } while (failure_record != NULL); + } + + CU_pRunSummary run_summary = CU_get_run_summary(); + int result = run_summary->nTestsFailed; + CU_cleanup_registry(); + + return result; +} diff --git a/pceplib/test/pcep_msg_object_error_types_test.c b/pceplib/test/pcep_msg_object_error_types_test.c new file mode 100644 index 000000000..7275eaf09 --- /dev/null +++ b/pceplib/test/pcep_msg_object_error_types_test.c @@ -0,0 +1,84 @@ +/* + * 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> + * + */ + + +#include <stdio.h> + +#include <CUnit/CUnit.h> + +#include "pcep_msg_object_error_types.h" +#include "pcep_msg_object_error_types_test.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +int pcep_object_error_types_test_suite_setup(void) +{ + pceplib_memory_reset(); + set_logging_level(LOG_DEBUG); + return 0; +} + +int pcep_object_error_types_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +void pcep_object_error_types_test_setup(void) +{ +} + +void pcep_object_error_types_test_teardown(void) +{ +} + +void test_get_error_type_str() +{ + const char *error_type_str; + int i = 0; + for (; i < MAX_ERROR_TYPE; i++) { + error_type_str = get_error_type_str(i); + CU_ASSERT_PTR_NOT_NULL(error_type_str); + } + + CU_ASSERT_PTR_NULL(get_error_type_str(-1)); + CU_ASSERT_PTR_NULL(get_error_type_str(MAX_ERROR_TYPE)); +} + +void test_get_error_value_str() +{ + const char *error_value_str; + int i = 0, j = 0; + + for (; i < MAX_ERROR_TYPE; i++) { + for (; j < MAX_ERROR_VALUE; j++) { + error_value_str = get_error_value_str(i, j); + CU_ASSERT_PTR_NOT_NULL(error_value_str); + } + } + + CU_ASSERT_PTR_NULL(get_error_value_str(-1, 0)); + CU_ASSERT_PTR_NULL(get_error_value_str(MAX_ERROR_TYPE, 0)); + CU_ASSERT_PTR_NULL(get_error_value_str(1, -1)); + CU_ASSERT_PTR_NULL(get_error_value_str(1, MAX_ERROR_VALUE)); +} diff --git a/pceplib/test/pcep_msg_object_error_types_test.h b/pceplib/test/pcep_msg_object_error_types_test.h new file mode 100644 index 000000000..863517d1e --- /dev/null +++ b/pceplib/test/pcep_msg_object_error_types_test.h @@ -0,0 +1,37 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_MSG_OBJECT_ERROR_TYPES_TEST_ +#define PCEP_MSG_OBJECT_ERROR_TYPES_TEST_ + +int pcep_object_error_types_test_suite_setup(void); +int pcep_object_error_types_test_suite_teardown(void); +void pcep_object_error_types_test_setup(void); +void pcep_object_error_types_test_teardown(void); +void test_get_error_type_str(void); +void test_get_error_value_str(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_msg_objects_test.c b/pceplib/test/pcep_msg_objects_test.c new file mode 100644 index 000000000..a4c069945 --- /dev/null +++ b/pceplib/test/pcep_msg_objects_test.c @@ -0,0 +1,1289 @@ +/* + * 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> + * + */ + + +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "pcep_msg_encoding.h" +#include "pcep_msg_objects.h" +#include "pcep_msg_tools.h" +#include "pcep_utils_memory.h" +#include "pcep_msg_objects_test.h" + +/* + * Notice: + * All of these object Unit Tests encode the created objects by explicitly + * calling pcep_encode_object() thus testing the object creation and the object + * encoding. All APIs expect IPs to be in network byte order. + */ + +static struct pcep_versioning *versioning = NULL; +static uint8_t object_buf[2000]; + +void reset_objects_buffer(void); + +int pcep_objects_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_objects_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +void reset_objects_buffer() +{ + memset(object_buf, 0, 2000); +} + +void pcep_objects_test_setup() +{ + versioning = create_default_pcep_versioning(); + reset_objects_buffer(); +} + +void pcep_objects_test_teardown() +{ + destroy_pcep_versioning(versioning); +} + +/* Internal util verification function */ +static void verify_pcep_obj_header2(uint8_t obj_class, uint8_t obj_type, + uint16_t obj_length, const uint8_t *obj_buf) +{ + /* Object Header + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Object-Class | OT |Res|P|I| Object Length (bytes) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + /* Not using CU_ASSERT_EQUAL here, so that in case of failure, + * we can provide more info in the error message. */ + if (obj_buf[0] != obj_class) { + fprintf(stderr, + "Test failure obj_class expected [%d] found [%d]\n", + obj_class, obj_buf[0]); + CU_FAIL("Object Header Class"); + } + + uint8_t found8 = (obj_buf[1] >> 4) & 0x0f; + if (obj_type != found8) { + fprintf(stderr, + "Test failure obj_class [%d] obj_type expected [%d] found [%d]\n", + obj_class, obj_type, found8); + CU_FAIL("Object Header Type"); + } + + uint8_t exp8 = 0; + found8 = obj_buf[1] & 0x0f; + if (exp8 != found8) { + fprintf(stderr, + "Test failure obj_class [%d] flags expected [%d] found [%d]\n", + obj_class, exp8, found8); + CU_FAIL("Object Header Flags"); + } + + uint16_t found16 = ntohs(*((uint16_t *)(obj_buf + 2))); + if (obj_length != found16) { + fprintf(stderr, + "Test failure obj_class [%d] obj_length expected [%d] found [%d]\n", + obj_class, obj_length, found16); + CU_FAIL("Object Header Length"); + } +} + +/* Internal util verification function */ +static void verify_pcep_obj_header(uint8_t obj_class, uint8_t obj_type, + struct pcep_object_header *obj_hdr) +{ + verify_pcep_obj_header2(obj_class, obj_type, + pcep_object_get_length_by_hdr(obj_hdr), + obj_hdr->encoded_object); +} + +void test_pcep_obj_create_open() +{ + uint8_t deadtimer = 60; + uint8_t keepalive = 30; + uint8_t sid = 1; + + struct pcep_object_open *open = + pcep_obj_create_open(keepalive, deadtimer, sid, NULL); + + CU_ASSERT_PTR_NOT_NULL(open); + pcep_encode_object(&open->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_OPEN, PCEP_OBJ_TYPE_OPEN, + &open->header); + + CU_ASSERT_EQUAL(open->header.encoded_object[4], + (PCEP_OBJECT_OPEN_VERSION << 5) & 0xe0); + CU_ASSERT_EQUAL(open->header.encoded_object[4] & 0x1f, 0); + CU_ASSERT_EQUAL(open->header.encoded_object[5], keepalive); + CU_ASSERT_EQUAL(open->header.encoded_object[6], deadtimer); + CU_ASSERT_EQUAL(open->header.encoded_object[7], sid); + + pcep_obj_free_object((struct pcep_object_header *)open); +} + +void test_pcep_obj_create_open_with_tlvs() +{ + uint8_t deadtimer = 60; + uint8_t keepalive = 30; + uint8_t sid = 1; + double_linked_list *tlv_list = dll_initialize(); + + struct pcep_object_tlv_stateful_pce_capability *tlv = + pcep_tlv_create_stateful_pce_capability(true, true, true, true, + true, true); + dll_append(tlv_list, tlv); + struct pcep_object_open *open = + pcep_obj_create_open(keepalive, deadtimer, sid, tlv_list); + + CU_ASSERT_PTR_NOT_NULL(open); + pcep_encode_object(&open->header, versioning, object_buf); + verify_pcep_obj_header2(PCEP_OBJ_CLASS_OPEN, PCEP_OBJ_TYPE_OPEN, + pcep_object_get_length_by_hdr(&open->header) + + sizeof(uint32_t) * 2, + open->header.encoded_object); + CU_ASSERT_PTR_NOT_NULL(open->header.tlv_list); + CU_ASSERT_EQUAL(open->header.tlv_list->num_entries, 1); + + CU_ASSERT_EQUAL(open->header.encoded_object[4], + (PCEP_OBJECT_OPEN_VERSION << 5) & 0xe0); + CU_ASSERT_EQUAL(open->header.encoded_object[4] & 0x1f, 0); + CU_ASSERT_EQUAL(open->header.encoded_object[5], keepalive); + CU_ASSERT_EQUAL(open->header.encoded_object[6], deadtimer); + CU_ASSERT_EQUAL(open->header.encoded_object[7], sid); + + pcep_obj_free_object((struct pcep_object_header *)open); +} + +void test_pcep_obj_create_rp() +{ + uint32_t reqid = 15; + uint8_t invalid_priority = 100; + uint8_t priority = 7; + + struct pcep_object_rp *rp = pcep_obj_create_rp( + invalid_priority, true, false, false, true, reqid, NULL); + CU_ASSERT_PTR_NULL(rp); + + rp = pcep_obj_create_rp(priority, true, false, false, true, reqid, + NULL); + CU_ASSERT_PTR_NOT_NULL(rp); + pcep_encode_object(&rp->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_RP, PCEP_OBJ_TYPE_RP, + &rp->header); + + CU_ASSERT_EQUAL(rp->header.encoded_object[4], 0); + CU_ASSERT_EQUAL(rp->header.encoded_object[5], 0); + CU_ASSERT_EQUAL(rp->header.encoded_object[6], 0); + CU_ASSERT_EQUAL((rp->header.encoded_object[7] & 0x07), priority); + CU_ASSERT_TRUE(rp->header.encoded_object[7] & OBJECT_RP_FLAG_R); + CU_ASSERT_TRUE(rp->header.encoded_object[7] & OBJECT_RP_FLAG_OF); + CU_ASSERT_TRUE(rp->header.encoded_object[7] & ~OBJECT_RP_FLAG_B); + CU_ASSERT_TRUE(rp->header.encoded_object[7] & ~OBJECT_RP_FLAG_O); + CU_ASSERT_EQUAL(*((uint32_t *)(rp->header.encoded_object + 8)), + htonl(reqid)); + + pcep_obj_free_object((struct pcep_object_header *)rp); +} + +void test_pcep_obj_create_nopath() +{ + uint8_t ni = 8; + uint32_t errorcode = 42; + + struct pcep_object_nopath *nopath = + pcep_obj_create_nopath(ni, true, errorcode); + + CU_ASSERT_PTR_NOT_NULL(nopath); + pcep_encode_object(&nopath->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_NOPATH, PCEP_OBJ_TYPE_NOPATH, + &nopath->header); + + CU_ASSERT_EQUAL(nopath->header.encoded_object[4], ni); + CU_ASSERT_TRUE(nopath->header.encoded_object[5] & OBJECT_NOPATH_FLAG_C); + CU_ASSERT_EQUAL(nopath->header.encoded_object[6], 0); + CU_ASSERT_EQUAL(nopath->header.encoded_object[7], 0); + + /* Verify the TLV */ + CU_ASSERT_PTR_NOT_NULL(nopath->header.tlv_list); + struct pcep_object_tlv_nopath_vector *tlv = + (struct pcep_object_tlv_nopath_vector *) + nopath->header.tlv_list->head->data; + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 4); + CU_ASSERT_EQUAL(tlv->header.type, 1); + CU_ASSERT_EQUAL(tlv->error_code, errorcode); + + CU_ASSERT_EQUAL(*((uint16_t *)(nopath->header.encoded_object + 8)), + htons(PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR)); + CU_ASSERT_EQUAL(*((uint16_t *)(nopath->header.encoded_object + 10)), + htons(4)); + CU_ASSERT_EQUAL(*((uint32_t *)(nopath->header.encoded_object + 12)), + htonl(errorcode)); + + pcep_obj_free_object((struct pcep_object_header *)nopath); +} +void test_pcep_obj_create_association_ipv4() +{ + + uint16_t all_assoc_groups = 0xffff; + struct in_addr src; + inet_pton(AF_INET, "192.168.1.2", &src); + + struct pcep_object_association_ipv4 *assoc = + pcep_obj_create_association_ipv4( + false, PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE, + all_assoc_groups, src); + CU_ASSERT_PTR_NOT_NULL(assoc); + CU_ASSERT_EQUAL(assoc->association_type, + PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE); + CU_ASSERT_EQUAL(assoc->association_id, all_assoc_groups); + CU_ASSERT_EQUAL(assoc->header.object_class, PCEP_OBJ_CLASS_ASSOCIATION); + CU_ASSERT_EQUAL(assoc->header.object_type, + PCEP_OBJ_TYPE_ASSOCIATION_IPV4); + CU_ASSERT_EQUAL(assoc->src.s_addr, src.s_addr); + + pcep_obj_free_object((struct pcep_object_header *)assoc); +} + +void test_pcep_obj_create_association_ipv6() +{ + uint32_t all_assoc_groups = 0xffff; + struct in6_addr src; + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src); + + struct pcep_object_association_ipv6 *assoc = + pcep_obj_create_association_ipv6( + false, PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE, + all_assoc_groups, src); + CU_ASSERT_PTR_NOT_NULL(assoc); + CU_ASSERT_EQUAL(assoc->association_type, + PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE); + CU_ASSERT_EQUAL(assoc->association_id, all_assoc_groups); + CU_ASSERT_EQUAL(assoc->header.object_class, PCEP_OBJ_CLASS_ASSOCIATION); + CU_ASSERT_EQUAL(assoc->header.object_type, + PCEP_OBJ_TYPE_ASSOCIATION_IPV6); + CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[0], + (src.__in6_u.__u6_addr32[0])); + CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[1], + (src.__in6_u.__u6_addr32[1])); + CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[2], + (src.__in6_u.__u6_addr32[2])); + CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[3], + (src.__in6_u.__u6_addr32[3])); + + pcep_obj_free_object((struct pcep_object_header *)assoc); +} + +void test_pcep_obj_create_endpoint_ipv4() +{ + struct in_addr src_ipv4, dst_ipv4; + inet_pton(AF_INET, "192.168.1.2", &src_ipv4); + inet_pton(AF_INET, "172.168.1.2", &dst_ipv4); + + struct pcep_object_endpoints_ipv4 *ipv4 = + pcep_obj_create_endpoint_ipv4(NULL, NULL); + CU_ASSERT_PTR_NULL(ipv4); + + ipv4 = pcep_obj_create_endpoint_ipv4(&src_ipv4, NULL); + CU_ASSERT_PTR_NULL(ipv4); + + ipv4 = pcep_obj_create_endpoint_ipv4(NULL, &dst_ipv4); + CU_ASSERT_PTR_NULL(ipv4); + + ipv4 = pcep_obj_create_endpoint_ipv4(&src_ipv4, &dst_ipv4); + CU_ASSERT_PTR_NOT_NULL(ipv4); + pcep_encode_object(&ipv4->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_ENDPOINTS, + PCEP_OBJ_TYPE_ENDPOINT_IPV4, &ipv4->header); + CU_ASSERT_EQUAL(*((uint32_t *)(ipv4->header.encoded_object + 4)), + src_ipv4.s_addr); + CU_ASSERT_EQUAL(*((uint32_t *)(ipv4->header.encoded_object + 8)), + dst_ipv4.s_addr); + + pcep_obj_free_object((struct pcep_object_header *)ipv4); +} + +void test_pcep_obj_create_endpoint_ipv6() +{ + struct in6_addr src_ipv6, dst_ipv6; + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src_ipv6); + inet_pton(AF_INET6, "2001:db8::8a2e:370:8446", &dst_ipv6); + + struct pcep_object_endpoints_ipv6 *ipv6 = + pcep_obj_create_endpoint_ipv6(NULL, NULL); + CU_ASSERT_PTR_NULL(ipv6); + + ipv6 = pcep_obj_create_endpoint_ipv6(&src_ipv6, NULL); + CU_ASSERT_PTR_NULL(ipv6); + + ipv6 = pcep_obj_create_endpoint_ipv6(NULL, &dst_ipv6); + CU_ASSERT_PTR_NULL(ipv6); + + ipv6 = pcep_obj_create_endpoint_ipv6(&src_ipv6, &dst_ipv6); + CU_ASSERT_PTR_NOT_NULL(ipv6); + pcep_encode_object(&ipv6->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_ENDPOINTS, + PCEP_OBJ_TYPE_ENDPOINT_IPV6, &ipv6->header); + uint32_t *uint32_ptr = (uint32_t *)(ipv6->header.encoded_object + 4); + CU_ASSERT_EQUAL(uint32_ptr[0], src_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[1], src_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[2], src_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[3], src_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(uint32_ptr[4], dst_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[5], dst_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[6], dst_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[7], dst_ipv6.__in6_u.__u6_addr32[3]); + + pcep_obj_free_object((struct pcep_object_header *)ipv6); +} + +void test_pcep_obj_create_bandwidth() +{ + /* 1.8 => binary 1.11001101 + * exponent = 127 => 0111 1111 + * fraction = 1100 1101 0000 0000 0000 000 */ + float bandwidth = 1.8; + + struct pcep_object_bandwidth *bw = pcep_obj_create_bandwidth(bandwidth); + + CU_ASSERT_PTR_NOT_NULL(bw); + pcep_encode_object(&bw->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_BANDWIDTH, + PCEP_OBJ_TYPE_BANDWIDTH_REQ, &bw->header); + CU_ASSERT_EQUAL(bw->header.encoded_object[4], 0x3f); + CU_ASSERT_EQUAL(bw->header.encoded_object[5], 0xe6); + CU_ASSERT_EQUAL(bw->header.encoded_object[6], 0x66); + CU_ASSERT_EQUAL(bw->header.encoded_object[7], 0x66); + + pcep_obj_free_object((struct pcep_object_header *)bw); +} + +void test_pcep_obj_create_metric() +{ + uint8_t type = PCEP_METRIC_BORDER_NODE_COUNT; + /* https://en.wikipedia.org/wiki/IEEE_754-1985 + * 0.15625 = 1/8 + 1/32 = binary 0.00101 = 1.01 x 10^-3 + * Exponent bias = 127, so exponent = (127-3) = 124 = 0111 1100 + * Sign Exponent Fraction + * (8 bits) (23 bits) + * 0.15625 => 0 0111 1100 010 0000 ... 0000 */ + float value = 0.15625; + + struct pcep_object_metric *metric = + pcep_obj_create_metric(type, true, true, value); + + CU_ASSERT_PTR_NOT_NULL(metric); + pcep_encode_object(&metric->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_METRIC, PCEP_OBJ_TYPE_METRIC, + &metric->header); + CU_ASSERT_EQUAL(metric->header.encoded_object[4], 0); + CU_ASSERT_EQUAL(metric->header.encoded_object[5], 0); + CU_ASSERT_TRUE(metric->header.encoded_object[6] & OBJECT_METRIC_FLAC_B); + CU_ASSERT_TRUE(metric->header.encoded_object[6] & OBJECT_METRIC_FLAC_C); + CU_ASSERT_EQUAL(metric->header.encoded_object[7], type); + /* See comments above for explanation of these values */ + CU_ASSERT_EQUAL(metric->header.encoded_object[8], 0x3e); + CU_ASSERT_EQUAL(metric->header.encoded_object[9], 0x20); + CU_ASSERT_EQUAL(metric->header.encoded_object[10], 0x00); + CU_ASSERT_EQUAL(metric->header.encoded_object[11], 0x00); + + pcep_obj_free_object((struct pcep_object_header *)metric); +} + +void test_pcep_obj_create_lspa() +{ + uint32_t exclude_any = 10; + uint32_t include_any = 20; + uint32_t include_all = 30; + uint8_t prio = 0; + uint8_t hold_prio = 10; + + struct pcep_object_lspa *lspa = pcep_obj_create_lspa( + exclude_any, include_any, include_all, prio, hold_prio, true); + + CU_ASSERT_PTR_NOT_NULL(lspa); + pcep_encode_object(&lspa->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_LSPA, PCEP_OBJ_TYPE_LSPA, + &lspa->header); + uint32_t *uint32_ptr = (uint32_t *)(lspa->header.encoded_object + 4); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(exclude_any)); + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(include_any)); + CU_ASSERT_EQUAL(uint32_ptr[2], htonl(include_all)); + CU_ASSERT_EQUAL(lspa->header.encoded_object[16], prio); + CU_ASSERT_EQUAL(lspa->header.encoded_object[17], hold_prio); + CU_ASSERT_TRUE(lspa->header.encoded_object[18] & OBJECT_LSPA_FLAG_L); + CU_ASSERT_EQUAL(lspa->header.encoded_object[19], 0); + + pcep_obj_free_object((struct pcep_object_header *)lspa); +} + +void test_pcep_obj_create_svec() +{ + struct pcep_object_svec *svec = + pcep_obj_create_svec(true, true, true, NULL); + CU_ASSERT_PTR_NULL(svec); + + double_linked_list *id_list = dll_initialize(); + uint32_t *uint32_ptr = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t)); + *uint32_ptr = 10; + dll_append(id_list, uint32_ptr); + + svec = pcep_obj_create_svec(true, true, true, id_list); + CU_ASSERT_PTR_NOT_NULL(svec); + pcep_encode_object(&svec->header, versioning, object_buf); + verify_pcep_obj_header2(PCEP_OBJ_CLASS_SVEC, PCEP_OBJ_TYPE_SVEC, + (OBJECT_HEADER_LENGTH + sizeof(uint32_t) * 2), + svec->header.encoded_object); + CU_ASSERT_EQUAL(svec->header.encoded_object[4], 0); + CU_ASSERT_EQUAL(svec->header.encoded_object[5], 0); + CU_ASSERT_EQUAL(svec->header.encoded_object[6], 0); + CU_ASSERT_TRUE(svec->header.encoded_object[7] & OBJECT_SVEC_FLAG_S); + CU_ASSERT_TRUE(svec->header.encoded_object[7] & OBJECT_SVEC_FLAG_N); + CU_ASSERT_TRUE(svec->header.encoded_object[7] & OBJECT_SVEC_FLAG_L); + CU_ASSERT_EQUAL(*((uint32_t *)(svec->header.encoded_object + 8)), + htonl(*uint32_ptr)); + + pcep_obj_free_object((struct pcep_object_header *)svec); +} + +void test_pcep_obj_create_error() +{ + uint8_t error_type = PCEP_ERRT_SESSION_FAILURE; + uint8_t error_value = PCEP_ERRV_RECVD_INVALID_OPEN_MSG; + + struct pcep_object_error *error = + pcep_obj_create_error(error_type, error_value); + + CU_ASSERT_PTR_NOT_NULL(error); + pcep_encode_object(&error->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_ERROR, PCEP_OBJ_TYPE_ERROR, + &error->header); + CU_ASSERT_EQUAL(error->header.encoded_object[4], 0); + CU_ASSERT_EQUAL(error->header.encoded_object[5], 0); + CU_ASSERT_EQUAL(error->header.encoded_object[6], error_type); + CU_ASSERT_EQUAL(error->header.encoded_object[7], error_value); + + pcep_obj_free_object((struct pcep_object_header *)error); +} + +void test_pcep_obj_create_close() +{ + uint8_t reason = PCEP_CLOSE_REASON_DEADTIMER; + + struct pcep_object_close *close = pcep_obj_create_close(reason); + + CU_ASSERT_PTR_NOT_NULL(close); + pcep_encode_object(&close->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_CLOSE, PCEP_OBJ_TYPE_CLOSE, + &close->header); + CU_ASSERT_EQUAL(close->header.encoded_object[4], 0); + CU_ASSERT_EQUAL(close->header.encoded_object[5], 0); + CU_ASSERT_EQUAL(close->header.encoded_object[6], 0); + CU_ASSERT_EQUAL(close->header.encoded_object[7], reason); + + pcep_obj_free_object((struct pcep_object_header *)close); +} + +void test_pcep_obj_create_srp() +{ + bool lsp_remove = true; + uint32_t srp_id_number = 0x89674523; + struct pcep_object_srp *srp = + pcep_obj_create_srp(lsp_remove, srp_id_number, NULL); + + CU_ASSERT_PTR_NOT_NULL(srp); + pcep_encode_object(&srp->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_SRP, PCEP_OBJ_TYPE_SRP, + &srp->header); + CU_ASSERT_EQUAL(srp->header.encoded_object[4], 0); + CU_ASSERT_EQUAL(srp->header.encoded_object[5], 0); + CU_ASSERT_EQUAL(srp->header.encoded_object[6], 0); + CU_ASSERT_TRUE(srp->header.encoded_object[7] & OBJECT_SRP_FLAG_R); + CU_ASSERT_EQUAL(*((uint32_t *)(srp->header.encoded_object + 8)), + htonl(srp_id_number)); + + pcep_obj_free_object((struct pcep_object_header *)srp); +} + +void test_pcep_obj_create_lsp() +{ + uint32_t plsp_id = 0x000fffff; + enum pcep_lsp_operational_status status = PCEP_LSP_OPERATIONAL_ACTIVE; + bool c_flag = true; + bool a_flag = true; + bool r_flag = true; + bool s_flag = true; + bool d_flag = true; + + /* Should return for invalid plsp_id */ + struct pcep_object_lsp *lsp = + pcep_obj_create_lsp(0x001fffff, status, c_flag, a_flag, r_flag, + s_flag, d_flag, NULL); + CU_ASSERT_PTR_NULL(lsp); + + /* Should return for invalid status */ + lsp = pcep_obj_create_lsp(plsp_id, 8, c_flag, a_flag, r_flag, s_flag, + d_flag, NULL); + CU_ASSERT_PTR_NULL(lsp); + + lsp = pcep_obj_create_lsp(plsp_id, status, c_flag, a_flag, r_flag, + s_flag, d_flag, NULL); + + CU_ASSERT_PTR_NOT_NULL(lsp); + pcep_encode_object(&lsp->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_LSP, PCEP_OBJ_TYPE_LSP, + &lsp->header); + CU_ASSERT_EQUAL((ntohl(*((uint32_t *)(lsp->header.encoded_object + 4))) + >> 12) & 0x000fffff, + plsp_id); + CU_ASSERT_EQUAL((lsp->header.encoded_object[7] >> 4) & 0x07, status); + CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_A); + CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_C); + CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_D); + CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_R); + CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_S); + + pcep_obj_free_object((struct pcep_object_header *)lsp); +} + +void test_pcep_obj_create_vendor_info() +{ + uint32_t enterprise_number = 0x01020304; + uint32_t enterprise_specific_info = 0x05060708; + + struct pcep_object_vendor_info *obj = pcep_obj_create_vendor_info( + enterprise_number, enterprise_specific_info); + + CU_ASSERT_PTR_NOT_NULL(obj); + pcep_encode_object(&obj->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_VENDOR_INFO, + PCEP_OBJ_TYPE_VENDOR_INFO, &obj->header); + uint32_t *uint32_ptr = (uint32_t *)(obj->header.encoded_object + 4); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(enterprise_number)); + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(enterprise_specific_info)); + + pcep_obj_free_object((struct pcep_object_header *)obj); +} + +/* Internal test function. The only difference between pcep_obj_create_ero(), + * pcep_obj_create_iro(), and pcep_obj_create_rro() is the object_class + * and the object_type. + */ +typedef struct pcep_object_ro *(*ro_func)(double_linked_list *); +static void test_pcep_obj_create_object_common(ro_func func_to_test, + uint8_t object_class, + uint8_t object_type) +{ + double_linked_list *ero_list = dll_initialize(); + + struct pcep_object_ro *ero = func_to_test(NULL); + CU_ASSERT_PTR_NOT_NULL(ero); + pcep_encode_object(&ero->header, versioning, object_buf); + verify_pcep_obj_header2(object_class, object_type, OBJECT_HEADER_LENGTH, + ero->header.encoded_object); + pcep_obj_free_object((struct pcep_object_header *)ero); + + reset_objects_buffer(); + ero = func_to_test(ero_list); + CU_ASSERT_PTR_NOT_NULL(ero); + pcep_encode_object(&ero->header, versioning, object_buf); + verify_pcep_obj_header2(object_class, object_type, OBJECT_HEADER_LENGTH, + ero->header.encoded_object); + pcep_obj_free_object((struct pcep_object_header *)ero); + + reset_objects_buffer(); + struct pcep_ro_subobj_32label *ro_subobj = + pcep_obj_create_ro_subobj_32label(false, 0, 101); + ero_list = dll_initialize(); + dll_append(ero_list, ro_subobj); + ero = func_to_test(ero_list); + CU_ASSERT_PTR_NOT_NULL(ero); + pcep_encode_object(&ero->header, versioning, object_buf); + /* 4 bytes for obj header + + * 2 bytes for ro_subobj header + + * 2 bytes for lable c-type and flags + + * 4 bytes for label */ + verify_pcep_obj_header2(object_class, object_type, + OBJECT_HEADER_LENGTH + sizeof(uint32_t) * 2, + ero->header.encoded_object); + pcep_obj_free_object((struct pcep_object_header *)ero); +} + +void test_pcep_obj_create_ero() +{ + test_pcep_obj_create_object_common( + pcep_obj_create_ero, PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO); +} + +void test_pcep_obj_create_rro() +{ + test_pcep_obj_create_object_common( + pcep_obj_create_rro, PCEP_OBJ_CLASS_RRO, PCEP_OBJ_TYPE_RRO); +} + +void test_pcep_obj_create_iro() +{ + test_pcep_obj_create_object_common( + pcep_obj_create_iro, PCEP_OBJ_CLASS_IRO, PCEP_OBJ_TYPE_IRO); +} + +/* Internal util function to wrap an RO Subobj in a RO and encode it */ +static struct pcep_object_ro *encode_ro_subobj(struct pcep_object_ro_subobj *sr) +{ + double_linked_list *sr_subobj_list = dll_initialize(); + dll_append(sr_subobj_list, sr); + struct pcep_object_ro *ro = pcep_obj_create_ero(sr_subobj_list); + pcep_encode_object(&ro->header, versioning, object_buf); + + return ro; +} + +static void verify_pcep_obj_ro_header(struct pcep_object_ro *ro, + struct pcep_object_ro_subobj *ro_subobj, + uint8_t ro_subobj_type, bool loose_hop, + uint16_t length) +{ + (void)ro_subobj; + + verify_pcep_obj_header2(PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO, length, + ro->header.encoded_object); + + /* TODO consider printing the stack trace: + * https://stackoverflow.com/questions/105659/how-can-one-grab-a-stack-trace-in-c + */ + + /* Not using CU_ASSERT_EQUAL here, so that in case of failure, + * we can provide more info in the error message. */ + uint8_t found_type = (ro->header.encoded_object[4] + & 0x7f); /* remove the Loose hop bit */ + if (found_type != ro_subobj_type) { + fprintf(stderr, + "Test failure ro_sub_obj_type expected [%d] found [%d]\n", + ro_subobj_type, found_type); + CU_FAIL("Sub Object Header Type"); + } + + bool loose_hop_found = (ro->header.encoded_object[4] & 0x80); + if (loose_hop != loose_hop_found) { + fprintf(stderr, + "Test failure ro_sub_obj Loose Hop bit expected [%d] found [%d]\n", + loose_hop, loose_hop_found); + CU_FAIL("Sub Object Header Loose Hop bit"); + } + + if (length - 4 != ro->header.encoded_object[5]) { + fprintf(stderr, + "Test failure ro_sub_obj length expected [%d] found [%d]\n", + length - 4, ro->header.encoded_object[5]); + CU_FAIL("Sub Object Length"); + } +} + +static void +verify_pcep_obj_ro_sr_header(struct pcep_object_ro *ro, + struct pcep_object_ro_subobj *ro_subobj, + uint8_t nai_type, bool loose_hop, uint16_t length) +{ + verify_pcep_obj_ro_header(ro, ro_subobj, RO_SUBOBJ_TYPE_SR, loose_hop, + length); + uint8_t found_nai_type = ((ro->header.encoded_object[6] >> 4) & 0x0f); + if (nai_type != found_nai_type) { + fprintf(stderr, + "Test failure ro_sr_sub_obj nai_type expected [%d] found [%d]\n", + nai_type, found_nai_type); + CU_FAIL("Sub Object SR NAI Type"); + } +} + +void test_pcep_obj_create_ro_subobj_ipv4() +{ + struct in_addr ro_ipv4; + inet_pton(AF_INET, "192.168.1.2", &ro_ipv4); + uint8_t prefix_len = 8; + + struct pcep_ro_subobj_ipv4 *ipv4 = + pcep_obj_create_ro_subobj_ipv4(true, NULL, prefix_len, false); + CU_ASSERT_PTR_NULL(ipv4); + + ipv4 = pcep_obj_create_ro_subobj_ipv4(false, &ro_ipv4, prefix_len, + true); + CU_ASSERT_PTR_NOT_NULL(ipv4); + struct pcep_object_ro *ro = encode_ro_subobj(&ipv4->ro_subobj); + verify_pcep_obj_ro_header(ro, &ipv4->ro_subobj, RO_SUBOBJ_TYPE_IPV4, + false, sizeof(uint32_t) * 3); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 6)), + ro_ipv4.s_addr); + CU_ASSERT_EQUAL(ro->header.encoded_object[10], prefix_len); + CU_ASSERT_TRUE(ro->header.encoded_object[11] + & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT); + pcep_obj_free_object((struct pcep_object_header *)ro); + + reset_objects_buffer(); + ipv4 = pcep_obj_create_ro_subobj_ipv4(true, &ro_ipv4, prefix_len, + false); + CU_ASSERT_PTR_NOT_NULL(ipv4); + ro = encode_ro_subobj(&ipv4->ro_subobj); + verify_pcep_obj_ro_header(ro, &ipv4->ro_subobj, RO_SUBOBJ_TYPE_IPV4, + true, sizeof(uint32_t) * 3); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 6)), + ro_ipv4.s_addr); + CU_ASSERT_EQUAL(ro->header.encoded_object[10], prefix_len); + CU_ASSERT_EQUAL(ro->header.encoded_object[11], 0); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_ipv6() +{ + struct in6_addr ro_ipv6; + uint8_t prefix_len = 16; + + struct pcep_ro_subobj_ipv6 *ipv6 = + pcep_obj_create_ro_subobj_ipv6(true, NULL, prefix_len, true); + CU_ASSERT_PTR_NULL(ipv6); + + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &ro_ipv6); + ipv6 = pcep_obj_create_ro_subobj_ipv6(false, &ro_ipv6, prefix_len, + true); + CU_ASSERT_PTR_NOT_NULL(ipv6); + struct pcep_object_ro *ro = encode_ro_subobj(&ipv6->ro_subobj); + verify_pcep_obj_ro_header(ro, &ipv6->ro_subobj, RO_SUBOBJ_TYPE_IPV6, + false, sizeof(uint32_t) * 6); + uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 6); + CU_ASSERT_EQUAL(uint32_ptr[0], ro_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[1], ro_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[2], ro_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[3], ro_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(ro->header.encoded_object[22], prefix_len); + CU_ASSERT_TRUE(ro->header.encoded_object[23] + & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT); + pcep_obj_free_object((struct pcep_object_header *)ro); + + reset_objects_buffer(); + ipv6 = pcep_obj_create_ro_subobj_ipv6(true, &ro_ipv6, prefix_len, + false); + CU_ASSERT_PTR_NOT_NULL(ipv6); + ro = encode_ro_subobj(&ipv6->ro_subobj); + verify_pcep_obj_ro_header(ro, &ipv6->ro_subobj, RO_SUBOBJ_TYPE_IPV6, + true, sizeof(uint32_t) * 6); + uint32_ptr = (uint32_t *)(ro->header.encoded_object + 6); + CU_ASSERT_EQUAL(uint32_ptr[0], ro_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[1], ro_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[2], ro_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[3], ro_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(ro->header.encoded_object[22], prefix_len); + CU_ASSERT_EQUAL(ro->header.encoded_object[23], 0); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_unnum() +{ + struct in_addr router_id; + uint32_t if_id = 123; + + struct pcep_ro_subobj_unnum *unnum = + pcep_obj_create_ro_subobj_unnum(NULL, if_id); + CU_ASSERT_PTR_NULL(unnum); + + inet_pton(AF_INET, "192.168.1.2", &router_id); + unnum = pcep_obj_create_ro_subobj_unnum(&router_id, if_id); + CU_ASSERT_PTR_NOT_NULL(unnum); + struct pcep_object_ro *ro = encode_ro_subobj(&unnum->ro_subobj); + verify_pcep_obj_ro_header(ro, &unnum->ro_subobj, RO_SUBOBJ_TYPE_UNNUM, + false, sizeof(uint32_t) * 4); + CU_ASSERT_EQUAL(ro->header.encoded_object[6], 0); + CU_ASSERT_EQUAL(ro->header.encoded_object[7], 0); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)), + router_id.s_addr); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 12)), + htonl(if_id)); + + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_32label() +{ + uint8_t class_type = 1; + uint32_t label = 0xeeffaabb; + + struct pcep_ro_subobj_32label *label32 = + pcep_obj_create_ro_subobj_32label(true, class_type, label); + CU_ASSERT_PTR_NOT_NULL(label32); + struct pcep_object_ro *ro = encode_ro_subobj(&label32->ro_subobj); + verify_pcep_obj_ro_header(ro, &label32->ro_subobj, RO_SUBOBJ_TYPE_LABEL, + false, sizeof(uint32_t) * 3); + CU_ASSERT_TRUE(ro->header.encoded_object[6] + & OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL); + CU_ASSERT_EQUAL(ro->header.encoded_object[7], class_type); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)), + htonl(label)); + + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_asn() +{ + uint16_t asn = 0x0102; + + struct pcep_ro_subobj_asn *asn_obj = pcep_obj_create_ro_subobj_asn(asn); + CU_ASSERT_PTR_NOT_NULL(asn_obj); + struct pcep_object_ro *ro = encode_ro_subobj(&asn_obj->ro_subobj); + verify_pcep_obj_ro_header(ro, &asn_obj->ro_subobj, RO_SUBOBJ_TYPE_ASN, + false, sizeof(uint32_t) * 2); + CU_ASSERT_EQUAL(*((uint16_t *)(ro->header.encoded_object + 6)), + htons(asn)); + + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_sr_nonai() +{ + uint32_t sid = 0x01020304; + + struct pcep_ro_subobj_sr *sr = + pcep_obj_create_ro_subobj_sr_nonai(false, sid, false, false); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_ABSENT, false, + sizeof(uint32_t) * 3); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + pcep_obj_free_object((struct pcep_object_header *)ro); + + reset_objects_buffer(); + sr = pcep_obj_create_ro_subobj_sr_nonai(true, sid, true, true); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_ABSENT, true, + sizeof(uint32_t) * 3); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_sr_ipv4_node() +{ + uint32_t sid = 0x01020304; + struct in_addr ipv4_node_id; + inet_pton(AF_INET, "192.168.1.2", &ipv4_node_id); + + /* (loose_hop, sid_absent, c_flag, m_flag, sid, ipv4_node_id) */ + struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv4_node( + true, false, true, true, sid, NULL); + CU_ASSERT_PTR_NULL(sr); + + /* Test the sid is absent */ + sr = pcep_obj_create_ro_subobj_sr_ipv4_node(true, true, false, false, + sid, &ipv4_node_id); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE, true, + sizeof(uint32_t) * 3); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_EQUAL(sr->sid, 0); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)), + ipv4_node_id.s_addr); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* Test the sid is present */ + reset_objects_buffer(); + inet_pton(AF_INET, "192.168.1.2", &ipv4_node_id); + sr = pcep_obj_create_ro_subobj_sr_ipv4_node(false, false, true, true, + sid, &ipv4_node_id); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE, false, + sizeof(uint32_t) * 4); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)), + htonl(sid)); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 12)), + ipv4_node_id.s_addr); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_sr_ipv6_node() +{ + uint32_t sid = 0x01020304; + struct in6_addr ipv6_node_id; + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &ipv6_node_id); + + /* (loose_hop, sid_absent, c_flag, m_flag, sid, ipv6_node_id) */ + struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv6_node( + false, true, true, true, sid, NULL); + CU_ASSERT_PTR_NULL(sr); + + /* Test the sid is absent */ + sr = pcep_obj_create_ro_subobj_sr_ipv6_node(true, true, true, true, sid, + &ipv6_node_id); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV6_NODE, true, + sizeof(uint32_t) * 6); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], ipv6_node_id.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[1], ipv6_node_id.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[2], ipv6_node_id.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[3], ipv6_node_id.__in6_u.__u6_addr32[3]); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* Test the sid is present */ + reset_objects_buffer(); + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &ipv6_node_id); + sr = pcep_obj_create_ro_subobj_sr_ipv6_node(false, false, true, true, + sid, &ipv6_node_id); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV6_NODE, false, + sizeof(uint32_t) * 7); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid)); + CU_ASSERT_EQUAL(uint32_ptr[1], ipv6_node_id.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[2], ipv6_node_id.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[3], ipv6_node_id.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[4], ipv6_node_id.__in6_u.__u6_addr32[3]); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_sr_ipv4_adj() +{ + struct in_addr local_ipv4; + struct in_addr remote_ipv4; + inet_pton(AF_INET, "192.168.1.2", &local_ipv4); + inet_pton(AF_INET, "172.168.1.2", &remote_ipv4); + + uint32_t sid = ENCODE_SR_ERO_SID(3, 7, 0, 188); + CU_ASSERT_EQUAL(sid, 16060); + + /* (loose_hop, sid_absent, c_flag, m_flag, sid, local_ipv4, remote_ipv4) + */ + struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv4_adj( + false, true, true, true, sid, NULL, NULL); + CU_ASSERT_PTR_NULL(sr); + + sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(false, true, true, true, sid, + &local_ipv4, NULL); + CU_ASSERT_PTR_NULL(sr); + + sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(false, true, true, true, sid, + NULL, &remote_ipv4); + CU_ASSERT_PTR_NULL(sr); + + /* Test the sid is absent */ + sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(true, true, true, true, sid, + &local_ipv4, &remote_ipv4); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, true, + sizeof(uint32_t) * 4); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_EQUAL(sr->sid, 0); + uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], local_ipv4.s_addr); + CU_ASSERT_EQUAL(uint32_ptr[1], remote_ipv4.s_addr); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* Test the sid is present */ + inet_pton(AF_INET, "192.168.1.2", &local_ipv4); + inet_pton(AF_INET, "172.168.1.2", &remote_ipv4); + reset_objects_buffer(); + sr = pcep_obj_create_ro_subobj_sr_ipv4_adj( + false, false, true, true, sid, &local_ipv4, &remote_ipv4); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, false, + sizeof(uint32_t) * 5); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid)); + CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv4.s_addr); + CU_ASSERT_EQUAL(uint32_ptr[2], remote_ipv4.s_addr); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_sr_ipv6_adj() +{ + uint32_t sid = 0x01020304; + struct in6_addr local_ipv6; + struct in6_addr remote_ipv6; + inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6); + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6); + + /* (loose_hop, sid_absent, c_flag, m_flag, sid, local_ipv6, remote_ipv6) + */ + struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv6_adj( + false, true, true, true, sid, NULL, NULL); + CU_ASSERT_PTR_NULL(sr); + + sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(false, true, true, true, sid, + &local_ipv6, NULL); + CU_ASSERT_PTR_NULL(sr); + + sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(false, true, true, true, sid, + NULL, &remote_ipv6); + CU_ASSERT_PTR_NULL(sr); + + /* Test the sid is absent */ + sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(true, true, true, true, sid, + &local_ipv6, &remote_ipv6); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, true, + sizeof(uint32_t) * 10); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_EQUAL(sr->sid, 0); + uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], local_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[3]); + + CU_ASSERT_EQUAL(uint32_ptr[4], remote_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[5], remote_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[3]); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* Test the sid is present */ + reset_objects_buffer(); + inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6); + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6); + sr = pcep_obj_create_ro_subobj_sr_ipv6_adj( + false, false, true, false, sid, &local_ipv6, &remote_ipv6); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, false, + sizeof(uint32_t) * 11); + /* All flags are false */ + CU_ASSERT_EQUAL(ro->header.encoded_object[7], 0); + uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid)); + CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[4], local_ipv6.__in6_u.__u6_addr32[3]); + + CU_ASSERT_EQUAL(uint32_ptr[5], remote_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[8], remote_ipv6.__in6_u.__u6_addr32[3]); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj() +{ + uint32_t sid = 0x01020304; + uint32_t local_node_id = 0x11223344; + uint32_t local_if_id = 0x55667788; + uint32_t remote_node_id = 0x99aabbcc; + uint32_t remote_if_id = 0xddeeff11; + + /* (loose_hop, sid_absent, c_flag, m_flag, + sid, local_node_id, local_if_id, remote_node_id, remote_if_id) */ + + /* Test the sid is absent */ + struct pcep_ro_subobj_sr *sr = + pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj( + true, true, true, true, sid, local_node_id, local_if_id, + remote_node_id, remote_if_id); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header( + ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, true, + sizeof(uint32_t) * 6); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_EQUAL(sr->sid, 0); + uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], local_node_id); + CU_ASSERT_EQUAL(uint32_ptr[1], local_if_id); + CU_ASSERT_EQUAL(uint32_ptr[2], remote_node_id); + CU_ASSERT_EQUAL(uint32_ptr[3], remote_if_id); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* Test the sid is present */ + reset_objects_buffer(); + sr = pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj( + false, false, true, true, sid, local_node_id, local_if_id, + remote_node_id, remote_if_id); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header( + ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, false, + sizeof(uint32_t) * 7); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid)); + CU_ASSERT_EQUAL(uint32_ptr[1], local_node_id); + CU_ASSERT_EQUAL(uint32_ptr[2], local_if_id); + CU_ASSERT_EQUAL(uint32_ptr[3], remote_node_id); + CU_ASSERT_EQUAL(uint32_ptr[4], remote_if_id); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* TODO Test draft07 types */ +} + +void test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj() +{ + uint32_t sid = 0x01020304; + uint32_t local_if_id = 0x11002200; + uint32_t remote_if_id = 0x00110022; + struct in6_addr local_ipv6; + struct in6_addr remote_ipv6; + inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6); + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6); + + /* (loose_hop, sid_absent, c_flag, m_flag, sid, local_ipv6, local_if_id, + * remote_ipv6, remote_if_id */ + struct pcep_ro_subobj_sr *sr = + pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj( + false, true, true, true, sid, NULL, local_if_id, NULL, + remote_if_id); + CU_ASSERT_PTR_NULL(sr); + + sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj( + false, true, true, true, sid, &local_ipv6, local_if_id, NULL, + remote_if_id); + CU_ASSERT_PTR_NULL(sr); + + sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj( + false, true, true, true, sid, NULL, local_if_id, &remote_ipv6, + remote_if_id); + CU_ASSERT_PTR_NULL(sr); + + /* Test the sid is absent */ + sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj( + true, true, true, true, sid, &local_ipv6, local_if_id, + &remote_ipv6, remote_if_id); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header( + ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, true, + sizeof(uint32_t) * 12); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_EQUAL(sr->sid, 0); + uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], local_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(uint32_ptr[4], local_if_id); + + CU_ASSERT_EQUAL(uint32_ptr[5], remote_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[8], remote_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(uint32_ptr[9], remote_if_id); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* Test the sid is present */ + inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6); + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6); + reset_objects_buffer(); + sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj( + false, false, true, true, sid, &local_ipv6, local_if_id, + &remote_ipv6, remote_if_id); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header( + ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, false, + sizeof(uint32_t) * 13); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid)); + CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[4], local_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(uint32_ptr[5], local_if_id); + + CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[8], remote_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[9], remote_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(uint32_ptr[10], remote_if_id); + pcep_obj_free_object((struct pcep_object_header *)ro); +} diff --git a/pceplib/test/pcep_msg_objects_test.h b/pceplib/test/pcep_msg_objects_test.h new file mode 100644 index 000000000..0f08193a5 --- /dev/null +++ b/pceplib/test/pcep_msg_objects_test.h @@ -0,0 +1,64 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + + +#ifndef PCEP_MSG_OBJECTS_TEST_H_ +#define PCEP_MSG_OBJECTS_TEST_H_ + +int pcep_objects_test_suite_setup(void); +int pcep_objects_test_suite_teardown(void); +void pcep_objects_test_setup(void); +void pcep_objects_test_teardown(void); +void test_pcep_obj_create_open(void); +void test_pcep_obj_create_open_with_tlvs(void); +void test_pcep_obj_create_rp(void); +void test_pcep_obj_create_nopath(void); +void test_pcep_obj_create_endpoint_ipv4(void); +void test_pcep_obj_create_endpoint_ipv6(void); +void test_pcep_obj_create_association_ipv4(void); +void test_pcep_obj_create_association_ipv6(void); +void test_pcep_obj_create_bandwidth(void); +void test_pcep_obj_create_metric(void); +void test_pcep_obj_create_lspa(void); +void test_pcep_obj_create_svec(void); +void test_pcep_obj_create_error(void); +void test_pcep_obj_create_close(void); +void test_pcep_obj_create_srp(void); +void test_pcep_obj_create_lsp(void); +void test_pcep_obj_create_vendor_info(void); +void test_pcep_obj_create_ero(void); +void test_pcep_obj_create_rro(void); +void test_pcep_obj_create_iro(void); +void test_pcep_obj_create_ro_subobj_ipv4(void); +void test_pcep_obj_create_ro_subobj_ipv6(void); +void test_pcep_obj_create_ro_subobj_unnum(void); +void test_pcep_obj_create_ro_subobj_32label(void); +void test_pcep_obj_create_ro_subobj_asn(void); +void test_pcep_obj_create_ro_subobj_sr_nonai(void); +void test_pcep_obj_create_ro_subobj_sr_ipv4_node(void); +void test_pcep_obj_create_ro_subobj_sr_ipv6_node(void); +void test_pcep_obj_create_ro_subobj_sr_ipv4_adj(void); +void test_pcep_obj_create_ro_subobj_sr_ipv6_adj(void); +void test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(void); +void test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(void); + +#endif diff --git a/pceplib/test/pcep_msg_tests_valgrind.sh b/pceplib/test/pcep_msg_tests_valgrind.sh new file mode 100755 index 000000000..4a9a99939 --- /dev/null +++ b/pceplib/test/pcep_msg_tests_valgrind.sh @@ -0,0 +1,2 @@ +source pceplib/test/pcep_tests_valgrind.sh +valgrind_test pceplib/test/pcep_msg_tests diff --git a/pceplib/test/pcep_msg_tlvs_test.c b/pceplib/test/pcep_msg_tlvs_test.c new file mode 100644 index 000000000..878e4d62a --- /dev/null +++ b/pceplib/test/pcep_msg_tlvs_test.c @@ -0,0 +1,671 @@ +/* + * 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> + * + */ + + +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "pcep_msg_encoding.h" +#include "pcep_msg_objects.h" +#include "pcep_msg_tlvs.h" +#include "pcep_msg_tools.h" +#include "pcep_utils_memory.h" +#include "pcep_msg_tlvs_test.h" + +/* + * Notice: + * All of these TLV Unit Tests encode the created TLVs by explicitly calling + * pcep_encode_tlv() thus testing the TLV creation and the TLV encoding. + * All APIs expect IPs to be in network byte order. + */ + +static struct pcep_versioning *versioning = NULL; +static uint8_t tlv_buf[2000]; + +void reset_tlv_buffer(void); + +int pcep_tlvs_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_tlvs_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +void reset_tlv_buffer() +{ + memset(tlv_buf, 0, 2000); +} + +void pcep_tlvs_test_setup() +{ + versioning = create_default_pcep_versioning(); + reset_tlv_buffer(); +} + +void pcep_tlvs_test_teardown() +{ + destroy_pcep_versioning(versioning); +} + +void test_pcep_tlv_create_stateful_pce_capability() +{ + struct pcep_object_tlv_stateful_pce_capability *tlv = + pcep_tlv_create_stateful_pce_capability(true, true, true, true, + true, true); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t)); + CU_ASSERT_TRUE(tlv->flag_u_lsp_update_capability); + CU_ASSERT_TRUE(tlv->flag_s_include_db_version); + CU_ASSERT_TRUE(tlv->flag_i_lsp_instantiation_capability); + CU_ASSERT_TRUE(tlv->flag_t_triggered_resync); + CU_ASSERT_TRUE(tlv->flag_d_delta_lsp_sync); + CU_ASSERT_TRUE(tlv->flag_f_triggered_initial_sync); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[7], 0x3f); + /* TODO add a new function: verify_tlv_header(tlv->header.encoded_tlv) + * to all tests */ + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_speaker_entity_id() +{ + struct pcep_object_tlv_speaker_entity_identifier *tlv = + pcep_tlv_create_speaker_entity_id(NULL); + CU_ASSERT_PTR_NULL(tlv); + + double_linked_list *list = dll_initialize(); + tlv = pcep_tlv_create_speaker_entity_id(list); + CU_ASSERT_PTR_NULL(tlv); + + uint32_t *speaker_entity = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t)); + *speaker_entity = 42; + dll_append(list, speaker_entity); + tlv = pcep_tlv_create_speaker_entity_id(list); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t)); + CU_ASSERT_PTR_NOT_NULL(tlv->speaker_entity_id_list); + CU_ASSERT_EQUAL(tlv->speaker_entity_id_list->num_entries, 1); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(*speaker_entity)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_lsp_db_version() +{ + uint64_t lsp_db_version = 0xf005ba11ba5eba11; + struct pcep_object_tlv_lsp_db_version *tlv = + pcep_tlv_create_lsp_db_version(lsp_db_version); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint64_t)); + CU_ASSERT_EQUAL(tlv->lsp_db_version, lsp_db_version); + CU_ASSERT_EQUAL(*((uint64_t *)(tlv->header.encoded_tlv + 4)), + be64toh(lsp_db_version)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_path_setup_type() +{ + uint8_t pst = 0x89; + + struct pcep_object_tlv_path_setup_type *tlv = + pcep_tlv_create_path_setup_type(pst); + CU_ASSERT_PTR_NOT_NULL(tlv); + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t)); + CU_ASSERT_EQUAL(tlv->path_setup_type, pst); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x000000FF & pst)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_path_setup_type_capability() +{ + /* The sub_tlv list is optional */ + + /* Should return NULL if pst_list is NULL */ + struct pcep_object_tlv_path_setup_type_capability *tlv = + pcep_tlv_create_path_setup_type_capability(NULL, NULL); + CU_ASSERT_PTR_NULL(tlv); + + /* Should return NULL if pst_list is empty */ + double_linked_list *pst_list = dll_initialize(); + tlv = pcep_tlv_create_path_setup_type_capability(pst_list, NULL); + CU_ASSERT_PTR_NULL(tlv); + + /* Should still return NULL if pst_list is NULL */ + double_linked_list *sub_tlv_list = dll_initialize(); + tlv = pcep_tlv_create_path_setup_type_capability(NULL, sub_tlv_list); + CU_ASSERT_PTR_NULL(tlv); + + /* Should still return NULL if pst_list is empty */ + tlv = pcep_tlv_create_path_setup_type_capability(pst_list, + sub_tlv_list); + CU_ASSERT_PTR_NULL(tlv); + + /* Test only populating the pst list */ + uint8_t *pst1 = pceplib_malloc(PCEPLIB_MESSAGES, 1); + uint8_t *pst2 = pceplib_malloc(PCEPLIB_MESSAGES, 1); + uint8_t *pst3 = pceplib_malloc(PCEPLIB_MESSAGES, 1); + *pst1 = 1; + *pst2 = 2; + *pst3 = 3; + dll_append(pst_list, pst1); + dll_append(pst_list, pst2); + dll_append(pst_list, pst3); + tlv = pcep_tlv_create_path_setup_type_capability(pst_list, + sub_tlv_list); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t) * 2); + CU_ASSERT_PTR_NOT_NULL(tlv->pst_list); + CU_ASSERT_EQUAL(tlv->pst_list->num_entries, 3); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x00000003)); + CU_ASSERT_EQUAL(uint32_ptr[2], htonl(0x01020300)); + pcep_obj_free_tlv(&tlv->header); + + /* Now test populating both the pst_list and the sub_tlv_list */ + reset_tlv_buffer(); + struct pcep_object_tlv_header *sub_tlv = + (struct pcep_object_tlv_header *) + pcep_tlv_create_sr_pce_capability(true, true, 0); + pst_list = dll_initialize(); + sub_tlv_list = dll_initialize(); + pst1 = pceplib_malloc(PCEPLIB_MESSAGES, 1); + *pst1 = 1; + dll_append(pst_list, pst1); + dll_append(sub_tlv_list, sub_tlv); + tlv = pcep_tlv_create_path_setup_type_capability(pst_list, + sub_tlv_list); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, + sizeof(uint32_t) * 2 + TLV_HEADER_LENGTH + + sub_tlv->encoded_tlv_length); + CU_ASSERT_PTR_NOT_NULL(tlv->pst_list); + CU_ASSERT_PTR_NOT_NULL(tlv->sub_tlv_list); + uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + uint16_t *uint16_ptr = (uint16_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint16_ptr[0], + htons(PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY)); + CU_ASSERT_EQUAL(uint16_ptr[1], htons(tlv->header.encoded_tlv_length)); + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x00000001)); + CU_ASSERT_EQUAL(uint32_ptr[2], htonl(0x01000000)); + /* Verify the Sub-TLV */ + uint16_ptr = (uint16_t *)(tlv->header.encoded_tlv + 12); + CU_ASSERT_EQUAL(uint16_ptr[0], + htons(PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY)); + CU_ASSERT_EQUAL(uint16_ptr[1], htons(4)); + CU_ASSERT_EQUAL(uint16_ptr[2], 0); + CU_ASSERT_EQUAL(uint16_ptr[3], htons(0x0300)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_sr_pce_capability() +{ + struct pcep_object_tlv_sr_pce_capability *tlv = + pcep_tlv_create_sr_pce_capability(true, true, 8); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t)); + uint16_t *uint16_ptr = (uint16_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint16_ptr[0], + htons(PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY)); + CU_ASSERT_EQUAL(uint16_ptr[1], htons(tlv->header.encoded_tlv_length)); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x00000308)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_symbolic_path_name() +{ + /* char *symbolic_path_name, uint16_t symbolic_path_name_length); */ + char path_name[16] = "Some Path Name"; + uint16_t path_name_length = 14; + struct pcep_object_tlv_symbolic_path_name *tlv = + pcep_tlv_create_symbolic_path_name(path_name, path_name_length); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, path_name_length); + /* Test the padding is correct */ + CU_ASSERT_EQUAL(0, strncmp((char *)&(tlv->header.encoded_tlv[4]), + &path_name[0], 4)); + CU_ASSERT_EQUAL(0, strncmp((char *)&(tlv->header.encoded_tlv[8]), + &path_name[4], 4)); + CU_ASSERT_EQUAL(0, strncmp((char *)&(tlv->header.encoded_tlv[12]), + &path_name[8], 4)); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[16], 'm'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[17], 'e'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[18], 0); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[19], 0); + pcep_obj_free_tlv(&tlv->header); + + reset_tlv_buffer(); + tlv = pcep_tlv_create_symbolic_path_name(path_name, 3); + CU_ASSERT_PTR_NOT_NULL(tlv); + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 3); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[4], 'S'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[5], 'o'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[6], 'm'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[7], 0); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_ipv4_lsp_identifiers() +{ + struct in_addr sender_ip, endpoint_ip; + uint16_t lsp_id = 7; + uint16_t tunnel_id = 16; + struct in_addr extended_tunnel_id; + extended_tunnel_id.s_addr = 256; + inet_pton(AF_INET, "192.168.1.1", &sender_ip); + inet_pton(AF_INET, "192.168.1.2", &endpoint_ip); + + struct pcep_object_tlv_ipv4_lsp_identifier *tlv = + pcep_tlv_create_ipv4_lsp_identifiers(NULL, &endpoint_ip, lsp_id, + tunnel_id, + &extended_tunnel_id); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_ipv4_lsp_identifiers( + &sender_ip, NULL, lsp_id, tunnel_id, &extended_tunnel_id); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_ipv4_lsp_identifiers( + NULL, NULL, lsp_id, tunnel_id, &extended_tunnel_id); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_ipv4_lsp_identifiers(&sender_ip, &endpoint_ip, + lsp_id, tunnel_id, + &extended_tunnel_id); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t) * 4); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], sender_ip.s_addr); + CU_ASSERT_EQUAL(uint32_ptr[2], + (uint32_t)(htons(tunnel_id) << 16) | htons(lsp_id)); + CU_ASSERT_EQUAL(uint32_ptr[3], extended_tunnel_id.s_addr); + CU_ASSERT_EQUAL(uint32_ptr[4], endpoint_ip.s_addr); + pcep_obj_free_tlv(&tlv->header); + + reset_tlv_buffer(); + tlv = pcep_tlv_create_ipv4_lsp_identifiers(&sender_ip, &endpoint_ip, + lsp_id, tunnel_id, NULL); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t) * 4); + uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], sender_ip.s_addr); + CU_ASSERT_EQUAL(uint32_ptr[2], + (uint32_t)(htons(tunnel_id) << 16) | htons(lsp_id)); + CU_ASSERT_EQUAL(uint32_ptr[3], INADDR_ANY); + CU_ASSERT_EQUAL(uint32_ptr[4], endpoint_ip.s_addr); + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_ipv6_lsp_identifiers() +{ + struct in6_addr sender_ip, endpoint_ip; + uint16_t lsp_id = 3; + uint16_t tunnel_id = 16; + uint32_t extended_tunnel_id[4]; + + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &sender_ip); + inet_pton(AF_INET6, "2001:db8::8a2e:370:8446", &endpoint_ip); + extended_tunnel_id[0] = 1; + extended_tunnel_id[1] = 2; + extended_tunnel_id[2] = 3; + extended_tunnel_id[3] = 4; + + struct pcep_object_tlv_ipv6_lsp_identifier *tlv = + pcep_tlv_create_ipv6_lsp_identifiers( + NULL, &endpoint_ip, lsp_id, tunnel_id, + (struct in6_addr *)&extended_tunnel_id); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_ipv6_lsp_identifiers( + &sender_ip, NULL, lsp_id, tunnel_id, + (struct in6_addr *)&extended_tunnel_id); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_ipv6_lsp_identifiers( + NULL, NULL, lsp_id, tunnel_id, + (struct in6_addr *)&extended_tunnel_id); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_ipv6_lsp_identifiers( + &sender_ip, &endpoint_ip, lsp_id, tunnel_id, + (struct in6_addr *)&extended_tunnel_id); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 52); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[5], + (uint32_t)(htons(tunnel_id) << 16) | htons(lsp_id)); + + pcep_obj_free_tlv(&tlv->header); +} +void test_pcep_tlv_create_srpag_pol_id_ipv4() +{ + uint32_t color = 1; + struct in_addr src; + inet_pton(AF_INET, "192.168.1.2", &src); + + struct pcep_object_tlv_srpag_pol_id *tlv = + pcep_tlv_create_srpag_pol_id_ipv4(color, (void *)&src); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, (PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID)); + CU_ASSERT_EQUAL( + tlv->header.encoded_tlv_length, + (8 /*draft-barth-pce-segment-routing-policy-cp-04#5.1*/)); + CU_ASSERT_EQUAL(tlv->color, (color)); + uint32_t aux_color = htonl(color); // Is color right encoded + CU_ASSERT_EQUAL(0, memcmp(&tlv_buf[0] + TLV_HEADER_LENGTH, &aux_color, + sizeof(color))); + CU_ASSERT_EQUAL(tlv->end_point.ipv4.s_addr, (src.s_addr)); + // Are simetrical? + struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf); + struct pcep_object_tlv_srpag_pol_id *dec_tlv = + (struct pcep_object_tlv_srpag_pol_id *)dec_hdr; + CU_ASSERT_EQUAL(tlv->color, dec_tlv->color); + + pceplib_free(PCEPLIB_MESSAGES, dec_hdr); + pcep_obj_free_tlv(&tlv->header); +} +void test_pcep_tlv_create_srpag_pol_id_ipv6() +{ + + uint32_t color = 1; + struct in6_addr src; + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src); + + struct pcep_object_tlv_srpag_pol_id *tlv = + pcep_tlv_create_srpag_pol_id_ipv6(color, &src); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, (PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID)); + CU_ASSERT_EQUAL( + tlv->header.encoded_tlv_length, + (20 /*draft-barth-pce-segment-routing-policy-cp-04#5.1*/)); + CU_ASSERT_EQUAL(tlv->color, (color)); + CU_ASSERT_EQUAL(0, memcmp(&tlv->end_point.ipv6, &src, sizeof(src))); + + uint32_t aux_color = htonl(color); + CU_ASSERT_EQUAL(0, memcmp(&aux_color, tlv_buf + TLV_HEADER_LENGTH, + sizeof(tlv->color))); + // Are simetrical? + struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf); + struct pcep_object_tlv_srpag_pol_id *dec_tlv = + (struct pcep_object_tlv_srpag_pol_id *)dec_hdr; + CU_ASSERT_EQUAL(tlv->color, dec_tlv->color); + + pceplib_free(PCEPLIB_MESSAGES, dec_hdr); + pcep_obj_free_tlv(&tlv->header); +} +void test_pcep_tlv_create_srpag_pol_name() +{ + const char *pol_name = "Some Pol Name"; + + struct pcep_object_tlv_srpag_pol_name *tlv = + pcep_tlv_create_srpag_pol_name(pol_name, strlen(pol_name)); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + (PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME)); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, + (normalize_pcep_tlv_length(strlen(pol_name)))); + CU_ASSERT_EQUAL(0, strcmp(pol_name, (char *)tlv->name)); + + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_srpag_cp_id() +{ + // draft-ietf-spring-segment-routing-policy-06.pdf#2.3 + // 10 PCEP, 20 BGP SR Policy, 30 Via Configuration + uint8_t proto_origin = 10; + uint32_t ASN = 0; + struct in6_addr with_mapped_ipv4; + inet_pton(AF_INET6, "::ffff:192.0.2.128", &with_mapped_ipv4); + uint32_t discriminator = 0; + + struct pcep_object_tlv_srpag_cp_id *tlv = pcep_tlv_create_srpag_cp_id( + proto_origin, ASN, &with_mapped_ipv4, discriminator); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + (PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID)); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, + (sizeof(proto_origin) + sizeof(ASN) + + sizeof(with_mapped_ipv4) + sizeof(discriminator))); + CU_ASSERT_EQUAL(tlv->proto, (proto_origin)); + CU_ASSERT_EQUAL(tlv->orig_asn, (ASN)); + CU_ASSERT_EQUAL(0, memcmp(&tlv->orig_addres, &with_mapped_ipv4, + sizeof(with_mapped_ipv4))); + CU_ASSERT_EQUAL(tlv->discriminator, (discriminator)); + // Are simetrical? + struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf); + struct pcep_object_tlv_srpag_cp_id *dec_tlv = + (struct pcep_object_tlv_srpag_cp_id *)dec_hdr; + CU_ASSERT_EQUAL(tlv->proto, dec_tlv->proto); + + pceplib_free(PCEPLIB_MESSAGES, dec_hdr); + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_srpag_cp_pref() +{ + uint32_t preference_default = 100; + + struct pcep_object_tlv_srpag_cp_pref *tlv = + pcep_tlv_create_srpag_cp_pref(preference_default); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + (PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE)); + printf(" encoded length vs sizeof pref (%d) vs (%ld)\n", + tlv->header.encoded_tlv_length, sizeof(preference_default)); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, + sizeof(preference_default)); + CU_ASSERT_EQUAL(tlv->preference, (preference_default)); + uint32_t aux_pref = htonl(preference_default); // Is pref right encoded + CU_ASSERT_EQUAL(0, memcmp(tlv_buf + TLV_HEADER_LENGTH, &aux_pref, + sizeof(preference_default))); + // Are simetrical? + struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf); + struct pcep_object_tlv_srpag_cp_pref *dec_tlv = + (struct pcep_object_tlv_srpag_cp_pref *)dec_hdr; + CU_ASSERT_EQUAL(tlv->preference, dec_tlv->preference); + + pceplib_free(PCEPLIB_MESSAGES, dec_hdr); + pcep_obj_free_tlv(&tlv->header); +} +void test_pcep_tlv_create_lsp_error_code() +{ + struct pcep_object_tlv_lsp_error_code *tlv = + pcep_tlv_create_lsp_error_code( + PCEP_TLV_LSP_ERROR_CODE_RSVP_SIGNALING_ERROR); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t)); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], + htonl(PCEP_TLV_LSP_ERROR_CODE_RSVP_SIGNALING_ERROR)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_rsvp_ipv4_error_spec() +{ + struct in_addr error_node_ip; + inet_pton(AF_INET, "192.168.1.1", &error_node_ip); + uint8_t error_code = 8; + uint16_t error_value = 0xaabb; + + struct pcep_object_tlv_rsvp_error_spec *tlv = + pcep_tlv_create_rsvp_ipv4_error_spec(NULL, error_code, + error_value); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_rsvp_ipv4_error_spec(&error_node_ip, error_code, + error_value); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 12); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_rsvp_ipv6_error_spec() +{ + struct in6_addr error_node_ip; + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &error_node_ip); + uint8_t error_code = 8; + uint16_t error_value = 0xaabb; + + struct pcep_object_tlv_rsvp_error_spec *tlv = + pcep_tlv_create_rsvp_ipv6_error_spec(NULL, error_code, + error_value); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_rsvp_ipv6_error_spec(&error_node_ip, error_code, + error_value); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 24); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_nopath_vector() +{ + uint32_t enterprise_number = 0x01020304; + uint32_t enterprise_specific_info = 0x05060708; + + struct pcep_object_tlv_vendor_info *tlv = pcep_tlv_create_vendor_info( + enterprise_number, enterprise_specific_info); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_VENDOR_INFO); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 8); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(enterprise_number)); + CU_ASSERT_EQUAL(uint32_ptr[2], htonl(enterprise_specific_info)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_arbitrary() +{ + char data[16] = "Some Data"; + uint16_t data_length = 9; + uint16_t tlv_id_unknown = 1; // 65505; // Whatever id to be created + struct pcep_object_tlv_arbitrary *tlv = pcep_tlv_create_tlv_arbitrary( + data, data_length, tlv_id_unknown); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, tlv_id_unknown); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, data_length); + /* Test the padding is correct */ + CU_ASSERT_EQUAL( + 0, strncmp((char *)&(tlv->header.encoded_tlv[4]), &data[0], 4)); + CU_ASSERT_EQUAL( + 0, strncmp((char *)&(tlv->header.encoded_tlv[8]), &data[4], 4)); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[11], 't'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[12], 'a'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[13], 0); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[14], 0); + pcep_obj_free_tlv(&tlv->header); + + reset_tlv_buffer(); + tlv = pcep_tlv_create_tlv_arbitrary(data, 3, tlv_id_unknown); + CU_ASSERT_PTR_NOT_NULL(tlv); + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, tlv_id_unknown); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 3); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[4], 'S'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[5], 'o'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[6], 'm'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[7], 0); + + pcep_obj_free_tlv(&tlv->header); +} diff --git a/pceplib/test/pcep_msg_tlvs_test.h b/pceplib/test/pcep_msg_tlvs_test.h new file mode 100644 index 000000000..a961d7e47 --- /dev/null +++ b/pceplib/test/pcep_msg_tlvs_test.h @@ -0,0 +1,51 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +#ifndef PCEP_MSG_TLVS_TEST_H_ +#define PCEP_MSG_TLVS_TEST_H_ + +int pcep_tlvs_test_suite_setup(void); +int pcep_tlvs_test_suite_teardown(void); +void pcep_tlvs_test_setup(void); +void pcep_tlvs_test_teardown(void); +void test_pcep_tlv_create_stateful_pce_capability(void); +void test_pcep_tlv_create_speaker_entity_id(void); +void test_pcep_tlv_create_lsp_db_version(void); +void test_pcep_tlv_create_path_setup_type(void); +void test_pcep_tlv_create_path_setup_type_capability(void); +void test_pcep_tlv_create_sr_pce_capability(void); +void test_pcep_tlv_create_symbolic_path_name(void); +void test_pcep_tlv_create_ipv4_lsp_identifiers(void); +void test_pcep_tlv_create_ipv6_lsp_identifiers(void); +void test_pcep_tlv_create_lsp_error_code(void); +void test_pcep_tlv_create_rsvp_ipv4_error_spec(void); +void test_pcep_tlv_create_rsvp_ipv6_error_spec(void); +void test_pcep_tlv_create_srpag_pol_id_ipv4(void); +void test_pcep_tlv_create_srpag_pol_id_ipv6(void); +void test_pcep_tlv_create_srpag_pol_name(void); +void test_pcep_tlv_create_srpag_cp_id(void); +void test_pcep_tlv_create_srpag_cp_pref(void); +void test_pcep_tlv_create_nopath_vector(void); +void test_pcep_tlv_create_arbitrary(void); + + +#endif diff --git a/pceplib/test/pcep_msg_tools_test.c b/pceplib/test/pcep_msg_tools_test.c new file mode 100644 index 000000000..a1260b118 --- /dev/null +++ b/pceplib/test/pcep_msg_tools_test.c @@ -0,0 +1,1258 @@ +/* + * 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> + * + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <CUnit/CUnit.h> + +#include "pcep_msg_encoding.h" +#include "pcep_msg_messages.h" +#include "pcep_msg_tools.h" +#include "pcep_msg_tools_test.h" +#include "pcep_utils_double_linked_list.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +const uint8_t any_obj_class = 255; + +uint16_t pcep_open_hexbyte_strs_length = 28; +const char *pcep_open_odl_hexbyte_strs[] = { + "20", "01", "00", "1c", "01", "10", "00", "18", "20", "1e", + "78", "55", "00", "10", "00", "04", "00", "00", "00", "3f", + "00", "1a", "00", "04", "00", "00", "00", "00"}; + +/* PCEP INITIATE str received from ODL with 4 objects: [SRP, LSP, Endpoints, + * ERO] The LSP has a SYMBOLIC_PATH_NAME TLV. The ERO has 2 IPV4 Endpoints. */ +uint16_t pcep_initiate_hexbyte_strs_length = 68; +const char *pcep_initiate_hexbyte_strs[] = { + "20", "0c", "00", "44", "21", "12", "00", "0c", "00", "00", "00", "00", + "00", "00", "00", "01", "20", "10", "00", "14", "00", "00", "00", "09", + "00", "11", "00", "08", "66", "61", "39", "33", "33", "39", "32", "39", + "04", "10", "00", "0c", "7f", "00", "00", "01", "28", "28", "28", "28", + "07", "10", "00", "14", "01", "08", "0a", "00", "01", "01", "18", "00", + "01", "08", "0a", "00", "07", "04", "18", "00"}; + +uint16_t pcep_initiate2_hexbyte_strs_length = 72; +const char *pcep_initiate2_hexbyte_strs[] = { + "20", "0c", "00", "48", "21", "12", "00", "14", "00", "00", "00", "00", + "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01", + "20", "10", "00", "14", "00", "00", "00", "09", "00", "11", "00", "08", + "36", "65", "31", "31", "38", "39", "32", "31", "04", "10", "00", "0c", + "c0", "a8", "14", "05", "01", "01", "01", "01", "07", "10", "00", "10", + "05", "0c", "10", "01", "03", "e8", "a0", "00", "01", "01", "01", "01"}; + +uint16_t pcep_update_hexbyte_strs_length = 48; +const char *pcep_update_hexbyte_strs[] = { + "20", "0b", "00", "30", "21", "12", "00", "14", "00", "00", "00", "00", + "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01", + "20", "10", "00", "08", "00", "02", "a0", "09", "07", "10", "00", "10", + "05", "0c", "10", "01", "03", "e8", "a0", "00", "01", "01", "01", "01"}; + +/* Test that pcep_msg_read() can read multiple messages in 1 call */ +uint16_t pcep_open_initiate_hexbyte_strs_length = 100; +const char *pcep_open_initiate_odl_hexbyte_strs[] = { + "20", "01", "00", "1c", "01", "10", "00", "18", "20", "1e", "78", "55", + "00", "10", "00", "04", "00", "00", "00", "3f", "00", "1a", "00", "04", + "00", "00", "00", "00", "20", "0c", "00", "48", "21", "12", "00", "14", + "00", "00", "00", "00", "00", "00", "00", "01", "00", "1c", "00", "04", + "00", "00", "00", "01", "20", "10", "00", "14", "00", "00", "00", "09", + "00", "11", "00", "08", "36", "65", "31", "31", "38", "39", "32", "31", + "04", "10", "00", "0c", "c0", "a8", "14", "05", "01", "01", "01", "01", + "07", "10", "00", "10", "05", "0c", "10", "01", "03", "e8", "a0", "00", + "01", "01", "01", "01"}; + +uint16_t pcep_open_cisco_pce_hexbyte_strs_length = 28; +const char *pcep_open_cisco_pce_hexbyte_strs[] = { + "20", "01", "00", "1c", "01", "10", "00", "18", "20", "3c", + "78", "00", "00", "10", "00", "04", "00", "00", "00", "05", + "00", "1a", "00", "04", "00", "00", "00", "0a"}; + +uint16_t pcep_update_cisco_pce_hexbyte_strs_length = 100; +const char *pcep_update_cisco_pce_hexbyte_strs[] = { + "20", "0b", "00", "64", "21", "10", "00", "14", "00", "00", "00", "00", + "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01", + "20", "10", "00", "18", "80", "00", "f0", "89", "00", "07", "00", "0c", + "00", "00", "00", "09", "00", "03", "00", "04", "00", "00", "00", "01", + "07", "10", "00", "28", "24", "0c", "10", "01", "04", "65", "50", "00", + "0a", "0a", "0a", "05", "24", "0c", "10", "01", "04", "65", "20", "00", + "0a", "0a", "0a", "02", "24", "0c", "10", "01", "04", "65", "10", "00", + "0a", "0a", "0a", "01", "06", "10", "00", "0c", "00", "00", "00", "02", + "41", "f0", "00", "00"}; + +uint16_t pcep_report_cisco_pcc_hexbyte_strs_length = 148; +const char *pcep_report_cisco_pcc_hexbyte_strs[] = { + "20", "0a", "00", "94", "21", "10", "00", "14", "00", "00", "00", "00", + "00", "00", "00", "00", "00", "1c", "00", "04", "00", "00", "00", "01", + "20", "10", "00", "3c", "80", "00", "f0", "09", "00", "12", "00", "10", + "0a", "0a", "0a", "06", "00", "02", "00", "0f", "0a", "0a", "0a", "06", + "0a", "0a", "0a", "01", "00", "11", "00", "0d", "63", "66", "67", "5f", + "52", "36", "2d", "74", "6f", "2d", "52", "31", "00", "00", "00", "00", + "ff", "e1", "00", "06", "00", "00", "05", "dd", "70", "00", "00", "00", + "07", "10", "00", "04", "09", "10", "00", "14", "00", "00", "00", "00", + "00", "00", "00", "00", "00", "00", "00", "00", "07", "07", "01", "00", + "05", "12", "00", "08", "00", "00", "00", "00", "05", "52", "00", "08", + "00", "00", "00", "00", "06", "10", "00", "0c", "00", "00", "00", "02", + "00", "00", "00", "00", "06", "10", "00", "0c", "00", "00", "01", "04", + "41", "80", "00", "00"}; + +/* Cisco PcInitiate with the following objects: + * SRP, LSP, Endpoint, Inter-layer, Switch-layer, ERO + */ +uint16_t pcep_initiate_cisco_pcc_hexbyte_strs_length = 104; +const char *pcep_initiate_cisco_pcc_hexbyte_strs[] = { + "20", "0c", "00", "68", "21", "10", "00", "14", "00", "00", "00", "00", + "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01", + "20", "10", "00", "30", "00", "00", "00", "89", "00", "11", "00", "13", + "50", "4f", "4c", "31", "5f", "50", "43", "49", "4e", "49", "54", "41", + "54", "45", "5f", "54", "45", "53", "54", "00", "00", "07", "00", "0c", + "00", "00", "00", "09", "00", "03", "00", "04", "00", "00", "00", "01", + "04", "10", "00", "0c", "0a", "0a", "0a", "0a", "0a", "0a", "0a", "04", + "24", "10", "00", "08", "00", "00", "01", "4d", "25", "10", "00", "08", + "00", "00", "00", "64", "07", "10", "00", "04"}; + +struct pcep_message *create_message(uint8_t msg_type, uint8_t obj1_class, + uint8_t obj2_class, uint8_t obj3_class, + uint8_t obj4_class); +int convert_hexstrs_to_binary(const char *hexbyte_strs[], + uint16_t hexbyte_strs_length); + +int pcep_tools_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_tools_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +void pcep_tools_test_setup(void) +{ +} + +void pcep_tools_test_teardown(void) +{ +} + +/* Reads an array of hexbyte strs, and writes them to a temporary file. + * The caller should close the returned file. */ +int convert_hexstrs_to_binary(const char *hexbyte_strs[], + uint16_t hexbyte_strs_length) +{ + int fd = fileno(tmpfile()); + + int i = 0; + for (; i < hexbyte_strs_length; i++) { + uint8_t byte = (uint8_t)strtol(hexbyte_strs[i], 0, 16); + if (write(fd, (char *)&byte, 1) < 0) { + return -1; + } + } + + /* Go back to the beginning of the file */ + lseek(fd, 0, SEEK_SET); + return fd; +} + +static bool pcep_obj_has_tlv(struct pcep_object_header *obj_hdr) +{ + if (obj_hdr->tlv_list == NULL) { + return false; + } + + return (obj_hdr->tlv_list->num_entries > 0); +} + +void test_pcep_msg_read_pcep_initiate() +{ + int fd = convert_hexstrs_to_binary(pcep_initiate_hexbyte_strs, + pcep_initiate_hexbyte_strs_length); + double_linked_list *msg_list = pcep_msg_read(fd); + CU_ASSERT_PTR_NOT_NULL(msg_list); + CU_ASSERT_EQUAL(msg_list->num_entries, 1); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_initiate_hexbyte_strs_length); + + /* Verify each of the object types */ + + /* SRP object */ + double_linked_list_node *node = msg->obj_list->head; + struct pcep_object_header *obj_hdr = + (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_SRP); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_SRP); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, + pcep_object_get_length_by_hdr(obj_hdr)); + CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr)); + + /* LSP object and its TLV*/ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_LSP); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20); + CU_ASSERT_EQUAL(((struct pcep_object_lsp *)obj_hdr)->plsp_id, 0); + CU_ASSERT_TRUE(((struct pcep_object_lsp *)obj_hdr)->flag_d); + CU_ASSERT_TRUE(((struct pcep_object_lsp *)obj_hdr)->flag_a); + CU_ASSERT_FALSE(((struct pcep_object_lsp *)obj_hdr)->flag_s); + CU_ASSERT_FALSE(((struct pcep_object_lsp *)obj_hdr)->flag_r); + CU_ASSERT_FALSE(((struct pcep_object_lsp *)obj_hdr)->flag_c); + + /* LSP TLV */ + CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr)); + CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1); + struct pcep_object_tlv_header *tlv = + (struct pcep_object_tlv_header *)obj_hdr->tlv_list->head->data; + CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME); + CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 8); + + /* Endpoints object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ENDPOINTS); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ENDPOINT_IPV4); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, + pcep_object_get_length_by_hdr(obj_hdr)); + CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr)); + + /* ERO object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ERO); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20); + + /* ERO Subobjects */ + double_linked_list *ero_subobj_list = + ((struct pcep_object_ro *)obj_hdr)->sub_objects; + CU_ASSERT_PTR_NOT_NULL(ero_subobj_list); + CU_ASSERT_EQUAL(ero_subobj_list->num_entries, 2); + double_linked_list_node *subobj_node = ero_subobj_list->head; + struct pcep_object_ro_subobj *subobj_hdr = + (struct pcep_object_ro_subobj *)subobj_node->data; + CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_IPV4); + struct in_addr ero_subobj_ip; + inet_pton(AF_INET, "10.0.1.1", &ero_subobj_ip); + CU_ASSERT_EQUAL( + ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->ip_addr.s_addr, + ero_subobj_ip.s_addr); + CU_ASSERT_EQUAL( + ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->prefix_length, 24); + + subobj_hdr = + (struct pcep_object_ro_subobj *)subobj_node->next_node->data; + CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_IPV4); + inet_pton(AF_INET, "10.0.7.4", &ero_subobj_ip); + CU_ASSERT_EQUAL( + ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->ip_addr.s_addr, + ero_subobj_ip.s_addr); + CU_ASSERT_EQUAL( + ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->prefix_length, 24); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + + +void test_pcep_msg_read_pcep_initiate2() +{ + int fd = convert_hexstrs_to_binary(pcep_initiate2_hexbyte_strs, + pcep_initiate2_hexbyte_strs_length); + double_linked_list *msg_list = pcep_msg_read(fd); + CU_ASSERT_PTR_NOT_NULL(msg_list); + CU_ASSERT_EQUAL(msg_list->num_entries, 1); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_initiate2_hexbyte_strs_length); + + /* Verify each of the object types */ + + /* SRP object */ + double_linked_list_node *node = msg->obj_list->head; + struct pcep_object_header *obj_hdr = + (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_SRP); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_SRP); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20); + CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr)); + /* TODO test the TLVs */ + + /* LSP object and its TLV*/ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_LSP); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20); + + /* LSP TLV */ + CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr)); + CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1); + struct pcep_object_tlv_header *tlv = + (struct pcep_object_tlv_header *)obj_hdr->tlv_list->head->data; + CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME); + CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 8); + + /* Endpoints object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ENDPOINTS); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ENDPOINT_IPV4); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, + pcep_object_get_length_by_hdr(obj_hdr)); + CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr)); + + /* ERO object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ERO); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 16); + + /* ERO Subobjects */ + double_linked_list *ero_subobj_list = + ((struct pcep_object_ro *)obj_hdr)->sub_objects; + CU_ASSERT_PTR_NOT_NULL(ero_subobj_list); + CU_ASSERT_EQUAL(ero_subobj_list->num_entries, 0); + double_linked_list_node *subobj_node = ero_subobj_list->head; + CU_ASSERT_PTR_NULL(subobj_node); + /* We no longer support draft07 SR sub-object type=5, and only support + type=36 struct pcep_object_ro_subobj *subobj_hdr = (struct + pcep_object_ro_subobj *) subobj_node->data; + CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_SR); + struct pcep_ro_subobj_sr *subobj_sr = (struct pcep_ro_subobj_sr *) + subobj_hdr; CU_ASSERT_EQUAL(subobj_sr->nai_type, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE); CU_ASSERT_TRUE(subobj_sr->flag_m); + CU_ASSERT_FALSE(subobj_sr->flag_c); + CU_ASSERT_FALSE(subobj_sr->flag_s); + CU_ASSERT_FALSE(subobj_sr->flag_f); + CU_ASSERT_EQUAL(subobj_sr->sid, 65576960); + CU_ASSERT_EQUAL(*((uint32_t *) subobj_sr->nai_list->head->data), + 0x01010101); + */ + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +void test_pcep_msg_read_pcep_open() +{ + int fd = convert_hexstrs_to_binary(pcep_open_odl_hexbyte_strs, + pcep_open_hexbyte_strs_length); + double_linked_list *msg_list = pcep_msg_read(fd); + CU_ASSERT_PTR_NOT_NULL(msg_list); + CU_ASSERT_EQUAL(msg_list->num_entries, 1); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_open_hexbyte_strs_length); + + /* Verify the Open message */ + struct pcep_object_header *obj_hdr = + (struct pcep_object_header *)msg->obj_list->head->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_OPEN); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 24); + CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr)); + + /* Open TLV: Stateful PCE Capability */ + CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 2); + double_linked_list_node *tlv_node = obj_hdr->tlv_list->head; + struct pcep_object_tlv_header *tlv = + (struct pcep_object_tlv_header *)tlv_node->data; + CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 4); + + /* Open TLV: SR PCE Capability */ + tlv_node = tlv_node->next_node; + tlv = (struct pcep_object_tlv_header *)tlv_node->data; + CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY); + CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 4); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +void test_pcep_msg_read_pcep_update() +{ + int fd = convert_hexstrs_to_binary(pcep_update_hexbyte_strs, + pcep_update_hexbyte_strs_length); + double_linked_list *msg_list = pcep_msg_read(fd); + CU_ASSERT_PTR_NOT_NULL(msg_list); + CU_ASSERT_EQUAL(msg_list->num_entries, 1); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 3); + + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_UPDATE); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_update_hexbyte_strs_length); + + /* Verify each of the object types */ + + double_linked_list_node *node = msg->obj_list->head; + + /* SRP object */ + struct pcep_object_header *obj_hdr = + (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_SRP); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_SRP); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20); + CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr)); + + /* SRP TLV */ + CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1); + struct pcep_object_tlv_header *tlv = + (struct pcep_object_tlv_header *)obj_hdr->tlv_list->head->data; + CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE); + CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 4); + /* TODO verify the path setup type */ + + /* LSP object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_LSP); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, + pcep_object_get_length_by_hdr(obj_hdr)); + CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr)); + + /* ERO object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ERO); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 16); + + /* ERO Subobjects */ + double_linked_list *ero_subobj_list = + ((struct pcep_object_ro *)obj_hdr)->sub_objects; + CU_ASSERT_PTR_NOT_NULL(ero_subobj_list); + CU_ASSERT_EQUAL(ero_subobj_list->num_entries, 0); + double_linked_list_node *subobj_node = ero_subobj_list->head; + CU_ASSERT_PTR_NULL(subobj_node); + /* We no longer support draft07 SR sub-object type=5, and only support + type=36 struct pcep_object_ro_subobj *subobj_hdr = (struct + pcep_object_ro_subobj *) subobj_node->data; + CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_SR); + struct pcep_ro_subobj_sr *subobj_sr = (struct pcep_ro_subobj_sr *) + subobj_hdr; CU_ASSERT_EQUAL(subobj_sr->nai_type, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE); CU_ASSERT_TRUE(subobj_sr->flag_m); + CU_ASSERT_FALSE(subobj_sr->flag_c); + CU_ASSERT_FALSE(subobj_sr->flag_s); + CU_ASSERT_FALSE(subobj_sr->flag_f); + CU_ASSERT_EQUAL(subobj_sr->sid, 65576960); + CU_ASSERT_EQUAL(*((uint32_t *) subobj_sr->nai_list->head->data), + 0x01010101); + */ + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +void test_pcep_msg_read_pcep_open_initiate() +{ + int fd = convert_hexstrs_to_binary( + pcep_open_initiate_odl_hexbyte_strs, + pcep_open_initiate_hexbyte_strs_length); + double_linked_list *msg_list = pcep_msg_read(fd); + CU_ASSERT_PTR_NOT_NULL(msg_list); + CU_ASSERT_EQUAL(msg_list->num_entries, 2); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_open_hexbyte_strs_length); + + msg = (struct pcep_message *)msg_list->head->next_node->data; + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_initiate2_hexbyte_strs_length); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +void test_pcep_msg_read_pcep_open_cisco_pce() +{ + int fd = convert_hexstrs_to_binary( + pcep_open_cisco_pce_hexbyte_strs, + pcep_open_cisco_pce_hexbyte_strs_length); + double_linked_list *msg_list = pcep_msg_read(fd); + CU_ASSERT_PTR_NOT_NULL(msg_list); + CU_ASSERT_EQUAL(msg_list->num_entries, 1); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_open_hexbyte_strs_length); + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 1); + + /* Open object */ + struct pcep_object_open *open = + (struct pcep_object_open *)msg->obj_list->head->data; + CU_ASSERT_EQUAL(open->header.object_class, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_EQUAL(open->header.object_type, PCEP_OBJ_TYPE_OPEN); + CU_ASSERT_EQUAL(open->header.encoded_object_length, 24); + CU_ASSERT_EQUAL(open->open_deadtimer, 120); + CU_ASSERT_EQUAL(open->open_keepalive, 60); + CU_ASSERT_EQUAL(open->open_sid, 0); + CU_ASSERT_EQUAL(open->open_version, 1); + CU_ASSERT_PTR_NOT_NULL(open->header.tlv_list); + CU_ASSERT_EQUAL(open->header.tlv_list->num_entries, 2); + + /* Stateful PCE Capability TLV */ + double_linked_list_node *tlv_node = open->header.tlv_list->head; + struct pcep_object_tlv_stateful_pce_capability *pce_cap_tlv = + (struct pcep_object_tlv_stateful_pce_capability *) + tlv_node->data; + CU_ASSERT_EQUAL(pce_cap_tlv->header.type, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + CU_ASSERT_EQUAL(pce_cap_tlv->header.encoded_tlv_length, 4); + CU_ASSERT_TRUE(pce_cap_tlv->flag_u_lsp_update_capability); + CU_ASSERT_TRUE(pce_cap_tlv->flag_i_lsp_instantiation_capability); + CU_ASSERT_FALSE(pce_cap_tlv->flag_s_include_db_version); + CU_ASSERT_FALSE(pce_cap_tlv->flag_t_triggered_resync); + CU_ASSERT_FALSE(pce_cap_tlv->flag_d_delta_lsp_sync); + CU_ASSERT_FALSE(pce_cap_tlv->flag_f_triggered_initial_sync); + + /* SR PCE Capability TLV */ + tlv_node = tlv_node->next_node; + struct pcep_object_tlv_sr_pce_capability *sr_pce_cap_tlv = + (struct pcep_object_tlv_sr_pce_capability *)tlv_node->data; + CU_ASSERT_EQUAL(sr_pce_cap_tlv->header.type, + PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY); + CU_ASSERT_EQUAL(sr_pce_cap_tlv->header.encoded_tlv_length, 4); + CU_ASSERT_FALSE(sr_pce_cap_tlv->flag_n); + CU_ASSERT_FALSE(sr_pce_cap_tlv->flag_x); + CU_ASSERT_EQUAL(sr_pce_cap_tlv->max_sid_depth, 10); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +void test_pcep_msg_read_pcep_update_cisco_pce() +{ + int fd = convert_hexstrs_to_binary( + pcep_update_cisco_pce_hexbyte_strs, + pcep_update_cisco_pce_hexbyte_strs_length); + double_linked_list *msg_list = pcep_msg_read(fd); + CU_ASSERT_PTR_NOT_NULL(msg_list); + CU_ASSERT_EQUAL(msg_list->num_entries, 1); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_UPDATE); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_update_cisco_pce_hexbyte_strs_length); + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4); + + /* SRP object */ + double_linked_list_node *obj_node = msg->obj_list->head; + struct pcep_object_srp *srp = (struct pcep_object_srp *)obj_node->data; + CU_ASSERT_EQUAL(srp->header.object_class, PCEP_OBJ_CLASS_SRP); + CU_ASSERT_EQUAL(srp->header.object_type, PCEP_OBJ_TYPE_SRP); + CU_ASSERT_EQUAL(srp->header.encoded_object_length, 20); + CU_ASSERT_PTR_NOT_NULL(srp->header.tlv_list); + CU_ASSERT_EQUAL(srp->header.tlv_list->num_entries, 1); + CU_ASSERT_EQUAL(srp->srp_id_number, 1); + CU_ASSERT_FALSE(srp->flag_lsp_remove); + + /* SRP Path Setup Type TLV */ + double_linked_list_node *tlv_node = srp->header.tlv_list->head; + struct pcep_object_tlv_path_setup_type *pst_tlv = + (struct pcep_object_tlv_path_setup_type *)tlv_node->data; + CU_ASSERT_EQUAL(pst_tlv->header.type, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE); + CU_ASSERT_EQUAL(pst_tlv->header.encoded_tlv_length, 4); + CU_ASSERT_EQUAL(pst_tlv->path_setup_type, 1); + + /* LSP object */ + obj_node = obj_node->next_node; + struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)obj_node->data; + CU_ASSERT_EQUAL(lsp->header.object_class, PCEP_OBJ_CLASS_LSP); + CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP); + CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 24); + CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list); + CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 1); + CU_ASSERT_EQUAL(lsp->plsp_id, 524303); + CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN); + CU_ASSERT_TRUE(lsp->flag_a); + CU_ASSERT_TRUE(lsp->flag_c); + CU_ASSERT_TRUE(lsp->flag_d); + CU_ASSERT_FALSE(lsp->flag_r); + CU_ASSERT_FALSE(lsp->flag_s); + + /* LSP Vendor Info TLV */ + tlv_node = lsp->header.tlv_list->head; + struct pcep_object_tlv_vendor_info *vendor_tlv = + (struct pcep_object_tlv_vendor_info *)tlv_node->data; + CU_ASSERT_EQUAL(vendor_tlv->header.type, PCEP_OBJ_TLV_TYPE_VENDOR_INFO); + CU_ASSERT_EQUAL(vendor_tlv->header.encoded_tlv_length, 12); + CU_ASSERT_EQUAL(vendor_tlv->enterprise_number, 9); + CU_ASSERT_EQUAL(vendor_tlv->enterprise_specific_info, 0x00030004); + + /* ERO object */ + obj_node = obj_node->next_node; + struct pcep_object_ro *ero = (struct pcep_object_ro *)obj_node->data; + CU_ASSERT_EQUAL(ero->header.object_class, PCEP_OBJ_CLASS_ERO); + CU_ASSERT_EQUAL(ero->header.object_type, PCEP_OBJ_TYPE_ERO); + CU_ASSERT_EQUAL(ero->header.encoded_object_length, 40); + CU_ASSERT_PTR_NULL(ero->header.tlv_list); + CU_ASSERT_PTR_NOT_NULL(ero->sub_objects); + CU_ASSERT_EQUAL(ero->sub_objects->num_entries, 3); + + /* ERO Subobjects */ + double_linked_list_node *ero_subobj_node = ero->sub_objects->head; + struct pcep_ro_subobj_sr *sr_subobj_ipv4_node = + (struct pcep_ro_subobj_sr *)ero_subobj_node->data; + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->ro_subobj.ro_subobj_type, + RO_SUBOBJ_TYPE_SR); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->ro_subobj.flag_subobj_loose_hop); + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->nai_type, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE); + CU_ASSERT_TRUE(sr_subobj_ipv4_node->flag_m); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_c); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_f); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_s); + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->sid, 73748480); + CU_ASSERT_EQUAL( + *((uint32_t *)sr_subobj_ipv4_node->nai_list->head->data), + htonl(0x0a0a0a05)); + + ero_subobj_node = ero_subobj_node->next_node; + sr_subobj_ipv4_node = (struct pcep_ro_subobj_sr *)ero_subobj_node->data; + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->ro_subobj.ro_subobj_type, + RO_SUBOBJ_TYPE_SR); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->ro_subobj.flag_subobj_loose_hop); + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->nai_type, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE); + CU_ASSERT_TRUE(sr_subobj_ipv4_node->flag_m); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_c); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_f); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_s); + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->sid, 73736192); + CU_ASSERT_EQUAL( + *((uint32_t *)sr_subobj_ipv4_node->nai_list->head->data), + htonl(0x0a0a0a02)); + + ero_subobj_node = ero_subobj_node->next_node; + sr_subobj_ipv4_node = (struct pcep_ro_subobj_sr *)ero_subobj_node->data; + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->ro_subobj.ro_subobj_type, + RO_SUBOBJ_TYPE_SR); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->ro_subobj.flag_subobj_loose_hop); + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->nai_type, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE); + CU_ASSERT_TRUE(sr_subobj_ipv4_node->flag_m); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_c); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_f); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_s); + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->sid, 73732096); + CU_ASSERT_EQUAL( + *((uint32_t *)sr_subobj_ipv4_node->nai_list->head->data), + htonl(0x0a0a0a01)); + + /* Metric object */ + obj_node = obj_node->next_node; + struct pcep_object_metric *metric = + (struct pcep_object_metric *)obj_node->data; + CU_ASSERT_EQUAL(metric->header.object_class, PCEP_OBJ_CLASS_METRIC); + CU_ASSERT_EQUAL(metric->header.object_type, PCEP_OBJ_TYPE_METRIC); + CU_ASSERT_EQUAL(metric->header.encoded_object_length, 12); + CU_ASSERT_PTR_NULL(metric->header.tlv_list); + CU_ASSERT_FALSE(metric->flag_b); + CU_ASSERT_FALSE(metric->flag_c); + CU_ASSERT_EQUAL(metric->type, PCEP_METRIC_TE); + CU_ASSERT_EQUAL(metric->value, 30.0); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +void test_pcep_msg_read_pcep_report_cisco_pcc() +{ + int fd = convert_hexstrs_to_binary( + pcep_report_cisco_pcc_hexbyte_strs, + pcep_report_cisco_pcc_hexbyte_strs_length); + double_linked_list *msg_list = pcep_msg_read(fd); + CU_ASSERT_PTR_NOT_NULL(msg_list); + CU_ASSERT_EQUAL(msg_list->num_entries, 1); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_REPORT); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_report_cisco_pcc_hexbyte_strs_length); + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 8); + + /* SRP object */ + double_linked_list_node *obj_node = msg->obj_list->head; + struct pcep_object_srp *srp = (struct pcep_object_srp *)obj_node->data; + CU_ASSERT_EQUAL(srp->header.object_class, PCEP_OBJ_CLASS_SRP); + CU_ASSERT_EQUAL(srp->header.object_type, PCEP_OBJ_TYPE_SRP); + CU_ASSERT_EQUAL(srp->header.encoded_object_length, 20); + CU_ASSERT_PTR_NOT_NULL(srp->header.tlv_list); + CU_ASSERT_EQUAL(srp->header.tlv_list->num_entries, 1); + CU_ASSERT_EQUAL(srp->srp_id_number, 0); + CU_ASSERT_FALSE(srp->flag_lsp_remove); + + /* SRP Path Setup Type TLV */ + double_linked_list_node *tlv_node = srp->header.tlv_list->head; + struct pcep_object_tlv_path_setup_type *pst_tlv = + (struct pcep_object_tlv_path_setup_type *)tlv_node->data; + CU_ASSERT_EQUAL(pst_tlv->header.type, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE); + CU_ASSERT_EQUAL(pst_tlv->header.encoded_tlv_length, 4); + CU_ASSERT_EQUAL(pst_tlv->path_setup_type, 1); + + /* LSP object */ + obj_node = obj_node->next_node; + struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)obj_node->data; + CU_ASSERT_EQUAL(lsp->header.object_class, PCEP_OBJ_CLASS_LSP); + CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP); + CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 60); + CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list); + /* The TLV with ID 65505 is not recognized, and its not in the list */ + CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 2); + CU_ASSERT_EQUAL(lsp->plsp_id, 524303); + CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN); + CU_ASSERT_TRUE(lsp->flag_a); + CU_ASSERT_TRUE(lsp->flag_d); + CU_ASSERT_FALSE(lsp->flag_c); + CU_ASSERT_FALSE(lsp->flag_r); + CU_ASSERT_FALSE(lsp->flag_s); + + /* LSP IPv4 LSP Identifier TLV */ + tlv_node = lsp->header.tlv_list->head; + struct pcep_object_tlv_ipv4_lsp_identifier *ipv4_lsp_id = + (struct pcep_object_tlv_ipv4_lsp_identifier *)tlv_node->data; + CU_ASSERT_EQUAL(ipv4_lsp_id->header.type, + PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS); + CU_ASSERT_EQUAL(ipv4_lsp_id->header.encoded_tlv_length, 16); + CU_ASSERT_EQUAL(ipv4_lsp_id->ipv4_tunnel_sender.s_addr, + htonl(0x0a0a0a06)); + CU_ASSERT_EQUAL(ipv4_lsp_id->ipv4_tunnel_endpoint.s_addr, + htonl(0x0a0a0a01)); + CU_ASSERT_EQUAL(ipv4_lsp_id->extended_tunnel_id.s_addr, + htonl(0x0a0a0a06)); + CU_ASSERT_EQUAL(ipv4_lsp_id->tunnel_id, 15); + CU_ASSERT_EQUAL(ipv4_lsp_id->lsp_id, 2); + + /* LSP Symbolic Path Name TLV */ + tlv_node = tlv_node->next_node; + struct pcep_object_tlv_symbolic_path_name *sym_path_name = + (struct pcep_object_tlv_symbolic_path_name *)tlv_node->data; + CU_ASSERT_EQUAL(sym_path_name->header.type, + PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME); + CU_ASSERT_EQUAL(sym_path_name->header.encoded_tlv_length, 13); + CU_ASSERT_EQUAL(sym_path_name->symbolic_path_name_length, 13); + CU_ASSERT_EQUAL( + strncmp(sym_path_name->symbolic_path_name, "cfg_R6-to-R1", 13), + 0); + + /* ERO object */ + obj_node = obj_node->next_node; + struct pcep_object_ro *ero = (struct pcep_object_ro *)obj_node->data; + CU_ASSERT_EQUAL(ero->header.object_class, PCEP_OBJ_CLASS_ERO); + CU_ASSERT_EQUAL(ero->header.object_type, PCEP_OBJ_TYPE_ERO); + CU_ASSERT_EQUAL(ero->header.encoded_object_length, 4); + CU_ASSERT_PTR_NULL(ero->header.tlv_list); + CU_ASSERT_PTR_NOT_NULL(ero->sub_objects); + CU_ASSERT_EQUAL(ero->sub_objects->num_entries, 0); + + /* LSPA object */ + obj_node = obj_node->next_node; + struct pcep_object_lspa *lspa = + (struct pcep_object_lspa *)obj_node->data; + CU_ASSERT_EQUAL(lspa->header.object_class, PCEP_OBJ_CLASS_LSPA); + CU_ASSERT_EQUAL(lspa->header.object_type, PCEP_OBJ_TYPE_LSPA); + CU_ASSERT_EQUAL(lspa->header.encoded_object_length, 20); + CU_ASSERT_PTR_NULL(lspa->header.tlv_list); + CU_ASSERT_TRUE(lspa->flag_local_protection); + CU_ASSERT_EQUAL(lspa->holding_priority, 7); + CU_ASSERT_EQUAL(lspa->setup_priority, 7); + CU_ASSERT_EQUAL(lspa->lspa_include_all, 0); + CU_ASSERT_EQUAL(lspa->lspa_include_any, 0); + CU_ASSERT_EQUAL(lspa->lspa_exclude_any, 0); + + /* Bandwidth object 1 */ + obj_node = obj_node->next_node; + struct pcep_object_bandwidth *bandwidth = + (struct pcep_object_bandwidth *)obj_node->data; + CU_ASSERT_EQUAL(bandwidth->header.object_class, + PCEP_OBJ_CLASS_BANDWIDTH); + CU_ASSERT_EQUAL(bandwidth->header.object_type, + PCEP_OBJ_TYPE_BANDWIDTH_REQ); + CU_ASSERT_EQUAL(bandwidth->header.encoded_object_length, 8); + CU_ASSERT_EQUAL(bandwidth->bandwidth, 0); + + /* Bandwidth object 2 */ + obj_node = obj_node->next_node; + bandwidth = (struct pcep_object_bandwidth *)obj_node->data; + CU_ASSERT_EQUAL(bandwidth->header.object_class, + PCEP_OBJ_CLASS_BANDWIDTH); + CU_ASSERT_EQUAL(bandwidth->header.object_type, + PCEP_OBJ_TYPE_BANDWIDTH_CISCO); + CU_ASSERT_EQUAL(bandwidth->header.encoded_object_length, 8); + CU_ASSERT_EQUAL(bandwidth->bandwidth, 0); + + /* Metric object 1 */ + obj_node = obj_node->next_node; + struct pcep_object_metric *metric = + (struct pcep_object_metric *)obj_node->data; + CU_ASSERT_EQUAL(metric->header.object_class, PCEP_OBJ_CLASS_METRIC); + CU_ASSERT_EQUAL(metric->header.object_type, PCEP_OBJ_TYPE_METRIC); + CU_ASSERT_EQUAL(metric->header.encoded_object_length, 12); + CU_ASSERT_PTR_NULL(metric->header.tlv_list); + CU_ASSERT_FALSE(metric->flag_b); + CU_ASSERT_FALSE(metric->flag_c); + CU_ASSERT_EQUAL(metric->type, PCEP_METRIC_TE); + CU_ASSERT_EQUAL(metric->value, 0); + + /* Metric object 2 */ + obj_node = obj_node->next_node; + metric = (struct pcep_object_metric *)obj_node->data; + CU_ASSERT_EQUAL(metric->header.object_class, PCEP_OBJ_CLASS_METRIC); + CU_ASSERT_EQUAL(metric->header.object_type, PCEP_OBJ_TYPE_METRIC); + CU_ASSERT_EQUAL(metric->header.encoded_object_length, 12); + CU_ASSERT_PTR_NULL(metric->header.tlv_list); + CU_ASSERT_TRUE(metric->flag_b); + CU_ASSERT_FALSE(metric->flag_c); + CU_ASSERT_EQUAL(metric->type, PCEP_METRIC_AGGREGATE_BW); + CU_ASSERT_EQUAL(metric->value, 16.0); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +void test_pcep_msg_read_pcep_initiate_cisco_pcc() +{ + int fd = convert_hexstrs_to_binary( + pcep_initiate_cisco_pcc_hexbyte_strs, + pcep_initiate_cisco_pcc_hexbyte_strs_length); + double_linked_list *msg_list = pcep_msg_read(fd); + CU_ASSERT_PTR_NOT_NULL(msg_list); + CU_ASSERT_EQUAL(msg_list->num_entries, 1); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_initiate_cisco_pcc_hexbyte_strs_length); + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 6); + + /* SRP object */ + double_linked_list_node *obj_node = msg->obj_list->head; + struct pcep_object_srp *srp = (struct pcep_object_srp *)obj_node->data; + CU_ASSERT_EQUAL(srp->header.object_class, PCEP_OBJ_CLASS_SRP); + CU_ASSERT_EQUAL(srp->header.object_type, PCEP_OBJ_TYPE_SRP); + CU_ASSERT_EQUAL(srp->header.encoded_object_length, 20); + CU_ASSERT_PTR_NOT_NULL(srp->header.tlv_list); + CU_ASSERT_EQUAL(srp->header.tlv_list->num_entries, 1); + CU_ASSERT_EQUAL(srp->srp_id_number, 1); + CU_ASSERT_FALSE(srp->flag_lsp_remove); + + /* LSP object */ + obj_node = obj_node->next_node; + struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)obj_node->data; + CU_ASSERT_EQUAL(lsp->header.object_class, PCEP_OBJ_CLASS_LSP); + CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP); + CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 48); + CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list); + CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 2); + CU_ASSERT_EQUAL(lsp->plsp_id, 0); + CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN); + CU_ASSERT_TRUE(lsp->flag_a); + CU_ASSERT_TRUE(lsp->flag_d); + CU_ASSERT_TRUE(lsp->flag_c); + CU_ASSERT_FALSE(lsp->flag_r); + CU_ASSERT_FALSE(lsp->flag_s); + + /* Endpoint object */ + obj_node = obj_node->next_node; + struct pcep_object_endpoints_ipv4 *endpoint = + (struct pcep_object_endpoints_ipv4 *)obj_node->data; + CU_ASSERT_EQUAL(endpoint->header.object_class, + PCEP_OBJ_CLASS_ENDPOINTS); + CU_ASSERT_EQUAL(endpoint->header.object_type, + PCEP_OBJ_TYPE_ENDPOINT_IPV4); + CU_ASSERT_EQUAL(endpoint->header.encoded_object_length, 12); + CU_ASSERT_PTR_NULL(endpoint->header.tlv_list); + CU_ASSERT_EQUAL(endpoint->src_ipv4.s_addr, htonl(0x0a0a0a0a)); + CU_ASSERT_EQUAL(endpoint->dst_ipv4.s_addr, htonl(0x0a0a0a04)); + + /* Inter-Layer object */ + obj_node = obj_node->next_node; + struct pcep_object_inter_layer *inter_layer = + (struct pcep_object_inter_layer *)obj_node->data; + CU_ASSERT_EQUAL(inter_layer->header.object_class, + PCEP_OBJ_CLASS_INTER_LAYER); + CU_ASSERT_EQUAL(inter_layer->header.object_type, + PCEP_OBJ_TYPE_INTER_LAYER); + CU_ASSERT_EQUAL(inter_layer->header.encoded_object_length, 8); + CU_ASSERT_PTR_NULL(inter_layer->header.tlv_list); + CU_ASSERT_TRUE(inter_layer->flag_i); + CU_ASSERT_FALSE(inter_layer->flag_m); + CU_ASSERT_TRUE(inter_layer->flag_t); + + /* Switch-Layer object */ + obj_node = obj_node->next_node; + struct pcep_object_switch_layer *switch_layer = + (struct pcep_object_switch_layer *)obj_node->data; + CU_ASSERT_EQUAL(switch_layer->header.object_class, + PCEP_OBJ_CLASS_SWITCH_LAYER); + CU_ASSERT_EQUAL(switch_layer->header.object_type, + PCEP_OBJ_TYPE_SWITCH_LAYER); + CU_ASSERT_EQUAL(switch_layer->header.encoded_object_length, 8); + CU_ASSERT_PTR_NULL(switch_layer->header.tlv_list); + CU_ASSERT_PTR_NOT_NULL(switch_layer->switch_layer_rows); + CU_ASSERT_EQUAL(switch_layer->switch_layer_rows->num_entries, 1); + struct pcep_object_switch_layer_row *switch_layer_row = + (struct pcep_object_switch_layer_row *) + switch_layer->switch_layer_rows->head->data; + CU_ASSERT_EQUAL(switch_layer_row->lsp_encoding_type, 0); + CU_ASSERT_EQUAL(switch_layer_row->switching_type, 0); + CU_ASSERT_FALSE(switch_layer_row->flag_i); + + /* ERO object */ + obj_node = obj_node->next_node; + struct pcep_object_ro *ero = (struct pcep_object_ro *)obj_node->data; + CU_ASSERT_EQUAL(ero->header.object_class, PCEP_OBJ_CLASS_ERO); + CU_ASSERT_EQUAL(ero->header.object_type, PCEP_OBJ_TYPE_ERO); + CU_ASSERT_EQUAL(ero->header.encoded_object_length, 4); + CU_ASSERT_PTR_NULL(ero->header.tlv_list); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +void test_validate_message_header() +{ + uint8_t pcep_message_invalid_version[] = {0x40, 0x01, 0x04, 0x00}; + uint8_t pcep_message_invalid_flags[] = {0x22, 0x01, 0x04, 0x00}; + uint8_t pcep_message_invalid_length[] = {0x20, 0x01, 0x00, 0x00}; + uint8_t pcep_message_invalid_type[] = {0x20, 0xff, 0x04, 0x00}; + uint8_t pcep_message_valid[] = {0x20, 0x01, 0x00, 0x04}; + + /* Verify invalid message header version */ + CU_ASSERT_TRUE( + pcep_decode_validate_msg_header(pcep_message_invalid_version) + < 0); + + /* Verify invalid message header flags */ + CU_ASSERT_TRUE( + pcep_decode_validate_msg_header(pcep_message_invalid_flags) + < 0); + + /* Verify invalid message header lengths */ + CU_ASSERT_TRUE( + pcep_decode_validate_msg_header(pcep_message_invalid_length) + < 0); + pcep_message_invalid_length[3] = 0x05; + CU_ASSERT_TRUE( + pcep_decode_validate_msg_header(pcep_message_invalid_length) + < 0); + + /* Verify invalid message header types */ + CU_ASSERT_TRUE( + pcep_decode_validate_msg_header(pcep_message_invalid_type) < 0); + pcep_message_invalid_type[1] = 0x00; + CU_ASSERT_TRUE( + pcep_decode_validate_msg_header(pcep_message_invalid_type) < 0); + + /* Verify a valid message header */ + CU_ASSERT_EQUAL(pcep_decode_validate_msg_header(pcep_message_valid), 4); +} + +/* Internal util function */ +struct pcep_message *create_message(uint8_t msg_type, uint8_t obj1_class, + uint8_t obj2_class, uint8_t obj3_class, + uint8_t obj4_class) +{ + struct pcep_message *msg = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message)); + msg->obj_list = dll_initialize(); + msg->msg_header = pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct pcep_message_header)); + msg->msg_header->type = msg_type; + msg->encoded_message = NULL; + + if (obj1_class > 0) { + struct pcep_object_header *obj_hdr = pceplib_malloc( + PCEPLIB_MESSAGES, sizeof(struct pcep_object_header)); + obj_hdr->object_class = obj1_class; + obj_hdr->tlv_list = NULL; + dll_append(msg->obj_list, obj_hdr); + } + + if (obj2_class > 0) { + struct pcep_object_header *obj_hdr = pceplib_malloc( + PCEPLIB_MESSAGES, sizeof(struct pcep_object_header)); + obj_hdr->object_class = obj2_class; + obj_hdr->tlv_list = NULL; + dll_append(msg->obj_list, obj_hdr); + } + + if (obj3_class > 0) { + struct pcep_object_header *obj_hdr = pceplib_malloc( + PCEPLIB_MESSAGES, sizeof(struct pcep_object_header)); + obj_hdr->object_class = obj3_class; + obj_hdr->tlv_list = NULL; + dll_append(msg->obj_list, obj_hdr); + } + + if (obj4_class > 0) { + struct pcep_object_header *obj_hdr = pceplib_malloc( + PCEPLIB_MESSAGES, sizeof(struct pcep_object_header)); + obj_hdr->object_class = obj4_class; + obj_hdr->tlv_list = NULL; + dll_append(msg->obj_list, obj_hdr); + } + + return msg; +} + +void test_validate_message_objects() +{ + /* Valid Open message */ + struct pcep_message *msg = + create_message(PCEP_TYPE_OPEN, PCEP_OBJ_CLASS_OPEN, 0, 0, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid KeepAlive message */ + msg = create_message(PCEP_TYPE_KEEPALIVE, 0, 0, 0, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid PcReq message */ + /* Using object_class=255 to verify it can take any object */ + msg = create_message(PCEP_TYPE_PCREQ, PCEP_OBJ_CLASS_RP, + PCEP_OBJ_CLASS_ENDPOINTS, any_obj_class, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid PcRep message */ + msg = create_message(PCEP_TYPE_PCREP, PCEP_OBJ_CLASS_RP, any_obj_class, + 0, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid Notify message */ + msg = create_message(PCEP_TYPE_PCNOTF, PCEP_OBJ_CLASS_NOTF, + any_obj_class, 0, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid Error message */ + msg = create_message(PCEP_TYPE_ERROR, PCEP_OBJ_CLASS_ERROR, + any_obj_class, 0, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid Close message */ + msg = create_message(PCEP_TYPE_CLOSE, PCEP_OBJ_CLASS_CLOSE, 0, 0, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid Report message */ + msg = create_message(PCEP_TYPE_REPORT, PCEP_OBJ_CLASS_SRP, + PCEP_OBJ_CLASS_LSP, any_obj_class, any_obj_class); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid Update message */ + msg = create_message(PCEP_TYPE_UPDATE, PCEP_OBJ_CLASS_SRP, + PCEP_OBJ_CLASS_LSP, any_obj_class, any_obj_class); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid Initiate message */ + msg = create_message(PCEP_TYPE_INITIATE, PCEP_OBJ_CLASS_SRP, + PCEP_OBJ_CLASS_LSP, any_obj_class, any_obj_class); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); +} + +void test_validate_message_objects_invalid() +{ + /* unsupported message ID = 0 + * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ + struct pcep_message *msg = create_message(0, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Open message + * {PCEP_OBJ_CLASS_OPEN, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ + msg = create_message(PCEP_TYPE_OPEN, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_OPEN, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_OPEN, PCEP_OBJ_CLASS_OPEN, any_obj_class, + 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* KeepAlive message + * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ + msg = create_message(PCEP_TYPE_KEEPALIVE, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* PcReq message + * {PCEP_OBJ_CLASS_RP, PCEP_OBJ_CLASS_ENDPOINTS, ANY_OBJECT, ANY_OBJECT} + */ + msg = create_message(PCEP_TYPE_PCREQ, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_PCREQ, PCEP_OBJ_CLASS_RP, any_obj_class, + 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* PcRep message + * {PCEP_OBJ_CLASS_RP, ANY_OBJECT, ANY_OBJECT, ANY_OBJECT} */ + msg = create_message(PCEP_TYPE_PCREP, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_PCREP, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Notify message + * {PCEP_OBJ_CLASS_NOTF, ANY_OBJECT, ANY_OBJECT, ANY_OBJECT} */ + msg = create_message(PCEP_TYPE_PCNOTF, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_PCNOTF, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Error message + * {PCEP_OBJ_CLASS_ERROR, ANY_OBJECT, ANY_OBJECT, ANY_OBJECT} */ + msg = create_message(PCEP_TYPE_ERROR, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_ERROR, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Close message + * {PCEP_OBJ_CLASS_CLOSE, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ + msg = create_message(PCEP_TYPE_CLOSE, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_CLOSE, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* unsupported message ID = 8 + * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ + msg = create_message(8, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* unsupported message ID = 9 + * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ + msg = create_message(9, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Report message + * {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, ANY_OBJECT} */ + msg = create_message(PCEP_TYPE_REPORT, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_REPORT, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_REPORT, PCEP_OBJ_CLASS_SRP, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_REPORT, PCEP_OBJ_CLASS_SRP, + any_obj_class, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Update message + * {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, ANY_OBJECT} */ + msg = create_message(PCEP_TYPE_UPDATE, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_UPDATE, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_UPDATE, PCEP_OBJ_CLASS_SRP, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_UPDATE, PCEP_OBJ_CLASS_SRP, + any_obj_class, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Initiate message + * {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, ANY_OBJECT} */ + msg = create_message(PCEP_TYPE_INITIATE, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_INITIATE, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_INITIATE, PCEP_OBJ_CLASS_SRP, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_INITIATE, PCEP_OBJ_CLASS_SRP, + any_obj_class, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); +} diff --git a/pceplib/test/pcep_msg_tools_test.h b/pceplib/test/pcep_msg_tools_test.h new file mode 100644 index 000000000..dc6639080 --- /dev/null +++ b/pceplib/test/pcep_msg_tools_test.h @@ -0,0 +1,48 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_MSG_TOOLS_TEST_H_ +#define PCEP_MSG_TOOLS_TEST_H_ + + +int pcep_tools_test_suite_setup(void); +int pcep_tools_test_suite_teardown(void); +void pcep_tools_test_setup(void); +void pcep_tools_test_teardown(void); +void test_pcep_msg_read_pcep_initiate(void); +void test_pcep_msg_read_pcep_initiate2(void); +void test_pcep_msg_read_pcep_update(void); +void test_pcep_msg_read_pcep_open(void); +void test_pcep_msg_read_pcep_open_initiate(void); +void test_validate_message_header(void); +void test_validate_message_objects(void); +void test_validate_message_objects_invalid(void); +void test_pcep_msg_read_pcep_open_cisco_pce(void); +void test_pcep_msg_read_pcep_update_cisco_pce(void); +void test_pcep_msg_read_pcep_report_cisco_pcc(void); +void test_pcep_msg_read_pcep_initiate_cisco_pcc(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_pcc_api_test.c b/pceplib/test/pcep_pcc_api_test.c new file mode 100644 index 000000000..c227dc1a3 --- /dev/null +++ b/pceplib/test/pcep_pcc_api_test.c @@ -0,0 +1,285 @@ +/* + * 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> + * + */ + + +#include <netdb.h> // gethostbyname +#include <pthread.h> +#include <stdlib.h> +#include <unistd.h> + +#include <CUnit/CUnit.h> + +#include "pcep_pcc_api.h" +#include "pcep_pcc_api_test.h" +#include "pcep_socket_comm_mock.h" +#include "pcep_utils_memory.h" + +extern pcep_event_queue *session_logic_event_queue_; +extern const char MESSAGE_RECEIVED_STR[]; +extern const char UNKNOWN_EVENT_STR[]; + +/* + * Test suite setup and teardown called before AND after the test suite. + */ + +int pcep_pcc_api_test_suite_setup() +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_pcc_api_test_suite_teardown() +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +/* + * Test case setup and teardown called before AND after each test. + */ + +void pcep_pcc_api_test_setup() +{ + setup_mock_socket_comm_info(); +} + + +void pcep_pcc_api_test_teardown() +{ + teardown_mock_socket_comm_info(); +} + +/* + * Unit test cases + */ + +void test_initialize_pcc() +{ + CU_ASSERT_TRUE(initialize_pcc()); + /* Give the PCC time to initialize */ + sleep(1); + CU_ASSERT_TRUE(destroy_pcc()); +} + +void test_connect_pce() +{ + pcep_configuration *config = create_default_pcep_configuration(); + struct hostent *host_info = gethostbyname("localhost"); + struct in_addr dest_address; + memcpy(&dest_address, host_info->h_addr, host_info->h_length); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + initialize_pcc(); + + pcep_session *session = connect_pce(config, &dest_address); + + CU_ASSERT_PTR_NOT_NULL(session); + CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 1); + /* 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 *open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN); + + pcep_msg_free_message(open_msg); + destroy_pcep_session(session); + destroy_pcep_configuration(config); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + destroy_pcc(); +} + +void test_connect_pce_ipv6() +{ + pcep_configuration *config = create_default_pcep_configuration(); + struct in6_addr dest_address; + dest_address.__in6_u.__u6_addr32[0] = 0; + dest_address.__in6_u.__u6_addr32[1] = 0; + dest_address.__in6_u.__u6_addr32[2] = 0; + dest_address.__in6_u.__u6_addr32[3] = htonl(1); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + initialize_pcc(); + + pcep_session *session = connect_pce_ipv6(config, &dest_address); + + CU_ASSERT_PTR_NOT_NULL(session); + CU_ASSERT_TRUE(session->socket_comm_session->is_ipv6); + CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 1); + /* 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 *open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN); + + pcep_msg_free_message(open_msg); + destroy_pcep_session(session); + destroy_pcep_configuration(config); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + destroy_pcc(); +} + +void test_connect_pce_with_src_ip() +{ + pcep_configuration *config = create_default_pcep_configuration(); + struct hostent *host_info = gethostbyname("localhost"); + struct in_addr dest_address; + memcpy(&dest_address, host_info->h_addr, host_info->h_length); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + config->src_ip.src_ipv4.s_addr = 0x0a0a0102; + + initialize_pcc(); + + pcep_session *session = connect_pce(config, &dest_address); + + CU_ASSERT_PTR_NOT_NULL(session); + CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 1); + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + struct pcep_message *open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN); + + pcep_msg_free_message(open_msg); + destroy_pcep_session(session); + destroy_pcep_configuration(config); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + destroy_pcc(); +} + +void test_disconnect_pce() +{ + pcep_configuration *config = create_default_pcep_configuration(); + struct hostent *host_info = gethostbyname("localhost"); + struct in_addr dest_address; + memcpy(&dest_address, host_info->h_addr, host_info->h_length); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + initialize_pcc(); + + pcep_session *session = connect_pce(config, &dest_address); + disconnect_pce(session); + + CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 2); + + /* First there should be an open message from connect_pce() */ + 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); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN); + pcep_msg_free_message(msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + /* Then there should be a close message from disconnect_pce() */ + encoded_msg = dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(msg); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_CLOSE); + + pcep_msg_free_message(msg); + destroy_pcep_session(session); + destroy_pcep_configuration(config); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + destroy_pcc(); +} + + +void test_send_message() +{ + pcep_configuration *config = create_default_pcep_configuration(); + struct hostent *host_info = gethostbyname("localhost"); + struct in_addr dest_address; + + initialize_pcc(); + + memcpy(&dest_address, host_info->h_addr, host_info->h_length); + pcep_session *session = connect_pce(config, &dest_address); + verify_socket_comm_times_called(0, 0, 1, 1, 0, 0, 0); + + struct pcep_message *msg = pcep_msg_create_keepalive(); + send_message(session, msg, false); + + verify_socket_comm_times_called(0, 0, 1, 2, 0, 0, 0); + + pcep_msg_free_message(msg); + destroy_pcep_session(session); + destroy_pcep_configuration(config); + + destroy_pcc(); +} + +void test_event_queue() +{ + /* This initializes the event_queue */ + CU_ASSERT_TRUE(initialize_pcc()); + + /* Verify correct behavior when the queue is empty */ + CU_ASSERT_TRUE(event_queue_is_empty()); + CU_ASSERT_EQUAL(event_queue_num_events_available(), 0); + CU_ASSERT_PTR_NULL(event_queue_get_event()); + destroy_pcep_event(NULL); + + /* Create an empty event and put it on the queue */ + pcep_event *event = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event)); + memset(event, 0, sizeof(pcep_event)); + pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex); + queue_enqueue(session_logic_event_queue_->event_queue, event); + pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex); + + /* Verify correct behavior when there is an entry in the queue */ + CU_ASSERT_FALSE(event_queue_is_empty()); + CU_ASSERT_EQUAL(event_queue_num_events_available(), 1); + pcep_event *queued_event = event_queue_get_event(); + CU_ASSERT_PTR_NOT_NULL(queued_event); + CU_ASSERT_PTR_EQUAL(event, queued_event); + destroy_pcep_event(queued_event); + + CU_ASSERT_TRUE(destroy_pcc()); +} + +void test_get_event_type_str() +{ + CU_ASSERT_EQUAL(strcmp(get_event_type_str(MESSAGE_RECEIVED), + MESSAGE_RECEIVED_STR), + 0); + CU_ASSERT_EQUAL(strcmp(get_event_type_str(1000), UNKNOWN_EVENT_STR), 0); +} diff --git a/pceplib/test/pcep_pcc_api_test.h b/pceplib/test/pcep_pcc_api_test.h new file mode 100644 index 000000000..d3db96e0c --- /dev/null +++ b/pceplib/test/pcep_pcc_api_test.h @@ -0,0 +1,43 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_PCC_API_TEST_ +#define PCEP_PCC_API_TEST_ + +int pcep_pcc_api_test_suite_setup(void); +int pcep_pcc_api_test_suite_teardown(void); +void pcep_pcc_api_test_setup(void); +void pcep_pcc_api_test_teardown(void); +void test_initialize_pcc(void); +void test_connect_pce(void); +void test_connect_pce_ipv6(void); +void test_connect_pce_with_src_ip(void); +void test_disconnect_pce(void); +void test_send_message(void); +void test_event_queue(void); +void test_get_event_type_str(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_pcc_api_tests.c b/pceplib/test/pcep_pcc_api_tests.c new file mode 100644 index 000000000..04895d634 --- /dev/null +++ b/pceplib/test/pcep_pcc_api_tests.c @@ -0,0 +1,88 @@ +/* + * 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> + * + */ + + +#include <CUnit/Basic.h> +#include <CUnit/CUnit.h> +#include <CUnit/TestDB.h> + +#include "pcep_pcc_api_test.h" + +int main(int argc, char **argv) +{ + /* Unused parameters cause compilation warnings */ + (void)argc; + (void)argv; + + CU_initialize_registry(); + + /* + * Tests defined in pcep_socket_comm_test.c + */ + CU_pSuite test_pcc_api_suite = CU_add_suite_with_setup_and_teardown( + "PCEP PCC API Test Suite", + pcep_pcc_api_test_suite_setup, // suite setup and cleanup + // function pointers + pcep_pcc_api_test_suite_teardown, + pcep_pcc_api_test_setup, // test case setup function pointer + pcep_pcc_api_test_teardown); // test case teardown function + // pointer + + CU_add_test(test_pcc_api_suite, "test_initialize_pcc", + test_initialize_pcc); + CU_add_test(test_pcc_api_suite, "test_connect_pce", test_connect_pce); + CU_add_test(test_pcc_api_suite, "test_connect_pce_ipv6", + test_connect_pce_ipv6); + CU_add_test(test_pcc_api_suite, "test_connect_pce_with_src_ip", + test_connect_pce_with_src_ip); + CU_add_test(test_pcc_api_suite, "test_disconnect_pce", + test_disconnect_pce); + CU_add_test(test_pcc_api_suite, "test_send_message", test_send_message); + CU_add_test(test_pcc_api_suite, "test_event_queue", test_event_queue); + CU_add_test(test_pcc_api_suite, "test_get_event_type_str", + test_get_event_type_str); + + /* + * Run the tests and cleanup. + */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_FailureRecord *failure_record = CU_get_failure_list(); + if (failure_record != NULL) { + printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n"); + do { + printf("\t [%s] [%s] [%s:%d]\n", + failure_record->pSuite->pName, + failure_record->pTest->pName, + failure_record->strFileName, + failure_record->uiLineNumber); + failure_record = failure_record->pNext; + + } while (failure_record != NULL); + } + + CU_pRunSummary run_summary = CU_get_run_summary(); + int result = run_summary->nTestsFailed; + CU_cleanup_registry(); + + return result; +} diff --git a/pceplib/test/pcep_pcc_api_tests_valgrind.sh b/pceplib/test/pcep_pcc_api_tests_valgrind.sh new file mode 100755 index 000000000..74494b752 --- /dev/null +++ b/pceplib/test/pcep_pcc_api_tests_valgrind.sh @@ -0,0 +1,2 @@ +source pceplib/test/pcep_tests_valgrind.sh +valgrind_test pceplib/test/pcep_pcc_api_tests diff --git a/pceplib/test/pcep_session_logic_loop_test.c b/pceplib/test/pcep_session_logic_loop_test.c new file mode 100644 index 000000000..38fabd4cc --- /dev/null +++ b/pceplib/test/pcep_session_logic_loop_test.c @@ -0,0 +1,219 @@ +/* + * 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> + * + */ + + +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <CUnit/CUnit.h> + +#include "pcep_msg_encoding.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_memory.h" +#include "pcep_session_logic_loop_test.h" + + +extern pcep_session_logic_handle *session_logic_handle_; +extern pcep_event_queue *session_logic_event_queue_; + +/* + * Test suite setup and teardown called before AND after the test suite. + */ + +int pcep_session_logic_loop_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_session_logic_loop_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_loop_test_setup() +{ + /* We need to setup the session_logic_handle_ without starting the + * thread */ + session_logic_handle_ = pceplib_malloc( + PCEPLIB_INFRA, sizeof(pcep_session_logic_handle)); + memset(session_logic_handle_, 0, sizeof(pcep_session_logic_handle)); + session_logic_handle_->active = true; + session_logic_handle_->session_logic_condition = false; + session_logic_handle_->session_list = + ordered_list_initialize(pointer_compare_function); + session_logic_handle_->session_event_queue = queue_initialize(); + pthread_cond_init(&(session_logic_handle_->session_logic_cond_var), + NULL); + pthread_mutex_init(&(session_logic_handle_->session_logic_mutex), NULL); + pthread_mutex_init(&(session_logic_handle_->session_list_mutex), NULL); + + 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(); +} + + +void pcep_session_logic_loop_test_teardown() +{ + ordered_list_destroy(session_logic_handle_->session_list); + queue_destroy(session_logic_handle_->session_event_queue); + pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex)); + pthread_mutex_destroy(&(session_logic_handle_->session_logic_mutex)); + pthread_mutex_destroy(&(session_logic_handle_->session_list_mutex)); + pceplib_free(PCEPLIB_INFRA, session_logic_handle_); + session_logic_handle_ = NULL; + + queue_destroy(session_logic_event_queue_->event_queue); + pceplib_free(PCEPLIB_INFRA, session_logic_event_queue_); + session_logic_event_queue_ = NULL; +} + + +/* + * Test cases + */ + +void test_session_logic_loop_null_data() +{ + /* Just testing that it does not core dump */ + session_logic_loop(NULL); +} + + +void test_session_logic_loop_inactive() +{ + session_logic_handle_->active = false; + + session_logic_loop(session_logic_handle_); +} + + +void test_session_logic_msg_ready_handler() +{ + /* Just testing that it does not core dump */ + CU_ASSERT_EQUAL(session_logic_msg_ready_handler(NULL, 0), -1); + + /* Read from an empty file should return 0, thus + * session_logic_msg_ready_handler returns -1 */ + int fd = fileno(tmpfile()); + pcep_session session; + memset(&session, 0, sizeof(pcep_session)); + session.session_id = 100; + CU_ASSERT_EQUAL(session_logic_msg_ready_handler(&session, fd), 0); + CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries, + 1); + 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); + pcep_session_event *socket_event = (pcep_session_event *)queue_dequeue( + session_logic_handle_->session_event_queue); + CU_ASSERT_PTR_NOT_NULL(socket_event); + CU_ASSERT_TRUE(socket_event->socket_closed); + pceplib_free(PCEPLIB_INFRA, socket_event); + + /* A pcep_session_event should be created */ + struct pcep_versioning *versioning = create_default_pcep_versioning(); + struct pcep_message *keep_alive_msg = pcep_msg_create_keepalive(); + pcep_encode_message(keep_alive_msg, versioning); + int retval = write(fd, (char *)keep_alive_msg->encoded_message, + keep_alive_msg->encoded_message_length); + CU_ASSERT_TRUE(retval > 0); + lseek(fd, 0, SEEK_SET); + CU_ASSERT_EQUAL(session_logic_msg_ready_handler(&session, fd), + keep_alive_msg->encoded_message_length); + CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries, + 1); + socket_event = (pcep_session_event *)queue_dequeue( + session_logic_handle_->session_event_queue); + CU_ASSERT_PTR_NOT_NULL(socket_event); + CU_ASSERT_FALSE(socket_event->socket_closed); + CU_ASSERT_PTR_EQUAL(socket_event->session, &session); + CU_ASSERT_EQUAL(socket_event->expired_timer_id, TIMER_ID_NOT_SET); + CU_ASSERT_PTR_NOT_NULL(socket_event->received_msg_list); + pcep_msg_free_message_list(socket_event->received_msg_list); + pcep_msg_free_message(keep_alive_msg); + destroy_pcep_versioning(versioning); + pceplib_free(PCEPLIB_INFRA, socket_event); + close(fd); +} + + +void test_session_logic_conn_except_notifier() +{ + /* Just testing that it does not core dump */ + session_logic_conn_except_notifier(NULL, 1); + + /* A pcep_session_event should be created */ + pcep_session session; + memset(&session, 0, sizeof(pcep_session)); + session.session_id = 100; + session_logic_conn_except_notifier(&session, 10); + CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries, + 1); + pcep_session_event *socket_event = (pcep_session_event *)queue_dequeue( + session_logic_handle_->session_event_queue); + CU_ASSERT_PTR_NOT_NULL_FATAL(socket_event); + CU_ASSERT_TRUE(socket_event->socket_closed); + CU_ASSERT_PTR_EQUAL(socket_event->session, &session); + CU_ASSERT_EQUAL(socket_event->expired_timer_id, TIMER_ID_NOT_SET); + CU_ASSERT_PTR_NULL(socket_event->received_msg_list); + + pceplib_free(PCEPLIB_INFRA, socket_event); +} + + +void test_session_logic_timer_expire_handler() +{ + /* Just testing that it does not core dump */ + session_logic_timer_expire_handler(NULL, 42); + + /* A pcep_session_event should be created */ + pcep_session session; + memset(&session, 0, sizeof(pcep_session)); + session.session_id = 100; + session_logic_timer_expire_handler(&session, 42); + CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries, + 1); + pcep_session_event *socket_event = (pcep_session_event *)queue_dequeue( + session_logic_handle_->session_event_queue); + CU_ASSERT_PTR_NOT_NULL_FATAL(socket_event); + CU_ASSERT_FALSE(socket_event->socket_closed); + CU_ASSERT_PTR_EQUAL(socket_event->session, &session); + CU_ASSERT_EQUAL(socket_event->expired_timer_id, 42); + CU_ASSERT_PTR_NULL(socket_event->received_msg_list); + + pceplib_free(PCEPLIB_INFRA, socket_event); +} diff --git a/pceplib/test/pcep_session_logic_loop_test.h b/pceplib/test/pcep_session_logic_loop_test.h new file mode 100644 index 000000000..ae3c3e375 --- /dev/null +++ b/pceplib/test/pcep_session_logic_loop_test.h @@ -0,0 +1,40 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_SESSION_LOGIC_LOOP_TEST_H_ +#define PCEP_SESSION_LOGIC_LOOP_TEST_H_ + +int pcep_session_logic_loop_test_suite_setup(void); +int pcep_session_logic_loop_test_suite_teardown(void); +void pcep_session_logic_loop_test_setup(void); +void pcep_session_logic_loop_test_teardown(void); +void test_session_logic_loop_null_data(void); +void test_session_logic_loop_inactive(void); +void test_session_logic_msg_ready_handler(void); +void test_session_logic_conn_except_notifier(void); +void test_session_logic_timer_expire_handler(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ 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 000000000..f75c16e39 --- /dev/null +++ b/pceplib/test/pcep_session_logic_states_test.c @@ -0,0 +1,919 @@ +/* + * 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> + * + */ + + +#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 doesnt 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); + 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); + 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); + /* 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); + 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); + 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); + 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); + 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); + msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(msg); + 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); +} diff --git a/pceplib/test/pcep_session_logic_states_test.h b/pceplib/test/pcep_session_logic_states_test.h new file mode 100644 index 000000000..e42b501ed --- /dev/null +++ b/pceplib/test/pcep_session_logic_states_test.h @@ -0,0 +1,52 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_SESSION_LOGIC_STATES_TEST_H +#define PCEP_SESSION_LOGIC_STATES_TEST_H + +int pcep_session_logic_states_test_suite_setup(void); +int pcep_session_logic_states_test_suite_teardown(void); +void pcep_session_logic_states_test_setup(void); +void pcep_session_logic_states_test_teardown(void); +void test_handle_timer_event_dead_timer(void); +void test_handle_timer_event_keep_alive(void); +void test_handle_timer_event_open_keep_wait(void); +void test_handle_socket_comm_event_null_params(void); +void test_handle_socket_comm_event_close(void); +void test_handle_socket_comm_event_open(void); +void test_handle_socket_comm_event_open_error(void); +void test_handle_socket_comm_event_keep_alive(void); +void test_handle_socket_comm_event_pcrep(void); +void test_handle_socket_comm_event_pcreq(void); +void test_handle_socket_comm_event_report(void); +void test_handle_socket_comm_event_update(void); +void test_handle_socket_comm_event_initiate(void); +void test_handle_socket_comm_event_notify(void); +void test_handle_socket_comm_event_error(void); +void test_handle_socket_comm_event_unknown_msg(void); +void test_connection_failure(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_session_logic_test.c b/pceplib/test/pcep_session_logic_test.c new file mode 100644 index 000000000..66db4fbae --- /dev/null +++ b/pceplib/test/pcep_session_logic_test.c @@ -0,0 +1,360 @@ +/* + * 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> + * + */ + + +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <CUnit/CUnit.h> + +#include "pcep_socket_comm_mock.h" +#include "pcep_session_logic.h" +#include "pcep_session_logic_test.h" + +/* + * Test suite setup and teardown called before AND after the test suite. + */ + +int pcep_session_logic_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_session_logic_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_test_setup() +{ + setup_mock_socket_comm_info(); +} + + +void pcep_session_logic_test_teardown() +{ + stop_session_logic(); + teardown_mock_socket_comm_info(); +} + + +/* + * Test cases + */ + +void test_run_stop_session_logic() +{ + CU_ASSERT_TRUE(run_session_logic()); + CU_ASSERT_TRUE(stop_session_logic()); +} + + +void test_run_session_logic_twice() +{ + CU_ASSERT_TRUE(run_session_logic()); + CU_ASSERT_FALSE(run_session_logic()); +} + + +void test_session_logic_without_run() +{ + /* Verify the functions that depend on run_session_logic() being called + */ + CU_ASSERT_FALSE(stop_session_logic()); +} + + +void test_create_pcep_session_null_params() +{ + pcep_configuration config; + struct in_addr pce_ip; + + CU_ASSERT_PTR_NULL(create_pcep_session(NULL, NULL)); + CU_ASSERT_PTR_NULL(create_pcep_session(NULL, &pce_ip)); + CU_ASSERT_PTR_NULL(create_pcep_session(&config, NULL)); +} + + +void test_create_destroy_pcep_session() +{ + pcep_session *session; + pcep_configuration config; + struct in_addr pce_ip; + + run_session_logic(); + + memset(&config, 0, sizeof(pcep_configuration)); + config.keep_alive_seconds = 5; + config.dead_timer_seconds = 5; + config.request_time_seconds = 5; + config.max_unknown_messages = 5; + config.max_unknown_requests = 5; + inet_pton(AF_INET, "127.0.0.1", &(pce_ip)); + + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + session = create_pcep_session(&config, &pce_ip); + CU_ASSERT_PTR_NOT_NULL(session); + /* 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 *open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + /* Should be an Open, with no TLVs: length = 12 */ + CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN); + CU_ASSERT_EQUAL(open_msg->encoded_message_length, 12); + destroy_pcep_session(session); + pcep_msg_free_message(open_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + stop_session_logic(); +} + + +void test_create_destroy_pcep_session_ipv6() +{ + pcep_session *session; + pcep_configuration config; + struct in6_addr pce_ip; + + run_session_logic(); + + memset(&config, 0, sizeof(pcep_configuration)); + config.keep_alive_seconds = 5; + config.dead_timer_seconds = 5; + config.request_time_seconds = 5; + config.max_unknown_messages = 5; + config.max_unknown_requests = 5; + config.is_src_ipv6 = true; + inet_pton(AF_INET6, "::1", &pce_ip); + + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + session = create_pcep_session_ipv6(&config, &pce_ip); + CU_ASSERT_PTR_NOT_NULL(session); + CU_ASSERT_TRUE(session->socket_comm_session->is_ipv6); + /* 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 *open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + /* Should be an Open, with no TLVs: length = 12 */ + CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN); + CU_ASSERT_EQUAL(open_msg->encoded_message_length, 12); + destroy_pcep_session(session); + pcep_msg_free_message(open_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + stop_session_logic(); +} + + +void test_create_pcep_session_open_tlvs() +{ + pcep_session *session; + struct in_addr pce_ip; + struct pcep_message *open_msg; + struct pcep_object_header *open_obj; + pcep_configuration config; + memset(&config, 0, sizeof(pcep_configuration)); + config.pcep_msg_versioning = create_default_pcep_versioning(); + inet_pton(AF_INET, "127.0.0.1", &(pce_ip)); + + run_session_logic(); + + /* Verify the created Open message only has 1 TLV: + * pcep_tlv_create_stateful_pce_capability() */ + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + config.support_stateful_pce_lsp_update = true; + config.pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = false; + config.support_sr_te_pst = false; + + session = create_pcep_session(&config, &pce_ip); + CU_ASSERT_PTR_NOT_NULL(session); + /* Get and verify the Open Message */ + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + /* Get and verify the Open Message objects */ + CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list); + CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0); + /* Get and verify the Open object */ + open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_PTR_NOT_NULL(open_obj); + /* Get and verify the Open object TLVs */ + CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list); + CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 1); + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *) + open_obj->tlv_list->head->data) + ->type, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + + destroy_pcep_session(session); + pcep_msg_free_message(open_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + /* Verify the created Open message only has 2 TLVs: + * pcep_tlv_create_stateful_pce_capability() + * pcep_tlv_create_lsp_db_version() */ + reset_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + config.support_include_db_version = true; + config.lsp_db_version = 100; + + session = create_pcep_session(&config, &pce_ip); + CU_ASSERT_PTR_NOT_NULL(session); + /* Get and verify the Open Message */ + encoded_msg = dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + /* Get and verify the Open Message objects */ + CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list); + CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0); + /* Get and verify the Open object */ + open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_PTR_NOT_NULL(open_obj); + /* Get and verify the Open object TLVs */ + CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list); + CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 2); + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *) + open_obj->tlv_list->head->data) + ->type, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *) + open_obj->tlv_list->head->next_node->data) + ->type, + PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION); + + destroy_pcep_session(session); + pcep_msg_free_message(open_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + + /* Verify the created Open message only has 4 TLVs: + * pcep_tlv_create_stateful_pce_capability() + * pcep_tlv_create_lsp_db_version() + * pcep_tlv_create_sr_pce_capability() + * pcep_tlv_create_path_setup_type_capability() */ + reset_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + config.support_sr_te_pst = true; + + session = create_pcep_session(&config, &pce_ip); + CU_ASSERT_PTR_NOT_NULL(session); + /* Get and verify the Open Message */ + encoded_msg = dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + /* Get and verify the Open Message objects */ + CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list); + CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0); + /* Get and verify the Open object */ + open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_PTR_NOT_NULL(open_obj); + /* Get and verify the Open object TLVs */ + CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list); + CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 3); + double_linked_list_node *tlv_node = open_obj->tlv_list->head; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + tlv_node = tlv_node->next_node; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION); + tlv_node = tlv_node->next_node; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY); + + destroy_pcep_session(session); + pcep_msg_free_message(open_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + /* Verify the created Open message only has 4 TLVs: + * pcep_tlv_create_stateful_pce_capability() + * pcep_tlv_create_lsp_db_version() + * pcep_tlv_create_sr_pce_capability() + * pcep_tlv_create_path_setup_type_capability() */ + reset_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + config.pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = true; + + session = create_pcep_session(&config, &pce_ip); + CU_ASSERT_PTR_NOT_NULL(session); + /* Get and verify the Open Message */ + encoded_msg = dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + /* Get and verify the Open Message objects */ + CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list); + CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0); + /* Get and verify the Open object */ + open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_PTR_NOT_NULL(open_obj); + /* Get and verify the Open object TLVs */ + CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list); + CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 4); + tlv_node = open_obj->tlv_list->head; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + tlv_node = tlv_node->next_node; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION); + tlv_node = tlv_node->next_node; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY); + tlv_node = tlv_node->next_node; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY); + + destroy_pcep_versioning(config.pcep_msg_versioning); + destroy_pcep_session(session); + pcep_msg_free_message(open_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + stop_session_logic(); +} + + +void test_destroy_pcep_session_null_session() +{ + /* Just testing that it does not core dump */ + destroy_pcep_session(NULL); +} diff --git a/pceplib/test/pcep_session_logic_test.h b/pceplib/test/pcep_session_logic_test.h new file mode 100644 index 000000000..6cc196325 --- /dev/null +++ b/pceplib/test/pcep_session_logic_test.h @@ -0,0 +1,43 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_SESSION_LOGIC_TEST_H_ +#define PCEP_SESSION_LOGIC_TEST_H_ + +int pcep_session_logic_test_suite_setup(void); +int pcep_session_logic_test_suite_teardown(void); +void pcep_session_logic_test_setup(void); +void pcep_session_logic_test_teardown(void); +void test_run_stop_session_logic(void); +void test_run_session_logic_twice(void); +void test_session_logic_without_run(void); +void test_create_pcep_session_null_params(void); +void test_create_destroy_pcep_session(void); +void test_create_destroy_pcep_session_ipv6(void); +void test_create_pcep_session_open_tlvs(void); +void test_destroy_pcep_session_null_session(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_session_logic_tests.c b/pceplib/test/pcep_session_logic_tests.c new file mode 100644 index 000000000..67bf6e22e --- /dev/null +++ b/pceplib/test/pcep_session_logic_tests.c @@ -0,0 +1,201 @@ +/* + * 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> + * + */ + + +#include <CUnit/Basic.h> +#include <CUnit/CUnit.h> +#include <CUnit/TestDB.h> + +#include "pcep_session_logic_loop_test.h" +#include "pcep_session_logic_states_test.h" +#include "pcep_session_logic_test.h" + + +int main(int argc, char **argv) +{ + /* Unused parameters cause compilation warnings */ + (void)argc; + (void)argv; + + CU_initialize_registry(); + + /* + * Tests defined in pcep_socket_comm_test.c + */ + CU_pSuite test_session_logic_suite = + CU_add_suite_with_setup_and_teardown( + "PCEP Session Logic Test Suite", + pcep_session_logic_test_suite_setup, // suite setup and + // cleanup function + // pointers + pcep_session_logic_test_suite_teardown, + pcep_session_logic_test_setup, // test case setup + // function pointer + pcep_session_logic_test_teardown); // test case teardown + // function pointer + + CU_add_test(test_session_logic_suite, "test_run_stop_session_logic", + test_run_stop_session_logic); + CU_add_test(test_session_logic_suite, "test_run_session_logic_twice", + test_run_session_logic_twice); + CU_add_test(test_session_logic_suite, "test_session_logic_without_run", + test_session_logic_without_run); + CU_add_test(test_session_logic_suite, + "test_create_pcep_session_null_params", + test_create_pcep_session_null_params); + CU_add_test(test_session_logic_suite, + "test_create_destroy_pcep_session", + test_create_destroy_pcep_session); + CU_add_test(test_session_logic_suite, + "test_create_destroy_pcep_session_ipv6", + test_create_destroy_pcep_session_ipv6); + CU_add_test(test_session_logic_suite, + "test_create_pcep_session_open_tlvs", + test_create_pcep_session_open_tlvs); + CU_add_test(test_session_logic_suite, + "test_destroy_pcep_session_null_session", + test_destroy_pcep_session_null_session); + + CU_pSuite test_session_logic_loop_suite = + CU_add_suite_with_setup_and_teardown( + "PCEP Session Logic Loop Test Suite", + pcep_session_logic_loop_test_suite_setup, // suite setup + // and cleanup + // function + // pointers + pcep_session_logic_loop_test_suite_teardown, + pcep_session_logic_loop_test_setup, // test case setup + // function pointer + pcep_session_logic_loop_test_teardown); // test case + // teardown + // function + // pointer + + CU_add_test(test_session_logic_loop_suite, + "test_session_logic_loop_null_data", + test_session_logic_loop_null_data); + CU_add_test(test_session_logic_loop_suite, + "test_session_logic_loop_inactive", + test_session_logic_loop_inactive); + CU_add_test(test_session_logic_loop_suite, + "test_session_logic_msg_ready_handler", + test_session_logic_msg_ready_handler); + CU_add_test(test_session_logic_loop_suite, + "test_session_logic_conn_except_notifier", + test_session_logic_conn_except_notifier); + CU_add_test(test_session_logic_loop_suite, + "test_session_logic_timer_expire_handler", + test_session_logic_timer_expire_handler); + + CU_pSuite test_session_logic_states_suite = + CU_add_suite_with_setup_and_teardown( + "PCEP Session Logic States Test Suite", + pcep_session_logic_states_test_suite_setup, // suite + // setup and + // cleanup + // function + // pointers + pcep_session_logic_states_test_suite_teardown, + pcep_session_logic_states_test_setup, // test case setup + // function + // pointer + pcep_session_logic_states_test_teardown); // test case + // teardown + // function + // pointer + + CU_add_test(test_session_logic_states_suite, + "test_handle_timer_event_dead_timer", + test_handle_timer_event_dead_timer); + CU_add_test(test_session_logic_states_suite, + "test_handle_timer_event_keep_alive", + test_handle_timer_event_keep_alive); + CU_add_test(test_session_logic_states_suite, + "test_handle_timer_event_open_keep_wait", + test_handle_timer_event_open_keep_wait); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_null_params", + test_handle_socket_comm_event_null_params); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_close", + test_handle_socket_comm_event_close); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_open", + test_handle_socket_comm_event_open); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_open_error", + test_handle_socket_comm_event_open_error); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_keep_alive", + test_handle_socket_comm_event_keep_alive); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_pcrep", + test_handle_socket_comm_event_pcrep); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_pcreq", + test_handle_socket_comm_event_pcreq); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_report", + test_handle_socket_comm_event_report); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_update", + test_handle_socket_comm_event_update); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_initiate", + test_handle_socket_comm_event_initiate); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_notify", + test_handle_socket_comm_event_notify); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_error", + test_handle_socket_comm_event_error); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_unknown_msg", + test_handle_socket_comm_event_unknown_msg); + CU_add_test(test_session_logic_states_suite, "test_connection_failure", + test_connection_failure); + + /* + * Run the tests and cleanup. + */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_FailureRecord *failure_record = CU_get_failure_list(); + if (failure_record != NULL) { + printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n"); + do { + printf("\t [%s] [%s] [%s:%d]\n", + failure_record->pSuite->pName, + failure_record->pTest->pName, + failure_record->strFileName, + failure_record->uiLineNumber); + failure_record = failure_record->pNext; + + } while (failure_record != NULL); + } + + CU_pRunSummary run_summary = CU_get_run_summary(); + int result = run_summary->nTestsFailed; + CU_cleanup_registry(); + + return result; +} diff --git a/pceplib/test/pcep_session_logic_tests_valgrind.sh b/pceplib/test/pcep_session_logic_tests_valgrind.sh new file mode 100755 index 000000000..435bb3d5c --- /dev/null +++ b/pceplib/test/pcep_session_logic_tests_valgrind.sh @@ -0,0 +1,2 @@ +source pceplib/test/pcep_tests_valgrind.sh +valgrind_test pceplib/test/pcep_session_logic_tests diff --git a/pceplib/test/pcep_socket_comm_loop_test.c b/pceplib/test/pcep_socket_comm_loop_test.c new file mode 100644 index 000000000..94f0983ca --- /dev/null +++ b/pceplib/test/pcep_socket_comm_loop_test.c @@ -0,0 +1,194 @@ +/* + * 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> + * + */ + + +#include <pthread.h> +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "pcep_socket_comm_internals.h" +#include "pcep_socket_comm_loop.h" +#include "pcep_socket_comm_loop_test.h" +#include "pcep_socket_comm.h" +#include "pcep_utils_memory.h" + +void test_loop_conn_except_notifier(void *session_data, int socket_fd); + +/* + * Functions to be tested, implemented in pcep_socket_comm_loop.c + */ + +typedef struct ready_to_read_handler_info_ { + bool handler_called; + bool except_handler_called; + void *data; + int socket_fd; + int bytes_read; + +} ready_to_read_handler_info; + +static ready_to_read_handler_info read_handler_info; +static pcep_socket_comm_session *test_comm_session; +static pcep_socket_comm_handle *test_socket_comm_handle = NULL; + +static int test_loop_message_ready_to_read_handler(void *session_data, + int socket_fd) +{ + read_handler_info.handler_called = true; + read_handler_info.data = session_data; + read_handler_info.socket_fd = socket_fd; + + return read_handler_info.bytes_read; +} + + +void test_loop_conn_except_notifier(void *session_data, int socket_fd) +{ + (void)session_data; + (void)socket_fd; + read_handler_info.except_handler_called = true; +} + + +/* + * Test case setup and teardown called before AND after each test. + */ +void pcep_socket_comm_loop_test_setup() +{ + test_socket_comm_handle = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_handle)); + memset(test_socket_comm_handle, 0, sizeof(pcep_socket_comm_handle)); + test_socket_comm_handle->active = false; + test_socket_comm_handle->read_list = + ordered_list_initialize(socket_fd_node_compare); + test_socket_comm_handle->write_list = + ordered_list_initialize(socket_fd_node_compare); + test_socket_comm_handle->session_list = + ordered_list_initialize(pointer_compare_function); + pthread_mutex_init(&test_socket_comm_handle->socket_comm_mutex, NULL); + test_socket_comm_handle->num_active_sessions = 0; + + test_comm_session = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_session)); + memset(test_comm_session, 0, sizeof(pcep_socket_comm_session)); + test_comm_session->message_ready_to_read_handler = + test_loop_message_ready_to_read_handler; + ordered_list_add_node(test_socket_comm_handle->session_list, + test_comm_session); + + read_handler_info.handler_called = false; + read_handler_info.except_handler_called = false; + read_handler_info.data = NULL; + read_handler_info.socket_fd = -1; + read_handler_info.bytes_read = 0; +} + + +void pcep_socket_comm_loop_test_teardown() +{ + pthread_mutex_destroy(&test_socket_comm_handle->socket_comm_mutex); + ordered_list_destroy(test_socket_comm_handle->read_list); + ordered_list_destroy(test_socket_comm_handle->write_list); + ordered_list_destroy(test_socket_comm_handle->session_list); + pceplib_free(PCEPLIB_INFRA, test_socket_comm_handle); + test_socket_comm_handle = NULL; + + if (test_comm_session != NULL) { + pceplib_free(PCEPLIB_INFRA, test_comm_session); + test_comm_session = NULL; + } +} + + +/* + * Test cases + */ + +void test_socket_comm_loop_null_handle() +{ + /* Verify that socket_comm_loop() correctly handles a NULL + * timers_context */ + socket_comm_loop(NULL); +} + + +void test_socket_comm_loop_not_active() +{ + /* Verify that event_loop() correctly handles an inactive flag */ + pcep_socket_comm_handle handle; + handle.active = false; + socket_comm_loop(&handle); +} + + +void test_handle_reads_no_read() +{ + CU_ASSERT_PTR_NULL(test_socket_comm_handle->read_list->head); + + handle_reads(test_socket_comm_handle); + + CU_ASSERT_FALSE(read_handler_info.handler_called); + CU_ASSERT_FALSE(read_handler_info.except_handler_called); + CU_ASSERT_PTR_NULL(test_socket_comm_handle->read_list->head); +} + + +void test_handle_reads_read_message() +{ + /* Setup the comm session so that it can read. + * It should read 100 bytes, which simulates a successful read */ + test_comm_session->socket_fd = 10; + read_handler_info.bytes_read = 100; + FD_SET(test_comm_session->socket_fd, + &test_socket_comm_handle->read_master_set); + ordered_list_add_node(test_socket_comm_handle->read_list, + test_comm_session); + + handle_reads(test_socket_comm_handle); + + CU_ASSERT_TRUE(read_handler_info.handler_called); + CU_ASSERT_FALSE(read_handler_info.except_handler_called); + CU_ASSERT_EQUAL(test_comm_session->received_bytes, + read_handler_info.bytes_read); +} + + +void test_handle_reads_read_message_close() +{ + /* Setup the comm session so that it can read. + * It should read 0 bytes, which simulates that the socket closed */ + test_comm_session->socket_fd = 11; + read_handler_info.bytes_read = 0; + FD_SET(test_comm_session->socket_fd, + &test_socket_comm_handle->read_master_set); + ordered_list_add_node(test_socket_comm_handle->read_list, + test_comm_session); + + handle_reads(test_socket_comm_handle); + + CU_ASSERT_TRUE(read_handler_info.handler_called); + CU_ASSERT_FALSE(read_handler_info.except_handler_called); + CU_ASSERT_EQUAL(test_comm_session->received_bytes, + read_handler_info.bytes_read); + CU_ASSERT_PTR_NULL(test_socket_comm_handle->read_list->head); +} diff --git a/pceplib/test/pcep_socket_comm_loop_test.h b/pceplib/test/pcep_socket_comm_loop_test.h new file mode 100644 index 000000000..d2e3f21ee --- /dev/null +++ b/pceplib/test/pcep_socket_comm_loop_test.h @@ -0,0 +1,38 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_SOCKET_COMM_LOOP_TEST_H_ +#define PCEP_SOCKET_COMM_LOOP_TEST_H_ + +void pcep_socket_comm_loop_test_setup(void); +void pcep_socket_comm_loop_test_teardown(void); +void test_socket_comm_loop_null_handle(void); +void test_socket_comm_loop_not_active(void); +void test_handle_reads_no_read(void); +void test_handle_reads_read_message(void); +void test_handle_reads_read_message_close(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_socket_comm_test.c b/pceplib/test/pcep_socket_comm_test.c new file mode 100644 index 000000000..35afbcbb1 --- /dev/null +++ b/pceplib/test/pcep_socket_comm_test.c @@ -0,0 +1,308 @@ +/* + * 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> + * + */ + + +#include <netinet/in.h> + +#include <CUnit/CUnit.h> + +#include "pcep_socket_comm.h" +#include "pcep_socket_comm_internals.h" +#include "pcep_socket_comm_test.h" + +extern pcep_socket_comm_handle *socket_comm_handle_; + +static pcep_socket_comm_session *test_session = NULL; +static struct in_addr test_host_ip; +static struct in_addr test_src_ip; +static struct in6_addr test_host_ipv6; +static struct in6_addr test_src_ipv6; +static short test_port = 4789; +static short test_src_port = 4999; +static uint32_t connect_timeout_millis = 500; + +/* + * Unit Test Basic pcep_socket_comm API usage. + * Testing sending messages, etc via sockets should be done + * with integration tests, not unit tests. + */ + +/* + * Different socket_comm handler test implementations + */ +static void test_message_received_handler(void *session_data, + const char *message_data, + unsigned int message_length) +{ + (void)session_data; + (void)message_data; + (void)message_length; +} + +static int test_message_ready_to_read_handler(void *session_data, int socket_fd) +{ + (void)session_data; + (void)socket_fd; + return 1; +} + +static void test_message_sent_handler(void *session_data, int socket_fd) +{ + (void)session_data; + (void)socket_fd; + return; +} + +static void test_connection_except_notifier(void *session_data, int socket_fd) +{ + (void)session_data; + (void)socket_fd; +} + + +/* + * Test case setup and teardown called before AND after each test. + */ +void pcep_socket_comm_test_setup() +{ + inet_pton(AF_INET, "127.0.0.1", &(test_host_ip)); + inet_pton(AF_INET, "127.0.0.1", &(test_src_ip)); + inet_pton(AF_INET6, "::1", &(test_host_ipv6)); + inet_pton(AF_INET6, "::1", &(test_src_ipv6)); +} + +void pcep_socket_comm_test_teardown() +{ + socket_comm_session_teardown(test_session); + test_session = NULL; +} + + +/* + * Test cases + */ + +void test_pcep_socket_comm_initialize() +{ + test_session = socket_comm_session_initialize( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_host_ip, test_port, + connect_timeout_millis, NULL, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_FALSE(test_session->is_ipv6); +} + + +void test_pcep_socket_comm_initialize_ipv6() +{ + test_session = socket_comm_session_initialize_ipv6( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_host_ipv6, test_port, + connect_timeout_millis, NULL, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_TRUE(test_session->is_ipv6); +} + + +void test_pcep_socket_comm_initialize_with_src() +{ + /* Test that INADDR_ANY will be used when src_ip is NULL */ + test_session = socket_comm_session_initialize_with_src( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, NULL, 0, &test_host_ip, + test_port, connect_timeout_millis, NULL, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL( + test_session->src_sock_addr.src_sock_addr_ipv4.sin_addr.s_addr, + INADDR_ANY); + CU_ASSERT_FALSE(test_session->is_ipv6); + + socket_comm_session_teardown(test_session); + test_session = socket_comm_session_initialize_with_src( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_src_ip, test_src_port, + &test_host_ip, test_port, connect_timeout_millis, NULL, false, + NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL( + test_session->src_sock_addr.src_sock_addr_ipv4.sin_addr.s_addr, + test_src_ip.s_addr); + CU_ASSERT_EQUAL(test_session->src_sock_addr.src_sock_addr_ipv4.sin_port, + ntohs(test_src_port)); + CU_ASSERT_FALSE(test_session->is_ipv6); +} + + +void test_pcep_socket_comm_initialize_with_src_ipv6() +{ + /* Test that INADDR6_ANY will be used when src_ip is NULL */ + test_session = socket_comm_session_initialize_with_src_ipv6( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, NULL, 0, &test_host_ipv6, + test_port, connect_timeout_millis, NULL, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL(memcmp(&test_session->src_sock_addr.src_sock_addr_ipv6 + .sin6_addr, + &in6addr_any, sizeof(struct in6_addr)), + 0); + CU_ASSERT_TRUE(test_session->is_ipv6); + + socket_comm_session_teardown(test_session); + test_session = socket_comm_session_initialize_with_src_ipv6( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_src_ipv6, test_src_port, + &test_host_ipv6, test_port, connect_timeout_millis, NULL, false, + NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL(memcmp(&test_session->src_sock_addr.src_sock_addr_ipv6 + .sin6_addr, + &test_src_ipv6, sizeof(struct in6_addr)), + 0); + CU_ASSERT_EQUAL( + test_session->src_sock_addr.src_sock_addr_ipv6.sin6_port, + ntohs(test_src_port)); + CU_ASSERT_TRUE(test_session->is_ipv6); +} + + +void test_pcep_socket_comm_initialize_tcpmd5() +{ + char tcp_md5_str[] = "hello"; + int tcp_md5_strlen = strlen(tcp_md5_str); + + test_session = socket_comm_session_initialize( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_host_ip, test_port, 1, + tcp_md5_str, true, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str, + test_session->tcp_authentication_str, + tcp_md5_strlen)); + CU_ASSERT_TRUE(test_session->is_tcp_auth_md5); + CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session)); + /* This call does not work, it returns errno=92, Protocol not available + getsockopt(test_session->socket_fd, SOL_SOCKET, TCP_MD5SIG, &sig, + &siglen);*/ + + socket_comm_session_teardown(test_session); + test_session = socket_comm_session_initialize( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_host_ip, test_port, 1, + tcp_md5_str, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str, + test_session->tcp_authentication_str, + tcp_md5_strlen)); + CU_ASSERT_FALSE(test_session->is_tcp_auth_md5); + CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session)); +} + + +void test_pcep_socket_comm_initialize_ipv6_tcpmd5() +{ + char tcp_md5_str[] = "hello"; + int tcp_md5_strlen = strlen(tcp_md5_str); + + test_session = socket_comm_session_initialize_ipv6( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_host_ipv6, test_port, 1, + tcp_md5_str, true, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str, + test_session->tcp_authentication_str, + tcp_md5_strlen)); + CU_ASSERT_TRUE(test_session->is_tcp_auth_md5); + CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session)); + /* This call does not work, it returns errno=92, Protocol not available + getsockopt(test_session->socket_fd, SOL_SOCKET, TCP_MD5SIG, &sig, + &siglen);*/ + + socket_comm_session_teardown(test_session); + test_session = socket_comm_session_initialize_ipv6( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_host_ipv6, test_port, 1, + tcp_md5_str, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str, + test_session->tcp_authentication_str, + tcp_md5_strlen)); + CU_ASSERT_FALSE(test_session->is_tcp_auth_md5); + CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session)); +} + + +void test_pcep_socket_comm_initialize_handlers() +{ + /* Verify incorrect handler usage is correctly handled */ + + /* Both receive handlers cannot be NULL */ + test_session = socket_comm_session_initialize( + NULL, NULL, NULL, test_connection_except_notifier, + &test_host_ip, test_port, connect_timeout_millis, NULL, false, + NULL); + CU_ASSERT_PTR_NULL(test_session); + + /* Both receive handlers cannot be set */ + test_session = socket_comm_session_initialize( + test_message_received_handler, + test_message_ready_to_read_handler, test_message_sent_handler, + test_connection_except_notifier, &test_host_ip, test_port, + connect_timeout_millis, NULL, false, NULL); + CU_ASSERT_PTR_NULL(test_session); + + /* Only one receive handler can be set */ + test_session = socket_comm_session_initialize( + NULL, test_message_ready_to_read_handler, + test_message_sent_handler, test_connection_except_notifier, + &test_host_ip, test_port, connect_timeout_millis, NULL, false, + NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); +} + + +void test_pcep_socket_comm_session_not_initialized() +{ + CU_ASSERT_FALSE(socket_comm_session_connect_tcp(NULL)); + CU_ASSERT_FALSE(socket_comm_session_close_tcp(NULL)); + CU_ASSERT_FALSE(socket_comm_session_close_tcp_after_write(NULL)); + socket_comm_session_send_message(NULL, NULL, 0, true); + CU_ASSERT_FALSE(socket_comm_session_teardown(NULL)); +} + + +void test_pcep_socket_comm_session_destroy() +{ + test_session = socket_comm_session_initialize( + test_message_received_handler, NULL, test_message_sent_handler, + test_connection_except_notifier, &test_host_ip, test_port, + connect_timeout_millis, NULL, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_PTR_NOT_NULL(socket_comm_handle_); + CU_ASSERT_EQUAL(socket_comm_handle_->num_active_sessions, 1); + + CU_ASSERT_TRUE(socket_comm_session_teardown(test_session)); + test_session = NULL; + CU_ASSERT_PTR_NOT_NULL(socket_comm_handle_); + + CU_ASSERT_TRUE(destroy_socket_comm_loop()); + CU_ASSERT_PTR_NULL(socket_comm_handle_); +} diff --git a/pceplib/test/pcep_socket_comm_test.h b/pceplib/test/pcep_socket_comm_test.h new file mode 100644 index 000000000..f857af087 --- /dev/null +++ b/pceplib/test/pcep_socket_comm_test.h @@ -0,0 +1,42 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_SOCKET_COMM_TEST_H_ +#define PCEP_SOCKET_COMM_TEST_H_ + +void pcep_socket_comm_test_teardown(void); +void pcep_socket_comm_test_setup(void); +void test_pcep_socket_comm_initialize(void); +void test_pcep_socket_comm_initialize_ipv6(void); +void test_pcep_socket_comm_initialize_with_src(void); +void test_pcep_socket_comm_initialize_with_src_ipv6(void); +void test_pcep_socket_comm_initialize_tcpmd5(void); +void test_pcep_socket_comm_initialize_ipv6_tcpmd5(void); +void test_pcep_socket_comm_initialize_handlers(void); +void test_pcep_socket_comm_session_not_initialized(void); +void test_pcep_socket_comm_session_destroy(void); + +#endif diff --git a/pceplib/test/pcep_socket_comm_tests.c b/pceplib/test/pcep_socket_comm_tests.c new file mode 100644 index 000000000..293678f1a --- /dev/null +++ b/pceplib/test/pcep_socket_comm_tests.c @@ -0,0 +1,128 @@ +/* + * 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> + * + */ + + +#include <CUnit/Basic.h> +#include <CUnit/CUnit.h> +#include <CUnit/TestDB.h> + +#include "pcep_socket_comm_loop_test.h" +#include "pcep_socket_comm_test.h" + + +int main(int argc, char **argv) +{ + /* Unused parameters cause compilation warnings */ + (void)argc; + (void)argv; + + CU_initialize_registry(); + + /* + * Tests defined in pcep_socket_comm_test.c + */ + CU_pSuite test_socket_comm_suite = CU_add_suite_with_setup_and_teardown( + "PCEP Socket Comm Test Suite", NULL, + NULL, // suite setup and cleanup function pointers + pcep_socket_comm_test_setup, // test case setup function pointer + pcep_socket_comm_test_teardown); // test case teardown function + // pointer + + CU_add_test(test_socket_comm_suite, "test_pcep_socket_comm_initialize", + test_pcep_socket_comm_initialize); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_initialize_ipv6", + test_pcep_socket_comm_initialize_ipv6); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_initialize_with_src", + test_pcep_socket_comm_initialize_with_src); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_initialize_with_src_ipv6", + test_pcep_socket_comm_initialize_with_src_ipv6); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_initialize_tcpmd5", + test_pcep_socket_comm_initialize_tcpmd5); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_initialize_ipv6_tcpmd5", + test_pcep_socket_comm_initialize_ipv6_tcpmd5); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_initialize_handlers", + test_pcep_socket_comm_initialize_handlers); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_session_not_initialized", + test_pcep_socket_comm_session_not_initialized); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_session_destroy", + test_pcep_socket_comm_session_destroy); + + /* + * Tests defined in pcep_socket_comm_loop_test.c + */ + CU_pSuite test_socket_comm_loop_suite = + CU_add_suite_with_setup_and_teardown( + "PCEP Socket Comm Loop Test Suite", NULL, NULL, + pcep_socket_comm_loop_test_setup, // suite setup + // function pointer + pcep_socket_comm_loop_test_teardown); // suite cleanup + // function + // pointer + + CU_add_test(test_socket_comm_loop_suite, + "test_socket_comm_loop_null_handle", + test_socket_comm_loop_null_handle); + CU_add_test(test_socket_comm_loop_suite, + "test_socket_comm_loop_not_active", + test_socket_comm_loop_not_active); + CU_add_test(test_socket_comm_loop_suite, "test_handle_reads_no_read", + test_handle_reads_no_read); + CU_add_test(test_socket_comm_loop_suite, + "test_handle_reads_read_message", + test_handle_reads_read_message); + CU_add_test(test_socket_comm_loop_suite, + "test_handle_reads_read_message_close", + test_handle_reads_read_message_close); + + /* + * Run the tests and cleanup. + */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_FailureRecord *failure_record = CU_get_failure_list(); + if (failure_record != NULL) { + printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n"); + do { + printf("\t [%s] [%s] [%s:%d]\n", + failure_record->pSuite->pName, + failure_record->pTest->pName, + failure_record->strFileName, + failure_record->uiLineNumber); + failure_record = failure_record->pNext; + + } while (failure_record != NULL); + } + + CU_pRunSummary run_summary = CU_get_run_summary(); + int result = run_summary->nTestsFailed; + CU_cleanup_registry(); + + return result; +} diff --git a/pceplib/test/pcep_socket_comm_tests_valgrind.sh b/pceplib/test/pcep_socket_comm_tests_valgrind.sh new file mode 100755 index 000000000..d9e95e4c1 --- /dev/null +++ b/pceplib/test/pcep_socket_comm_tests_valgrind.sh @@ -0,0 +1,2 @@ +source pceplib/test/pcep_tests_valgrind.sh +valgrind_test pceplib/test/pcep_socket_comm_tests diff --git a/pceplib/test/pcep_tests_valgrind.sh b/pceplib/test/pcep_tests_valgrind.sh new file mode 100755 index 000000000..ca4772cb6 --- /dev/null +++ b/pceplib/test/pcep_tests_valgrind.sh @@ -0,0 +1,15 @@ +# +# Common function definition for PCEPlib valgrind tests +# + +function valgrind_test() +{ + local test_suite=$1 + [[ -z ${test_suite} ]] && { echo "${FUNCNAME}(): test_suite not specified."; exit 1; } + [[ ! -x "${test_suite}" ]] && { echo "${test_suite} is not an executable file."; exit 1; } + + G_SLICE=always-malloc + G_DEBUG=gc-friendly + VALGRIND="valgrind -v --tool=memcheck --leak-check=full --num-callers=40 --error-exitcode=1" + ${VALGRIND} --log-file=${test_suite}.val.log ./${test_suite} || ({ echo "Valgrind memory check error"; exit 1; }) +} diff --git a/pceplib/test/pcep_timers_event_loop_test.c b/pceplib/test/pcep_timers_event_loop_test.c new file mode 100644 index 000000000..9fcacaf0f --- /dev/null +++ b/pceplib/test/pcep_timers_event_loop_test.c @@ -0,0 +1,160 @@ +/* + * 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> + * + */ + + +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "pcep_timers.h" +#include "pcep_utils_memory.h" +#include "pcep_timers_event_loop.h" +#include "pcep_timers_event_loop_test.h" + + +typedef struct timer_expire_handler_info_ { + bool handler_called; + void *data; + int timerId; + +} timer_expire_handler_info; + +static pcep_timers_context *test_timers_context = NULL; +static timer_expire_handler_info expire_handler_info; +#define TEST_EVENT_LOOP_TIMER_ID 500 + + +/* Called when a timer expires */ +static void test_timer_expire_handler(void *data, int timerId) +{ + expire_handler_info.handler_called = true; + expire_handler_info.data = data; + expire_handler_info.timerId = timerId; +} + + +/* Test case setup called before each test. + * Declared in pcep_timers_tests.c */ +void pcep_timers_event_loop_test_setup() +{ + test_timers_context = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_timers_context)); + memset(test_timers_context, 0, sizeof(pcep_timers_context)); + if (pthread_mutex_init(&(test_timers_context->timer_list_lock), NULL) + != 0) { + fprintf(stderr, + "ERROR initializing timers, cannot initialize the mutex\n"); + } + test_timers_context->active = false; + test_timers_context->expire_handler = test_timer_expire_handler; + test_timers_context->timer_list = + ordered_list_initialize(timer_list_node_timer_id_compare); + + expire_handler_info.handler_called = false; + expire_handler_info.data = NULL; + expire_handler_info.timerId = -1; +} + + +/* Test case teardown called after each test. + * Declared in pcep_timers_tests.c */ +void pcep_timers_event_loop_test_teardown() +{ + pthread_mutex_unlock(&test_timers_context->timer_list_lock); + pthread_mutex_destroy(&(test_timers_context->timer_list_lock)); + ordered_list_destroy(test_timers_context->timer_list); + pceplib_free(PCEPLIB_INFRA, test_timers_context); + test_timers_context = NULL; +} + + +/* + * Test functions + */ + +void test_walk_and_process_timers_no_timers() +{ + CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 0); + CU_ASSERT_PTR_NULL(test_timers_context->timer_list->head); + + walk_and_process_timers(test_timers_context); + + CU_ASSERT_FALSE(expire_handler_info.handler_called); + CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 0); + CU_ASSERT_PTR_NULL(test_timers_context->timer_list->head); +} + + +void test_walk_and_process_timers_timer_not_expired() +{ + pcep_timer timer; + timer.data = &timer; + // Set the timer to expire 100 seconds from now + timer.expire_time = time(NULL) + 100; + timer.timer_id = TEST_EVENT_LOOP_TIMER_ID; + ordered_list_add_node(test_timers_context->timer_list, &timer); + + walk_and_process_timers(test_timers_context); + + /* The timer should still be in the list, since it hasnt expired yet */ + CU_ASSERT_FALSE(expire_handler_info.handler_called); + CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 1); + CU_ASSERT_PTR_NOT_NULL(test_timers_context->timer_list->head); +} + + +void test_walk_and_process_timers_timer_expired() +{ + /* We need to alloc it, since it will be free'd in + * walk_and_process_timers */ + pcep_timer *timer = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_timer)); + timer->data = timer; + // Set the timer to expire 10 seconds ago + timer->expire_time = time(NULL) - 10; + timer->timer_id = TEST_EVENT_LOOP_TIMER_ID; + ordered_list_add_node(test_timers_context->timer_list, timer); + + walk_and_process_timers(test_timers_context); + + /* Since the timer expired, the expire_handler should have been called + * and the timer should have been removed from the timer list */ + CU_ASSERT_TRUE(expire_handler_info.handler_called); + CU_ASSERT_PTR_EQUAL(expire_handler_info.data, timer); + CU_ASSERT_EQUAL(expire_handler_info.timerId, TEST_EVENT_LOOP_TIMER_ID); + CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 0); + CU_ASSERT_PTR_NULL(test_timers_context->timer_list->head); +} + +void test_event_loop_null_handle() +{ + /* Verify that event_loop() correctly handles a NULL timers_context */ + event_loop(NULL); +} + + +void test_event_loop_not_active() +{ + /* Verify that event_loop() correctly handles an inactive timers_context + * flag */ + test_timers_context->active = false; + event_loop(test_timers_context); +} diff --git a/pceplib/test/pcep_timers_event_loop_test.h b/pceplib/test/pcep_timers_event_loop_test.h new file mode 100644 index 000000000..19fd26485 --- /dev/null +++ b/pceplib/test/pcep_timers_event_loop_test.h @@ -0,0 +1,38 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_TIMERS_EVENT_LOOP_TEST_H_ +#define PCEP_TIMERS_EVENT_LOOP_TEST_H_ + +void pcep_timers_event_loop_test_setup(void); +void pcep_timers_event_loop_test_teardown(void); +void test_walk_and_process_timers_no_timers(void); +void test_walk_and_process_timers_timer_not_expired(void); +void test_walk_and_process_timers_timer_expired(void); +void test_event_loop_null_handle(void); +void test_event_loop_not_active(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_timers_test.c b/pceplib/test/pcep_timers_test.c new file mode 100644 index 000000000..9d9e0f6c1 --- /dev/null +++ b/pceplib/test/pcep_timers_test.c @@ -0,0 +1,109 @@ +/* + * 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> + * + */ + + +#include <stdbool.h> +#include <CUnit/CUnit.h> + +#include "pcep_timers.h" +#include "pcep_timers_test.h" + +/* Test case teardown called after each test. + * Declared in pcep_timers_tests.c */ +void pcep_timers_test_teardown() +{ + teardown_timers(); +} + +static void test_timer_expire_handler(void *data, int timerId) +{ + (void)data; + (void)timerId; +} + + +void test_double_initialization(void) +{ + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true); + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), false); +} + + +void test_initialization_null_callback(void) +{ + CU_ASSERT_EQUAL(initialize_timers(NULL), false); +} + + +void test_not_initialized(void) +{ + /* All of these should fail if initialize_timers() hasnt been called */ + CU_ASSERT_EQUAL(create_timer(5, NULL), -1); + CU_ASSERT_EQUAL(cancel_timer(7), false); + CU_ASSERT_EQUAL(reset_timer(7), false); + CU_ASSERT_EQUAL(teardown_timers(), false); +} + + +void test_create_timer(void) +{ + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true); + + int timer_id = create_timer(0, NULL); + CU_ASSERT_TRUE(timer_id > -1); +} + + +void test_cancel_timer(void) +{ + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true); + + int timer_id = create_timer(10, NULL); + CU_ASSERT_TRUE(timer_id > -1); + + CU_ASSERT_EQUAL(cancel_timer(timer_id), true); +} + + +void test_cancel_timer_invalid(void) +{ + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true); + CU_ASSERT_EQUAL(cancel_timer(1), false); +} + + +void test_reset_timer(void) +{ + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true); + + int timer_id = create_timer(10, NULL); + CU_ASSERT_TRUE(timer_id > -1); + + CU_ASSERT_EQUAL(reset_timer(timer_id), true); +} + + +void test_reset_timer_invalid(void) +{ + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true); + CU_ASSERT_EQUAL(reset_timer(1), false); +} diff --git a/pceplib/test/pcep_timers_test.h b/pceplib/test/pcep_timers_test.h new file mode 100644 index 000000000..6ac9a90e4 --- /dev/null +++ b/pceplib/test/pcep_timers_test.h @@ -0,0 +1,40 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_TIMERS_TEST_H_ +#define PCEP_TIMERS_TEST_H_ + +void pcep_timers_test_teardown(void); +void test_double_initialization(void); +void test_initialization_null_callback(void); +void test_not_initialized(void); +void test_create_timer(void); +void test_cancel_timer(void); +void test_cancel_timer_invalid(void); +void test_reset_timer(void); +void test_reset_timer_invalid(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_timers_tests.c b/pceplib/test/pcep_timers_tests.c new file mode 100644 index 000000000..adfea17e2 --- /dev/null +++ b/pceplib/test/pcep_timers_tests.c @@ -0,0 +1,113 @@ +/* + * 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> + * + */ + + +#include <CUnit/Basic.h> +#include <CUnit/CUnit.h> +#include <CUnit/TestDB.h> + +#include "pcep_timers_test.h" +#include "pcep_timers_event_loop_test.h" + + +int main(int argc, char **argv) +{ + /* Unused parameters cause compilation warnings */ + (void)argc; + (void)argv; + + CU_initialize_registry(); + + /* + * Tests defined in pcep_timers_test.c + */ + CU_pSuite test_timers_suite = CU_add_suite_with_setup_and_teardown( + "PCEP Timers Test Suite", NULL, + NULL, // suite setup and cleanup function pointers + NULL, pcep_timers_test_teardown); // test case setup and + // teardown function pointers + CU_add_test(test_timers_suite, "test_double_initialization", + test_double_initialization); + CU_add_test(test_timers_suite, "test_initialization_null_callback", + test_initialization_null_callback); + CU_add_test(test_timers_suite, "test_not_initialized", + test_not_initialized); + CU_add_test(test_timers_suite, "test_create_timer", test_create_timer); + CU_add_test(test_timers_suite, "test_cancel_timer", test_cancel_timer); + CU_add_test(test_timers_suite, "test_cancel_timer_invalid", + test_cancel_timer_invalid); + CU_add_test(test_timers_suite, "test_reset_timer", test_reset_timer); + CU_add_test(test_timers_suite, "test_reset_timer_invalid", + test_reset_timer_invalid); + + /* + * Tests defined in pcep_timers_event_loop_test.c + */ + CU_pSuite test_timers_event_loop_suite = + CU_add_suite_with_setup_and_teardown( + "PCEP Timers Event Loop Test Suite", NULL, + NULL, // suite setup and cleanup function pointers + pcep_timers_event_loop_test_setup, // test case setup + // function pointer + pcep_timers_event_loop_test_teardown); // test case + // teardown + // function + // pointer + CU_add_test(test_timers_event_loop_suite, + "test_walk_and_process_timers_no_timers", + test_walk_and_process_timers_no_timers); + CU_add_test(test_timers_event_loop_suite, + "test_walk_and_process_timers_timer_not_expired", + test_walk_and_process_timers_timer_not_expired); + CU_add_test(test_timers_event_loop_suite, + "test_walk_and_process_timers_timer_expired", + test_walk_and_process_timers_timer_expired); + CU_add_test(test_timers_event_loop_suite, "test_event_loop_null_handle", + test_event_loop_null_handle); + CU_add_test(test_timers_event_loop_suite, "test_event_loop_not_active", + test_event_loop_not_active); + + /* + * Run the tests and cleanup. + */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_FailureRecord *failure_record = CU_get_failure_list(); + if (failure_record != NULL) { + printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n"); + do { + printf("\t [%s] [%s] [%s:%d]\n", + failure_record->pSuite->pName, + failure_record->pTest->pName, + failure_record->strFileName, + failure_record->uiLineNumber); + failure_record = failure_record->pNext; + + } while (failure_record != NULL); + } + + CU_pRunSummary run_summary = CU_get_run_summary(); + int result = run_summary->nTestsFailed; + CU_cleanup_registry(); + + return result; +} diff --git a/pceplib/test/pcep_timers_tests_valgrind.sh b/pceplib/test/pcep_timers_tests_valgrind.sh new file mode 100755 index 000000000..f9bff3b2a --- /dev/null +++ b/pceplib/test/pcep_timers_tests_valgrind.sh @@ -0,0 +1,2 @@ +source pceplib/test/pcep_tests_valgrind.sh +valgrind_test pceplib/test/pcep_timers_tests diff --git a/pceplib/test/pcep_utils_counters_test.c b/pceplib/test/pcep_utils_counters_test.c new file mode 100644 index 000000000..6f53e4d40 --- /dev/null +++ b/pceplib/test/pcep_utils_counters_test.c @@ -0,0 +1,254 @@ +/* + * 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> + * + */ + + +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "pcep_utils_counters.h" +#include "pcep_utils_counters_test.h" + + +void test_create_counters_group() +{ + const char group_name[] = "group"; + uint16_t num_subgroups = 10; + + struct counters_group *group = + create_counters_group(NULL, num_subgroups); + CU_ASSERT_PTR_NULL(group); + + group = create_counters_group(group_name, MAX_COUNTER_GROUPS + 1); + CU_ASSERT_PTR_NULL(group); + + group = create_counters_group(group_name, num_subgroups); + CU_ASSERT_PTR_NOT_NULL(group); + + CU_ASSERT_EQUAL(group->num_subgroups, 0); + CU_ASSERT_EQUAL(group->max_subgroups, num_subgroups); + CU_ASSERT_EQUAL(strcmp(group->counters_group_name, group_name), 0); + + delete_counters_group(group); +} + +void test_create_counters_subgroup() +{ + const char subgroup_name[] = "subgroup"; + uint16_t subgroup_id = 10; + uint16_t num_counters = 20; + + struct counters_subgroup *subgroup = + create_counters_subgroup(NULL, subgroup_id, num_counters); + CU_ASSERT_PTR_NULL(subgroup); + + subgroup = create_counters_subgroup( + subgroup_name, MAX_COUNTER_GROUPS + 1, num_counters); + CU_ASSERT_PTR_NULL(subgroup); + + subgroup = create_counters_subgroup(subgroup_name, subgroup_id, + MAX_COUNTERS + 1); + CU_ASSERT_PTR_NULL(subgroup); + + subgroup = create_counters_subgroup(subgroup_name, subgroup_id, + num_counters); + CU_ASSERT_PTR_NOT_NULL(subgroup); + + CU_ASSERT_EQUAL(subgroup->subgroup_id, subgroup_id); + CU_ASSERT_EQUAL(subgroup->num_counters, 0); + CU_ASSERT_EQUAL(subgroup->max_counters, num_counters); + CU_ASSERT_EQUAL(strcmp(subgroup->counters_subgroup_name, subgroup_name), + 0); + + delete_counters_subgroup(subgroup); +} + +void test_add_counters_subgroup() +{ + struct counters_group *group = create_counters_group("group", 1); + struct counters_subgroup *subgroup1 = + create_counters_subgroup("subgroup", 0, 5); + struct counters_subgroup *subgroup2 = + create_counters_subgroup("subgroup", 1, 5); + + CU_ASSERT_FALSE(add_counters_subgroup(NULL, NULL)); + CU_ASSERT_FALSE(add_counters_subgroup(NULL, subgroup1)); + CU_ASSERT_FALSE(add_counters_subgroup(group, NULL)); + + CU_ASSERT_EQUAL(group->num_subgroups, 0); + CU_ASSERT_TRUE(add_counters_subgroup(group, subgroup1)); + CU_ASSERT_EQUAL(group->num_subgroups, 1); + /* Cant add more than num_subgroups to the group */ + CU_ASSERT_FALSE(add_counters_subgroup(group, subgroup2)); + + CU_ASSERT_PTR_NOT_NULL(find_subgroup(group, 0)); + CU_ASSERT_PTR_NULL(find_subgroup(group, 1)); + + delete_counters_group(group); + delete_counters_subgroup(subgroup2); +} + +void test_create_subgroup_counter() +{ + uint16_t counter_id = 1; + char counter_name[] = "my counter"; + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", 1, 2); + + CU_ASSERT_FALSE( + create_subgroup_counter(NULL, counter_id, counter_name)); + CU_ASSERT_FALSE(create_subgroup_counter(subgroup, counter_id + 1, + counter_name)); + CU_ASSERT_FALSE(create_subgroup_counter(subgroup, counter_id, NULL)); + CU_ASSERT_EQUAL(subgroup->num_counters, 0); + CU_ASSERT_TRUE( + create_subgroup_counter(subgroup, counter_id, counter_name)); + CU_ASSERT_EQUAL(subgroup->num_counters, 1); + + delete_counters_subgroup(subgroup); +} + +void test_delete_counters_group() +{ + struct counters_group *group = create_counters_group("group", 1); + + CU_ASSERT_FALSE(delete_counters_group(NULL)); + CU_ASSERT_TRUE(delete_counters_group(group)); +} + +void test_delete_counters_subgroup() +{ + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", 1, 1); + + CU_ASSERT_FALSE(delete_counters_subgroup(NULL)); + CU_ASSERT_TRUE(delete_counters_subgroup(subgroup)); +} + +void test_reset_group_counters() +{ + uint16_t subgroup_id = 1; + uint16_t counter_id = 1; + struct counters_group *group = create_counters_group("group", 10); + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", subgroup_id, 10); + create_subgroup_counter(subgroup, counter_id, "counter"); + add_counters_subgroup(group, subgroup); + + struct counter *counter = subgroup->counters[counter_id]; + counter->counter_value = 100; + + CU_ASSERT_FALSE(reset_group_counters(NULL)); + CU_ASSERT_TRUE(reset_group_counters(group)); + CU_ASSERT_EQUAL(counter->counter_value, 0); + + delete_counters_group(group); +} + +void test_reset_subgroup_counters() +{ + uint16_t counter_id = 1; + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", 1, 10); + create_subgroup_counter(subgroup, counter_id, "counter"); + + struct counter *counter = subgroup->counters[counter_id]; + counter->counter_value = 100; + + CU_ASSERT_FALSE(reset_subgroup_counters(NULL)); + CU_ASSERT_TRUE(reset_subgroup_counters(subgroup)); + CU_ASSERT_EQUAL(counter->counter_value, 0); + + delete_counters_subgroup(subgroup); +} + +void test_increment_counter() +{ + uint16_t subgroup_id = 1; + uint16_t counter_id = 1; + struct counters_group *group = create_counters_group("group", 10); + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", subgroup_id, 10); + create_subgroup_counter(subgroup, counter_id, "counter"); + add_counters_subgroup(group, subgroup); + + struct counter *counter = subgroup->counters[counter_id]; + counter->counter_value = 100; + + CU_ASSERT_FALSE(increment_counter(NULL, subgroup_id, counter_id)); + CU_ASSERT_FALSE(increment_counter(group, 100, counter_id)); + CU_ASSERT_FALSE(increment_counter(group, subgroup_id, 123)); + CU_ASSERT_TRUE(increment_counter(group, subgroup_id, counter_id)); + CU_ASSERT_EQUAL(counter->counter_value, 101); + CU_ASSERT_EQUAL(subgroup_counters_total(subgroup), 101); + + delete_counters_group(group); +} + +void test_increment_subgroup_counter() +{ + int counter_id = 1; + uint32_t counter_value = 100; + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", 1, 10); + create_subgroup_counter(subgroup, counter_id, "counter"); + + struct counter *counter = subgroup->counters[counter_id]; + counter->counter_value = counter_value; + + CU_ASSERT_FALSE(increment_subgroup_counter(NULL, counter_id)); + CU_ASSERT_FALSE(increment_subgroup_counter(subgroup, counter_id + 1)); + CU_ASSERT_TRUE(increment_subgroup_counter(subgroup, counter_id)); + CU_ASSERT_EQUAL(counter->counter_value, counter_value + 1); + + delete_counters_subgroup(subgroup); +} + +void test_dump_counters_group_to_log() +{ + uint16_t subgroup_id = 1; + uint16_t counter_id = 1; + struct counters_group *group = create_counters_group("group", 10); + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", subgroup_id, 10); + create_subgroup_counter(subgroup, counter_id, "counter"); + add_counters_subgroup(group, subgroup); + + CU_ASSERT_FALSE(dump_counters_group_to_log(NULL)); + CU_ASSERT_TRUE(dump_counters_group_to_log(group)); + + delete_counters_group(group); +} + +void test_dump_counters_subgroup_to_log() +{ + uint16_t subgroup_id = 1; + uint16_t counter_id = 1; + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", subgroup_id, 10); + create_subgroup_counter(subgroup, counter_id, "counter"); + + CU_ASSERT_FALSE(dump_counters_subgroup_to_log(NULL)); + CU_ASSERT_TRUE(dump_counters_subgroup_to_log(subgroup)); + + delete_counters_subgroup(subgroup); +} diff --git a/pceplib/test/pcep_utils_counters_test.h b/pceplib/test/pcep_utils_counters_test.h new file mode 100644 index 000000000..07236dcb5 --- /dev/null +++ b/pceplib/test/pcep_utils_counters_test.h @@ -0,0 +1,43 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_UTILS_COUNTERS_TEST_H_ +#define PCEP_UTILS_COUNTERS_TEST_H_ + +void test_create_counters_group(void); +void test_create_counters_subgroup(void); +void test_add_counters_subgroup(void); +void test_create_subgroup_counter(void); +void test_delete_counters_group(void); +void test_delete_counters_subgroup(void); +void test_reset_group_counters(void); +void test_reset_subgroup_counters(void); +void test_increment_counter(void); +void test_increment_subgroup_counter(void); +void test_dump_counters_group_to_log(void); +void test_dump_counters_subgroup_to_log(void); + +#endif diff --git a/pceplib/test/pcep_utils_double_linked_list_test.c b/pceplib/test/pcep_utils_double_linked_list_test.c new file mode 100644 index 000000000..d2600e66c --- /dev/null +++ b/pceplib/test/pcep_utils_double_linked_list_test.c @@ -0,0 +1,297 @@ +/* + * 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> + * + */ + + +#include <CUnit/CUnit.h> + +#include "pcep_utils_double_linked_list.h" +#include "pcep_utils_double_linked_list_test.h" + +typedef struct dll_node_data_ { + int int_data; + +} dll_node_data; + +void test_empty_dl_list() +{ + double_linked_list *handle = dll_initialize(); + + CU_ASSERT_PTR_NULL(dll_delete_first_node(handle)); + CU_ASSERT_PTR_NULL(dll_delete_last_node(handle)); + CU_ASSERT_PTR_NULL(dll_delete_node(handle, NULL)); + + dll_destroy(handle); +} + +void test_null_dl_list_handle() +{ + dll_destroy(NULL); + CU_ASSERT_PTR_NULL(dll_prepend(NULL, NULL)); + CU_ASSERT_PTR_NULL(dll_append(NULL, NULL)); + CU_ASSERT_PTR_NULL(dll_delete_first_node(NULL)); + CU_ASSERT_PTR_NULL(dll_delete_last_node(NULL)); + CU_ASSERT_PTR_NULL(dll_delete_node(NULL, NULL)); +} + +void test_dll_prepend_data() +{ + dll_node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + double_linked_list *handle = dll_initialize(); + + CU_ASSERT_PTR_NOT_NULL(dll_prepend(handle, &data3)); + CU_ASSERT_PTR_NOT_NULL(dll_prepend(handle, &data2)); + CU_ASSERT_PTR_NOT_NULL(dll_prepend(handle, &data1)); + + CU_ASSERT_EQUAL(handle->num_entries, 3); + + double_linked_list_node *node = handle->head; + CU_ASSERT_PTR_EQUAL(node->data, &data1); + CU_ASSERT_PTR_NULL(node->prev_node); + CU_ASSERT_PTR_NOT_NULL(node->next_node); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data2); + CU_ASSERT_PTR_NOT_NULL(node->prev_node); + CU_ASSERT_PTR_NOT_NULL(node->next_node); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data3); + CU_ASSERT_PTR_NOT_NULL(node->prev_node); + CU_ASSERT_PTR_NULL(node->next_node); + CU_ASSERT_PTR_EQUAL(handle->tail, node); + + dll_destroy(handle); +} + + +void test_dll_append_data() +{ + dll_node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + double_linked_list *handle = dll_initialize(); + + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1)); + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data2)); + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data3)); + + CU_ASSERT_EQUAL(handle->num_entries, 3); + + double_linked_list_node *node = handle->head; + CU_ASSERT_PTR_EQUAL(node->data, &data1); + CU_ASSERT_PTR_NULL(node->prev_node); + CU_ASSERT_PTR_NOT_NULL(node->next_node); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data2); + CU_ASSERT_PTR_NOT_NULL(node->prev_node); + CU_ASSERT_PTR_NOT_NULL(node->next_node); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data3); + CU_ASSERT_PTR_NOT_NULL(node->prev_node); + CU_ASSERT_PTR_NULL(node->next_node); + CU_ASSERT_PTR_EQUAL(handle->tail, node); + + dll_destroy(handle); +} + + +void test_dll_delete_first_node() +{ + dll_node_data data1, data2; + data1.int_data = 1; + data2.int_data = 2; + + double_linked_list *handle = dll_initialize(); + + /* Test deleting with just 1 node in the list */ + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1)); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + void *deleted_data = dll_delete_first_node(handle); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data1, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 0); + CU_ASSERT_PTR_NULL(handle->head); + CU_ASSERT_PTR_NULL(handle->tail); + + /* Test deleting with 2 nodes in the list */ + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1)); + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data2)); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + deleted_data = dll_delete_first_node(handle); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data1, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 1); + CU_ASSERT_PTR_EQUAL(handle->head->data, &data2); + CU_ASSERT_PTR_EQUAL(handle->head, handle->tail); + CU_ASSERT_PTR_NULL(handle->head->prev_node); + CU_ASSERT_PTR_NULL(handle->head->next_node); + + dll_destroy(handle); +} + + +void test_dll_delete_last_node() +{ + dll_node_data data1, data2; + data1.int_data = 1; + data2.int_data = 2; + + double_linked_list *handle = dll_initialize(); + + /* Test deleting with just 1 node in the list */ + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1)); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + void *deleted_data = dll_delete_last_node(handle); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data1, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 0); + CU_ASSERT_PTR_NULL(handle->head); + CU_ASSERT_PTR_NULL(handle->tail); + + /* Test deleting with 2 nodes in the list */ + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1)); + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data2)); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + deleted_data = dll_delete_last_node(handle); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data2, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 1); + CU_ASSERT_PTR_EQUAL(handle->head->data, &data1); + CU_ASSERT_PTR_EQUAL(handle->head, handle->tail); + CU_ASSERT_PTR_NULL(handle->head->prev_node); + CU_ASSERT_PTR_NULL(handle->head->next_node); + + dll_destroy(handle); +} + + +void test_dll_delete_node() +{ + dll_node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + double_linked_list_node *node1, *node2, *node3; + double_linked_list *handle; + + /* Test deleting with just 1 node in the list */ + handle = dll_initialize(); + node1 = dll_append(handle, &data1); + CU_ASSERT_PTR_NOT_NULL(node1); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + void *deleted_data = dll_delete_node(handle, node1); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data1, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 0); + CU_ASSERT_PTR_NULL(handle->head); + CU_ASSERT_PTR_NULL(handle->tail); + + /* + * Test deleting the head with 2 nodes in the list + */ + node1 = dll_append(handle, &data1); + node2 = dll_append(handle, &data2); + CU_ASSERT_PTR_NOT_NULL(node1); + CU_ASSERT_PTR_NOT_NULL(node2); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + /* Delete the head entry */ + deleted_data = dll_delete_node(handle, node1); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data1, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 1); + CU_ASSERT_PTR_EQUAL(handle->head->data, &data2); + CU_ASSERT_PTR_EQUAL(handle->head, handle->tail); + CU_ASSERT_PTR_NULL(handle->head->prev_node); + CU_ASSERT_PTR_NULL(handle->head->next_node); + dll_destroy(handle); + + /* + * Test deleting the tail with 2 nodes in the list + */ + handle = dll_initialize(); + node1 = dll_append(handle, &data1); + node2 = dll_append(handle, &data2); + CU_ASSERT_PTR_NOT_NULL(node1); + CU_ASSERT_PTR_NOT_NULL(node2); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + /* Delete the tail entry */ + deleted_data = dll_delete_node(handle, node2); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data2, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 1); + CU_ASSERT_PTR_EQUAL(handle->head->data, &data1); + CU_ASSERT_PTR_EQUAL(handle->head, handle->tail); + CU_ASSERT_PTR_NULL(handle->head->prev_node); + CU_ASSERT_PTR_NULL(handle->head->next_node); + dll_destroy(handle); + + /* + * Test deleting in the middle with 3 nodes in the list + */ + handle = dll_initialize(); + node1 = dll_append(handle, &data1); + node2 = dll_append(handle, &data2); + node3 = dll_append(handle, &data3); + CU_ASSERT_PTR_NOT_NULL(node1); + CU_ASSERT_PTR_NOT_NULL(node2); + CU_ASSERT_PTR_NOT_NULL(node3); + CU_ASSERT_EQUAL(handle->num_entries, 3); + + /* Delete the middle entry */ + deleted_data = dll_delete_node(handle, node2); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data2, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 2); + CU_ASSERT_PTR_EQUAL(handle->head, node1); + CU_ASSERT_PTR_EQUAL(handle->tail, node3); + CU_ASSERT_PTR_EQUAL(node1->data, &data1); + CU_ASSERT_PTR_EQUAL(node3->data, &data3); + CU_ASSERT_PTR_EQUAL(node1->next_node, node3); + CU_ASSERT_PTR_EQUAL(node3->prev_node, node1); + CU_ASSERT_PTR_NULL(node1->prev_node); + CU_ASSERT_PTR_NULL(node3->next_node); + + dll_destroy(handle); +} diff --git a/pceplib/test/pcep_utils_double_linked_list_test.h b/pceplib/test/pcep_utils_double_linked_list_test.h new file mode 100644 index 000000000..ddb6467cb --- /dev/null +++ b/pceplib/test/pcep_utils_double_linked_list_test.h @@ -0,0 +1,38 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_UTILS_DOUBLE_LINKED_LIST_TEST_H_ +#define PCEP_UTILS_DOUBLE_LINKED_LIST_TEST_H_ + +void test_empty_dl_list(void); +void test_null_dl_list_handle(void); +void test_dll_prepend_data(void); +void test_dll_append_data(void); +void test_dll_delete_first_node(void); +void test_dll_delete_last_node(void); +void test_dll_delete_node(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_utils_memory_test.c b/pceplib/test/pcep_utils_memory_test.c new file mode 100644 index 000000000..b0b528f08 --- /dev/null +++ b/pceplib/test/pcep_utils_memory_test.c @@ -0,0 +1,241 @@ +/* + * 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> + * + */ + + +#include <stdlib.h> +#include <stdint.h> + +#include <CUnit/CUnit.h> + +#include "pcep_utils_memory.h" +#include "pcep_utils_memory_test.h" + +void *test_pceplib_malloc(void *mem_type, size_t size); +void *test_pceplib_calloc(void *mem_type, size_t size); +void *test_pceplib_realloc(void *mem_type, void *ptr, size_t size); +void *test_pceplib_strdup(void *mem_type, const char *str); +void test_pceplib_free(void *mem_type, void *ptr); +void verify_memory_type(struct pceplib_memory_type *mt, uint32_t num_alloc, + uint32_t alloc_bytes, uint32_t num_free, + uint32_t free_bytes); +void verify_ext_memory_type(void *mt, int num_malloc_calls, + int num_calloc_calls, int num_realloc_calls, + int num_strdup_calls, int num_free_calls); + +struct test_memory_type { + int num_malloc_calls; + int num_calloc_calls; + int num_realloc_calls; + int num_strdup_calls; + int num_free_calls; +}; + +void *test_pceplib_malloc(void *mem_type, size_t size) +{ + ((struct test_memory_type *)mem_type)->num_malloc_calls++; + return malloc(size); +} + +void *test_pceplib_calloc(void *mem_type, size_t size) +{ + ((struct test_memory_type *)mem_type)->num_calloc_calls++; + return calloc(1, size); +} + +void *test_pceplib_realloc(void *mem_type, void *ptr, size_t size) +{ + ((struct test_memory_type *)mem_type)->num_realloc_calls++; + return realloc(ptr, size); +} + +void *test_pceplib_strdup(void *mem_type, const char *str) +{ + ((struct test_memory_type *)mem_type)->num_strdup_calls++; + return strdup(str); +} + +void test_pceplib_free(void *mem_type, void *ptr) +{ + ((struct test_memory_type *)mem_type)->num_free_calls++; + free(ptr); +} + +void verify_memory_type(struct pceplib_memory_type *mt, uint32_t num_alloc, + uint32_t alloc_bytes, uint32_t num_free, + uint32_t free_bytes) +{ + CU_ASSERT_EQUAL(num_alloc, mt->num_allocates); + CU_ASSERT_EQUAL(alloc_bytes, mt->total_bytes_allocated); + CU_ASSERT_EQUAL(num_free, mt->num_frees); + CU_ASSERT_EQUAL(free_bytes, mt->total_bytes_freed); +} + +void verify_ext_memory_type(void *mt, int num_malloc_calls, + int num_calloc_calls, int num_realloc_calls, + int num_strdup_calls, int num_free_calls) +{ + struct test_memory_type *mt_ptr = (struct test_memory_type *)mt; + CU_ASSERT_EQUAL(num_malloc_calls, mt_ptr->num_malloc_calls); + CU_ASSERT_EQUAL(num_calloc_calls, mt_ptr->num_calloc_calls); + CU_ASSERT_EQUAL(num_realloc_calls, mt_ptr->num_realloc_calls); + CU_ASSERT_EQUAL(num_strdup_calls, mt_ptr->num_strdup_calls); + CU_ASSERT_EQUAL(num_free_calls, mt_ptr->num_free_calls); +} + +void test_memory_internal_impl() +{ + int alloc_size = 100; + struct pceplib_memory_type *pceplib_infra_ptr = + (struct pceplib_memory_type *)PCEPLIB_INFRA; + struct pceplib_memory_type *pceplib_messages_ptr = + (struct pceplib_memory_type *)PCEPLIB_MESSAGES; + int alloc_counter = 1; + int free_counter = 1; + + /* reset the memory type counters for easier testing */ + pceplib_infra_ptr->num_allocates = + pceplib_infra_ptr->total_bytes_allocated = + pceplib_infra_ptr->num_frees = + pceplib_infra_ptr->total_bytes_freed = 0; + pceplib_messages_ptr->num_allocates = + pceplib_messages_ptr->total_bytes_allocated = + pceplib_messages_ptr->num_frees = + pceplib_messages_ptr->total_bytes_freed = 0; + + /* Make sure nothing crashes when all these are set NULL, since the + * internal default values should still be used. */ + pceplib_memory_initialize(NULL, NULL, NULL, NULL, NULL, NULL, NULL); + + /* Test malloc() */ + void *ptr = pceplib_malloc(PCEPLIB_INFRA, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_INFRA, ptr); + verify_memory_type(pceplib_infra_ptr, alloc_counter, alloc_size, + free_counter++, 0); + + /* Test calloc() */ + ptr = pceplib_calloc(PCEPLIB_INFRA, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_INFRA, ptr); + alloc_counter++; + verify_memory_type(pceplib_infra_ptr, alloc_counter, + alloc_size * alloc_counter, free_counter++, 0); + + /* Test realloc() */ + ptr = pceplib_malloc(PCEPLIB_INFRA, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + ptr = pceplib_realloc(PCEPLIB_INFRA, ptr, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_INFRA, ptr); + alloc_counter += 2; + verify_memory_type(pceplib_infra_ptr, alloc_counter, + alloc_size * alloc_counter, free_counter++, 0); + + /* Test strdup() */ + ptr = pceplib_malloc(PCEPLIB_INFRA, alloc_size); + /* Make strdup duplicate (alloc_size - 1) bytes */ + memset(ptr, 'a', alloc_size); + ((char *)ptr)[alloc_size - 1] = '\0'; + char *str = pceplib_strdup(PCEPLIB_INFRA, (char *)ptr); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_INFRA, ptr); + pceplib_free(PCEPLIB_INFRA, str); + alloc_counter += 2; + free_counter++; + verify_memory_type(pceplib_infra_ptr, alloc_counter, + (alloc_size * alloc_counter) - 1, free_counter, 0); + + /* Make sure only the pceplib_infra_ptr memory counters are incremented + */ + verify_memory_type(pceplib_messages_ptr, 0, 0, 0, 0); +} + +void test_memory_external_impl() +{ + int alloc_size = 100; + struct pceplib_memory_type *pceplib_infra_ptr = + (struct pceplib_memory_type *)PCEPLIB_INFRA; + struct pceplib_memory_type *pceplib_messages_ptr = + (struct pceplib_memory_type *)PCEPLIB_MESSAGES; + + /* reset the internal memory type counters to later verify they are NOT + * incremented since an external impl was provided */ + pceplib_infra_ptr->num_allocates = + pceplib_infra_ptr->total_bytes_allocated = + pceplib_infra_ptr->num_frees = + pceplib_infra_ptr->total_bytes_freed = 0; + pceplib_messages_ptr->num_allocates = + pceplib_messages_ptr->total_bytes_allocated = + pceplib_messages_ptr->num_frees = + pceplib_messages_ptr->total_bytes_freed = 0; + + /* Setup the external memory type */ + struct test_memory_type infra_mt, messages_mt; + void *infra_ptr = &infra_mt; + void *messages_ptr = &messages_mt; + memset(infra_ptr, 0, sizeof(struct test_memory_type)); + memset(messages_ptr, 0, sizeof(struct test_memory_type)); + int free_counter = 1; + + /* Initialize the PCEPlib memory system with an external implementation + */ + pceplib_memory_initialize(infra_ptr, messages_ptr, test_pceplib_malloc, + test_pceplib_calloc, test_pceplib_realloc, + test_pceplib_strdup, test_pceplib_free); + + /* Test malloc() */ + void *ptr = pceplib_malloc(PCEPLIB_MESSAGES, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_MESSAGES, ptr); + verify_ext_memory_type(messages_ptr, 1, 0, 0, 0, free_counter++); + + /* Test calloc() */ + ptr = pceplib_calloc(PCEPLIB_MESSAGES, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_MESSAGES, ptr); + verify_ext_memory_type(messages_ptr, 1, 1, 0, 0, free_counter++); + + /* Test realloc() */ + ptr = pceplib_malloc(PCEPLIB_MESSAGES, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + ptr = pceplib_realloc(PCEPLIB_MESSAGES, ptr, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_MESSAGES, ptr); + verify_ext_memory_type(messages_ptr, 2, 1, 1, 0, free_counter++); + + /* Test strdup() */ + ptr = pceplib_malloc(PCEPLIB_MESSAGES, alloc_size); + /* Make strdup duplicate (alloc_size - 1) bytes */ + memset(ptr, 'a', alloc_size); + ((char *)ptr)[alloc_size - 1] = '\0'; + char *str = pceplib_strdup(PCEPLIB_MESSAGES, (char *)ptr); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_MESSAGES, ptr); + pceplib_free(PCEPLIB_MESSAGES, str); + verify_ext_memory_type(messages_ptr, 3, 1, 1, 1, free_counter + 1); + + /* Make sure the internal memory counters are NOT incremented */ + verify_memory_type(pceplib_infra_ptr, 0, 0, 0, 0); + verify_memory_type(pceplib_messages_ptr, 0, 0, 0, 0); + + verify_ext_memory_type(infra_ptr, 0, 0, 0, 0, 0); +} diff --git a/pceplib/test/pcep_utils_memory_test.h b/pceplib/test/pcep_utils_memory_test.h new file mode 100644 index 000000000..4e0c3fadf --- /dev/null +++ b/pceplib/test/pcep_utils_memory_test.h @@ -0,0 +1,33 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_MEMORY_TEST_H_ +#define PCEP_MEMORY_TEST_H_ + +void test_memory_internal_impl(void); +void test_memory_external_impl(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_utils_ordered_list_test.c b/pceplib/test/pcep_utils_ordered_list_test.c new file mode 100644 index 000000000..fe9ee5882 --- /dev/null +++ b/pceplib/test/pcep_utils_ordered_list_test.c @@ -0,0 +1,248 @@ +/* + * 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> + * + */ + + +#include <CUnit/CUnit.h> + +#include "pcep_utils_ordered_list.h" +#include "pcep_utils_ordered_list_test.h" + +typedef struct node_data_ { + int int_data; + +} node_data; + + +int node_data_compare(void *list_entry, void *new_entry) +{ + /* + * < 0 if new_entry < list_entry + * == 0 if new_entry == list_entry (new_entry will be inserted after + * list_entry) > 0 if new_entry > list_entry + */ + + return ((node_data *)new_entry)->int_data + - ((node_data *)list_entry)->int_data; +} + + +void test_empty_list() +{ + ordered_list_handle *handle = + ordered_list_initialize(node_data_compare); + + CU_ASSERT_PTR_NOT_NULL(handle); + CU_ASSERT_PTR_NULL(handle->head); + CU_ASSERT_PTR_NOT_NULL(handle->compare_function); + CU_ASSERT_EQUAL(handle->num_entries, 0); + + ordered_list_destroy(handle); +} + + +void test_null_list_handle() +{ + node_data data; + ordered_list_node node_data; + + void *ptr = ordered_list_add_node(NULL, &data); + CU_ASSERT_PTR_NULL(ptr); + + ptr = ordered_list_find(NULL, &data); + CU_ASSERT_PTR_NULL(ptr); + + ptr = ordered_list_remove_first_node(NULL); + CU_ASSERT_PTR_NULL(ptr); + + ptr = ordered_list_remove_first_node_equals(NULL, &data); + CU_ASSERT_PTR_NULL(ptr); + + ptr = ordered_list_remove_node(NULL, &node_data, &node_data); + CU_ASSERT_PTR_NULL(ptr); +} + + +void test_add_to_list() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + ordered_list_handle *handle = + ordered_list_initialize(node_data_compare); + + ordered_list_add_node(handle, &data3); + ordered_list_add_node(handle, &data1); + ordered_list_add_node(handle, &data2); + + CU_ASSERT_EQUAL(handle->num_entries, 3); + + ordered_list_node *node = handle->head; + CU_ASSERT_PTR_EQUAL(node->data, &data1); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data2); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data3); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node, NULL); + + ordered_list_destroy(handle); +} + + +void test_find() +{ + node_data data1, data2, data3, data_not_inList; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + data_not_inList.int_data = 5; + + ordered_list_handle *handle = + ordered_list_initialize(node_data_compare); + + ordered_list_add_node(handle, &data3); + ordered_list_add_node(handle, &data2); + ordered_list_add_node(handle, &data1); + + ordered_list_node *node = ordered_list_find(handle, &data1); + CU_ASSERT_PTR_NOT_NULL(node); + CU_ASSERT_PTR_EQUAL(node->data, &data1); + + node = ordered_list_find(handle, &data2); + CU_ASSERT_PTR_NOT_NULL(node); + CU_ASSERT_PTR_EQUAL(node->data, &data2); + + node = ordered_list_find(handle, &data3); + CU_ASSERT_PTR_NOT_NULL(node); + CU_ASSERT_PTR_EQUAL(node->data, &data3); + + node = ordered_list_find(handle, &data_not_inList); + CU_ASSERT_PTR_NULL(node); + + ordered_list_destroy(handle); +} + + +void test_remove_first_node() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + ordered_list_handle *handle = + ordered_list_initialize(node_data_compare); + + ordered_list_add_node(handle, &data1); + ordered_list_add_node(handle, &data2); + ordered_list_add_node(handle, &data3); + + void *node_data = ordered_list_remove_first_node(handle); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data1); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + node_data = ordered_list_remove_first_node(handle); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data2); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + node_data = ordered_list_remove_first_node(handle); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data3); + CU_ASSERT_EQUAL(handle->num_entries, 0); + CU_ASSERT_PTR_NULL(handle->head); + + node_data = ordered_list_remove_first_node(handle); + CU_ASSERT_PTR_NULL(node_data); + + ordered_list_destroy(handle); +} + + +void test_remove_first_node_equals() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + ordered_list_handle *handle = + ordered_list_initialize(node_data_compare); + + ordered_list_add_node(handle, &data1); + ordered_list_add_node(handle, &data2); + ordered_list_add_node(handle, &data3); + + void *node_data = ordered_list_remove_first_node_equals(handle, &data2); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data2); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + node_data = ordered_list_remove_first_node_equals(handle, &data3); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data3); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + node_data = ordered_list_remove_first_node_equals(handle, &data1); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data1); + CU_ASSERT_EQUAL(handle->num_entries, 0); + + node_data = ordered_list_remove_first_node_equals(handle, &data1); + CU_ASSERT_PTR_NULL(node_data); + + ordered_list_destroy(handle); +} + + +void test_remove_node() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + ordered_list_handle *handle = + ordered_list_initialize(node_data_compare); + + ordered_list_node *node1 = ordered_list_add_node(handle, &data1); + ordered_list_node *node2 = ordered_list_add_node(handle, &data2); + ordered_list_node *node3 = ordered_list_add_node(handle, &data3); + + void *node_data = ordered_list_remove_node(handle, node2, node3); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data3); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + node_data = ordered_list_remove_node(handle, node1, node2); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data2); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + ordered_list_destroy(handle); +} diff --git a/pceplib/test/pcep_utils_ordered_list_test.h b/pceplib/test/pcep_utils_ordered_list_test.h new file mode 100644 index 000000000..3686848b6 --- /dev/null +++ b/pceplib/test/pcep_utils_ordered_list_test.h @@ -0,0 +1,39 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_UTILS_ORDERED_LIST_TEST_H_ +#define PCEP_UTILS_ORDERED_LIST_TEST_H_ + +void test_empty_list(void); +void test_null_list_handle(void); +void test_add_to_list(void); +void test_find(void); +void test_remove_first_node(void); +void test_remove_first_node_equals(void); +void test_remove_node(void); +int node_data_compare(void *list_entry, void *new_entry); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_utils_queue_test.c b/pceplib/test/pcep_utils_queue_test.c new file mode 100644 index 000000000..173145778 --- /dev/null +++ b/pceplib/test/pcep_utils_queue_test.c @@ -0,0 +1,157 @@ +/* + * 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> + * + */ + + +#include <CUnit/CUnit.h> + +#include "pcep_utils_queue.h" +#include "pcep_utils_queue_test.h" + +typedef struct node_data_ { + int int_data; + +} node_data; + + +void test_empty_queue() +{ + queue_handle *handle = queue_initialize(); + + CU_ASSERT_PTR_NOT_NULL(handle); + CU_ASSERT_PTR_NULL(handle->head); + CU_ASSERT_EQUAL(handle->num_entries, 0); + + queue_destroy(handle); +} + + +void test_null_queue_handle() +{ + /* test each method handles a NULL handle without crashing */ + node_data data; + queue_destroy(NULL); + void *ptr = queue_enqueue(NULL, &data); + CU_ASSERT_PTR_NULL(ptr); + + ptr = queue_dequeue(NULL); + CU_ASSERT_PTR_NULL(ptr); +} + + +void test_enqueue() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + queue_handle *handle = queue_initialize(); + + queue_enqueue(handle, &data1); + queue_enqueue(handle, &data2); + queue_enqueue(handle, &data3); + + CU_ASSERT_EQUAL(handle->num_entries, 3); + + queue_node *node = handle->head; + CU_ASSERT_PTR_EQUAL(node->data, &data1); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data2); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data3); + + node = node->next_node; + CU_ASSERT_PTR_NULL(node); + + queue_destroy(handle); +} + + +void test_enqueue_with_limit() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + queue_handle *handle = queue_initialize_with_size(2); + + queue_node *node = queue_enqueue(handle, &data1); + CU_ASSERT_PTR_NOT_NULL(node); + + node = queue_enqueue(handle, &data2); + CU_ASSERT_PTR_NOT_NULL(node); + + node = queue_enqueue(handle, &data3); + CU_ASSERT_PTR_NULL(node); + + CU_ASSERT_EQUAL(handle->num_entries, 2); + + node = handle->head; + CU_ASSERT_PTR_EQUAL(node->data, &data1); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data2); + + node = node->next_node; + CU_ASSERT_PTR_NULL(node); + + queue_destroy(handle); +} + + +void test_dequeue() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + queue_handle *handle = queue_initialize(); + + /* first test dequeue handles an empty queue */ + void *node_data = queue_dequeue(handle); + CU_ASSERT_PTR_NULL(node_data); + + queue_enqueue(handle, &data1); + queue_enqueue(handle, &data2); + queue_enqueue(handle, &data3); + + node_data = queue_dequeue(handle); + CU_ASSERT_PTR_EQUAL(node_data, &data1); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + node_data = queue_dequeue(handle); + CU_ASSERT_PTR_EQUAL(node_data, &data2); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + node_data = queue_dequeue(handle); + CU_ASSERT_PTR_EQUAL(node_data, &data3); + CU_ASSERT_EQUAL(handle->num_entries, 0); + + node_data = queue_dequeue(handle); + CU_ASSERT_PTR_NULL(node_data); + + queue_destroy(handle); +} diff --git a/pceplib/test/pcep_utils_queue_test.h b/pceplib/test/pcep_utils_queue_test.h new file mode 100644 index 000000000..16236d0d9 --- /dev/null +++ b/pceplib/test/pcep_utils_queue_test.h @@ -0,0 +1,36 @@ +/* + * 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 : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_UTILS_QUEUE_TEST_H_ +#define PCEP_UTILS_QUEUE_TEST_H_ + +void test_empty_queue(void); +void test_null_queue_handle(void); +void test_enqueue(void); +void test_enqueue_with_limit(void); +void test_dequeue(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_utils_tests.c b/pceplib/test/pcep_utils_tests.c new file mode 100644 index 000000000..452b9fa09 --- /dev/null +++ b/pceplib/test/pcep_utils_tests.c @@ -0,0 +1,136 @@ +/* + * 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> + * + */ + + +#include <CUnit/Basic.h> +#include <CUnit/CUnit.h> +#include <CUnit/TestDB.h> +#include "pcep_utils_ordered_list_test.h" +#include "pcep_utils_queue_test.h" +#include "pcep_utils_double_linked_list_test.h" +#include "pcep_utils_counters_test.h" +#include "pcep_utils_memory_test.h" + + +int main(int argc, char **argv) +{ + /* Unused parameters cause compilation warnings */ + (void)argc; + (void)argv; + + CU_initialize_registry(); + + CU_pSuite test_queue_suite = + CU_add_suite("PCEP Utils Queue Test Suite", NULL, NULL); + CU_add_test(test_queue_suite, "test_empty_queue", test_empty_queue); + CU_add_test(test_queue_suite, "test_null_queue_handle", + test_null_queue_handle); + CU_add_test(test_queue_suite, "test_enqueue", test_enqueue); + CU_add_test(test_queue_suite, "test_enqueue_with_limit", + test_enqueue_with_limit); + CU_add_test(test_queue_suite, "test_dequeue", test_dequeue); + + CU_pSuite test_list_suite = + CU_add_suite("PCEP Utils Ordered List Test Suite", NULL, NULL); + CU_add_test(test_list_suite, "test_empty_list", test_empty_list); + CU_add_test(test_list_suite, "test_null_handle", test_null_list_handle); + CU_add_test(test_list_suite, "test_add_toList", test_add_to_list); + CU_add_test(test_list_suite, "test_find", test_find); + CU_add_test(test_list_suite, "test_remove_first_node", + test_remove_first_node); + CU_add_test(test_list_suite, "test_remove_first_node_equals", + test_remove_first_node_equals); + CU_add_test(test_list_suite, "test_remove_node", test_remove_node); + + CU_pSuite test_dl_list_suite = CU_add_suite( + "PCEP Utils Double Linked List Test Suite", NULL, NULL); + CU_add_test(test_dl_list_suite, "test_empty_dl_list", + test_empty_dl_list); + CU_add_test(test_dl_list_suite, "test_null_dl_handle", + test_null_dl_list_handle); + CU_add_test(test_dl_list_suite, "test_dll_prepend_data", + test_dll_prepend_data); + CU_add_test(test_dl_list_suite, "test_dll_append_data", + test_dll_append_data); + CU_add_test(test_dl_list_suite, "test_dll_delete_first_node", + test_dll_delete_first_node); + CU_add_test(test_dl_list_suite, "test_dll_delete_last_node", + test_dll_delete_last_node); + CU_add_test(test_dl_list_suite, "test_dll_delete_node", + test_dll_delete_node); + + CU_pSuite test_counters_suite = + CU_add_suite("PCEP Utils Counters Test Suite", NULL, NULL); + CU_add_test(test_counters_suite, "test_create_counters_group", + test_create_counters_group); + CU_add_test(test_counters_suite, "test_create_counters_subgroup", + test_create_counters_subgroup); + CU_add_test(test_counters_suite, "test_add_counters_subgroup", + test_add_counters_subgroup); + CU_add_test(test_counters_suite, "test_create_subgroup_counter", + test_create_subgroup_counter); + CU_add_test(test_counters_suite, "test_delete_counters_group", + test_delete_counters_group); + CU_add_test(test_counters_suite, "test_delete_counters_subgroup", + test_delete_counters_subgroup); + CU_add_test(test_counters_suite, "test_reset_group_counters", + test_reset_group_counters); + CU_add_test(test_counters_suite, "test_reset_subgroup_counters", + test_reset_subgroup_counters); + CU_add_test(test_counters_suite, "test_increment_counter", + test_increment_counter); + CU_add_test(test_counters_suite, "test_increment_subgroup_counter", + test_increment_subgroup_counter); + CU_add_test(test_counters_suite, "test_dump_counters_group_to_log", + test_dump_counters_group_to_log); + CU_add_test(test_counters_suite, "test_dump_counters_subgroup_to_log", + test_dump_counters_subgroup_to_log); + + CU_pSuite test_memory_suite = + CU_add_suite("PCEP Utils Memory Test Suite", NULL, NULL); + CU_add_test(test_memory_suite, "test_memory_internal_impl", + test_memory_internal_impl); + CU_add_test(test_memory_suite, "test_memory_external_impl", + test_memory_external_impl); + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_FailureRecord *failure_record = CU_get_failure_list(); + if (failure_record != NULL) { + printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n"); + do { + printf("\t [%s] [%s] [%s:%d]\n", + failure_record->pSuite->pName, + failure_record->pTest->pName, + failure_record->strFileName, + failure_record->uiLineNumber); + failure_record = failure_record->pNext; + + } while (failure_record != NULL); + } + + CU_pRunSummary run_summary = CU_get_run_summary(); + int result = run_summary->nTestsFailed; + CU_cleanup_registry(); + + return result; +} diff --git a/pceplib/test/pcep_utils_tests_valgrind.sh b/pceplib/test/pcep_utils_tests_valgrind.sh new file mode 100755 index 000000000..6348d8270 --- /dev/null +++ b/pceplib/test/pcep_utils_tests_valgrind.sh @@ -0,0 +1,2 @@ +source pceplib/test/pcep_tests_valgrind.sh +valgrind_test pceplib/test/pcep_utils_tests diff --git a/pceplib/test/subdir.am b/pceplib/test/subdir.am new file mode 100644 index 000000000..0ae61d1bc --- /dev/null +++ b/pceplib/test/subdir.am @@ -0,0 +1,122 @@ +if PATHD_PCEP +if PATHD_PCEP_TEST + +# The default Automake target is check, add a test target to call check. +# Also make sure the binaries are current before running the tests. +test: pceplib/test/pcep_msg_tests pceplib/test/pcep_pcc_api_tests pceplib/test/pcep_session_logic_tests pceplib/test/pcep_socket_comm_tests pceplib/test/pcep_timers_tests pceplib/test/pcep_utils_tests + +check_SCRIPTS = pceplib/test/pcep_msg_tests pceplib/test/pcep_pcc_api_tests pceplib/test/pcep_session_logic_tests pceplib/test/pcep_socket_comm_tests pceplib/test/pcep_timers_tests pceplib/test/pcep_utils_tests +TESTS = $(check_SCRIPTS) + + +# Definitions to build the Unit Test binaries with CUnit +noinst_PROGRAMS += pceplib/test/pcep_msg_tests \ + pceplib/test/pcep_pcc_api_tests \ + pceplib/test/pcep_session_logic_tests \ + pceplib/test/pcep_socket_comm_tests \ + pceplib/test/pcep_timers_tests \ + pceplib/test/pcep_utils_tests + +noinst_HEADERS += pceplib/test/pcep_msg_messages_test.h \ + pceplib/test/pcep_msg_object_error_types_test.h \ + pceplib/test/pcep_msg_objects_test.h \ + pceplib/test/pcep_msg_tlvs_test.h \ + pceplib/test/pcep_msg_tools_test.h \ + pceplib/test/pcep_pcc_api_test.h \ + pceplib/test/pcep_session_logic_loop_test.h \ + pceplib/test/pcep_session_logic_states_test.h \ + pceplib/test/pcep_session_logic_test.h \ + pceplib/test/pcep_socket_comm_loop_test.h \ + pceplib/test/pcep_socket_comm_test.h \ + pceplib/test/pcep_timers_event_loop_test.h \ + pceplib/test/pcep_timers_test.h \ + pceplib/test/pcep_utils_counters_test.h \ + pceplib/test/pcep_utils_double_linked_list_test.h \ + pceplib/test/pcep_utils_memory_test.h \ + pceplib/test/pcep_utils_ordered_list_test.h \ + pceplib/test/pcep_utils_queue_test.h + +pceplib_test_pcep_msg_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_msg_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread +pceplib_test_pcep_msg_tests_SOURCES = pceplib/test/pcep_msg_messages_test.c \ + pceplib/test/pcep_msg_messages_tests.c \ + pceplib/test/pcep_msg_object_error_types_test.c \ + pceplib/test/pcep_msg_objects_test.c \ + pceplib/test/pcep_msg_tlvs_test.c \ + pceplib/test/pcep_msg_tools_test.c + +# The pcc_api_tests and pcep_session_logic_tests use the +# socket_comm_mock, so the LDADD variable needs to be modified +pceplib_test_pcep_pcc_api_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_pcc_api_tests_LDADD = $(top_builddir)/pceplib/libsocket_comm_mock.la $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread +pceplib_test_pcep_pcc_api_tests_SOURCES = pceplib/test/pcep_pcc_api_test.c pceplib/test/pcep_pcc_api_tests.c + +pceplib_test_pcep_session_logic_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_session_logic_tests_LDADD = $(top_builddir)/pceplib/libsocket_comm_mock.la $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread +pceplib_test_pcep_session_logic_tests_SOURCES = pceplib/test/pcep_session_logic_loop_test.c \ + pceplib/test/pcep_session_logic_states_test.c \ + pceplib/test/pcep_session_logic_test.c \ + pceplib/test/pcep_session_logic_tests.c + +pceplib_test_pcep_socket_comm_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_socket_comm_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread +pceplib_test_pcep_socket_comm_tests_SOURCES = pceplib/test/pcep_socket_comm_loop_test.c \ + pceplib/test/pcep_socket_comm_test.c \ + pceplib/test/pcep_socket_comm_tests.c + +pceplib_test_pcep_timers_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_timers_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread +pceplib_test_pcep_timers_tests_SOURCES = pceplib/test/pcep_timers_event_loop_test.c \ + pceplib/test/pcep_timers_test.c \ + pceplib/test/pcep_timers_tests.c + +pceplib_test_pcep_utils_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_utils_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread +pceplib_test_pcep_utils_tests_SOURCES = pceplib/test/pcep_utils_counters_test.c \ + pceplib/test/pcep_utils_double_linked_list_test.c \ + pceplib/test/pcep_utils_memory_test.c \ + pceplib/test/pcep_utils_ordered_list_test.c \ + pceplib/test/pcep_utils_queue_test.c \ + pceplib/test/pcep_utils_tests.c + +# These test scripts will call the test binaries +# defined above in noinst_PROGRAMS with Valgrind +if HAVE_VALGRIND_PCEP + +dist_noinst_SCRIPTS = pceplib/test/pcep_pcc_api_tests_valgrind.sh \ + pceplib/test/pcep_session_logic_tests_valgrind.sh \ + pceplib/test/pcep_socket_comm_tests_valgrind.sh \ + pceplib/test/pcep_timers_tests_valgrind.sh \ + pceplib/test/pcep_utils_tests_valgrind.sh \ + pceplib/test/pcep_msg_tests_valgrind.sh \ + pceplib/test/pcep_tests_valgrind.sh + +check_SCRIPTS += pceplib/test/pcep_msg_tests_valgrind.sh \ + pceplib/test/pcep_pcc_api_tests_valgrind.sh \ + pceplib/test/pcep_session_logic_tests_valgrind.sh \ + pceplib/test/pcep_socket_comm_tests_valgrind.sh \ + pceplib/test/pcep_timers_tests_valgrind.sh \ + pceplib/test/pcep_utils_tests_valgrind.sh + +TESTS += $(check_SCRIPTS) + + + +pceplib/test/pcep_msg_tests_valgrind.sh: + chmod +x pceplib/test/pcep_msg_tests_valgrind.sh +pceplib/test/pcep_pcc_api_tests_valgrind.sh: + chmod +x pceplib/test/pcep_pcc_api_tests_valgrind.sh +pceplib/test/pcep_session_logic_tests_valgrind.sh: + chmod +x pceplib/test/pcep_session_logic_tests_valgrind.sh +pceplib/test/pcep_socket_comm_tests_valgrind.sh: + chmod +x pceplib/test/pcep_socket_comm_tests_valgrind.sh +pceplib/test/pcep_timers_tests_valgrind.sh: + chmod +x pceplib/test/pcep_timers_tests_valgrind.sh +pceplib/test/pcep_utils_tests_valgrind.sh: + chmod +x pceplib/test/pcep_utils_tests_valgrind.sh + + +endif + +endif +endif |