void test_KineticBuilder_BuildPut_should_build_and_execute_a_PUT_operation_to_create_a_new_object(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),
    };

    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);
}
void test_KineticClient_Delete_should_execute_DELETE_operation(void)
{
    ByteArray key = ByteArray_CreateWithCString("some_key");
    ByteArray tag = ByteArray_CreateWithCString("SomeTagValue");
    KineticEntry entry = {
        .key = ByteBuffer_CreateWithArray(key),
        .tag = ByteBuffer_CreateWithArray(tag),
    };

    KineticConnection_FromHandle_ExpectAndReturn(DummyHandle, &Connection);
    KineticAllocator_NewPDU_ExpectAndReturn(&Connection.pdus, &Request);
    KineticAllocator_NewPDU_ExpectAndReturn(&Connection.pdus, &Response);
    KineticPDU_Init_Expect(&Request, &Connection);
    KineticPDU_Init_Expect(&Response, &Connection);
    KineticConnection_IncrementSequence_Expect(&Connection);
    KineticMessage_ConfigureKeyValue_Expect(&Request.protoData.message, &entry);
    KineticPDU_Send_ExpectAndReturn(&Request, KINETIC_STATUS_SUCCESS);
    KineticPDU_Receive_ExpectAndReturn(&Response, KINETIC_STATUS_SUCCESS);
    KineticPDU_GetStatus_ExpectAndReturn(&Response, KINETIC_STATUS_SUCCESS);
    KineticAllocator_FreePDU_Expect(&Connection.pdus, &Request);
    KineticAllocator_FreePDU_Expect(&Connection.pdus, &Response);

    KineticStatus status = KineticClient_Delete(DummyHandle, &entry);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}
Example #3
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);
    }

    do_put_and_get(session);
    
    // Shutdown client connection and cleanup
    KineticClient_DestroySession(session);
    KineticClient_Shutdown(client);
    return 0;
}
Example #4
0
void test_KineticHMAC_Validate_should_return_false_if_the_HMAC_presence_is_false_for_the_supplied_message_and_key_is_incorrect(void)
{
    KineticHMAC actual;
    Com__Seagate__Kinetic__Proto__Command__Status status = COM__SEAGATE__KINETIC__PROTO__COMMAND__STATUS__INIT;
    Com__Seagate__Kinetic__Proto__Command command = COM__SEAGATE__KINETIC__PROTO__COMMAND__INIT;
    status.code = COM__SEAGATE__KINETIC__PROTO__COMMAND__STATUS__STATUS_CODE__NO_SPACE;
    status.has_code = true;
    command.status = &status;
    Com__Seagate__Kinetic__Proto__Message proto = COM__SEAGATE__KINETIC__PROTO__MESSAGE__INIT;
    Com__Seagate__Kinetic__Proto__Message__HMACauth hmacAuth = COM__SEAGATE__KINETIC__PROTO__MESSAGE__HMACAUTH__INIT;
    uint8_t data[KINETIC_HMAC_MAX_LEN];
    ProtobufCBinaryData hmac = {.len = KINETIC_HMAC_MAX_LEN, .data = data};
    const ByteArray key = ByteArray_CreateWithCString("1234567890ABCDEFGHIJK");
    proto.has_commandbytes = true;
    uint8_t packedCmd[128];
    size_t packedLen = com__seagate__kinetic__proto__command__pack(&command, packedCmd);
    proto.commandbytes = (ProtobufCBinaryData){.data = packedCmd, .len = packedLen};
    hmacAuth.identity = 7;
    hmacAuth.has_identity = true;
    hmacAuth.hmac = hmac;
    hmacAuth.has_hmac = true;
    proto.hmacauth = &hmacAuth;
    proto.authtype = COM__SEAGATE__KINETIC__PROTO__MESSAGE__AUTH_TYPE__HMACAUTH;
    proto.has_authtype = true;

    KineticHMAC_Init(&actual, COM__SEAGATE__KINETIC__PROTO__COMMAND__SECURITY__ACL__HMACALGORITHM__HmacSHA1);
    KineticHMAC_Populate(&actual, &proto, key);

    TEST_ASSERT_TRUE(KineticHMAC_Validate(&proto, key));

    // Bork the HMAC
    hmacAuth.has_hmac = false;

    TEST_ASSERT_FALSE(KineticHMAC_Validate(&proto, key));
}
Example #5
0
void test_ByteArray_CreateWithCString_should_create_ByteArray_using_C_string(void)
{
    char* str = "some string";
    size_t len = strlen(str);

    ByteArray array = ByteArray_CreateWithCString(str);

    TEST_ASSERT_EQUAL_PTR(str, array.data);
    TEST_ASSERT_EQUAL(len, array.len);
    TEST_ASSERT_EQUAL_HEX8_ARRAY(str, array.data, len);
}
void setUp(void)
{
    HMACKey = ByteArray_CreateWithCString("some_hmac_key");
    KINETIC_CONNECTION_INIT(&Connection);
    Connection.connectionID = ConnectionID;
    KINETIC_PDU_INIT_WITH_MESSAGE(&Request, &Connection);
    KINETIC_PDU_INIT_WITH_MESSAGE(&Response, &Connection);
    KINETIC_OPERATION_INIT(&Operation, &Connection);
    Operation.request = &Request;
    Operation.response = &Response;
}
void test_KineticBuilder_BuildPut_should_return_BUFFER_OVERRUN_if_object_value_too_long(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),
    };
    entry.value.bytesUsed = KINETIC_OBJ_SIZE + 1;

    KineticOperation_ValidateOperation_Expect(&Operation);

    // Build the operation
    KineticStatus status = KineticBuilder_BuildPut(&Operation, &entry);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_BUFFER_OVERRUN, status);
}
void setUp(void)
{
    KINETIC_CONNECTION_INIT(&Connection);
    Connection.connected = false; // Ensure gets set appropriately by internal connect call
    HmacKey = ByteArray_CreateWithCString("some hmac key");
    KINETIC_SESSION_INIT(&Session, "somehost.com", ClusterVersion, Identity, HmacKey);

    KineticConnection_NewConnection_ExpectAndReturn(&Session, DummyHandle);
    KineticConnection_FromHandle_ExpectAndReturn(DummyHandle, &Connection);
    KineticConnection_Connect_ExpectAndReturn(&Connection, KINETIC_STATUS_SUCCESS);

    KineticStatus status = KineticClient_Connect(&Session, &SessionHandle);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    TEST_ASSERT_EQUAL(DummyHandle, SessionHandle);
}
void test_KineticAdminClient_GetDeviceSpecificLog_should_request_the_specified_device_specific_log_data_from_the_device(void)
{
    const char* nameData = "com.Seagate";
    ByteArray name = ByteArray_CreateWithCString(nameData);
    KineticLogInfo* info;
    KineticOperation operation;

    KineticAllocator_NewOperation_ExpectAndReturn(&Session, &operation);
    KineticBuilder_BuildGetLog_ExpectAndReturn(&operation, COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__DEVICE, name, &info, KINETIC_STATUS_SUCCESS);
    KineticController_ExecuteOperation_ExpectAndReturn(&operation, NULL, KINETIC_STATUS_SUCCESS);

    KineticStatus status = KineticAdminClient_GetDeviceSpecificLog(&Session, name, &info, NULL);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}
