示例#1
0
void test_KineticPDU_Send_should_send_the_PDU_and_return_true_upon_successful_transmission_of_full_PDU_with_value_payload(void)
{
    LOG_LOCATION;
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));

    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    uint8_t valueData[128];
    ByteBuffer valueBuffer = ByteBuffer_Create(valueData, sizeof(valueData));
    ByteBuffer_AppendCString(&valueBuffer, "Some arbitrary value");
    KineticEntry entry = {.value = valueBuffer};
    KineticPDU_AttachEntry(&PDU, &entry);

    KineticHMAC_Init_Expect(&PDU.hmac, KINETIC_PROTO_SECURITY_ACL_HMACALGORITHM_HmacSHA1);
    KineticHMAC_Populate_Expect(&PDU.hmac,
                                &PDU.protoData.message.proto, PDU.connection->session.hmacKey);
    KineticSocket_Write_ExpectAndReturn(Connection.socket, &headerNBO, KINETIC_STATUS_SUCCESS);
    KineticSocket_WriteProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS);
    KineticSocket_Write_ExpectAndReturn(Connection.socket, &PDU.entry.value, KINETIC_STATUS_SUCCESS);

    TEST_IGNORE_MESSAGE("Need to figure out how to handle address of PDU header");

    KineticStatus status = KineticPDU_Send(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}
void test_kinetic_client_should_store_a_binary_object_split_across_entries_via_overlapped_asynchronous_IO_operations(void)
{
    ByteBuffer test_data = ByteBuffer_Malloc(PAYLOAD_SIZE);
    ByteBuffer_AppendDummyData(&test_data, test_data.array.len);

    uint8_t tag_data[] = {0x00, 0x01, 0x02, 0x03};
    ByteBuffer tag = ByteBuffer_Create(tag_data, sizeof(tag_data), sizeof(tag_data));
    for (size_t i = 0; i < NUM_PUTS; i++) {
        put_statuses[i] = (PutStatus) {
            .sem = KineticSemaphore_Create(),
             .status = KINETIC_STATUS_INVALID,
        };
    };

    printf("Waiting for put finish\n");

    struct timeval start_time;
    gettimeofday(&start_time, NULL);

    for (uint32_t put = 0; put < NUM_PUTS; put++) {
        keys[put] = put;
        ByteBuffer key = ByteBuffer_Create(&keys[put], sizeof(keys[put]), sizeof(keys[put]));

        KineticSynchronization sync = (put == NUM_PUTS - 1)
                                      ? KINETIC_SYNCHRONIZATION_FLUSH
                                      : KINETIC_SYNCHRONIZATION_WRITEBACK;

        entries[put] = (KineticEntry) {
            .key = key,
             .tag = tag,
              .algorithm = KINETIC_ALGORITHM_SHA1,
               .value = test_data,
                .synchronization = sync,
        };

        KineticStatus status = KineticClient_Put(Fixture.session,
                               &entries[put],
        &(KineticCompletionClosure) {
            .callback = put_finished,
             .clientData = &put_statuses[put],
        }
                                                );

        if (status != KINETIC_STATUS_SUCCESS) {
            fprintf(stderr, "PUT failed w/status: %s\n", Kinetic_GetStatusDescription(status));
            TEST_FAIL();
        }
    }
示例#3
0
void test_KineticPDU_Send_should_send_the_PDU_and_return_true_upon_successful_transmission_of_full_PDU_with_no_value_payload(void)
{
    LOG_LOCATION;
    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));

    KineticEntry entry = {.value = BYTE_BUFFER_NONE};
    KineticPDU_AttachEntry(&PDU, &entry);

    // Create NBO copy of header for sending
    PDU.headerNBO.versionPrefix = 'F';
    PDU.headerNBO.protobufLength =
        KineticNBO_FromHostU32(KineticProto__get_packed_size(PDU.proto));
    PDU.headerNBO.valueLength = 0;

    KineticHMAC_Init_Expect(&PDU.hmac,
                            KINETIC_PROTO_SECURITY_ACL_HMACALGORITHM_HmacSHA1);
    KineticHMAC_Populate_Expect(&PDU.hmac,
                                &PDU.protoData.message.proto, PDU.connection->session.hmacKey);
    KineticSocket_Write_ExpectAndReturn(Connection.socket, &headerNBO, KINETIC_STATUS_SUCCESS);
    KineticSocket_WriteProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS);

    TEST_IGNORE_MESSAGE("Need to figure out how to handle address of PDU header");

    KineticStatus status = KineticPDU_Send(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}
void setUp(void)
{
    KineticLogger_Init("stdout", 3);

    // Configure start and end key buffers
    StartKey = ByteBuffer_Create(StartKeyData, sizeof(StartKeyData), sizeof(StartKeyData));
    EndKey = ByteBuffer_Create(EndKeyData, sizeof(EndKeyData), sizeof(EndKeyData));

    // Initialize buffers to hold returned keys in requested range
    for (int i = 0; i < MAX_KEYS_RETRIEVED; i++) {
        Keys[i] = ByteBuffer_Create(&KeyRangeData[i], sizeof(KeyRangeData[i]), sizeof(KeyRangeData[i]));
        char keyBuf[64];
        snprintf(keyBuf, sizeof(keyBuf), "key_range_00_%02d", i);
        ByteBuffer_AppendCString(&Keys[i], keyBuf);
    }
}
void test_KineticClient_GetPrevious_should_expose_memory_errors(void)
{
    uint8_t key[] = "schlage";
    ByteBuffer KeyBuffer = ByteBuffer_Create(key, sizeof(key), sizeof(key));

    uint8_t value[1024];
    ByteBuffer ValueBuffer = ByteBuffer_Create(value, sizeof(value), 0);

    KineticEntry entry = {
        .key = KeyBuffer,
        .value = ValueBuffer,
    };

    KineticAllocator_NewOperation_ExpectAndReturn(&Session, NULL);
    KineticStatus status = KineticClient_GetPrevious(&Session, &entry, NULL);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_MEMORY_ERROR, status);
}
示例#6
0
void test_KineticPDU_Receive_should_receive_a_message_with_no_value_payload_and_forward_status_upon_receipt_of_valid_PDU_with_non_successful_status(void)
{
    LOG_LOCATION;
    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    PDU.protoData.message.status.code = KINETIC_PROTO_STATUS_STATUS_CODE_PERM_DATA_ERROR;
    PDU.protoData.message.status.has_code = true;
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));

    // Fake value/payload length
    uint8_t data[1024];
    ByteArray expectedValue = {.data = data, .len = sizeof(data)};
    ByteArray_FillWithDummyData(expectedValue);
    KineticEntry entry = {.value = ByteBuffer_CreateWithArray(expectedValue)};
    KineticPDU_AttachEntry(&PDU, &entry);

    PDU.headerNBO.valueLength = KineticNBO_FromHostU32(0);
    KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS);
    KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS);
    KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, true);
    EnableAndSetPDUStatus(&PDU, KINETIC_PROTO_STATUS_STATUS_CODE_PERM_DATA_ERROR);

    KineticStatus status = KineticPDU_Receive(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DATA_ERROR, status);
    TEST_ASSERT_EQUAL(
        KINETIC_PROTO_STATUS_STATUS_CODE_PERM_DATA_ERROR,
        PDU.protoData.message.status.code);
}

void test_KineticPDU_Receive_should_receive_a_message_for_the_exchange_and_return_false_upon_failure_to_read_header(void)
{
    LOG_LOCATION;
    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));

    KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_CONNECTION_ERROR);

    KineticStatus status = KineticPDU_Receive(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_CONNECTION_ERROR, status);
}
示例#7
0
void test_ByteBuffer_Create_should_create_ByteBuffer_with_specified_array_and_max_length_and_used_bytes(void)
{
    uint8_t data[] = {0x1u, 0x2u, 0x3u, 0x4u};
    size_t len = sizeof(data);

    ByteBuffer buffer = ByteBuffer_Create(data, len, 2);

    TEST_ASSERT_EQUAL_PTR(data, buffer.array.data);
    TEST_ASSERT_EQUAL(len, buffer.array.len);
    TEST_ASSERT_EQUAL_HEX8_ARRAY(data, buffer.array.data, len);
    TEST_ASSERT_EQUAL(2, buffer.bytesUsed);
}
void test_KineticClient_GetPrevious_should_execute_GETNEXT(void)
{
    uint8_t key[] = "schlage";
    ByteBuffer KeyBuffer = ByteBuffer_Create(key, sizeof(key), sizeof(key));

    uint8_t value[1024];
    ByteBuffer ValueBuffer = ByteBuffer_Create(value, sizeof(value), 0);

    KineticEntry entry = {
        .key = KeyBuffer,
        .value = ValueBuffer,
    };
    KineticOperation operation;

    KineticAllocator_NewOperation_ExpectAndReturn(&Session, &operation);
    KineticBuilder_BuildGetPrevious_ExpectAndReturn(&operation, &entry, KINETIC_STATUS_SUCCESS);
    KineticController_ExecuteOperation_ExpectAndReturn(&operation, NULL, KINETIC_STATUS_SUCCESS);

    KineticStatus status = KineticClient_GetPrevious(&Session, &entry, NULL);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}
示例#9
0
void test_KineticPDU_Receive_should_receive_a_message_for_the_exchange_and_return_false_upon_failure_to_read_protobuf(void)
{
    LOG_LOCATION;

    KineticPDU_Init(&PDU, &Connection);
    PDU.protoData.message.status.code = KINETIC_PROTO_STATUS_STATUS_CODE_PERM_DATA_ERROR;
    PDU.protoData.message.status.has_code = true;

    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));
    PDU.headerNBO = (KineticPDUHeader) {
        .versionPrefix = (uint8_t)'F',
         .protobufLength = KineticNBO_FromHostU32(12),
          .valueLength = 0
    };

    KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS);
    KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_DEVICE_BUSY);

    KineticStatus status = KineticPDU_Receive(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DEVICE_BUSY, status)
}