void test_KineticClient_Put_should_execute_PUT_operation(void)
{
    ByteArray value = ByteArray_CreateWithCString("Four score, and seven years ago");
    KineticEntry entry = {.value = ByteBuffer_CreateWithArray(value)};
    KineticOperation operation;
    operation.session = &Session;
    
    KineticAllocator_NewOperation_ExpectAndReturn(&Session, &operation);
    KineticBuilder_BuildPut_ExpectAndReturn(&operation, &entry, KINETIC_STATUS_SUCCESS);
    KineticController_ExecuteOperation_ExpectAndReturn(&operation, NULL, KINETIC_STATUS_VERSION_MISMATCH);

    KineticStatus status = KineticClient_Put(&Session, &entry, NULL);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_VERSION_MISMATCH, status);
}
static void ConnectSession(void)
{
    KINETIC_CONNECTION_INIT(&Connection);
    Connection.connected = false; // Ensure gets set appropriately by internal connect call
    Connection.connectionID = 12374626536; // Fake connection ID to allow connection to complete for these tests
    HmacKey = ByteArray_CreateWithCString("some hmac key");
    KINETIC_SESSION_INIT(&Session, "somehost.com", ClusterVersion, Identity, HmacKey);

    KineticConnection_NewConnection_ExpectAndReturn(&Session, DummyHandle);
    KineticConnection_FromHandle_ExpectAndReturn(DummyHandle, &Connection);
    KineticConnection_Connect_ExpectAndReturn(&Connection, KINETIC_STATUS_SUCCESS);
    // KineticConnection_ReceiveDeviceStatusMessage_ExpectAndReturn(&Connection, KINETIC_STATUS_SUCCESS);

    KineticStatus status = KineticClient_Connect(&Session, &SessionHandle);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    TEST_ASSERT_EQUAL(DummyHandle, SessionHandle);
}
Example #12
0
void setUp(void)
{
    KineticLogger_Init("stdout", 3);

    // Create and configure a new Kinetic protocol instance
;
    Session = (KineticSession) {
        .connected = true,
        .socket = 456,
        .config = (KineticSessionConfig) {
            .port = 1234,
            .host = "valid-host.com",
            .hmacKey = ByteArray_CreateWithCString("some valid HMAC key..."),
            .clusterVersion = ClusterVersion,
        }
    };
    ByteArray_FillWithDummyData(Value);
}
Example #13
0
void setUp(void)
{
    KineticLogger_Init("stdout", 3);
    Session = (KineticSession) {
        .connected = true,
        .socket = 456,
        .config = (KineticSessionConfig) {
            .port = 1234,
            .host = "valid-host.com",
            .hmacKey = ByteArray_CreateWithCString("some valid HMAC key..."),
            .clusterVersion = ClusterVersion,
        }
    };
    KineticRequest_Init(&Request, &Session);
    ByteArray_FillWithDummyData(Value);

    memset(si_buf, 0, SI_BUF_SIZE);
}
Example #14
0
void setUp(void)
{
    // Create and configure a new Kinetic protocol instance
    Key = ByteArray_CreateWithCString("some valid HMAC key...");
    Session = (KineticSession) {
        .nonBlocking = false,
         .port = 1234,
          .host = "valid-host.com",
        .hmacKey = (ByteArray) {.data = &Session.keyData[0], .len = Key.len},
    };
    memcpy(Session.hmacKey.data, Key.data, Key.len);

    KINETIC_CONNECTION_INIT(&Connection);
    Connection.connected = true;
    Connection.socket = 456;
    Connection.session = Session;

    KINETIC_PDU_INIT(&PDU, &Connection);
    ByteArray_FillWithDummyData(Value);
    KineticLogger_Init(NULL);
}
Example #15
0
void test_KineticHMAC_Populate_should_compute_and_populate_the_SHA1_HMAC_for_the_supplied_message_and_key(void)
{
    KineticHMAC actual;
    Com__Seagate__Kinetic__Proto__Message msg = COM__SEAGATE__KINETIC__PROTO__MESSAGE__INIT;
    Com__Seagate__Kinetic__Proto__Message__HMACauth hmacAuth = COM__SEAGATE__KINETIC__PROTO__MESSAGE__HMACAUTH__INIT;
    uint8_t data[KINETIC_HMAC_MAX_LEN];
    ProtobufCBinaryData hmac = {.len = KINETIC_HMAC_MAX_LEN, .data = data};
    const ByteArray key = ByteArray_CreateWithCString("1234567890ABCDEFGHIJK");
    uint8_t commandBytes[123];
    ByteArray commandArray = ByteArray_Create(commandBytes, sizeof(commandBytes));
    ByteArray_FillWithDummyData(commandArray);
    ProtobufCBinaryData dummyCommandData = {.data = commandArray.data, .len = commandArray.len};

    msg.commandbytes = dummyCommandData;
    msg.has_commandbytes = true;
    msg.authtype = COM__SEAGATE__KINETIC__PROTO__MESSAGE__AUTH_TYPE__HMACAUTH;
    msg.has_authtype = true;
    hmacAuth.has_hmac = true;
    hmacAuth.hmac = hmac;
    msg.hmacauth = &hmacAuth;

    KineticHMAC_Init(&actual, COM__SEAGATE__KINETIC__PROTO__COMMAND__SECURITY__ACL__HMACALGORITHM__HmacSHA1);
    KineticHMAC_Populate(&actual, &msg, key);

    TEST_ASSERT_TRUE(msg.hmacauth->has_hmac);
    TEST_ASSERT_EQUAL_PTR(hmac.data, msg.hmacauth->hmac.data);
    TEST_ASSERT_EQUAL(KINETIC_HMAC_MAX_LEN, msg.hmacauth->hmac.len);

    LOG0("Computed HMAC: ");
    LOGF0("  %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
         actual.data[0],  actual.data[1],  actual.data[2],  actual.data[3],
         actual.data[4],  actual.data[5],  actual.data[6],  actual.data[7]);
    LOGF0("  %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
         actual.data[8],  actual.data[9],  actual.data[10], actual.data[11],
         actual.data[12], actual.data[13], actual.data[14], actual.data[15]);
    LOGF0("  %02hhX%02hhX%02hhX%02hhX",
         actual.data[16], actual.data[17], actual.data[18], actual.data[19]);
}