void test_KineticPDU_Receive_should_receive_a_message_for_the_exchange_and_return_false_upon_HMAC_validation_failure(void)
{
    LOG_LOCATION;
    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));

    KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS);
    KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS);
    KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, false);

    KineticStatus status = KineticPDU_Receive(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DATA_ERROR, status);
}
示例#10
0
void test_KineticPDU_Receive_should_receive_a_message_with_no_value_payload_and_return_true_upon_successful_receipt_of_valid_PDU(void)
{
    LOG_LOCATION;
    Connection.connectionID = 98765;
    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));

    KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS);
    KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS);
    KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, true);
    EnableAndSetPDUConnectionID(&PDU, 12345);
    EnableAndSetPDUStatus(&PDU, KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS);

    KineticStatus status = KineticPDU_Receive(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    TEST_ASSERT_EQUAL(KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS,
                      PDU.protoData.message.status.code);
}
示例#11
0
KineticStatus KineticSocket_ReadProtobuf(int socket, KineticPDU* pdu)
{
    size_t bytesToRead = pdu->header.protobufLength;
    #ifdef KINETIC_LOG_SOCKET_OPERATIONS
    LOGF("Reading %zd bytes of protobuf", bytesToRead);
    #endif

    uint8_t* packed = (uint8_t*)malloc(bytesToRead);
    if (packed == NULL) {
        LOG("Failed allocating memory for protocol buffer");
        return KINETIC_STATUS_MEMORY_ERROR;
    }

    ByteBuffer recvBuffer = ByteBuffer_Create(packed, bytesToRead);
    KineticStatus status = KineticSocket_Read(socket, &recvBuffer, bytesToRead);

    if (status != KINETIC_STATUS_SUCCESS) {
        LOG("Protobuf read failed!");
        free(packed);
        return status;
    }
    else {
        pdu->proto = KineticProto__unpack(
            NULL, recvBuffer.bytesUsed, recvBuffer.array.data);
    }

    free(packed);

    if (pdu->proto == NULL) {
        pdu->protobufDynamicallyExtracted = false;
        LOG("Error unpacking incoming Kinetic protobuf message!");
        return KINETIC_STATUS_DATA_ERROR;
    }
    else {
        pdu->protobufDynamicallyExtracted = true;
        #ifdef KINETIC_LOG_SOCKET_OPERATIONS
        LOG("Protobuf unpacked successfully!");
        #endif
        return KINETIC_STATUS_SUCCESS;
    }
}
示例#12
0
KineticStatus KineticSocket_WriteProtobuf(int socket, KineticPDU* pdu)
{
    assert(pdu != NULL);
    LOGF1("Writing protobuf (%zd bytes)...", pdu->header.protobufLength);

    uint8_t* packed = (uint8_t*)malloc(pdu->header.protobufLength);

    if (packed == NULL) {
        LOG0("Failed allocating memory for protocol buffer");
        return KINETIC_STATUS_MEMORY_ERROR;
    }
    size_t len = KineticProto_Message__pack(&pdu->protoData.message.message, packed);
    assert(len == pdu->header.protobufLength);

    ByteBuffer buffer = ByteBuffer_Create(packed, len, len);

    KineticStatus status = KineticSocket_Write(socket, &buffer);

    free(packed);
    return status;
}
示例#13
0
KineticStatus KineticSocket_WriteProtobuf(int socket, KineticPDU* pdu)
{
    assert(pdu != NULL);
    #ifdef KINETIC_LOG_SOCKET_OPERATIONS
    LOGF("Writing protobuf (%zd bytes)...", pdu->header.protobufLength);
    #endif

    uint8_t* packed = (uint8_t*)malloc(pdu->header.protobufLength);

    if (packed == NULL) {
        LOG("Failed allocating memory for protocol buffer");
        return KINETIC_STATUS_MEMORY_ERROR;
    }
    size_t len = KineticProto__pack(&pdu->protoData.message.proto, packed);
    assert(len == pdu->header.protobufLength);

    ByteBuffer buffer = ByteBuffer_Create(packed, len);
    buffer.bytesUsed = len;

    KineticStatus status = KineticSocket_Write(socket, &buffer);

    free(packed);
    return status;
}
示例#14
0
    peerConfig.port = GetSystemTestPort2();
    status = KineticClient_CreateSession(&peerConfig, client, &peerSession);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    KineticSessionConfig peerAdminConfig = {
        .clusterVersion = 0,
        .useSsl = true,
        .identity = 1,
        .hmacKey = ByteArray_CreateWithCString(HmacKeyString),
    };
    strncpy(peerAdminConfig.host, GetSystemTestHost2(), sizeof(peerAdminConfig.host)-1);
    peerAdminConfig.port = GetSystemTestTlsPort2();
    status = KineticAdminClient_CreateSession(&peerAdminConfig, client, &peerAdminSession);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);

    // Create some test entries to have content to copy
    TagBuffer     = ByteBuffer_Create(dummyTagData, sizeof(dummyTagData), sizeof(dummyTagData));
    Key1Buffer    = ByteBuffer_Create(key1Data, sizeof(key1Data), sizeof(key1Data));
    Value1Buffer  = ByteBuffer_Create(value1Data, sizeof(value1Data), sizeof(value1Data));
    KineticEntry putEntry1 = {
        .key = Key1Buffer,
        .tag = TagBuffer,
        .algorithm = KINETIC_ALGORITHM_SHA1,
        .value = Value1Buffer,
        .force = true,
        .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH,
    };
    status = KineticClient_Put(session, &putEntry1, NULL);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    Key2Buffer    = ByteBuffer_Create(key2Data, sizeof(key2Data), sizeof(key2Data));
    Value2Buffer  = ByteBuffer_Create(value2Data, sizeof(value2Data), sizeof(value2Data));
    KineticEntry putEntry2 = {
static void do_put_and_getkeyrange(KineticSession * const session) {
    for (int i = 0; i < 5; i++) {
        char key[] = "keyX";
        key[3] = '0' + i;
        ByteBuffer put_key_buf = ByteBuffer_MallocAndAppend(key, strlen(key));
        
        uint8_t value[] = "valueX";
        value[5] = '0' + i;
        ByteBuffer put_value_buf = ByteBuffer_MallocAndAppend(value, sizeof(value));
        
        /* Populate tag with SHA1 of value */
        ByteBuffer put_tag_buf = ByteBuffer_Malloc(20);
        uint8_t sha1[20];
        SHA1(put_value_buf.array.data, put_value_buf.bytesUsed, &sha1[0]);
        ByteBuffer_Append(&put_tag_buf, sha1, sizeof(sha1));
        
        KineticEntry put_entry = {
            .key = put_key_buf,
            .value = put_value_buf,
            .tag = put_tag_buf,
            .algorithm = KINETIC_ALGORITHM_SHA1,
            /* Set sync to WRITETHROUGH, which will wait to complete
             * until the drive has persistend the write. (WRITEBACK
             * returns as soon as the drive has buffered the write.) */
            .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH,
        };

        /* Put "keyX" => "valueX", where 'X' is 0..4.
         * This will block, because the callback field (arg 3) is NULL. */
        KineticStatus status = KineticClient_Put(session, &put_entry, NULL);
        printf("Put status: %s\n", Kinetic_GetStatusDescription(status));

        ByteBuffer_Free(put_key_buf);
        ByteBuffer_Free(put_value_buf);
        ByteBuffer_Free(put_tag_buf);
    }

    const size_t max_key_count = 5;
    const size_t max_key_length = 64;
    uint8_t first_key[max_key_length];
    uint8_t last_key[max_key_length];

    KineticKeyRange range = {
        .startKey = ByteBuffer_CreateAndAppendCString(first_key, sizeof(first_key), "key"),
        .endKey = ByteBuffer_CreateAndAppendCString(last_key, sizeof(last_key), "key\xFF"),
        .startKeyInclusive = true,
        .endKeyInclusive = true,
        .maxReturned = max_key_count,
    };
    
    uint8_t key_mem[max_key_count][max_key_length];
    memset(key_mem, 0, sizeof(key_mem));

    ByteBuffer key_buffers[max_key_count];
    for (size_t i = 0; i < max_key_count; i++) {
        key_buffers[i] = ByteBuffer_Create(&key_buffers[i], max_key_length, 0);
    }
    ByteBufferArray keys = {
        .buffers = key_buffers,
        .count = max_key_count,
    };

    /* Request the key range as specified in &range, populating the keys in &keys. */
    KineticStatus status = KineticClient_GetKeyRange(session, &range, &keys, NULL);
    printf("GetKeyRange status: %s\n", Kinetic_GetStatusDescription(status));
    
    if (status == KINETIC_STATUS_SUCCESS) {
        for (size_t i = 0; i < max_key_count; i++) {
            printf("%zd: %s\n", i, key_buffers[i].array.data);
        }
    }

    /* No cleanup necessary */
}

int main(int argc, char** argv)
{
    (void)argc;
    (void)argv;

    // Initialize kinetic-c and configure sessions
    KineticSession* session;
    KineticClientConfig clientConfig = {
        .logFile = "stdout",
        .logLevel = 1,
    };
    KineticClient * client = KineticClient_Init(&clientConfig);
    if (client == NULL) { return 1; }
    const char HmacKeyString[] = "asdfasdf";
    KineticSessionConfig sessionConfig = {
        .host = "localhost",
        .port = KINETIC_PORT,
        .clusterVersion = 0,
        .identity = 1,
        .hmacKey = ByteArray_CreateWithCString(HmacKeyString),
    };
    KineticStatus status = KineticClient_CreateSession(&sessionConfig, client, &session);
    if (status != KINETIC_STATUS_SUCCESS) {
        fprintf(stderr, "Failed connecting to the Kinetic device w/status: %s\n",
            Kinetic_GetStatusDescription(status));
        exit(1);
    }

    do_put_and_getkeyrange(session);
    
    // Shutdown client connection and cleanup
    KineticClient_DestroySession(session);
    KineticClient_Shutdown(client);
    return 0;
}
示例#16
0
void ConfigureEntry(struct UtilConfig * cfg, const char* key, const char* tag,
    const char* version, KineticAlgorithm algorithm, bool force, const char* value)
{
    assert(cfg != NULL);

    // Setup to write some test data
    cfg->entry = (KineticEntry) {
        .key = ByteBuffer_CreateAndAppendCString(cfg->keyData, sizeof(cfg->keyData), key),
        .tag = ByteBuffer_CreateAndAppendCString(cfg->tagData, sizeof(cfg->tagData), tag),
        .newVersion = ByteBuffer_CreateAndAppendCString(cfg->newVersionData, sizeof(cfg->newVersionData), version),
        .dbVersion = ByteBuffer_Create(cfg->versionData, sizeof(cfg->versionData), 0),
        .algorithm = algorithm,
        .value = ByteBuffer_CreateAndAppendCString(cfg->valueData, sizeof(cfg->valueData), value),
        .force = force,
    };
}

int ParseOptions(
    const int argc,
    char** const argv,
    struct UtilConfig * cfg)
{
    // Create an ArgP processor to parse arguments
    struct {
        OptionID opID;
        int logLevel;
        char host[HOST_NAME_MAX];
        int port;
        int tlsPort;
        int64_t clusterVersion;
        int64_t identity;
        char hmacKey[KINETIC_MAX_KEY_LEN];
        char logType[64];
        char deviceLogName[64];
        char key[64];
        char version[64];
        char tag[64];
        KineticAlgorithm algorithm;
        bool force;
        char value[1024];
    } opts = {
        .logLevel = 0,
        .host = "localhost",
        .port = KINETIC_PORT,
        .tlsPort = KINETIC_TLS_PORT,
        .clusterVersion = 0,
        .identity = 1,
        .hmacKey = "asdfasdf",
        .logType = "utilizations",
        .key = "foo",
        .tag = "SomeTagValue",
        .algorithm = KINETIC_ALGORITHM_SHA1,
        .force = true,
        .value = "Hello!",
    };

    // Create configuration for long format options
    struct option long_options[] = {

        // Help
        {"help",                        no_argument,       0, OPT_HELP},

        // Commands
        {"noop",                        no_argument,       0, OPT_NOOP},
        {"put",                         no_argument,       0, OPT_PUT},
        {"get",                         no_argument,       0, OPT_GET},
        {"delete",                      no_argument,       0, OPT_DELETE},
        {"getnext",                     no_argument,       0, OPT_GETNEXT},
        {"getprevious",                 no_argument,       0, OPT_GETPREVIOUS},
        {"getlog",                      no_argument,       0, OPT_GETLOG},
        {"getdevicespecificlog",        no_argument,       0, OPT_GETDEVICESPECIFICLOG},
        {"seterasepin",                 no_argument,       0, OPT_SETERASEPIN},
        {"instanterase",                no_argument,       0, OPT_INSTANTERASE},
        {"secureerase",                 no_argument,       0, OPT_SECUREERASE},
        {"setlockpin",                  no_argument,       0, OPT_SETLOCKPIN},
        {"lockdevice",                  no_argument,       0, OPT_LOCKDEVICE},
        {"unlockdevice",                no_argument,       0, OPT_UNLOCKDEVICE},
        {"setclusterversion",           no_argument,       0, OPT_SETCLUSTERVERSION},
        {"setacl",                      no_argument,       0, OPT_SETACL},
        {"updatefirmware",              no_argument,       0, OPT_UPDATEFIRMWARE},

        // Options
        {"loglevel",                    required_argument, 0, OPT_LOGLEVEL},
        {"host",                        required_argument, 0, OPT_HOST},
        {"port",                        required_argument, 0, OPT_PORT},
        {"tlsport",                     required_argument, 0, OPT_TLSPORT},
        {"identity",                    required_argument, 0, OPT_IDENTITY},
        {"hmackey",                     required_argument, 0, OPT_HMACKEY},
        {"clusterversion",              required_argument, 0, OPT_CLUSTERVERSION},
        {"file",                        required_argument, 0, OPT_FILE},
        {"newclusterversion",           required_argument, 0, OPT_NEWCLUSTERVERSION},
        {"pin",                         required_argument, 0, OPT_PIN},
        {"newpin",                      required_argument, 0, OPT_NEWPIN},
        {"logtype",                     required_argument, 0, OPT_LOGTYPE},
        {"devicelogname",               required_argument, 0, OPT_DEVICELOGNAME},
        {"key",                         required_argument, 0, OPT_KEY},
        {"value",                       required_argument, 0, OPT_VALUE},
        {0,                             0,                 0, 0},
    };

    // Parse the options from the command line
    extern char *optarg;
    extern int optind;
    int option, optionIndex = 0;
    while ((option = getopt_long(argc, argv, "?lhptics:", long_options, &optionIndex)) != -1) {
        switch (option) {
            case 0:
                // If this option, just set the flag
                if (long_options[optionIndex].flag != 0) {break;}
                // assert(false);
                // break;
            case OPT_LOGLEVEL:
                opts.logLevel = atoi(optarg);
                break;
            case OPT_HOST:
                strncpy(opts.host, optarg, sizeof(opts.host));
                break;
            case OPT_PORT:
                opts.port = atoi(optarg);
                break;
            case OPT_TLSPORT:
                opts.tlsPort = atoi(optarg);
                break;
            case OPT_IDENTITY:
                opts.identity = atoi(optarg);
                break;
            case OPT_HMACKEY:
                strncpy(opts.hmacKey, optarg, sizeof(opts.hmacKey)-1);
                break;
            case OPT_KEY:
                strncpy(opts.key, optarg, sizeof(opts.key)-1);
                break;
            case OPT_VALUE:
                strncpy(opts.value, optarg, sizeof(opts.value)-1);
                break;
            case OPT_CLUSTERVERSION:
                opts.clusterVersion = (int64_t)atol(optarg);
                break;
            case OPT_NEWCLUSTERVERSION:
                cfg->newClusterVersion = (int64_t)atol(optarg);
                break;
            case OPT_FILE:
                strncpy(cfg->file, optarg, sizeof(cfg->file)-1);
                break;
            case OPT_PIN:
                strncpy(cfg->pin, optarg, sizeof(cfg->pin)-1);
                break;
            case OPT_NEWPIN:
                strncpy(cfg->newPin, optarg, sizeof(cfg->newPin)-1);
                break;
            case OPT_LOGTYPE:
                strncpy(opts.logType, optarg, sizeof(opts.logType)-1);
                break;
            case OPT_DEVICELOGNAME:
                strncpy(cfg->deviceLogName, optarg, sizeof(cfg->deviceLogName)-1);
                break;

            case OPT_NOOP:
            case OPT_PUT:
            case OPT_GET:
            case OPT_DELETE:
            case OPT_GETNEXT:
            case OPT_GETPREVIOUS:
            case OPT_GETLOG:
            case OPT_GETDEVICESPECIFICLOG:
            case OPT_SETERASEPIN:
            case OPT_INSTANTERASE:
            case OPT_SECUREERASE:
            case OPT_SETLOCKPIN:
            case OPT_LOCKDEVICE:
            case OPT_UNLOCKDEVICE:
            case OPT_SETCLUSTERVERSION:
            case OPT_SETACL:
            case OPT_UPDATEFIRMWARE:
                if ((int)opts.opID == 0) {
                    opts.opID = option;
                    break;
                }
                fprintf(stderr, "Multiple operations specified!\n");
                PrintUsage(argv[0]);
                exit(-1);
            case OPT_HELP:
                PrintUsage(argv[0]);
                exit(0);
            default:
                PrintUsage(argv[0]);
                exit(-1);
        }
    }

    // Configure client
    cfg->logLevel = opts.logLevel;

    // Configure session
    cfg->config = (KineticSessionConfig) {
        .port = opts.port,
        .clusterVersion = opts.clusterVersion,
        .identity = opts.identity,
        .hmacKey = ByteArray_Create(cfg->hmacKeyData, strlen(opts.hmacKey)),
    };
    memcpy(cfg->hmacKeyData, opts.hmacKey, strlen(opts.hmacKey));
    strncpy(cfg->config.host, opts.host, sizeof(cfg->config.host)-1);

    // Configure admin session
    cfg->adminConfig = cfg->config;
    cfg->adminConfig.port = opts.tlsPort;
    cfg->adminConfig.useSsl = true;

    // Populate and configure the entry to be used for operations
    ConfigureEntry(cfg,
        opts.key, opts.tag, opts.version, opts.algorithm, opts.force, opts.value);

    cfg->opID = opts.opID;

    // Parse log type from string
    if (strcmp("utilizations", opts.logType) == 0) {
        cfg->logType = KINETIC_DEVICE_INFO_TYPE_UTILIZATIONS;
    }
    else if (strcmp("temperatures", opts.logType) == 0) {
        cfg->logType = KINETIC_DEVICE_INFO_TYPE_TEMPERATURES;
    }
    else if (strcmp("capacities", opts.logType) == 0) {
        cfg->logType = KINETIC_DEVICE_INFO_TYPE_CAPACITIES;
    }
    else if (strcmp("configuration", opts.logType) == 0) {
        cfg->logType = KINETIC_DEVICE_INFO_TYPE_CONFIGURATION;
    }
    else if (strcmp("statistics", opts.logType) == 0) {
        cfg->logType = KINETIC_DEVICE_INFO_TYPE_STATISTICS;
    }
    else if (strcmp("messages", opts.logType) == 0) {
        cfg->logType = KINETIC_DEVICE_INFO_TYPE_MESSAGES;
    }
    else if (strcmp("limits", opts.logType) == 0) {
        cfg->logType = KINETIC_DEVICE_INFO_TYPE_LIMITS;
    }
    else {
        fprintf(stderr, "Invalid log info type: %s\n", opts.logType);
        exit(1);
    }

    return optind;
}
void test_kinetic_client_should_be_able_to_store_an_arbitrarily_large_binary_object_and_split_across_entries_via_ovelapped_IO_operations(void)
{
    const int maxIterations = 4;
    const int numCopiesToStore = 4;
    const KineticSession sessionConfig = {
        .host = "localhost",
        .port = KINETIC_PORT,
        .nonBlocking = false,
        .clusterVersion = 0,
        .identity = 1,
        .hmacKey = ByteArray_CreateWithCString("asdfasdf"),
    };

    for (int iteration = 0; iteration < maxIterations; iteration++) {

        printf("Overlapped PUT operation (iteration %d of %d)\n",
               iteration + 1, maxIterations);

        char* buf = malloc(sizeof(char) * BUFSIZE);
        int fd = open("test/support/data/test.data", O_RDONLY);
        int dataLen = read(fd, buf, BUFSIZE);
        close(fd);
        TEST_ASSERT_MESSAGE(dataLen > 0, "read error");

        /* thread structure */
        struct kinetic_thread_arg* kt_arg;
        pthread_t thread_id[KINETIC_MAX_THREADS];

        kinetic_client = malloc(sizeof(KineticSessionHandle) * numCopiesToStore);
        TEST_ASSERT_NOT_NULL_MESSAGE(kinetic_client, "kinetic_client malloc failed");

        kt_arg = malloc(sizeof(struct kinetic_thread_arg) * numCopiesToStore);
        TEST_ASSERT_NOT_NULL_MESSAGE(kt_arg, "kinetic_thread_arg malloc failed");

        for (int i = 0; i < numCopiesToStore; i++) {

            printf("    Overlapped PUT operations (writing copy %d of %d) on IP (iteration %d of %d):%s\n",
                   i + 1, numCopiesToStore, iteration + 1, maxIterations, sessionConfig.host);

            // Establish connection
            TEST_ASSERT_EQUAL_KineticStatus(
                KINETIC_STATUS_SUCCESS,
                KineticClient_Connect(&sessionConfig, &kinetic_client[i]));
            strcpy(kt_arg[i].ip, sessionConfig.host);

            // Configure the KineticEntry
            char keyPrefix[128];
            snprintf(keyPrefix, sizeof(keyPrefix), "pre_%02d%02d", iteration, i);
            LOGF("NEW HUNK PREFIX: %s", keyPrefix);
            ByteBuffer keyBuf = ByteBuffer_Create(kt_arg[i].key, sizeof(kt_arg[i].key));
            ByteBuffer_AppendCString(&keyBuf, keyPrefix);
            kt_arg[i].keyPrefixLength = keyBuf.bytesUsed;

            ByteBuffer verBuf = ByteBuffer_Create(kt_arg[i].version, sizeof(kt_arg[i].version));
            ByteBuffer_AppendCString(&verBuf, "v1.0");

            ByteBuffer tagBuf = ByteBuffer_Create(kt_arg[i].tag, sizeof(kt_arg[i].tag));
            ByteBuffer_AppendCString(&tagBuf, "some_value_tag...");

            ByteBuffer valBuf = ByteBuffer_Create(kt_arg[i].value, sizeof(kt_arg[i].value));
            
            kt_arg[i].entry = (KineticEntry) {
                .key = keyBuf,
                .newVersion = verBuf,
                .tag = tagBuf,
                .metadataOnly = false,
                .algorithm = KINETIC_ALGORITHM_SHA1,
                .value = valBuf,
            };

            // Create a ByteBuffer for consuming chunks of data out of for overlapped PUTs
            kt_arg[i].data = ByteBuffer_Create(buf, dataLen);

            // Spawn the worker thread
            kt_arg[i].sessionHandle = kinetic_client[i];
            int create_status = pthread_create(&thread_id[i], NULL, kinetic_put, &kt_arg[i]);
            TEST_ASSERT_EQUAL_MESSAGE(0, create_status, "pthread create failed");
        }

        // Wait for each overlapped PUT operations to complete and cleanup
        printf("  Waiting for PUT threads to exit...\n");
        for (int i = 0; i < numCopiesToStore; i++) {
            int join_status = pthread_join(thread_id[i], NULL);
            TEST_ASSERT_EQUAL_MESSAGE(0, join_status, "pthread join failed");
            KineticClient_Disconnect(&kinetic_client[i]);
        }

        // Cleanup the rest of the reources
        free(kinetic_client);
        free(kt_arg);
        free(buf);

        printf("  Iteration complete!\n");
    }

    printf("Overlapped PUT operation test complete!\n");
}
示例#18
0
void test_KineticPDU_Send_should_send_the_specified_message_and_return_false_upon_failure_to_send_header(void)
{
    LOG_LOCATION;
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));

    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    char valueData[] = "Some arbitrary value";
    KineticEntry entry = {.value = ByteBuffer_Create(valueData, strlen(valueData))};
    KineticPDU_AttachEntry(&PDU, &entry);

    KineticHMAC_Init_Expect(&PDU.hmac, KINETIC_PROTO_SECURITY_ACL_HMACALGORITHM_HmacSHA1);
    KineticHMAC_Populate_Expect(&PDU.hmac, &PDU.protoData.message.proto, PDU.connection->session.hmacKey);
    KineticSocket_Write_ExpectAndReturn(Connection.socket, &headerNBO, KINETIC_STATUS_SOCKET_ERROR);

    TEST_IGNORE_MESSAGE("Need to figure out how to handle address of PDU header");

    KineticStatus status = KineticPDU_Send(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SOCKET_ERROR, status);
}