void test_KineticHMAC_Validate_should_return_true_if_the_HMAC_for_the_supplied_message_and_key_is_correct(void)
{
    KineticHMAC actual;
    Com__Seagate__Kinetic__Proto__Command__Status status = COM__SEAGATE__KINETIC__PROTO__COMMAND__STATUS__INIT;
    Com__Seagate__Kinetic__Proto__Command command = COM__SEAGATE__KINETIC__PROTO__COMMAND__INIT;
    status.code = COM__SEAGATE__KINETIC__PROTO__COMMAND__STATUS__STATUS_CODE__NO_SPACE;
    status.has_code = true;
    command.status = &status;
    Com__Seagate__Kinetic__Proto__Message proto = COM__SEAGATE__KINETIC__PROTO__MESSAGE__INIT;
    Com__Seagate__Kinetic__Proto__Message__HMACauth hmacAuth = COM__SEAGATE__KINETIC__PROTO__MESSAGE__HMACAUTH__INIT;
    uint8_t data[KINETIC_HMAC_MAX_LEN];
    ProtobufCBinaryData hmac = {.len = KINETIC_HMAC_MAX_LEN, .data = data};
    const ByteArray key = ByteArray_CreateWithCString("1234567890ABCDEFGHIJK");
    proto.has_commandbytes = true;
    uint8_t packedCmd[128];
    size_t packedLen = com__seagate__kinetic__proto__command__pack(&command, packedCmd);
    proto.commandbytes = (ProtobufCBinaryData){.data = packedCmd, .len = packedLen};
    hmacAuth.identity = 7;
    hmacAuth.has_identity = true;
    hmacAuth.hmac = hmac;
    hmacAuth.has_hmac = true;
    proto.hmacauth = &hmacAuth;
    proto.authtype = COM__SEAGATE__KINETIC__PROTO__MESSAGE__AUTH_TYPE__HMACAUTH;
    proto.has_authtype = true;

    KineticHMAC_Init(&actual, COM__SEAGATE__KINETIC__PROTO__COMMAND__SECURITY__ACL__HMACALGORITHM__HmacSHA1);
    KineticHMAC_Populate(&actual, &proto, key);

    TEST_ASSERT_TRUE(KineticHMAC_Validate(&proto, key));
}
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;
}
Example #17
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_KineticOperation_BuildPut_should_build_and_execute_a_PUT_operation_to_create_a_new_object(void)
{
    LOG_LOCATION;
    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");

    KineticConnection_IncrementSequence_Expect(&Connection);

    // PUT
    // The PUT operation sets the value and metadata for a given key. If a value
    // already exists in the store for the given key, the client must pass a
    // value for dbVersion which matches the stored version for this key to
    // overwrite the value metadata. This behavior can be overridden (so that
    // the version is ignored and the value and metadata are always written) by
    // setting forced to true in the KeyValue option.
    //
    // Request Message:
    //
    // command {
    //   // See top level cross cutting concerns for header details
    //   header {
    //     clusterVersion: ...
    //     identity: ...
    //     connectionID: ...
    //     sequence: ...
    //     messageType: PUT
    //   }
    //   body: {
    //     keyValue {
    //       // Required bytes
    //       // The key for the value being set
    //       key: "..."
    //
    //       // Required bytes
    //       // Versions are set on objects to support optimistic locking.
    //       // For operations that modify data, if the dbVersion sent in the
    //       // request message does not match the version stored in the db, the
    //       // request will fail.
    //       dbVersion: "..."
    //
    //       // Required bytes
    //       // Specifies what the next version of the data will be if this
    //       // operation is successful.
    //       newVersion: "..."
    //
    //       // Optional bool, default false
    //       // Setting force to true ignores potential version mismatches
    //       // and carries out the operation.
    //       force: true
    //
    //       // Optional bytes
    //       // The integrity value for the data. This value should be computed
    //       // by the client application by applying the hash algorithm
    //       // specified below to the value (and only to the value).
    //       // The algorithm used should be specified in the algorithm field.
    //       // The Kinetic Device will not do any processing on this value.
    //       tag: "..."
    //
    //       // Optional enum
    //       // The algorithm used by the client to compute the tag.
    //       // The allowed values are: SHA1, SHA2, SHA3, CRC32, CRC64
    //       algorithm: ...
    //
    //       // Optional Synchronization enum value, defaults to WRITETHROUGH
    //       // Allows client to specify if the data must be written to disk
    //       // immediately, or can be written in the future.
    //       //
    //       // WRITETHROUGH:  This request is made persistent before returning.
    //       //                This does not effect any other pending operations.
    //       // WRITEBACK:     They can be made persistent when the drive chooses,
    //       //            or when a subsequent FLUSH is give to the drive.
    //       // FLUSH:     All pending information that has not been written is
    //       //        pushed to the disk and the command that specifies
    //       //        FLUSH is written last and then returned. All WRITEBACK writes
    //       //        that have received ending status will be guaranteed to be
    //       //        written before the FLUSH operation is returned completed.
    //       synchronization: ...
    //     }
    KineticEntry entry = {
        .key = ByteBuffer_CreateWithArray(key),
        .newVersion = ByteBuffer_CreateWithArray(newVersion),
        // .dbVersion = ByteBuffer_CreateWithArray(BYTE_ARRAY_NONE),
        .tag = ByteBuffer_CreateWithArray(tag),
        .algorithm = KINETIC_ALGORITHM_SHA1,
        .value = ByteBuffer_CreateWithArray(value),
    };
    KineticMessage_ConfigureKeyValue_Expect(&Operation.request->protoData.message, &entry);
    //   }
    // }
    // hmac: "..."
    //

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

    // Ensure proper message type
    TEST_ASSERT_TRUE(Request.proto->command->header->has_messageType);
    TEST_ASSERT_EQUAL(KINETIC_PROTO_MESSAGE_TYPE_PUT, Request.proto->command->header->messageType);

    TEST_ASSERT_EQUAL_ByteArray(value, Operation.request->entry.value.array);
    TEST_ASSERT_EQUAL(0, Operation.request->entry.value.bytesUsed);
    TEST_ASSERT_ByteBuffer_NULL(Response.entry.value);
}
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);
}
Example #20
0
void setUp(void)
{
    SystemTestSetup(0, true);

    KeyBuffer = ByteBuffer_CreateAndAppendCString(KeyData, sizeof(KeyData), strKey);
    ExpectedKeyBuffer = ByteBuffer_CreateAndAppendCString(ExpectedKeyData, sizeof(ExpectedKeyData), strKey);
    TagBuffer = ByteBuffer_CreateAndAppendCString(TagData, sizeof(TagData), "SomeTagValue");
    ExpectedTagBuffer = ByteBuffer_CreateAndAppendCString(ExpectedTagData, sizeof(ExpectedTagData), "SomeTagValue");
    TestValue = ByteArray_CreateWithCString("lorem ipsum... blah blah blah... etc.");
    ValueBuffer = ByteBuffer_CreateAndAppendArray(ValueData, sizeof(ValueData), TestValue);

    // Setup to write some test data
    KineticEntry putEntry = {
        .key = KeyBuffer,
        .tag = TagBuffer,
        .algorithm = KINETIC_ALGORITHM_SHA1,
        .value = ValueBuffer,
        .force = true,
        .synchronization = KINETIC_SYNCHRONIZATION_FLUSH,
    };

    KineticStatus status = KineticClient_Put(Fixture.session, &putEntry, NULL);
    if (status != KINETIC_STATUS_SUCCESS) {
        failing = true;
        TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    }

    // Validate the object exists initially
    KineticEntry getEntry = {
        .key = KeyBuffer,
        .tag = TagBuffer,
        .algorithm = KINETIC_ALGORITHM_SHA1,
        .value = ValueBuffer,
        .force = true,
        .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH,
    };
    status = KineticClient_Get(Fixture.session, &getEntry, NULL);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    TEST_ASSERT_EQUAL_ByteArray(putEntry.key.array, getEntry.key.array);
    TEST_ASSERT_EQUAL_ByteArray(putEntry.tag.array, getEntry.tag.array);
    TEST_ASSERT_EQUAL(putEntry.algorithm, getEntry.algorithm);
    TEST_ASSERT_EQUAL_ByteBuffer(putEntry.value, getEntry.value);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);

    // Set the erase PIN to something non-empty
    strcpy(NewPinData, SESSION_PIN);
    OldPin = ByteArray_Create(OldPinData, 0);
    NewPin = ByteArray_Create(NewPinData, strlen(NewPinData));
    status = KineticAdminClient_SetErasePin(Fixture.adminSession,
        OldPin, NewPin);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}

void tearDown(void)
{
    KineticStatus status = KINETIC_STATUS_INVALID;
    
    if (failing) { return; }

    // Validate the object no longer exists
    KineticEntry regetEntryMetadata = {
        .key = KeyBuffer,
        .tag = TagBuffer,
        .metadataOnly = true,
    };
    status = KineticClient_Get(Fixture.session, &regetEntryMetadata, NULL);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_NOT_FOUND, status);
    TEST_ASSERT_ByteArray_EMPTY(regetEntryMetadata.value.array);

    SystemTestShutDown();
}

void test_SecureErase_should_erase_device_contents(void)
{
    KineticStatus status = KineticAdminClient_SecureErase(Fixture.adminSession, NewPin);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}

void test_InstantErase_should_erase_device_contents(void)
{
    KineticStatus status = KineticAdminClient_InstantErase(Fixture.adminSession, NewPin);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}
void test_KineticClient_Connect_should_return_KINETIC_STATUS_HOST_EMPTY_upon_NULL_host(void)
{
    ByteArray key = ByteArray_CreateWithCString("some_key");
    KineticSession config = {
        .host = "",
        .hmacKey = key,
    };
    SessionHandle = 17;

    KineticStatus status = KineticClient_Connect(&config, &SessionHandle);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_HOST_EMPTY, status);
    TEST_ASSERT_EQUAL(KINETIC_HANDLE_INVALID, SessionHandle);
}

void test_KineticClient_Connect_should_return_KINETIC_STATUS_HMAC_EMPTY_upon_NULL_HMAC_key(void)
{
    ByteArray key = {.len = 4, .data = NULL};
    KineticSession config = {
        .host = "somehost.com",
        .hmacKey = key,
    };
    SessionHandle = 17;

    KineticStatus status = KineticClient_Connect(&config, &SessionHandle);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_HMAC_EMPTY, status);
    TEST_ASSERT_EQUAL(KINETIC_HANDLE_INVALID, SessionHandle);
}