void test_KineticPDU_Send_should_send_the_specified_message_and_return_false_upon_failure_to_send_protobuf(void)
{
    LOG_LOCATION;
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));

    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    char valueData[] = "Some arbitrary value";
    KineticEntry entry = {.value = ByteBuffer_Create(valueData, strlen(valueData))};
    KineticPDU_AttachEntry(&PDU, &entry);

    KineticHMAC_Init_Expect(&PDU.hmac, KINETIC_PROTO_SECURITY_ACL_HMACALGORITHM_HmacSHA1);
    KineticHMAC_Populate_Expect(&PDU.hmac,
                                &PDU.protoData.message.proto, PDU.connection->session.hmacKey);
    KineticSocket_Write_ExpectAndReturn(Connection.socket, &headerNBO, KINETIC_STATUS_SUCCESS);
    KineticSocket_WriteProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SOCKET_TIMEOUT);

    TEST_IGNORE_MESSAGE("Need to figure out how to handle address of PDU header");

    KineticStatus status = KineticPDU_Send(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SOCKET_TIMEOUT, status);
}

void test_KineticPDU_Send_should_send_the_specified_message_and_return_KineticStatus_if_value_write_fails(void)
{
    LOG_LOCATION;
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));

    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    uint8_t valueData[128];
    KineticEntry entry = {.value = ByteBuffer_Create(valueData, sizeof(valueData))};
    ByteBuffer_AppendCString(&entry.value, "Some arbitrary value");
    KineticPDU_AttachEntry(&PDU, &entry);

    KineticHMAC_Init_Expect(&PDU.hmac, KINETIC_PROTO_SECURITY_ACL_HMACALGORITHM_HmacSHA1);
    KineticHMAC_Populate_Expect(&PDU.hmac, &PDU.protoData.message.proto, PDU.connection->session.hmacKey);
    KineticSocket_Write_ExpectAndReturn(Connection.socket, &headerNBO, KINETIC_STATUS_SUCCESS);
    KineticSocket_WriteProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS);
    KineticSocket_Write_ExpectAndReturn(Connection.socket, &entry.value, KINETIC_STATUS_SOCKET_TIMEOUT);

    TEST_IGNORE_MESSAGE("Need to figure out how to handle address of PDU header");

    KineticStatus status = KineticPDU_Send(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SOCKET_TIMEOUT, status);
}


void test_KineticPDU_Receive_should_receive_a_message_with_value_payload_and_return_true_upon_receipt_of_valid_PDU(void)
{
    LOG_LOCATION;
    Connection.connectionID = 98765;
    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));

    // Fake value/payload length
    uint8_t data[1024];
    ByteArray expectedValue = ByteArray_Create(data, sizeof(data));
    ByteArray_FillWithDummyData(expectedValue);
    KineticEntry entry = {.value = ByteBuffer_CreateWithArray(expectedValue)};
    KineticPDU_AttachEntry(&PDU, &entry);

    KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS);
    KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS);
    KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, true);
    KineticSocket_Read_ExpectAndReturn(Connection.socket, &entry.value, expectedValue.len, KINETIC_STATUS_SUCCESS);

    PDU.headerNBO.valueLength = KineticNBO_FromHostU32(expectedValue.len);
    EnableAndSetPDUConnectionID(&PDU, 12345);
    EnableAndSetPDUStatus(&PDU, KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS);

    KineticStatus status = KineticPDU_Receive(&PDU);

    TEST_ASSERT_EQUAL(KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS,
                      PDU.protoData.message.status.code);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}
static void do_put_and_getprevious_getnext(KineticSession *session) {
    for (int i = 0; i < 3; i++) {
        char key[] = "keyX";
        key[3] = '0' + i;
        ByteBuffer put_key_buf = ByteBuffer_MallocAndAppend(key, strlen(key));

        uint8_t value[] = "valueX";
        value[5] = '0' + i;
        ByteBuffer put_value_buf = ByteBuffer_MallocAndAppend(value, sizeof(value));

        /* Populate tag with SHA1 of value */
        ByteBuffer put_tag_buf = ByteBuffer_Malloc(20);
        uint8_t sha1[20];
        SHA1(put_value_buf.array.data, put_value_buf.bytesUsed, &sha1[0]);
        ByteBuffer_Append(&put_tag_buf, sha1, sizeof(sha1));

        KineticEntry put_entry = {
            .key = put_key_buf,
            .value = put_value_buf,
            .tag = put_tag_buf,
            .algorithm = KINETIC_ALGORITHM_SHA1,
            /* Set sync to WRITETHROUGH, which will wait to complete
             * until the drive has persistend the write. (WRITEBACK
             * returns as soon as the drive has buffered the write.) */
            .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH,
        };

        /* Put "keyX" => "valueX", where 'X' is 0..4.
         * This will block, because the callback field (arg 3) is NULL. */
        KineticStatus status = KineticClient_Put(session, &put_entry, NULL);
        printf("Put status: %s\n", Kinetic_GetStatusDescription(status));

        ByteBuffer_Free(put_key_buf);
        ByteBuffer_Free(put_value_buf);
        ByteBuffer_Free(put_tag_buf);
    }

    printf("\n\n\n");

    for (int i = 1; i < 3; i++) {
        KineticStatus status = KINETIC_STATUS_INVALID;
        static const ssize_t sz = 100;
        char key_buf[sz];
        char tag_buf[sz];
        char value_buf[sz];
        ByteBuffer keyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key%d", i);
        ByteBuffer tagBuffer = ByteBuffer_CreateAndAppendFormattedCString(tag_buf, sz, "tag%d", i);
        ByteBuffer valueBuffer = ByteBuffer_Create(value_buf, sz, 0);

        KineticEntry entry = {
            .key = keyBuffer,
            .tag = tagBuffer,
            .value = valueBuffer,
            .algorithm = KINETIC_ALGORITHM_SHA1,
        };

        if (i > 0) {
            status = KineticClient_GetPrevious(session, &entry, NULL);
            printf("GetPrevious status: %s\n", Kinetic_GetStatusDescription(status));
            if (status == KINETIC_STATUS_SUCCESS) {
                printf("Previous key before 'key%d': '%s', value '%s'\n",
                       i, key_buf, value_buf);
            }
        }
    }

    for (int i = 0; i < 2; i++) {
        KineticStatus status = KINETIC_STATUS_INVALID;
        static const ssize_t sz = 100;
        char key_buf[sz];
        char tag_buf[sz];
        char value_buf[sz];
        ByteBuffer keyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key%d", i);
        ByteBuffer tagBuffer = ByteBuffer_CreateAndAppendFormattedCString(tag_buf, sz, "tag%d", i);
        ByteBuffer valueBuffer = ByteBuffer_Create(value_buf, sz, 0);

        KineticEntry entry = {
            .key = keyBuffer,
            .tag = tagBuffer,
            .value = valueBuffer,
            .algorithm = KINETIC_ALGORITHM_SHA1,
        };

        if (i < 2) {
            status = KineticClient_GetNext(session, &entry, NULL);
            printf("GetNext status: %s\n", Kinetic_GetStatusDescription(status));
            if (status == KINETIC_STATUS_SUCCESS) {
                printf("Next key after 'key%d': '%s', value '%s'\n",
                       i, key_buf, value_buf);
            }
        }
    }

    /* No cleanup necessary */
}
示例#20
0
int KineticSocket_Connect(const char* host, int port, bool nonBlocking)
{
    char port_str[32];
    struct addrinfo hints;
    struct addrinfo* ai_result = NULL;
    struct addrinfo* ai = NULL;
    socket99_result result;

    // Setup server address info
    socket99_config cfg = {
        .host = (char*)host,
        .port = port,
        .nonblocking = nonBlocking,
    };
    sprintf(port_str, "%d", port);

    // Open socket
    LOGF0("Connecting to %s:%d", host, port);
    if (!socket99_open(&cfg, &result)) {
        LOGF0("Failed to open socket connection with host: status %d, errno %d",
             result.status, result.saved_errno);
        return KINETIC_SOCKET_DESCRIPTOR_INVALID;
    }

    // Configure the socket
    socket99_set_hints(&cfg, &hints);
    if (getaddrinfo(cfg.host, port_str, &hints, &ai_result) != 0) {
        LOGF0("Failed to get socket address info: errno %d", errno);
        close(result.fd);
        return KINETIC_SOCKET_DESCRIPTOR_INVALID;
    }

    for (ai = ai_result; ai != NULL; ai = ai->ai_next) {
        int setsockopt_result;
        int buffer_size = KINETIC_OBJ_SIZE;

#if defined(SO_NOSIGPIPE) && !defined(__APPLE__)
        // On BSD-like systems we can set SO_NOSIGPIPE on the socket to
        // prevent it from sending a PIPE signal and bringing down the whole
        // application if the server closes the socket forcibly
        int enable = 1;
        setsockopt_result = setsockopt(result.fd,
                                       SOL_SOCKET, SO_NOSIGPIPE,
                                       &enable, sizeof(enable));
        // Allow ENOTSOCK because it allows tests to use pipes instead of
        // real sockets
        if (setsockopt_result != 0 && setsockopt_result != ENOTSOCK) {
            LOG0("Failed to set SO_NOSIGPIPE on socket");
            continue;
        }
#endif

        // Increase send buffer to KINETIC_OBJ_SIZE
        // Note: OS allocates 2x this value for its overhead
        setsockopt_result = setsockopt(result.fd,
                                       SOL_SOCKET, SO_SNDBUF,
                                       &buffer_size, sizeof(buffer_size));
        if (setsockopt_result == -1) {
            LOG0("Error setting socket send buffer size");
            continue;
        }

        // Increase receive buffer to KINETIC_OBJ_SIZE
        // Note: OS allocates 2x this value for its overheadbuffer_size
        setsockopt_result = setsockopt(result.fd,
                                       SOL_SOCKET, SO_RCVBUF,
                                       &buffer_size, sizeof(buffer_size));
        if (setsockopt_result == -1) {
            LOG0("Error setting socket receive buffer size");
            continue;
        }

        break;
    }

    freeaddrinfo(ai_result);

    if (ai == NULL || result.fd == KINETIC_SOCKET_DESCRIPTOR_INVALID) {
        // we went through all addresses without finding one we could bind to
        LOGF0("Could not connect to %s:%d", host, port);
        return KINETIC_SOCKET_DESCRIPTOR_INVALID;
    }
    else {
        LOGF1("Successfully connected to %s:%d (fd=%d)", host, port, result.fd);
        return result.fd;
    }
}