void test_KineticClient_Connect_should_return_false_upon_empty_HMAC_key(void)
{
    uint8_t keyData[] = {0, 1, 2, 3};
    ByteArray key = {.len = 0, .data = keyData};
    KineticSession config = {
        .host = "somehost.com",
        .hmacKey = key,
    };
    SessionHandle = 17;

    KineticStatus status = KineticClient_Connect(&config, &SessionHandle);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_HMAC_EMPTY, status);
    TEST_ASSERT_EQUAL(KINETIC_HANDLE_INVALID, SessionHandle);
}

void test_KineticClient_Connect_should_return_KINETIC_STATUS_SESSION_EMPTY_upon_NULL_handle(void)
{
    KineticSession config = {
        .host = "somehost.com",
        .hmacKey = ByteArray_CreateWithCString("some_key"),
    };
    SessionHandle = 17;

    KineticStatus status = KineticClient_Connect(&config, NULL);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SESSION_EMPTY, status);
}

void test_KineticClient_Connect_should_return_KINETIC_STATUS_SESSION_INVALID_if_connection_for_handle_is_NULL(void)
{
    KineticSession config = {
        .host = "somehost.com",
        .hmacKey = ByteArray_CreateWithCString("some_key"),
    };
    SessionHandle = 17;

    KineticConnection_NewConnection_ExpectAndReturn(&config, DummyHandle);
    KineticConnection_FromHandle_ExpectAndReturn(DummyHandle, NULL);

    KineticStatus status = KineticClient_Connect(&config, &SessionHandle);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_CONNECTION_ERROR, status);
}

void test_KineticClient_Connect_should_return_status_from_a_failed_connection(void)
{
    KineticSession config = {
        .host = "somehost.com",
        .hmacKey = ByteArray_CreateWithCString("some_key"),
    };
    SessionHandle = 17;

    KineticConnection_NewConnection_ExpectAndReturn(&config, DummyHandle);
    KineticConnection_FromHandle_ExpectAndReturn(DummyHandle, &Connection);
    KineticConnection_Connect_ExpectAndReturn(&Connection, KINETIC_STATUS_HMAC_EMPTY);
    KineticConnection_FreeConnection_Expect(&SessionHandle);

    KineticStatus status = KineticClient_Connect(&config, &SessionHandle);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_HMAC_EMPTY, status);
    TEST_ASSERT_EQUAL(KINETIC_HANDLE_INVALID, SessionHandle);
}



void test_KineticClient_Disconnect_should_return_KINETIC_STATUS_CONNECTION_ERROR_upon_failure_to_get_connection_from_handle(void)
{
    SessionHandle = DummyHandle;
    KineticConnection_FromHandle_ExpectAndReturn(DummyHandle, NULL);
    KineticStatus status = KineticClient_Disconnect(&SessionHandle);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_CONNECTION_ERROR, status);
}

void test_KineticClient_Disconnect_should_disconnect_and_free_the_connection_associated_with_handle(void)
{
    SessionHandle = DummyHandle;
    KineticConnection_FromHandle_ExpectAndReturn(DummyHandle, &Connection);
    KineticConnection_Disconnect_ExpectAndReturn(&Connection, KINETIC_STATUS_SUCCESS);
    KineticConnection_FreeConnection_Expect(&SessionHandle);
    KineticStatus status = KineticClient_Disconnect(&SessionHandle);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    TEST_ASSERT_EQUAL(KINETIC_HANDLE_INVALID, SessionHandle);
}

void test_KineticClient_Disconnect_should_return_status_from_KineticConnection_upon_faileure(void)
{
    SessionHandle = DummyHandle;
    KineticConnection_FromHandle_ExpectAndReturn(DummyHandle, &Connection);
    KineticConnection_Disconnect_ExpectAndReturn(&Connection, KINETIC_STATUS_SESSION_INVALID);
    KineticConnection_FreeConnection_Expect(&SessionHandle);
    KineticStatus status = KineticClient_Disconnect(&SessionHandle);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SESSION_INVALID, status);
    TEST_ASSERT_EQUAL(KINETIC_HANDLE_INVALID, SessionHandle);
}
void test_KineticOperation_BuildGet_should_build_a_GET_operation(void)
{
    LOG_LOCATION;
    const ByteArray key = ByteArray_CreateWithCString("foobar");
    ByteArray value = {.data = ValueData, .len = sizeof(ValueData)};
    KineticEntry entry = {
        .key = ByteBuffer_CreateWithArray(key),
        .value = ByteBuffer_CreateWithArray(value),
    };

    KineticConnection_IncrementSequence_Expect(&Connection);
    KineticMessage_ConfigureKeyValue_Expect(&Request.protoData.message, &entry);

    KineticOperation_BuildGet(&Operation, &entry);

    // GET
    // The GET operation is used to retrieve the value and metadata for a given key.
    //
    // Request Message:
    // command {
    //   header {
    //     // See above for descriptions of these fields
    //     clusterVersion: ...
    //     identity: ...
    //     connectionID: ...
    //     sequence: ...
    //
    //     // The mesageType should be GET
    //     messageType: GET
    TEST_ASSERT_TRUE(Request.proto->command->header->has_messageType);
    TEST_ASSERT_EQUAL(KINETIC_PROTO_MESSAGE_TYPE_GET, Request.proto->command->header->messageType);
    //   }
    //   body {
    //     keyValue {
    //       // See above
    //       key: "..."
    //     }
    //   }
    // }
    // // See above
    // hmac: "..."

    TEST_ASSERT_ByteBuffer_NULL(Request.entry.value);
    TEST_ASSERT_EQUAL_ByteArray(value, Operation.response->entry.value.array);
    TEST_ASSERT_EQUAL(0, Operation.response->entry.value.bytesUsed);
}