void KineticSocket_Close(int socket)
{
    if (socket == -1) {
        LOG1("Not connected so no cleanup needed");
    }
    else {
        LOGF0("Closing socket with fd=%d", socket);
        if (close(socket) == 0) {
            LOG2("Socket closed successfully");
        }
        else {
            LOGF0("Error closing socket file descriptor!"
                 " (fd=%d, errno=%d, desc='%s')",
                 socket, errno, strerror(errno));
        }
    }
}

KineticWaitStatus KineticSocket_WaitUntilDataAvailable(int socket, int timeout)
{
    if (socket < 0) {return -1;}
    struct pollfd fd = {
        .fd = socket,
        .events = POLLIN,
        .revents = 0,
    };

    int res = poll(&fd, 1, timeout);

    if (res > 0) {
        //if (fd.revents & POLLHUP) // hung up
        if (fd.revents & POLLIN)
        {
            return KINETIC_WAIT_STATUS_DATA_AVAILABLE;
        }
        else
        {
            return KINETIC_WAIT_STATUS_FATAL_ERROR;
        }
    }
    else if (res == 0)
    {
        return KINETIC_WAIT_STATUS_TIMED_OUT;
    }
    else if ((errno & (EAGAIN | EINTR)) != 0)
    {
        return KINETIC_WAIT_STATUS_RETRYABLE_ERROR;
    }
    else
    {
        return KINETIC_WAIT_STATUS_FATAL_ERROR;
    }
}

int KineticSocket_DataBytesAvailable(int socket)
{
    if (socket < 0) {return -1;}
    int count = -1;
    ioctl(socket, FIONREAD, &count);
    return count;
}

KineticStatus KineticSocket_Read(int socket, ByteBuffer* dest, size_t len)
{
    LOGF2("Reading %zd bytes into buffer @ 0x%zX from fd=%d",
         len, (size_t)dest->array.data, socket);

    KineticStatus status = KINETIC_STATUS_INVALID;

    // Read "up to" the allocated number of bytes into dest buffer
    size_t bytesToReadIntoBuffer = len;
    if (dest->array.len < len) {
        bytesToReadIntoBuffer = dest->array.len;
    }
    while (dest->bytesUsed < bytesToReadIntoBuffer) {
        int opStatus;
        fd_set readSet;
        struct timeval timeout;

        // Time out after 5 seconds
        timeout.tv_sec = 5;
        timeout.tv_usec = 0;

        FD_ZERO(&readSet);
        FD_SET(socket, &readSet);
        opStatus = select(socket + 1, &readSet, NULL, NULL, &timeout);

        if (opStatus < 0) { // Error occurred
            LOGF0("Failed waiting to read from socket!"
                 " status=%d, errno=%d, desc='%s'",
                 opStatus, errno, strerror(errno));
            return KINETIC_STATUS_SOCKET_ERROR;
        }
        else if (opStatus == 0) { // Timeout occurred
            LOG0("Timed out waiting for socket data to arrive!");
            return KINETIC_STATUS_SOCKET_TIMEOUT;
        }
        else if (opStatus > 0) { // Data available to read
            // The socket is ready for reading
            opStatus = read(socket,
                            &dest->array.data[dest->bytesUsed],
                            dest->array.len - dest->bytesUsed);
            // Retry if no data yet...
            if (opStatus == -1 &&
                ((errno == EINTR) ||
                 (errno == EAGAIN) ||
                 (errno == EWOULDBLOCK)
                )) {
                continue;
            }
            else if (opStatus <= 0) {
                LOGF0("Failed to read from socket!"
                     " status=%d, errno=%d, desc='%s'",
                     opStatus, errno, strerror(errno));
                return KINETIC_STATUS_SOCKET_ERROR;
            }
            else {
                dest->bytesUsed += opStatus;
                LOGF3("Received %d bytes (%zd of %zd)",
                     opStatus, dest->bytesUsed, len);
            }
        }
    }

    // Flush any remaining data, in case of a truncated read w/short dest buffer
    if (dest->bytesUsed < len) {
        bool abortFlush = false;

        uint8_t* discardedBytes = malloc(len - dest->bytesUsed);
        if (discardedBytes == NULL) {
            LOG0("Failed allocating a socket read discard buffer!");
            abortFlush = true;
            status = KINETIC_STATUS_MEMORY_ERROR;
        }

        while (!abortFlush && dest->bytesUsed < len) {
            int opStatus;
            fd_set readSet;
            struct timeval timeout;
            size_t remainingLen = len - dest->bytesUsed;

            // Time out after 5 seconds
            timeout.tv_sec = 5;
            timeout.tv_usec = 0;

            FD_ZERO(&readSet);
            FD_SET(socket, &readSet);
            opStatus = select(socket + 1, &readSet, NULL, NULL, &timeout);

            if (opStatus < 0) { // Error occurred
                LOGF0("Failure trying to flush read socket data!"
                     " status=%d, errno=%d, desc='%s'",
                     status, errno, strerror(errno));
                abortFlush = true;
                status = KINETIC_STATUS_SOCKET_ERROR;
                continue;
            }
            else if (opStatus == 0) { // Timeout occurred
                LOG0("Timed out waiting to flush socket data!");
                abortFlush = true;
                status = KINETIC_STATUS_SOCKET_TIMEOUT;
                continue;
            }
            else if (opStatus > 0) { // Data available to read
                // The socket is ready for reading
                opStatus = read(socket, discardedBytes, remainingLen);
                // Retry if no data yet...
                if (opStatus == -1 &&
                    ((errno == EINTR) ||
                     (errno == EAGAIN) ||
                     (errno == EWOULDBLOCK)
                    )) {
                    continue;
                }
                else if (opStatus <= 0) {
                    LOGF0("Failed to read from socket while flushing!"
                         " status=%d, errno=%d, desc='%s'",
                         opStatus, errno, strerror(errno));
                    abortFlush = true;
                    status = KINETIC_STATUS_SOCKET_ERROR;
                }
                else {
                    dest->bytesUsed += opStatus;
                    LOGF3("Flushed %d bytes from socket read pipe (%zd of %zd)",
                         opStatus, dest->bytesUsed, len);
                }
            }
        }

        // Free up dynamically allocated memory before returning
        if (discardedBytes != NULL) {
            free(discardedBytes);
        }

        // Report any error that occurred during socket flush
        if (abortFlush) {
            LOG0("Socket read pipe flush aborted!");
            assert(status == KINETIC_STATUS_SUCCESS);
            return status;
        }

        // Report truncation of data for any variable length byte arrays
        LOGF1("Socket read buffer was truncated due to buffer overrun!"
             " received=%zu, copied=%zu",
             len, dest->array.len);
        return KINETIC_STATUS_BUFFER_OVERRUN;
    }
    LOGF3("Received %zd of %zd bytes requested", dest->bytesUsed, len);
    return KINETIC_STATUS_SUCCESS;
}

KineticStatus KineticSocket_ReadProtobuf(int socket, KineticPDU* pdu)
{
    size_t bytesToRead = pdu->header.protobufLength;
    LOGF2("Reading %zd bytes of protobuf", bytesToRead);

    uint8_t* packed = (uint8_t*)malloc(bytesToRead);
    if (packed == NULL) {
        LOG0("Failed allocating memory for protocol buffer");
        return KINETIC_STATUS_MEMORY_ERROR;
    }

    ByteBuffer recvBuffer = ByteBuffer_Create(packed, bytesToRead, 0);
    KineticStatus status = KineticSocket_Read(socket, &recvBuffer, bytesToRead);

    if (status != KINETIC_STATUS_SUCCESS) {
        LOG0("Protobuf read failed!");
        free(packed);
        return status;
    }
    else {
        pdu->proto = KineticProto_Message__unpack(
                         NULL, recvBuffer.bytesUsed, recvBuffer.array.data);
    }

    free(packed);

    if (pdu->proto == NULL) {
        pdu->protobufDynamicallyExtracted = false;
        LOG0("Error unpacking incoming Kinetic protobuf message!");
        return KINETIC_STATUS_DATA_ERROR;
    }
    else {
        pdu->protobufDynamicallyExtracted = true;
        LOG3("Protobuf unpacked successfully!");
        return KINETIC_STATUS_SUCCESS;
    }
}
示例#21
0
void test_KineticPDU_Receive_should_receive_a_message_for_the_exchange_and_return_false_upon_value_field_receive_failure(void)
{
    LOG_LOCATION;
    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    PDU.protoData.message.status.code = KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS;
    PDU.protoData.message.status.has_code = true;
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));
    PDU.headerNBO = (KineticPDUHeader) {
        .versionPrefix = 'F', .protobufLength = KineticNBO_ToHostU32(17),
         .valueLength = KineticNBO_ToHostU32(124)
    };

    // Fake value/payload length
    uint8_t data[124];
    size_t bytesToRead = sizeof(data);
    ByteArray expectedValue = ByteArray_Create(data, sizeof(data));
    ByteArray_FillWithDummyData(expectedValue);
    KineticEntry entry = {.value = ByteBuffer_CreateWithArray(expectedValue)};
    KineticPDU_AttachEntry(&PDU, &entry);

    KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS);
    KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS);
    KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, true);
    KineticSocket_Read_ExpectAndReturn(Connection.socket, &entry.value, bytesToRead, KINETIC_STATUS_SOCKET_ERROR);

    KineticStatus status = KineticPDU_Receive(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SOCKET_ERROR, status);
    TEST_ASSERT_EQUAL(17, PDU.header.protobufLength);
    TEST_ASSERT_EQUAL(bytesToRead, expectedValue.len);
    TEST_ASSERT_EQUAL(expectedValue.len, PDU.header.valueLength);
}

void test_KineticPDU_Receive_should_receive_a_message_and_update_the_ConnectionID_for_the_connection_when_provided(void)
{
    LOG_LOCATION;
    Connection.connectionID = 98765;
    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    PDU.protoData.message.status.code = KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS;
    PDU.protoData.message.status.has_code = true;
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));

    // Fake value/payload length
    uint8_t data[124];
    size_t bytesToRead = sizeof(data);
    ByteArray expectedValue = {.data = data, .len = sizeof(data)};
    ByteArray_FillWithDummyData(expectedValue);
    KineticEntry entry = {.value = ByteBuffer_CreateWithArray(expectedValue)};
    KineticPDU_AttachEntry(&PDU, &entry);

    KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS);
    KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS);
    KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, true);
    KineticSocket_Read_ExpectAndReturn(Connection.socket, &entry.value, bytesToRead, KINETIC_STATUS_SUCCESS);

    PDU.headerNBO.valueLength = KineticNBO_FromHostU32(expectedValue.len);
    EnableAndSetPDUConnectionID(&PDU, 12345);
    EnableAndSetPDUStatus(&PDU, KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS);

    KineticStatus status = KineticPDU_Receive(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    TEST_ASSERT_EQUAL(KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS, PDU.protoData.message.status.code);
    TEST_ASSERT_EQUAL(12345, PDU.proto->command->header->connectionID);
    TEST_ASSERT_EQUAL(12345, PDU.connection->connectionID);
}

void test_KineticPDU_Receive_should_receive_a_message_and_NOT_update_the_ConnectionID_for_the_connection_if_not_provided(void)
{
    LOG_LOCATION;
    Connection.connectionID = 98765;
    KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection);
    PDU.protoData.message.status.code = KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS;
    PDU.protoData.message.status.has_code = true;
    ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader));

    // Fake value/payload length
    uint8_t data[124];
    size_t bytesToRead = sizeof(data);
    ByteArray expectedValue = {.data = data, .len = sizeof(data)};
    ByteArray_FillWithDummyData(expectedValue);
    KineticEntry entry = {.value = ByteBuffer_CreateWithArray(expectedValue)};
    KineticPDU_AttachEntry(&PDU, &entry);

    KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS);
    KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS);
    KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, true);
    KineticSocket_Read_ExpectAndReturn(Connection.socket, &entry.value, bytesToRead, KINETIC_STATUS_SUCCESS);

    PDU.headerNBO.valueLength = KineticNBO_FromHostU32(expectedValue.len);
    EnableAndSetPDUStatus(&PDU, KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS);

    KineticStatus status = KineticPDU_Receive(&PDU);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    TEST_ASSERT_EQUAL(KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS, PDU.protoData.message.status.code);
    TEST_ASSERT_EQUAL(98765, PDU.proto->command->header->connectionID);
    TEST_ASSERT_EQUAL(98765, PDU.connection->connectionID);
}



void test_KineticPDU_GetStatus_should_return_KINETIC_STATUS_INVALID_if_no_KineticProto_Status_StatusCode_in_response(void)
{
    LOG_LOCATION;
    KineticStatus status;

    status = KineticPDU_GetStatus(NULL);
    TEST_ASSERT_EQUAL(KINETIC_STATUS_INVALID, status);

    PDU.proto = NULL;
    status = KineticPDU_GetStatus(&PDU);
    TEST_ASSERT_EQUAL(KINETIC_STATUS_INVALID, status);

    PDU.proto = &PDU.protoData.message.proto;
    PDU.proto->command = NULL;
    status = KineticPDU_GetStatus(&PDU);
    TEST_ASSERT_EQUAL(KINETIC_STATUS_INVALID, status);

    PDU.proto->command = &PDU.protoData.message.command;
    status = KineticPDU_GetStatus(&PDU);
    TEST_ASSERT_EQUAL(KINETIC_STATUS_INVALID, status);

    PDU.proto->command->status = &PDU.protoData.message.status;
    PDU.proto->command->status->has_code = false;
    status = KineticPDU_GetStatus(&PDU);
    TEST_ASSERT_EQUAL(KINETIC_STATUS_INVALID, status);

    PDU.proto->command->status->has_code = true;
    PDU.proto->command->status->code = KINETIC_PROTO_STATUS_STATUS_CODE_INVALID_STATUS_CODE;
    status = KineticPDU_GetStatus(&PDU);
    TEST_ASSERT_EQUAL(KINETIC_STATUS_INVALID, status);
}
int main(int argc, char** argv)
{
    (void)argc;
    (void)argv;

    // Initialize kinetic-c and configure sessions
    KineticSession* session;
    KineticClientConfig clientConfig = {
        .logFile = "stdout",
        .logLevel = 1,
    };
    KineticClient * client = KineticClient_Init(&clientConfig);
    if (client == NULL) { return 1; }
    const char HmacKeyString[] = "asdfasdf";
    KineticSessionConfig sessionConfig = {
        .host = "localhost",
        .port = KINETIC_PORT,
        .clusterVersion = 0,
        .identity = 1,
        .hmacKey = ByteArray_CreateWithCString(HmacKeyString),
    };
    KineticStatus status = KineticClient_CreateSession(&sessionConfig, client, &session);
    if (status != KINETIC_STATUS_SUCCESS) {
        fprintf(stderr, "Failed connecting to the Kinetic device w/status: %s\n",
            Kinetic_GetStatusDescription(status));
        return -1;
    }

    // Read in file contents to store
    const char* dataFile = "test/support/data/test.data";
    struct stat st;
    stat(dataFile, &st);
    char* buf = malloc(st.st_size);
    int fd = open(dataFile, O_RDONLY);
    long dataLen = read(fd, buf, st.st_size);
    close(fd);
    if (dataLen <= 0) {
        fprintf(stderr, "Failed reading data file to store: %s\n", dataFile);
        exit(-1);
    }

    write_args* writeArgs = calloc(NUM_FILES, sizeof(write_args));
    if (writeArgs == NULL) {
        fprintf(stderr, "Failed allocating overlapped thread arguments!\n");
    }

    // Kick off a thread for each file to store
    for (int i = 0; i < NUM_FILES; i++) {

        // Establish connection
        status = KineticClient_CreateSession(&sessionConfig, client, &writeArgs[i].session);
        if (status != KINETIC_STATUS_SUCCESS) {
            fprintf(stderr, "Failed connecting to the Kinetic device w/status: %s\n",
                Kinetic_GetStatusDescription(status));
            return -1;
        }
        strcpy(writeArgs[i].ip, sessionConfig.host);

        // Create a ByteBuffer for consuming chunks of data out of for overlapped PUTs
        writeArgs[i].data = ByteBuffer_Create(buf, dataLen, 0);

        // Configure common entry attributes
        struct timeval now;
        gettimeofday(&now, NULL);
        snprintf(writeArgs[i].keyPrefix, sizeof(writeArgs[i].keyPrefix), "%010llu_%02d_",
            (unsigned long long)now.tv_sec, i);
        ByteBuffer valBuf = ByteBuffer_Create(writeArgs[i].value, sizeof(writeArgs[i].value), 0);
        writeArgs[i].entry = (KineticEntry) {
            .key = ByteBuffer_CreateAndAppendCString(
                writeArgs[i].key, sizeof(writeArgs[i].key), writeArgs[i].keyPrefix),
            .tag = ByteBuffer_CreateAndAppendCString(
                writeArgs[i].tag, sizeof(writeArgs[i].tag), "some_value_tag..."),
            .algorithm = KINETIC_ALGORITHM_SHA1,
            .value = valBuf,
        };

        // Store the entry
        int threadCreateStatus = pthread_create(&writeArgs[i].threadID, NULL, store_data, &writeArgs[i]);
        REPORT_ERRNO(threadCreateStatus, "pthread_create");
        if (threadCreateStatus != 0) {
            fprintf(stderr, "pthread create failed!\n");
            exit(-2);
        }
    }

    // Wait for all PUT operations to complete and cleanup
    for (int i = 0; i < NUM_FILES; i++) {
        int joinStatus = pthread_join(writeArgs[i].threadID, NULL);
        if (joinStatus != 0) {
            fprintf(stderr, "pthread join failed!\n");
        }
        KineticClient_DestroySession(writeArgs[i].session);
    }

    // Shutdown client connection and cleanup
    KineticClient_Shutdown(client);
    free(writeArgs);
    free(buf);

    return 0;
}
void run_throughput_tests(KineticClient * client, size_t num_ops, size_t value_size)
{
    LOGF0("STRESS THREAD: object_size: %zu bytes, count: %zu entries", value_size, num_ops);

    // Configure and establish a session with the specified device
    KineticSession* session;
    const char HmacKeyString[] = "asdfasdf";
    KineticSessionConfig config = {
        .clusterVersion = 0,
        .identity = 1,
        .hmacKey = ByteArray_CreateWithCString(HmacKeyString),
    };
    strncpy(config.host, GetSystemTestHost1(), sizeof(config.host)-1);
    config.port = GetSystemTestPort1();
    KineticStatus status = KineticClient_CreateSession(&config, client, &session);
    if (status != KINETIC_STATUS_SUCCESS) {
        char msg[128];
        sprintf(msg, "Failed connecting to the Kinetic device w/status: %s", Kinetic_GetStatusDescription(status));
        TEST_FAIL_MESSAGE(msg);
    }

    // Generate test entry data
    ByteBuffer test_data = ByteBuffer_Malloc(value_size);
    ByteBuffer_AppendDummyData(&test_data, test_data.array.len);
    uint8_t tag_data[] = {0x00, 0x01, 0x02, 0x03};
    ByteBuffer tag = ByteBuffer_Create(tag_data, sizeof(tag_data), sizeof(tag_data));
    uint64_t r = rand();
    uint64_t keys[num_ops];
    KineticEntry entries[num_ops];
    for (uint32_t put = 0; put < num_ops; put++) {
        keys[put] = put | (r << 16);
    }

    // Measure PUT performance
    {
        OpStatus put_statuses[num_ops];
        for (size_t i = 0; i < num_ops; i++) {
            put_statuses[i] = (OpStatus){
                .sem = KineticSemaphore_Create(),
                .status = KINETIC_STATUS_INVALID,
            };
        };

        struct timeval start_time;
        gettimeofday(&start_time, NULL);

        for (uint32_t put = 0; put < num_ops; put++) {
            ByteBuffer key = ByteBuffer_Create(&keys[put], sizeof(keys[put]), sizeof(keys[put]));

            KineticSynchronization sync = (put == num_ops - 1)
                ? KINETIC_SYNCHRONIZATION_FLUSH
                : KINETIC_SYNCHRONIZATION_WRITEBACK;

            entries[put] = (KineticEntry) {
                .key = key,
                .tag = tag,
                .algorithm = KINETIC_ALGORITHM_SHA1,
                .value = test_data,
                .synchronization = sync,
            };

            KineticStatus status = KineticClient_Put(
                session,
                &entries[put],
                &(KineticCompletionClosure) {
                    .callback = op_finished,
                    .clientData = &put_statuses[put],
                }
            );

            if (status != KINETIC_STATUS_SUCCESS) {
                char msg[128];
                sprintf(msg, "PUT failed w/status: %s", Kinetic_GetStatusDescription(status));
                TEST_FAIL_MESSAGE(msg);
            }
        }

        for (size_t i = 0; i < num_ops; i++)
        {
            KineticSemaphore_WaitForSignalAndDestroy(put_statuses[i].sem);
            if (put_statuses[i].status != KINETIC_STATUS_SUCCESS) {
                char msg[128];
                sprintf(msg, "PUT failed w/status: %s", Kinetic_GetStatusDescription(put_statuses[i].status));
                TEST_FAIL_MESSAGE(msg);
            }
        }

        struct timeval stop_time;
        gettimeofday(&stop_time, NULL);
        size_t bytes_written = num_ops * test_data.array.len;
        int64_t elapsed_us = ((stop_time.tv_sec - start_time.tv_sec) * 1000000)
            + (stop_time.tv_usec - start_time.tv_usec);
        float elapsed_ms = elapsed_us / 1000.0f;
        float bandwidth = (bytes_written * 1000.0f) / (elapsed_ms * 1024 * 1024);
        LOGF0("PUT Performance: wrote: %.1f kB, duration: %.3f sec, throughput: %.2f MB/sec",
            bytes_written / 1024.0f, elapsed_ms / 1000.0f, bandwidth);
    }

    // Measure GET performance
    {
        OpStatus get_statuses[num_ops];
        for (size_t i = 0; i < num_ops; i++) {
            get_statuses[i] = (OpStatus){
                .sem = KineticSemaphore_Create(),
                .status = KINETIC_STATUS_INVALID,
            };
        };

        ByteBuffer test_get_datas[num_ops];
        for (size_t i = 0; i < num_ops; i++)
        {
            test_get_datas[i] = ByteBuffer_Malloc(value_size);
        }

        struct timeval start_time;
        gettimeofday(&start_time, NULL);

        for (uint32_t get = 0; get < num_ops; get++) {
            ByteBuffer key = ByteBuffer_Create(&keys[get], sizeof(keys[get]), sizeof(keys[get]));

            entries[get] = (KineticEntry) {
                .key = key,
                .tag = tag,
                .value = test_get_datas[get],
            };

            KineticStatus status = KineticClient_Get(
                session,
                &entries[get],
                &(KineticCompletionClosure) {
                    .callback = op_finished,
                    .clientData = &get_statuses[get],
                }
            );

            if (status != KINETIC_STATUS_SUCCESS) {
                char msg[128];
                sprintf(msg, "GET failed w/status: %s", Kinetic_GetStatusDescription(status));
                TEST_FAIL_MESSAGE(msg);
            }
        }

        size_t bytes_read = 0;
        for (size_t i = 0; i < num_ops; i++)
        {
            KineticSemaphore_WaitForSignalAndDestroy(get_statuses[i].sem);
            if (get_statuses[i].status != KINETIC_STATUS_SUCCESS) {
                char msg[128];
                sprintf(msg, "GET failed w/status: %s", Kinetic_GetStatusDescription(get_statuses[i].status));
                TEST_FAIL_MESSAGE(msg);
            }
            else
            {
                bytes_read += entries[i].value.bytesUsed;
            }
        }

        // Check data for integrity
        size_t numFailures = 0;
        for (size_t i = 0; i < num_ops; i++) {
            int res = memcmp(test_data.array.data, test_get_datas[i].array.data, test_data.array.len);
            if (res != 0) {
                LOGF0("Failed validating data in object %zu of %zu!", i+1, num_ops);
                numFailures++;
            }
        }
        TEST_ASSERT_EQUAL_MESSAGE(0, numFailures, "DATA INTEGRITY CHECK FAILED UPON READBACK!");

        // Calculate and report performance
        struct timeval stop_time;
        gettimeofday(&stop_time, NULL);
        int64_t elapsed_us = ((stop_time.tv_sec - start_time.tv_sec) * 1000000)
            + (stop_time.tv_usec - start_time.tv_usec);
        float elapsed_ms = elapsed_us / 1000.0f;
        float bandwidth = (bytes_read * 1000.0f) / (elapsed_ms * 1024 * 1024);
        LOGF0("GET Performance: read: %.1f kB, duration: %.3f sec, throughput: %.2f MB/sec",
            bytes_read / 1024.0f, elapsed_ms / 1000.0f, bandwidth);

        for (size_t i = 0; i < num_ops; i++) {
            ByteBuffer_Free(test_get_datas[i]);
        }
    }
示例#24
0
KineticStatus KineticPDU_ReceiveMain(KineticPDU* const response)
{
    assert(response != NULL);
    assert(response->connection != NULL);
    const int fd = response->connection->socket;
    assert(fd >= 0);
    LOGF1("\nReceiving PDU via fd=%d", fd);

    KineticStatus status;
    KineticMessage* msg = &response->protoData.message;

    // Receive the PDU header
    ByteBuffer rawHeader =
        ByteBuffer_Create(&response->headerNBO, sizeof(KineticPDUHeader), 0);
    status = KineticSocket_Read(fd, &rawHeader, rawHeader.array.len);
    if (status != KINETIC_STATUS_SUCCESS) {
        LOG0("Failed to receive PDU header!");
        return status;
    }
    else {
        LOG3("PDU header received successfully");
        KineticPDUHeader* headerNBO = &response->headerNBO;
        response->header = (KineticPDUHeader) {
            .versionPrefix = headerNBO->versionPrefix,
            .protobufLength = KineticNBO_ToHostU32(headerNBO->protobufLength),
            .valueLength = KineticNBO_ToHostU32(headerNBO->valueLength),
        };
        KineticLogger_LogHeader(1, &response->header);
    }

    // Receive the protobuf message
    status = KineticSocket_ReadProtobuf(fd, response);
    if (status != KINETIC_STATUS_SUCCESS) {
        LOG0("Failed to receive PDU protobuf message!");
        return status;
    }
    else {
        LOG3("Received PDU protobuf");
        KineticLogger_LogProtobuf(2, response->proto);
    }

    // Validate the HMAC for the recevied protobuf message
    if (response->proto->authType == KINETIC_PROTO_MESSAGE_AUTH_TYPE_HMACAUTH) {
        if(!KineticHMAC_Validate(
          response->proto, response->connection->session.hmacKey)) {
            LOG0("Received PDU protobuf message has invalid HMAC!");
            msg->has_command = true;
            msg->command.status = &msg->status;
            msg->status.code = KINETIC_PROTO_COMMAND_STATUS_STATUS_CODE_DATA_ERROR;
            return KINETIC_STATUS_DATA_ERROR;
        }
        else {
            LOG3("Received protobuf HMAC validation succeeded");
        }
    }
    else if (response->proto->authType == KINETIC_PROTO_MESSAGE_AUTH_TYPE_PINAUTH) {
        LOG0("PIN-based authentication not yet supported!");
        return KINETIC_STATUS_DATA_ERROR;
    }
    else if (response->proto->authType == KINETIC_PROTO_MESSAGE_AUTH_TYPE_UNSOLICITEDSTATUS) {
        LOG3("Unsolicited status message is not authenticated");
    }

    // Extract embedded command, if supplied
    KineticProto_Message* pMsg = response->proto;
    if (pMsg->has_commandBytes &&
      pMsg->commandBytes.data != NULL &&
      pMsg->commandBytes.len > 0) {
        response->command = KineticProto_command__unpack(
            NULL,
            pMsg->commandBytes.len,
            pMsg->commandBytes.data);
    }

    status = KineticPDU_GetStatus(response);
    if (status == KINETIC_STATUS_SUCCESS) {
        LOG2("PDU received successfully!");
    }
    return status;
}

KineticStatus KineticPDU_ReceiveValue(int socket_desc, ByteBuffer* value, size_t value_length)
{
    assert(socket_desc >= 0);
    assert(value != NULL);
    assert(value->array.data != NULL);

    // Receive value payload
    LOGF1("Receiving value payload (%lld bytes)...", value_length);
    ByteBuffer_Reset(value);
    KineticStatus status = KineticSocket_Read(socket_desc, value, value_length);
    if (status != KINETIC_STATUS_SUCCESS) {
        LOG0("Failed to receive PDU value payload!");
        return status;
    }
    LOG1("Received value payload successfully");
    KineticLogger_LogByteBuffer(3, "Value Buffer", *value);
    return status;
}
示例#25
0
int main(int argc, char** argv)
{
    (void)argc;
    (void)argv;

    // Initialize kinetic-c and configure sessions
    KineticSession* session;
    KineticClientConfig clientConfig = {
        .logFile = "stdout",
        .logLevel = 1,
    };
    KineticClient * client = KineticClient_Init(&clientConfig);
    if (client == NULL) { return 1; }
    const char HmacKeyString[] = "asdfasdf";
    KineticSessionConfig sessionConfig = {
        .host = "localhost",
        .port = KINETIC_PORT,
        .clusterVersion = 0,
        .identity = 1,
        .hmacKey = ByteArray_CreateWithCString(HmacKeyString),
    };
    KineticStatus status = KineticClient_CreateSession(&sessionConfig, client, &session);
    if (status != KINETIC_STATUS_SUCCESS) {
        fprintf(stderr, "Failed connecting to the Kinetic device w/status: %s\n",
            Kinetic_GetStatusDescription(status));
        exit(1);
    }

    // Read in file contents to store
    const char* dataFile = "test/support/data/test.data";
    struct stat st;
    stat(dataFile, &st);
    char* buf = malloc(st.st_size);
    int fd = open(dataFile, O_RDONLY);
    long dataLen = read(fd, buf, st.st_size);
    close(fd);
    if (dataLen <= 0) {
        fprintf(stderr, "Failed reading data file to store: %s\n", dataFile);
        exit(-1);
    }


    write_args* writeArgs = calloc(1, sizeof(write_args));
    writeArgs->session = session;
    
    // Create a ByteBuffer for consuming chunks of data out of for overlapped PUTs
    writeArgs->data = ByteBuffer_Create(buf, dataLen, 0);

    // Configure common meta-data for the entries
    struct timeval now;
    gettimeofday(&now, NULL);
    snprintf(writeArgs->keyPrefix, sizeof(writeArgs->keyPrefix), "%010ld_", now.tv_sec);
    ByteBuffer verBuf = ByteBuffer_Create(writeArgs->version, sizeof(writeArgs->version), 0);
    ByteBuffer_AppendCString(&verBuf, "v1.0");
    ByteBuffer tagBuf = ByteBuffer_Create(writeArgs->tag, sizeof(writeArgs->tag), 0);
    ByteBuffer_AppendCString(&tagBuf, "some_value_tag...");
    writeArgs->entry = (KineticEntry) {
        .key = ByteBuffer_Create(writeArgs->key, sizeof(writeArgs->key), 0),
        // .newVersion = verBuf,
        .tag = tagBuf,
        .algorithm = KINETIC_ALGORITHM_SHA1,
        .value = ByteBuffer_Create(writeArgs->value, sizeof(writeArgs->value), 0),
        .synchronization = KINETIC_SYNCHRONIZATION_WRITEBACK,
    };
    strcpy(writeArgs->ip, sessionConfig.host);

    // Store the data
    printf("\nWriting data file to the Kinetic device...\n");
    store_data(writeArgs);

    // Shutdown client connection and cleanup
    KineticClient_DestroySession(writeArgs->session);
    KineticClient_Shutdown(client);
    free(writeArgs);
    free(buf);

    return 0;
}
void test_KineticBuilder_BuildPut_should_build_and_execute_a_PUT_operation_to_create_a_new_object_with_calculated_tag(void)
{
    ByteArray value = ByteArray_CreateWithCString("Luke, I am your father");
    ByteArray key = ByteArray_CreateWithCString("foobar");
    ByteArray newVersion = ByteArray_CreateWithCString("v1.0");
    ByteArray tag = ByteArray_CreateWithCString("some_tag");

    KineticEntry entry = {
        .key = ByteBuffer_CreateWithArray(key),
        .newVersion = ByteBuffer_CreateWithArray(newVersion),
        .tag = ByteBuffer_CreateWithArray(tag),
        .algorithm = KINETIC_ALGORITHM_SHA1,
        .value = ByteBuffer_CreateWithArray(value),
        .computeTag = true,
    };

    KineticOperation_ValidateOperation_Expect(&Operation);
    KineticMessage_ConfigureKeyValue_Expect(&Operation.request->message, &entry);

    // Build the operation
    KineticBuilder_BuildPut(&Operation, &entry);

    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL_PTR(entry.value.array.data, Operation.value.data);
    TEST_ASSERT_EQUAL(entry.value.bytesUsed, Operation.value.len);
    TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__PUT,
        Request.message.command.header->messagetype);
    TEST_ASSERT_EQUAL_ByteArray(value, Operation.entry->value.array);
    TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed);
    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);
    TEST_ASSERT_NULL(Operation.response);
}