void test_KineticOperation_BuildGet_should_build_a_GET_operation_requesting_metadata_only(void)
{
    LOG_LOCATION;
    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),
    };

    KineticConnection_IncrementSequence_Expect(&Connection);
    KineticMessage_ConfigureKeyValue_Expect(&Request.protoData.message, &entry);

    KineticOperation_BuildGet(&Operation, &entry);

    // GET
    // The GET operation is used to retrieve the value and metadata for a given key.
    //
    // Request Message:
    // command {
    //   header {
    //     // See above for descriptions of these fields
    //     clusterVersion: ...
    //     identity: ...
    //     connectionID: ...
    //     sequence: ...
    //
    //     // The mesageType should be GET
    //     messageType: GET
    TEST_ASSERT_TRUE(Request.proto->command->header->has_messageType);
    TEST_ASSERT_EQUAL(KINETIC_PROTO_MESSAGE_TYPE_GET, Request.proto->command->header->messageType);
    //   }
    //   body {
    //     keyValue {
    //       // See above
    //       key: "..."
    //     }
    //   }
    // }
    // // See above
    // hmac: "..."

    TEST_ASSERT_ByteBuffer_NULL(Request.entry.value);
    TEST_ASSERT_ByteBuffer_NULL(Response.entry.value);
}


void test_KineticOperation_BuildDelete_should_build_a_DELETE_operation(void)
{
    LOG_LOCATION;
    const ByteArray key = ByteArray_CreateWithCString("foobar");
    KineticEntry entry = {.key = ByteBuffer_CreateWithArray(key)};

    KineticConnection_IncrementSequence_Expect(&Connection);
    KineticMessage_ConfigureKeyValue_Expect(&Request.protoData.message, &entry);

    KineticOperation_BuildDelete(&Operation, &entry);

    // The `DELETE` operation removes the entry for a given key. It respects the
    // same locking behavior around `dbVersion` and `force` as described in the previous sections.
    // The following request will remove a key value pair to the store.
    //
    // ```
    // command {
    //   // See top level cross cutting concerns for header details
    //   header {
    //     clusterVersion: ...
    //     identity: ...
    //     connectionID: ...
    //     sequence: ...
    //     // messageType should be DELETE
    //     messageType: DELETE
    TEST_ASSERT_TRUE(Request.proto->command->header->has_messageType);
    TEST_ASSERT_EQUAL(KINETIC_PROTO_MESSAGE_TYPE_DELETE, Request.proto->command->header->messageType);
    //   }
    //   body {
    //     keyValue {
    //       key: "..."
    //       // See write operation cross cutting concerns
    //       synchronization: ...
    //     }
    //   }
    // }
    // hmac: "..."

    TEST_ASSERT_ByteBuffer_NULL(Request.entry.value);
    TEST_ASSERT_ByteBuffer_NULL(Response.entry.value);
}
void setUp(void)
{
    NewPinSet = false;
    Locked = false;

    SystemTestSetup(1, true);

    KeyBuffer = ByteBuffer_CreateAndAppendCString(KeyData, sizeof(KeyData), strKey);
    ExpectedKeyBuffer = ByteBuffer_CreateAndAppendCString(ExpectedKeyData, sizeof(ExpectedKeyData), strKey);
    TagBuffer = ByteBuffer_CreateAndAppendCString(TagData, sizeof(TagData), "SomeTagValue");
    ExpectedTagBuffer = ByteBuffer_CreateAndAppendCString(ExpectedTagData, sizeof(ExpectedTagData), "SomeTagValue");
    TestValue = ByteArray_CreateWithCString("lorem ipsum... blah blah blah... etc.");
    ValueBuffer = ByteBuffer_CreateAndAppendArray(ValueData, sizeof(ValueData), TestValue);

    // Setup to write some test data
    KineticEntry putEntry = {
        .key = KeyBuffer,
        .tag = TagBuffer,
        .algorithm = KINETIC_ALGORITHM_SHA1,
        .value = ValueBuffer,
        .force = true,
        .synchronization = KINETIC_SYNCHRONIZATION_FLUSH,
    };

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

    // Validate the object exists initially
    KineticEntry getEntry = {
        .key = KeyBuffer,
        .tag = TagBuffer,
        .algorithm = KINETIC_ALGORITHM_SHA1,
        .value = ValueBuffer,
        .force = true,
        .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH,
    };
    status = KineticClient_Get(Fixture.session, &getEntry, NULL);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    TEST_ASSERT_EQUAL_ByteArray(putEntry.key.array, getEntry.key.array);
    TEST_ASSERT_EQUAL_ByteArray(putEntry.tag.array, getEntry.tag.array);
    TEST_ASSERT_EQUAL(putEntry.algorithm, getEntry.algorithm);
    TEST_ASSERT_EQUAL_ByteBuffer(putEntry.value, getEntry.value);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);

    // Set the erase PIN to something non-empty
    strcpy(NewPinData, SESSION_PIN);
    OldPin = ByteArray_Create(OldPinData, 0);
    NewPin = ByteArray_Create(NewPinData, strlen(NewPinData));
    status = KineticAdminClient_SetLockPin(Fixture.adminSession,
        OldPin, NewPin);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    NewPinSet = true;
}

void tearDown(void)
{
    KineticStatus status;

    // Unlock if for some reason we are still locked in order to
    // prevent the device from staying in a locked/unusable state
    if (Locked) {
        status = KineticAdminClient_UnlockDevice(Fixture.adminSession, NewPin);
        TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
        Locked = false;
    }

    // Set the lock PIN back to empty
    if (NewPinSet) {
        status = KineticAdminClient_SetLockPin(Fixture.adminSession, NewPin, OldPin);
        TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
        NewPinSet = false;
    }

    SystemTestShutDown();
}