uint8_t ValueData[KINETIC_OBJ_SIZE];

void test_KineticBuilder_BuildGet_should_build_a_GET_operation(void)
{
    const ByteArray key = ByteArray_CreateWithCString("foobar");
    ByteArray value = {.data = ValueData, .len = sizeof(ValueData)};
    KineticEntry entry = {
        .key = ByteBuffer_CreateWithArray(key),
        .value = ByteBuffer_CreateWithArray(value),
    };
    entry.value.bytesUsed = 123; // Set to non-empty state, since it should be reset to 0

    KineticOperation_ValidateOperation_Expect(&Operation);
    KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry);

    KineticBuilder_BuildGet(&Operation, &entry);

    TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GET, Request.message.command.header->messagetype);
    TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Get, Operation.opCallback);
    TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data);
    TEST_ASSERT_EQUAL(value.len, Operation.entry->value.array.len);
    TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed);
    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);
    TEST_ASSERT_NULL(Operation.response);
    TEST_ASSERT_FALSE(Operation.entry->metadataOnly);
}

void test_KineticBuilder_BuildGet_should_build_a_GET_operation_requesting_metadata_only(void)
{
    const ByteArray key = ByteArray_CreateWithCString("foobar");
    ByteArray value = ByteArray_Create(ValueData, sizeof(ValueData));
    KineticEntry entry = {
        .key = ByteBuffer_CreateWithArray(key),
        .metadataOnly = true,
        .value = ByteBuffer_CreateWithArray(value),
    };
    entry.value.bytesUsed = 123; // Set to non-empty state, since it should be reset to 0 for a metadata-only request

    KineticOperation_ValidateOperation_Expect(&Operation);
    KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry);

    KineticBuilder_BuildGet(&Operation, &entry);

    TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GET, Request.message.command.header->messagetype);
    TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Get, Operation.opCallback);
    TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data);
    TEST_ASSERT_EQUAL_PTR(value.len, Operation.entry->value.array.len);
    TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed);
    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);
    TEST_ASSERT_NULL(Operation.response);
    TEST_ASSERT_TRUE(Operation.entry->metadataOnly);
}

void test_KineticBuilder_BuildGetNext_should_build_a_GETNEXT_operation(void)
{
    const ByteArray key = ByteArray_CreateWithCString("foobar");
    ByteArray value = {.data = ValueData, .len = sizeof(ValueData)};
    KineticEntry entry = {
        .key = ByteBuffer_CreateWithArray(key),
        .value = ByteBuffer_CreateWithArray(value),
    };
    entry.value.bytesUsed = 123; // Set to non-empty state, since it should be reset to 0

    KineticOperation_ValidateOperation_Expect(&Operation);
    KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry);

    KineticBuilder_BuildGetNext(&Operation, &entry);

    TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETNEXT,
        Request.message.command.header->messagetype);
    TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Get, Operation.opCallback);
    TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data);
    TEST_ASSERT_EQUAL(value.len, Operation.entry->value.array.len);
    TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed);
    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);
    TEST_ASSERT_NULL(Operation.response);
    TEST_ASSERT_FALSE(Operation.entry->metadataOnly);
}

void test_KineticBuilder_BuildGetNext_should_build_a_GETNEXT_operation_with_metadata_only(void)
{
    const ByteArray key = ByteArray_CreateWithCString("foobar");
    ByteArray value = ByteArray_Create(ValueData, sizeof(ValueData));
    KineticEntry entry = {
        .key = ByteBuffer_CreateWithArray(key),
        .metadataOnly = true,
        .value = ByteBuffer_CreateWithArray(value),
    };
    entry.value.bytesUsed = 123; // Set to non-empty state, since it should be reset to 0 for a metadata-only request

    KineticOperation_ValidateOperation_Expect(&Operation);
    KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry);

    KineticBuilder_BuildGetNext(&Operation, &entry);

    TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETNEXT,
        Request.message.command.header->messagetype);
    TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Get, Operation.opCallback);
    TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data);
    TEST_ASSERT_EQUAL_PTR(value.len, Operation.entry->value.array.len);
    TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed);
    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);
    TEST_ASSERT_NULL(Operation.response);
    TEST_ASSERT_TRUE(Operation.entry->metadataOnly);
}

void test_KineticBuilder_BuildGetPrevious_should_build_a_GETPREVIOUS_operation(void)
{
    const ByteArray key = ByteArray_CreateWithCString("foobar");
    ByteArray value = {.data = ValueData, .len = sizeof(ValueData)};
    KineticEntry entry = {
        .key = ByteBuffer_CreateWithArray(key),
        .value = ByteBuffer_CreateWithArray(value),
    };
    entry.value.bytesUsed = 123; // Set to non-empty state, since it should be reset to 0

    KineticOperation_ValidateOperation_Expect(&Operation);
    KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry);

    KineticBuilder_BuildGetPrevious(&Operation, &entry);

    TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETPREVIOUS,
        Request.message.command.header->messagetype);
    TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Get, Operation.opCallback);
    TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data);
    TEST_ASSERT_EQUAL(value.len, Operation.entry->value.array.len);
    TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed);
    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);
    TEST_ASSERT_NULL(Operation.response);
    TEST_ASSERT_FALSE(Operation.entry->metadataOnly);
}

void test_KineticBuilder_BuildGetPrevious_should_build_a_GETPREVIOUS_operation_with_metadata_only(void)
{
    const ByteArray key = ByteArray_CreateWithCString("foobar");
    ByteArray value = ByteArray_Create(ValueData, sizeof(ValueData));
    KineticEntry entry = {
        .key = ByteBuffer_CreateWithArray(key),
        .metadataOnly = true,
        .value = ByteBuffer_CreateWithArray(value),
    };
    entry.value.bytesUsed = 123; // Set to non-empty state, since it should be reset to 0 for a metadata-only request

    KineticOperation_ValidateOperation_Expect(&Operation);
    KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry);

    KineticBuilder_BuildGetPrevious(&Operation, &entry);

    TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETPREVIOUS,
        Request.message.command.header->messagetype);
    TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Get, Operation.opCallback);
    TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data);
    TEST_ASSERT_EQUAL_PTR(value.len, Operation.entry->value.array.len);
    TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed);
    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);
    TEST_ASSERT_NULL(Operation.response);
    TEST_ASSERT_TRUE(Operation.entry->metadataOnly);
}



void test_KineticBuilder_BuildFlush_should_build_a_FLUSHALLDATA_operation(void)
{
    KineticOperation_ValidateOperation_Expect(&Operation);

    KineticBuilder_BuildFlush(&Operation);

    TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__FLUSHALLDATA,
        Request.message.command.header->messagetype);
    TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Basic, Operation.opCallback);
    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);

    TEST_ASSERT_NULL(Operation.response);
}