void test_KineticAdmin_should_lock_and_unlock_a_device(void)
{
    KineticStatus status;

    status = KineticAdminClient_LockDevice(Fixture.adminSession, NewPin);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    Locked = true;

    /* Currently, the device appears to just hang up on us rather than
     * returning DEVICE_LOCKED (unlike the simulator). Some sort of
     * command here to confirm that the device lock succeeded would
     * be a better test. We need to check if the drive has another
     * interface that exposes this. */
    if (SystemTestIsUnderSimulator()) {
        // Validate the object cannot being accessed while locked
        KineticEntry getEntry = {
            .key = KeyBuffer,
            .tag = TagBuffer,
            .value = ValueBuffer,
            .force = true,
        };
        status = KineticClient_Get(Fixture.session, &getEntry, NULL);
        TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DEVICE_LOCKED, status);
    }
    
    status = KineticAdminClient_UnlockDevice(Fixture.adminSession, NewPin);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    Locked = false;
}
Example #24
0
static const char HmacKeyString[] = "asdfasdf";

void setUp(void)
{
    KineticClientConfig clientConfig = {
        .logFile = "stdout",
        .logLevel = 1,
    };
    client = KineticClient_Init(&clientConfig);

    // Create sessions with primary device
    KineticSessionConfig sessionConfig = {
        .clusterVersion = 0,
        .identity = 1,
        .hmacKey = ByteArray_CreateWithCString(HmacKeyString),
    };
    strncpy(sessionConfig.host, GetSystemTestHost1(), sizeof(sessionConfig.host)-1);
    sessionConfig.port = GetSystemTestPort1();
    KineticStatus status = KineticClient_CreateSession(&sessionConfig, client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    KineticSessionConfig adminSessionConfig = {
        .clusterVersion = 0,
        .identity = 1,
        .hmacKey = ByteArray_CreateWithCString(HmacKeyString),
        .useSsl = true,
    };
    strncpy(adminSessionConfig.host, GetSystemTestHost1(), sizeof(adminSessionConfig.host)-1);
    adminSessionConfig.port = GetSystemTestTlsPort1();
    status = KineticAdminClient_CreateSession(&adminSessionConfig, client, &adminSession);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
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]);
        }
    }
Example #26
0
void test_KineticClient_CreateSession_should_return_KINETIC_STATUS_HOST_EMPTY_upon_NULL_host(void)
{
    KineticClient client;
    ByteArray key = ByteArray_CreateWithCString("some_key");
    KineticSessionConfig config = {
        .host = "",
        .hmacKey = key,
    };
    KineticSession* session = NULL;

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_HOST_EMPTY, status);
}

void test_KineticClient_CreateSession_should_return_KINETIC_STATUS_HMAC_REQUIRED_upon_NULL_HMAC_key(void)
{
    KineticClient client;
    ByteArray key = {.len = 4, .data = NULL};
    KineticSessionConfig config = {
        .host = "somehost.com",
        .hmacKey = key,
    };
    KineticSession* session;

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_HMAC_REQUIRED, status);
}

void test_KineticClient_CreateSession_should_return_false_upon_empty_HMAC_key(void)
{
    KineticClient client;
    uint8_t keyData[] = {0, 1, 2, 3};
    ByteArray key = {.len = 0, .data = keyData};
    KineticSessionConfig config = {
        .host = "somehost.com",
        .hmacKey = key,
    };
    KineticSession* session;

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_HMAC_REQUIRED, status);
}

void test_KineticClient_CreateSession_should_return_MEMORY_ERROR_if_unable_to_allocate_a_session(void)
{
    KineticClient client;
    client.bus = &MessageBus;
    KineticSessionConfig config = {
        .host = "somehost.com",
        .hmacKey = ByteArray_CreateWithCString("some_key"),
    };
    KineticSession* session = NULL;

    KineticAllocator_NewSession_ExpectAndReturn(&MessageBus, &config, NULL);

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_MEMORY_ERROR, status);
}

void test_KineticClient_CreateSession_should_return_KINETIC_STATUS_MEMORY_ERROR_upon_NULL_connection(void)
{
    KineticClient client = {
        .bus = &MessageBus,
    };
    KineticSessionConfig config = {
        .host = "somehost.com",
        .hmacKey = ByteArray_CreateWithCString("some_key"),
    };
    KineticSession* session = NULL;

    KineticAllocator_NewSession_ExpectAndReturn(&MessageBus, &config, NULL);

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_MEMORY_ERROR, status);
    TEST_ASSERT_NULL(session);
}

void test_KineticClient_CreateSession_should_return_status_from_a_failed_connection(void)
{
    KineticClient client;
    client.bus = &MessageBus;
    KineticSessionConfig config = {
        .host = "somehost.com",
        .hmacKey = ByteArray_CreateWithCString("some_key"),
    };
    KineticSession* session;

    KineticAllocator_NewSession_ExpectAndReturn(&MessageBus, &config, &Session);
    KineticSession_Create_ExpectAndReturn(&Session, &client, KINETIC_STATUS_SUCCESS);
    KineticSession_Connect_ExpectAndReturn(&Session, KINETIC_STATUS_HMAC_REQUIRED);
    KineticAllocator_FreeSession_Expect(&Session);

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_HMAC_REQUIRED, status);
}