void test_KineticBuilder_BuildDelete_should_build_a_DELETE_operation(void)
{
    const ByteArray key = ByteArray_CreateWithCString("foobar");
    ByteArray value = ByteArray_Create(ValueData, sizeof(ValueData));
    KineticEntry entry = {.key = ByteBuffer_CreateWithArray(key), .value = ByteBuffer_CreateWithArray(value)};

    KineticOperation_ValidateOperation_Expect(&Operation);
    KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry);

    KineticBuilder_BuildDelete(&Operation, &entry);

    TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__DELETE,
        Request.message.command.header->messagetype);
    TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Delete, Operation.opCallback);
    TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data);
    TEST_ASSERT_EQUAL_PTR(value.len, Operation.entry->value.array.len);
    TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed);
    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);
    TEST_ASSERT_NULL(Operation.response);
}


void test_KineticBuilder_BuildGetKeyRange_should_build_a_GetKeyRange_request(void)
{
    const int maxKeyLen = 32; // arbitrary key length for test
    uint8_t startKeyData[maxKeyLen];
    uint8_t endKeyData[maxKeyLen];
    ByteBuffer startKey, endKey;
    startKey = ByteBuffer_Create(startKeyData, sizeof(startKeyData), 0);
    ByteBuffer_AppendCString(&startKey, "key_range_00_00");
    endKey = ByteBuffer_Create(endKeyData, sizeof(endKeyData), 0);
    ByteBuffer_AppendCString(&endKey, "key_range_00_03");
    const int numKeysInRange = 4;
    KineticKeyRange range = {
        .startKey = startKey,
        .endKey = endKey,
        .startKeyInclusive = true,
        .endKeyInclusive = true,
        .maxReturned = numKeysInRange,
        .reverse = false,
    };

    uint8_t keysData[numKeysInRange][maxKeyLen];
    ByteBuffer keyBuffers[numKeysInRange];
    for (int i = 0; i < numKeysInRange; i++) {
        keyBuffers[i] = ByteBuffer_Create(keysData[i], maxKeyLen, 0);
    }
    ByteBufferArray keys = {.buffers = keyBuffers, .count = numKeysInRange};

    KineticOperation_ValidateOperation_Expect(&Operation);
    KineticMessage_ConfigureKeyRange_Expect(&Request.message, &range);

    KineticBuilder_BuildGetKeyRange(&Operation, &range, &keys);

    TEST_ASSERT_TRUE(Request.command->header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETKEYRANGE,
        Request.command->header->messagetype);
    TEST_ASSERT_EQUAL_PTR(KineticCallbacks_GetKeyRange, Operation.opCallback);
    TEST_ASSERT_NULL(Operation.entry);
    TEST_ASSERT_EQUAL_PTR(&Request, Operation.request);
    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);
    TEST_ASSERT_NULL(Operation.response);
    TEST_ASSERT_EQUAL_PTR(&Request.message.command, Request.command);
}


void test_KineticBuilder_BuildP2POperation_should_build_a_P2POperation_request(void)
{
    ByteBuffer oldKey1 = ByteBuffer_Create((void*)0x1234, 10, 10);
    ByteBuffer newKey1 = ByteBuffer_Create((void*)0x4321, 33, 33);
    ByteBuffer version1 = ByteBuffer_Create((void*)0xABC, 6, 6);

    ByteBuffer oldKey2 = ByteBuffer_Create((void*)0x5678, 12, 12);
    ByteBuffer newKey2 = ByteBuffer_Create((void*)0x8765, 200, 200);

    KineticP2P_OperationData ops2[] ={
        {
            .key = oldKey2,
            .newKey = newKey2,
        }
    };

    KineticP2P_Operation chained_p2pOp = {
        .peer = {
            .hostname = "hostname1",
            .port = 4321,
        },
        .numOperations = 1,
        .operations = ops2
    };

    KineticP2P_OperationData ops[] ={
        {
            .key = oldKey1,
            .version = version1,
            .newKey = newKey1,
            .chainedOperation = &chained_p2pOp,
        },
        {
            .key = oldKey2,
            .newKey = newKey2,
        }
    };

    KineticP2P_Operation p2pOp = {
        .peer = {
            .hostname = "hostname",
            .port = 1234,
            .tls = true,
        },
        .numOperations = 2,
        .operations = ops
    };

    KineticOperation_ValidateOperation_Expect(&Operation);

    KineticBuilder_BuildP2POperation(&Operation, &p2pOp);

    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__PEER2PEERPUSH,
        Request.message.command.header->messagetype);
    TEST_ASSERT_EQUAL_PTR(&Request.message.body, Request.command->body);
    
    TEST_ASSERT_NOT_NULL(Request.command->body->p2poperation);

    TEST_ASSERT_EQUAL("hostname",
        Request.command->body->p2poperation->peer->hostname);

    TEST_ASSERT_TRUE(Request.command->body->p2poperation->peer->has_port);

    TEST_ASSERT_EQUAL(1234,
        Request.command->body->p2poperation->peer->port);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->peer->has_tls);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->peer->tls);
    TEST_ASSERT_FALSE(Request.command->body->p2poperation->allchildoperationssucceeded);
    TEST_ASSERT_FALSE(Request.command->body->p2poperation->has_allchildoperationssucceeded);

    TEST_ASSERT_EQUAL(2,
        Request.command->body->p2poperation->n_operation);

    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->has_key);
    TEST_ASSERT_EQUAL(oldKey1.array.data,
        Request.command->body->p2poperation->operation[0]->key.data);
    TEST_ASSERT_EQUAL(oldKey1.bytesUsed,
        Request.command->body->p2poperation->operation[0]->key.len);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->has_newkey);
    TEST_ASSERT_EQUAL(newKey1.array.data,
        Request.command->body->p2poperation->operation[0]->newkey.data);
    TEST_ASSERT_EQUAL(newKey1.bytesUsed,
        Request.command->body->p2poperation->operation[0]->newkey.len);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->has_version);
    TEST_ASSERT_EQUAL(version1.array.data,
        Request.command->body->p2poperation->operation[0]->version.data);
    TEST_ASSERT_EQUAL(version1.bytesUsed,
        Request.command->body->p2poperation->operation[0]->version.len);
    TEST_ASSERT_FALSE(Request.command->body->p2poperation->operation[0]->has_force);
    TEST_ASSERT_FALSE(Request.command->body->p2poperation->operation[0]->force);

    TEST_ASSERT_NOT_NULL(Request.command->body->p2poperation->operation[0]->p2pop);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->p2pop->peer->has_port);
    TEST_ASSERT_EQUAL(4321,
        Request.command->body->p2poperation->operation[0]->p2pop->peer->port);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->p2pop->peer->has_tls);
    TEST_ASSERT_FALSE(Request.command->body->p2poperation->operation[0]->p2pop->peer->tls);
    TEST_ASSERT_EQUAL(1,
        Request.command->body->p2poperation->operation[0]->p2pop->n_operation);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->has_key);
    TEST_ASSERT_EQUAL(oldKey2.array.data,
        Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->key.data);
    TEST_ASSERT_EQUAL(oldKey2.bytesUsed,
        Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->key.len);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->has_newkey);
    TEST_ASSERT_EQUAL(newKey2.array.data,
        Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->newkey.data);
    TEST_ASSERT_EQUAL(newKey2.bytesUsed,
        Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->newkey.len);
    TEST_ASSERT_FALSE(Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->has_version);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->has_force);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->force);
    TEST_ASSERT_NULL(Request.command->body->p2poperation->operation[0]->status);

    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[1]->has_key);
    TEST_ASSERT_EQUAL(oldKey2.array.data,
        Request.command->body->p2poperation->operation[1]->key.data);
    TEST_ASSERT_EQUAL(oldKey2.bytesUsed,
        Request.command->body->p2poperation->operation[1]->key.len);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[1]->has_newkey);
    TEST_ASSERT_EQUAL(newKey2.array.data,
        Request.command->body->p2poperation->operation[1]->newkey.data);
    TEST_ASSERT_EQUAL(newKey2.bytesUsed,
        Request.command->body->p2poperation->operation[1]->newkey.len);
    TEST_ASSERT_FALSE(Request.command->body->p2poperation->operation[1]->has_version);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[1]->has_force);
    TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[1]->force);
    TEST_ASSERT_NULL(Request.command->body->p2poperation->operation[1]->p2pop);
    TEST_ASSERT_NULL(Request.command->body->p2poperation->operation[1]->status);

    TEST_ASSERT_EQUAL_PTR(&p2pOp, Operation.p2pOp);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);

    TEST_ASSERT_NULL(Operation.response);

    // This just free's the malloc'd memory and sets statuses to "invalid" (since no operation was actually performed)
    KineticAllocator_FreeP2PProtobuf(Request.command->body->p2poperation);
}



/*******************************************************************************
 * Admin Client Operations
*******************************************************************************/

void test_KineticBuilder_BuildGetLog_should_build_a_GetLog_request(void)
{
    KineticLogInfo* pInfo;

    KineticOperation_ValidateOperation_Expect(&Operation);

    KineticStatus status = KineticBuilder_BuildGetLog(&Operation,
        KINETIC_DEVICE_INFO_TYPE_STATISTICS, BYTE_ARRAY_NONE, &pInfo);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETLOG,
        Request.message.command.header->messagetype);
    TEST_ASSERT_EQUAL_PTR(&Request.message.body, Request.command->body);
    TEST_ASSERT_EQUAL_PTR(&Request.message.getLog, Request.command->body->getlog);
    TEST_ASSERT_NOT_NULL(Request.command->body->getlog->types);
    TEST_ASSERT_EQUAL(1, Request.command->body->getlog->n_types);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__STATISTICS,
        Request.command->body->getlog->types[0]);
    TEST_ASSERT_EQUAL_PTR(&pInfo, Operation.deviceInfo);
    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);
    TEST_ASSERT_NULL(Operation.response);
}

void test_KineticBuilder_BuildGetLog_should_build_a_GetLog_request_to_retrieve_device_specific_log_info(void)
{
    KineticLogInfo* pInfo;
    const char nameData[] = "com.WD";
    ByteArray name = ByteArray_CreateWithCString(nameData);

    KineticOperation_ValidateOperation_Expect(&Operation);

    KineticStatus status = KineticBuilder_BuildGetLog(&Operation, COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__DEVICE, name, &pInfo);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETLOG,
        Request.message.command.header->messagetype);
    TEST_ASSERT_EQUAL_PTR(&Request.message.body, Request.command->body);
    TEST_ASSERT_EQUAL_PTR(&Request.message.getLog, Request.command->body->getlog);
    TEST_ASSERT_NOT_NULL(Request.command->body->getlog->types);
    TEST_ASSERT_EQUAL(1, Request.command->body->getlog->n_types);
    TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__DEVICE,
        Request.command->body->getlog->types[0]);
    TEST_ASSERT_EQUAL_PTR(&Request.message.getLogDevice, Request.command->body->getlog->device);
    TEST_ASSERT_TRUE(Request.command->body->getlog->device->has_name);
    TEST_ASSERT_EQUAL_PTR(nameData, Request.command->body->getlog->device->name.data);
    TEST_ASSERT_EQUAL(strlen(nameData), Request.command->body->getlog->device->name.len);
    TEST_ASSERT_EQUAL_PTR(&pInfo, Operation.deviceInfo);
    TEST_ASSERT_FALSE(Request.pinAuth);
    TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds);
    TEST_ASSERT_NULL(Operation.response);
}

void test_KineticBuilder_BuildGetLog_should_return_KINETIC_STATUS_DEVICE_NAME_REQUIRED_if_name_not_specified_correctly(void)
{
    KineticLogInfo* pInfo;
    char nameData[] = "com.WD";
    ByteArray name;
    KineticStatus status;

    // Length is zero
    name.data = (uint8_t*)nameData;
    name.len = 0;
    KineticOperation_ValidateOperation_Expect(&Operation);
    status = KineticBuilder_BuildGetLog(&Operation,
        COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__DEVICE, name, &pInfo);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DEVICE_NAME_REQUIRED, status);

    // Data is NULL
    name.data = NULL;
    name.len = strlen(nameData);
    KineticOperation_ValidateOperation_Expect(&Operation);
    status = KineticBuilder_BuildGetLog(&Operation,
        COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__DEVICE, name, &pInfo);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DEVICE_NAME_REQUIRED, status);

    // Length is zero and data is NULL
    name.data = NULL;
    name.len = 0;
    KineticOperation_ValidateOperation_Expect(&Operation);
    status = KineticBuilder_BuildGetLog(&Operation,
        COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__DEVICE, name, &pInfo);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DEVICE_NAME_REQUIRED, status);
}
static bool add_keys(int count)
{
    static const ssize_t sz = 10;
    char key_buf[sz];
    char tag_buf[sz];
    char value_buf[sz];

    for (int i = 0; i < count; i++) {

        KineticEntry entry = {
            .key = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key_%d", i),
            .tag = ByteBuffer_CreateAndAppendFormattedCString(tag_buf, sz, "tag_%d", i),
            .value = ByteBuffer_CreateAndAppendFormattedCString(value_buf, sz, "val_%d", i),
            .algorithm = KINETIC_ALGORITHM_SHA1,
            .force = true,
        };

        KineticStatus status = KineticClient_Put(Fixture.session, &entry, NULL);
        TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    }
    return true;
}

typedef enum { CMD_NEXT, CMD_PREVIOUS } GET_CMD;

static void compare_against_offset_key(GET_CMD cmd, bool metadataOnly)
{
    static const ssize_t sz = 10;
    char key_buf[sz];
    char tag_buf[sz];
    char value_buf[sz];
    char key_exp_buf[sz];
    char value_exp_buf[sz];

    const int count = 3;

    TEST_ASSERT_TRUE(add_keys(count));    /* add keys [key_X -> test_X] */

    int low = 0;
    int high = count;
    int8_t offset = 0;

    switch (cmd) {
    case CMD_NEXT:
        low = 1;
        offset = -1;
        break;
    case CMD_PREVIOUS:
        high = count - 1;
        offset = +1;
        break;
    default:
        TEST_ASSERT(false);
    }

    for (int i = low; i < high; i++) {
        ByteBuffer keyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key_%d", i + offset);
        ByteBuffer tagBuffer = ByteBuffer_CreateAndAppendFormattedCString(tag_buf, sz, "tag_%d", i + offset);
        ByteBuffer valueBuffer = ByteBuffer_Create(value_buf, sz, 0);

        printf("KEY '%s'\n", key_buf);

        KineticEntry entry = {
            .key = keyBuffer,
            .tag = tagBuffer,
            .value = valueBuffer,
            .algorithm = KINETIC_ALGORITHM_SHA1,
            .metadataOnly = metadataOnly,
        };
        KineticStatus status = KINETIC_STATUS_INVALID;

        switch (cmd) {
        case CMD_NEXT:
            status = KineticClient_GetNext(Fixture.session, &entry, NULL);
            break;
        case CMD_PREVIOUS:
            status = KineticClient_GetPrevious(Fixture.session, &entry, NULL);
            break;
        default:
            TEST_ASSERT(false);
        }
        
        TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);

        ByteBuffer expectedKeyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_exp_buf, sz, "key_%d", i);
        ByteBuffer expectedValueBuffer = ByteBuffer_CreateAndAppendFormattedCString(value_exp_buf, sz, "val_%d", i);

        TEST_ASSERT_EQUAL_ByteBuffer(expectedKeyBuffer, entry.key);
        if (!metadataOnly) {
            TEST_ASSERT_EQUAL_ByteBuffer(expectedValueBuffer, entry.value);
        }
    }
}

void test_GetNext_should_retrieve_object_and_metadata_from_device(void)
{
    compare_against_offset_key(CMD_NEXT, false);
}
void test_put_get_delete_one_entry_by_one_entry(void)
{
    uint8_t version_data[DEFAULT_BUFFER_SIZE], tag_data[DEFAULT_BUFFER_SIZE], value_data[DEFAULT_BUFFER_SIZE];
    ByteBuffer version_buffer, tag_buffer, value_buffer;
    version_buffer = ByteBuffer_CreateAndAppendCString(version_data, sizeof(version_data), "v1.0");
    ExpectedVersionBuffer = ByteBuffer_CreateAndAppendCString(version_data, sizeof(version_data), "v1.0");
    tag_buffer = ByteBuffer_CreateAndAppendCString(tag_data, sizeof(tag_data), "SomeTagValue");
    ExpectedTagBuffer = ByteBuffer_CreateAndAppendCString(tag_data, sizeof(tag_data), "SomeTagValue");
    value_buffer = ByteBuffer_Create(value_data, DEFAULT_BUFFER_SIZE, 0);

    unsigned int i;
    for (i=0; i<KV_PAIRS_PER_GROUP; i++)
    {
    	// put object
        KineticEntry putEntry = {
   	       .key = generate_entry_key_by_index(i),
   	       .tag = tag_buffer,
   	       .newVersion = version_buffer,
           .algorithm = KINETIC_ALGORITHM_SHA1,
           .value = generate_entry_value_by_index(i),
           .force = true,
           .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH,
        };

        KineticStatus status = KineticClient_Put(Fixture.session, &putEntry, NULL);
        TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);

        ByteBuffer_Reset(&value_buffer);

        // get object
		value_buffer = ByteBuffer_Create(value_data, DEFAULT_BUFFER_SIZE, 0);
		KineticEntry getEntry = {
	        .key = generate_entry_key_by_index(i),
			.dbVersion = version_buffer,
	        .tag = tag_buffer,
			.value = value_buffer,
	    };

	    status = KineticClient_Get(Fixture.session, &getEntry, NULL);

	    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
	    TEST_ASSERT_EQUAL_ByteBuffer(ExpectedVersionBuffer, getEntry.dbVersion);
	    TEST_ASSERT_ByteBuffer_NULL(getEntry.newVersion);
	    TEST_ASSERT_EQUAL_ByteBuffer(generate_entry_key_by_index(i), getEntry.key);
	    TEST_ASSERT_EQUAL_ByteBuffer(ExpectedTagBuffer, getEntry.tag);
	    TEST_ASSERT_EQUAL(KINETIC_ALGORITHM_SHA1, getEntry.algorithm);
	    TEST_ASSERT_EQUAL_ByteBuffer(generate_entry_value_by_index(i), getEntry.value);

	    TEST_ASSERT_EQUAL_ByteBuffer(ExpectedVersionBuffer, version_buffer);
   	    // delete object
	    KineticEntry deleteEntry = {
	        .key = generate_entry_key_by_index(i),
			.dbVersion = version_buffer,
	    };
	    TEST_ASSERT_EQUAL_ByteBuffer(ExpectedVersionBuffer, version_buffer);
	    status = KineticClient_Delete(Fixture.session, &deleteEntry, NULL);
	    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
	    TEST_ASSERT_EQUAL(0, deleteEntry.value.bytesUsed);

   	    // get object again
     	status = KineticClient_Get(Fixture.session, &getEntry, NULL);
     	TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_NOT_FOUND, status);
    }
}

void test_put_get_delete_one_group_by_one_group(void)
{
    uint8_t version_data[DEFAULT_BUFFER_SIZE], tag_data[DEFAULT_BUFFER_SIZE], value_data[DEFAULT_BUFFER_SIZE];
    ByteBuffer version_buffer, tag_buffer, value_buffer;
    version_buffer = ByteBuffer_CreateAndAppendCString(version_data, sizeof(version_data), "v1.0");
    ExpectedVersionBuffer = ByteBuffer_CreateAndAppendCString(version_data, sizeof(version_data), "v1.0");
    tag_buffer = ByteBuffer_CreateAndAppendCString(tag_data, sizeof(tag_data), "SomeTagValue");
    ExpectedTagBuffer = ByteBuffer_CreateAndAppendCString(tag_data, sizeof(tag_data), "SomeTagValue");
    value_buffer = ByteBuffer_Create(value_data, DEFAULT_BUFFER_SIZE, 0);

    unsigned int i, j;
    for (i =0; i<TOTAL_GROUPS; i++)
    {
    	KineticStatus status;

    	// put a group of entries
        for (j=0; j<KV_PAIRS_PER_GROUP; j++)
        {
            KineticEntry putEntry = {
       	       .key = generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + j),
       	       .tag = tag_buffer,
       	       .newVersion = version_buffer,
               .algorithm = KINETIC_ALGORITHM_SHA1,
               .value = generate_entry_value_by_index(i*KV_PAIRS_PER_GROUP + j),
               .force = true,
               .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH,
            };

            status = KineticClient_Put(Fixture.session, &putEntry, NULL);
            TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
        }

        // get key_range
        KineticKeyRange range = {
            .startKey = generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP),
            .endKey = generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + KV_PAIRS_PER_GROUP -1),
            .startKeyInclusive = true,
            .endKeyInclusive = true,
            .maxReturned = KV_PAIRS_PER_GROUP,
        };

        ByteBuffer keyBuff[KV_PAIRS_PER_GROUP];
        uint8_t keysData[KV_PAIRS_PER_GROUP][DEFAULT_BUFFER_SIZE];
        for (j = 0; j < KV_PAIRS_PER_GROUP; j++) {
            memset(&keysData[j], 0, DEFAULT_BUFFER_SIZE);
            keyBuff[j] = ByteBuffer_Create(&keysData[j], DEFAULT_BUFFER_SIZE, 0);
        }
        ByteBufferArray keys = {.buffers = keyBuff, .count = KV_PAIRS_PER_GROUP, .used = 0};

        status = KineticClient_GetKeyRange(Fixture.session, &range, &keys, NULL);
        TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
        TEST_ASSERT_EQUAL(KV_PAIRS_PER_GROUP, keys.used);
        for (j = 0; j < KV_PAIRS_PER_GROUP; j++)
        {
        	TEST_ASSERT_EQUAL_ByteBuffer(generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + j), keys.buffers[j]);
        }

        // delete a group of entries
        for (j=0; j<KV_PAIRS_PER_GROUP; j++)
        {
        	ByteBuffer_Reset(&value_buffer);

   	        // get object
   			value_buffer = ByteBuffer_Create(value_data, DEFAULT_BUFFER_SIZE, 0);
   			KineticEntry getEntry = {
   		        .key = generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + j),
   				.dbVersion = version_buffer,
   		        .tag = tag_buffer,
   				.value = value_buffer,
   		    };

   		    status = KineticClient_Get(Fixture.session, &getEntry, NULL);

   		    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
   		    TEST_ASSERT_EQUAL_ByteBuffer(ExpectedVersionBuffer, getEntry.dbVersion);
   		    TEST_ASSERT_ByteBuffer_NULL(getEntry.newVersion);
   		    TEST_ASSERT_EQUAL_ByteBuffer(generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + j), getEntry.key);
   		    TEST_ASSERT_EQUAL_ByteBuffer(ExpectedTagBuffer, getEntry.tag);
   		    TEST_ASSERT_EQUAL(KINETIC_ALGORITHM_SHA1, getEntry.algorithm);
   		    TEST_ASSERT_EQUAL_ByteBuffer(generate_entry_value_by_index(i*KV_PAIRS_PER_GROUP + j), getEntry.value);
   		    TEST_ASSERT_EQUAL_ByteBuffer(ExpectedVersionBuffer, version_buffer);
        }

        // delete a group of entries
        for (j=0; j<KV_PAIRS_PER_GROUP; j++)
        {
        	   	    // delete object
  		    KineticEntry deleteEntry = {
   		        .key = generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + j),
   				.dbVersion = version_buffer,
   		    };
   		    TEST_ASSERT_EQUAL_ByteBuffer(ExpectedVersionBuffer, version_buffer);
   		    status = KineticClient_Delete(Fixture.session, &deleteEntry, NULL);
   		    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
   		    TEST_ASSERT_EQUAL(0, deleteEntry.value.bytesUsed);

   	   	    // get object again
        	ByteBuffer_Reset(&value_buffer);

   	        // get object
   			value_buffer = ByteBuffer_Create(value_data, DEFAULT_BUFFER_SIZE, 0);
   			KineticEntry getEntry = {
   		        .key = generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + j),
   				.dbVersion = version_buffer,
   		        .tag = tag_buffer,
   				.value = value_buffer,
   		    };
   	     	status = KineticClient_Get(Fixture.session, &getEntry, NULL);
   	     	TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_NOT_FOUND, status);
        }
    }
}
示例#29
0
int main(int argc, char** argv)
{
    (void)argc;
    (void)argv;

    // Initialize kinetic-c and configure sessions
    KineticSession* session;
    KineticClientConfig clientConfig = {
        .logFile = "stdout",
        .logLevel = 1,
    };
    KineticClient * client = KineticClient_Init(&clientConfig);
    if (client == NULL) { return 1; }
    const char HmacKeyString[] = "asdfasdf";
    KineticSessionConfig sessionConfig = {
        .host = "localhost",
        .port = KINETIC_PORT,
        .clusterVersion = 0,
        .identity = 1,
        .hmacKey = ByteArray_CreateWithCString(HmacKeyString),
    };
    KineticStatus status = KineticClient_CreateSession(&sessionConfig, client, &session);
    if (status != KINETIC_STATUS_SUCCESS) {
        fprintf(stderr, "Failed connecting to the Kinetic device w/status: %s\n",
            Kinetic_GetStatusDescription(status));
        exit(1);
    }

    // Create some entries so that we can query the keys
    printf("Storing some entries on the device...\n");
    const size_t numKeys = 3;
    if (!create_entries(session, numKeys)) {
        return 2;
    }

    // Query a range of keys
    const size_t keyLen = 64;
    uint8_t startKeyData[keyLen], endKeyData[keyLen];
    KineticKeyRange range = {
        .startKey = ByteBuffer_CreateAndAppendCString(startKeyData, sizeof(startKeyData), "key_prefix_00"),
        .endKey = ByteBuffer_CreateAndAppendCString(endKeyData, sizeof(endKeyData), "key_prefix_01"),
        .startKeyInclusive = true,
        .endKeyInclusive = true,
        .maxReturned = 3,
    };
    uint8_t keysData[numKeys][keyLen];
    ByteBuffer keyBuff[] = {
        ByteBuffer_Create(&keysData[0], keyLen, 0),
        ByteBuffer_Create(&keysData[1], keyLen, 0),
        ByteBuffer_Create(&keysData[2], keyLen, 0),
    };
    ByteBufferArray keys = {.buffers = &keyBuff[0], .count = numKeys};

    status = KineticClient_GetKeyRange(session, &range, &keys, NULL);
    if (status != KINETIC_STATUS_SUCCESS) {
        fprintf(stderr, "FAILURE: Failed retrieving key range from device!\n");
        return 3;
    }

    if (keys.used != 2) {
        fprintf(stderr, "FAILURE: Unexpected number of keys in returned range!\n");
        return 4;
    };
    if (keyBuff[0].bytesUsed != strlen("key_prefix_00")) {
        fprintf(stderr, "FAILURE: Key 0 length check failed!\n");
        return 4;
    }
    if (keyBuff[1].bytesUsed != strlen("key_prefix_01")) {
        fprintf(stderr, "FAILURE: Key 1 length check failed!\n");
        return 4;
    }
    if (keyBuff[2].bytesUsed != 0) {
        fprintf(stderr, "FAILURE: Key 2 was not empty as expected!\n");
        return 4;
    }

    // Shutdown client connection and cleanup
    KineticClient_DestroySession(session);
    KineticClient_Shutdown(client);
    printf("Key range retrieved successfully!\n");

    return 0;
}

static bool create_entries(KineticSession * const session, const int count)
{
    static const ssize_t sz = 20;
    char key_buf[sz];
    char value_buf[sz];

    for (int i = 0; i < count; i++) {

        ByteBuffer KeyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key_prefix_%02d", i);
        ByteBuffer ValueBuffer = ByteBuffer_CreateAndAppendFormattedCString(value_buf, sz, "val_%02d", i);
        
        /* Populate tag with SHA1 of value */
        ByteBuffer put_tag_buf = ByteBuffer_Malloc(20);
        uint8_t sha1[20];
        SHA1(ValueBuffer.array.data, ValueBuffer.bytesUsed, &sha1[0]);
        ByteBuffer_Append(&put_tag_buf, sha1, sizeof(sha1));
        
        KineticEntry entry = {
            .key = KeyBuffer,
            .value = ValueBuffer,
            .tag = put_tag_buf,
            .algorithm = KINETIC_ALGORITHM_SHA1,
            .force = true,
            .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH,
        };

        KineticStatus status = KineticClient_Put(session, &entry, NULL);
        if (KINETIC_STATUS_SUCCESS != status) { return false; }
    }

    return true;
}