void test_KineticClient_DestroySession_should_disconnect_and_free_the_connection_associated_with_handle(void)
{
    KineticSession_Disconnect_ExpectAndReturn(&Session, KINETIC_STATUS_SUCCESS);
    KineticSession_Destroy_ExpectAndReturn(&Session, KINETIC_STATUS_SUCCESS);
    KineticStatus status = KineticClient_DestroySession(&Session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}

void test_KineticClient_DestroySession_should_return_status_from_KineticSession_upon_faileure(void)
{
    KineticSession_Disconnect_ExpectAndReturn(&Session, KINETIC_STATUS_SESSION_INVALID);
    KineticSession_Destroy_ExpectAndReturn(&Session, KINETIC_STATUS_SUCCESS);
    KineticStatus status = KineticClient_DestroySession(&Session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SESSION_INVALID, status);
}

void test_KineticClient_GetTerminationStatus_should_delegate_to_session(void)
{
    KineticSession_GetTerminationStatus_ExpectAndReturn(&Session, KINETIC_STATUS_DATA_ERROR);
    KineticStatus status = KineticClient_GetTerminationStatus(&Session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DATA_ERROR, status);
}
Example #27
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);
    }

    // some dummy data to PUT
    uint8_t value_data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
    ByteBuffer value = ByteBuffer_MallocAndAppend(value_data, sizeof(value_data));

    // a dummy key
    uint8_t key_data[] = {0x00, 0x01, 0x02, 0x03, 0x04};
    ByteBuffer key = ByteBuffer_MallocAndAppend(key_data, sizeof(key_data));

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

    KineticEntry entry = {
        .key = key,
        .tag = tag,
        .algorithm = KINETIC_ALGORITHM_SHA1,
        .value = value,
        .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH,
    };

    // Do a blocking put to make sure there is something there to read back
    KineticStatus put_status = KineticClient_Put(session, &entry, NULL);

    if (put_status != KINETIC_STATUS_SUCCESS) {
        fprintf(stderr, "Put failed w/status: %s\n", Kinetic_GetStatusDescription(put_status));
        return 1;
    }

    // Create structure to populate with GET status in callback
    //   a semaphore is used to notify the main thread that it's
    //   safe to proceed.
    GetStatus get_status = {
        .sem = KineticSemaphore_Create(),
        .status = KINETIC_STATUS_INVALID,
    };

    ByteBuffer getTag = ByteBuffer_Malloc(tag.bytesUsed);
    ByteBuffer getValue = ByteBuffer_Malloc(value.bytesUsed);

    // Because I'm passing a pointer to this entry to KineticClient_Put(), this entry must not
    //   go out of scope until the GET completes
    KineticEntry get_entry = {
        .key = key,
        .tag = getTag,
        .algorithm = KINETIC_ALGORITHM_SHA1,
        .value = getValue,
        .force = true,
    };

    status = KineticClient_Get(
        session,
        &get_entry,
        &(KineticCompletionClosure) {
            .callback = get_finished,
            .clientData = &get_status,
        }
    );
    if (status != KINETIC_STATUS_SUCCESS) {
        fprintf(stderr, "Get failed w/status: %s\n", Kinetic_GetStatusDescription(status));
        return 1;
    }

    // Wait for GET to finish
    KineticSemaphore_WaitForSignalAndDestroy(get_status.sem);

    if (get_status.status != KINETIC_STATUS_SUCCESS) {
        fprintf(stderr, "GET failed w/status: %s\n", Kinetic_GetStatusDescription(get_status.status));
        return 1;
    }

    if ((value.bytesUsed == getValue.bytesUsed) &&
        (memcmp(value.array.data, getValue.array.data, getValue.bytesUsed) != 0)) {
        fprintf(stderr, "GET completed but returned unexpected value");
        return 1;
    }
    printf("GET completed successfully!\n");

    // Free malloc'd buffers
    ByteBuffer_Free(value);
    ByteBuffer_Free(key);
    ByteBuffer_Free(tag);

    ByteBuffer_Free(getValue);
    ByteBuffer_Free(getTag);
    

    // Shutdown client connection and cleanup
    KineticClient_DestroySession(session);
    KineticClient_Shutdown(client);

    return 0;
}

static void get_finished(KineticCompletionData* kinetic_data, void* clientData)
{
    GetStatus * get_status = clientData;

    // Save GET result status
    get_status->status = kinetic_data->status;
    // Signal that we're done
    KineticSemaphore_Signal(get_status->sem);
}
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");
}
Example #29
0
void test_KineticClient_Init_should_initialize_the_message_bus_and_return_a_new_client(void)
{
    KineticClient client;
    KineticClientConfig config = {
        .logFile = "stdout",
        .logLevel = 3,
    };

    KineticCalloc_ExpectAndReturn(1, sizeof(KineticClient), &client);
    KineticBus_Init_ExpectAndReturn(&client, &config, true);

    KineticClient * result = KineticClient_Init(&config);

    TEST_ASSERT_EQUAL(&client, result);
}

void test_KineticClient_Init_should_return_null_if_calloc_returns_null(void)
{
    KineticClientConfig config = {
        .logFile = "stdout",
        .logLevel = 3,
    };

    KineticCalloc_ExpectAndReturn(1, sizeof(KineticClient), NULL);

    KineticClient * result = KineticClient_Init(&config);

    TEST_ASSERT_NULL(result);
}

void test_KineticClient_Init_should_free_client_if_bus_init_fails(void)
{
    KineticClient client;

    KineticClientConfig config = {
        .logFile = "stdout",
        .logLevel = 3,
    };
    KineticCalloc_ExpectAndReturn(1, sizeof(KineticClient), &client);
    KineticBus_Init_ExpectAndReturn(&client, &config, false);
    KineticFree_Expect(&client);

    KineticClient * result = KineticClient_Init(&config);
    TEST_ASSERT_NULL(result);
}

static void ConnectSession(void)
{
    KineticClient client;
    client.bus = &MessageBus;
    HmacKey = ByteArray_CreateWithCString("some hmac key");
    KineticSessionConfig config = {
        .host = "localhost",
        .port = KINETIC_PORT,
        .clusterVersion = ClusterVersion,
        .identity = Identity,
        .hmacKey = HmacKey,
    };
    Session.connected = false; // Ensure gets set appropriately by internal connect call
    Session.config = config;
    KineticSession* session;

    KineticAllocator_NewSession_ExpectAndReturn(&MessageBus, &config, &Session);
    KineticSession_Create_ExpectAndReturn(&Session, &client, KINETIC_STATUS_SUCCESS);
    KineticSession_Connect_ExpectAndReturn(&Session, KINETIC_STATUS_SUCCESS);

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}


void test_KineticClient_CreateSession_should_configure_a_session_and_connect_to_specified_host(void)
{
    ConnectSession();
}

void test_KineticClient_CreateSession_should_return_KINETIC_STATUS_SESSION_EMPTY_upon_NULL_session_config(void)
{
    KineticStatus status = KineticClient_CreateSession(NULL, NULL, NULL);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SESSION_INVALID, status);
}
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;
}