Commit 0feb3d14 authored by willem's avatar willem
Browse files

Initial commit

parents
#include <assert.h>
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "CuTest.h"
/*-------------------------------------------------------------------------*
* CuStr
*-------------------------------------------------------------------------*/
char* CuStrAlloc(int size)
{
char* newStr = (char*) malloc( sizeof(char) * (size) );
return newStr;
}
char* CuStrCopy(const char* old)
{
int len = strlen(old);
char* newStr = CuStrAlloc(len + 1);
strcpy(newStr, old);
return newStr;
}
/*-------------------------------------------------------------------------*
* CuString
*-------------------------------------------------------------------------*/
void CuStringInit(CuString* str)
{
str->length = 0;
str->size = STRING_MAX;
str->buffer = (char*) malloc(sizeof(char) * str->size);
str->buffer[0] = '\0';
}
CuString* CuStringNew(void)
{
CuString* str = (CuString*) malloc(sizeof(CuString));
str->length = 0;
str->size = STRING_MAX;
str->buffer = (char*) malloc(sizeof(char) * str->size);
str->buffer[0] = '\0';
return str;
}
void CuStringResize(CuString* str, int newSize)
{
str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize);
str->size = newSize;
}
void CuStringAppend(CuString* str, const char* text)
{
int length;
if (text == NULL) {
text = "NULL";
}
length = strlen(text);
if (str->length + length + 1 >= str->size)
CuStringResize(str, str->length + length + 1 + STRING_INC);
str->length += length;
strcat(str->buffer, text);
}
void CuStringAppendChar(CuString* str, char ch)
{
char text[2];
text[0] = ch;
text[1] = '\0';
CuStringAppend(str, text);
}
void CuStringAppendFormat(CuString* str, const char* format, ...)
{
va_list argp;
char buf[HUGE_STRING_LEN];
va_start(argp, format);
vsprintf(buf, format, argp);
va_end(argp);
CuStringAppend(str, buf);
}
void CuStringInsert(CuString* str, const char* text, int pos)
{
int length = strlen(text);
if (pos > str->length)
pos = str->length;
if (str->length + length + 1 >= str->size)
CuStringResize(str, str->length + length + 1 + STRING_INC);
memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1);
str->length += length;
memcpy(str->buffer + pos, text, length);
}
/*-------------------------------------------------------------------------*
* CuTest
*-------------------------------------------------------------------------*/
void CuTestInit(CuTest* t, const char* name, TestFunction function)
{
t->name = CuStrCopy(name);
t->failed = 0;
t->ran = 0;
t->message = NULL;
t->function = function;
t->jumpBuf = NULL;
}
CuTest* CuTestNew(const char* name, TestFunction function)
{
CuTest* tc = CU_ALLOC(CuTest);
CuTestInit(tc, name, function);
return tc;
}
void CuTestRun(CuTest* tc)
{
printf(" running %s\n", tc->name);
jmp_buf buf;
tc->jumpBuf = &buf;
if (setjmp(buf) == 0)
{
tc->ran = 1;
(tc->function)(tc);
}
tc->jumpBuf = 0;
}
static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string)
{
char buf[HUGE_STRING_LEN];
sprintf(buf, "%s:%d: ", file, line);
CuStringInsert(string, buf, 0);
tc->failed = 1;
tc->message = string->buffer;
if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0);
}
void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message)
{
CuString string;
CuStringInit(&string);
if (message2 != NULL)
{
CuStringAppend(&string, message2);
CuStringAppend(&string, ": ");
}
CuStringAppend(&string, message);
CuFailInternal(tc, file, line, &string);
}
void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition)
{
if (condition) return;
CuFail_Line(tc, file, line, NULL, message);
}
void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
const char* expected, const char* actual)
{
CuString string;
if ((expected == NULL && actual == NULL) ||
(expected != NULL && actual != NULL &&
strcmp(expected, actual) == 0))
{
return;
}
CuStringInit(&string);
if (message != NULL)
{
CuStringAppend(&string, message);
CuStringAppend(&string, ": ");
}
CuStringAppend(&string, "expected <");
CuStringAppend(&string, expected);
CuStringAppend(&string, "> but was <");
CuStringAppend(&string, actual);
CuStringAppend(&string, ">");
CuFailInternal(tc, file, line, &string);
}
void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
int expected, int actual)
{
char buf[STRING_MAX];
if (expected == actual) return;
sprintf(buf, "expected <%d> but was <%d>", expected, actual);
CuFail_Line(tc, file, line, message, buf);
}
void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
double expected, double actual, double delta)
{
char buf[STRING_MAX];
if (fabs(expected - actual) <= delta) return;
sprintf(buf, "expected <%lf> but was <%lf>", expected, actual);
CuFail_Line(tc, file, line, message, buf);
}
void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
void* expected, void* actual)
{
char buf[STRING_MAX];
if (expected == actual) return;
sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
CuFail_Line(tc, file, line, message, buf);
}
/*-------------------------------------------------------------------------*
* CuSuite
*-------------------------------------------------------------------------*/
void CuSuiteInit(CuSuite* testSuite)
{
testSuite->count = 0;
testSuite->failCount = 0;
}
CuSuite* CuSuiteNew(void)
{
CuSuite* testSuite = CU_ALLOC(CuSuite);
CuSuiteInit(testSuite);
return testSuite;
}
void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase)
{
assert(testSuite->count < MAX_TEST_CASES);
testSuite->list[testSuite->count] = testCase;
testSuite->count++;
}
void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2)
{
int i;
for (i = 0 ; i < testSuite2->count ; ++i)
{
CuTest* testCase = testSuite2->list[i];
CuSuiteAdd(testSuite, testCase);
}
}
void CuSuiteRun(CuSuite* testSuite)
{
int i;
for (i = 0 ; i < testSuite->count ; ++i)
{
CuTest* testCase = testSuite->list[i];
CuTestRun(testCase);
if (testCase->failed) { testSuite->failCount += 1; }
}
}
void CuSuiteSummary(CuSuite* testSuite, CuString* summary)
{
int i;
for (i = 0 ; i < testSuite->count ; ++i)
{
CuTest* testCase = testSuite->list[i];
CuStringAppend(summary, testCase->failed ? "F" : ".");
}
CuStringAppend(summary, "\n\n");
}
void CuSuiteDetails(CuSuite* testSuite, CuString* details)
{
int i;
int failCount = 0;
if (testSuite->failCount == 0)
{
int passCount = testSuite->count - testSuite->failCount;
const char* testWord = passCount == 1 ? "test" : "tests";
CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord);
}
else
{
if (testSuite->failCount == 1)
CuStringAppend(details, "There was 1 failure:\n");
else
CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount);
for (i = 0 ; i < testSuite->count ; ++i)
{
CuTest* testCase = testSuite->list[i];
if (testCase->failed)
{
failCount++;
CuStringAppendFormat(details, "%d) %s: %s\n",
failCount, testCase->name, testCase->message);
}
}
CuStringAppend(details, "\n!!!FAILURES!!!\n");
CuStringAppendFormat(details, "Runs: %d ", testSuite->count);
CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount);
CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount);
}
}
#ifndef CU_TEST_H
#define CU_TEST_H
#include <setjmp.h>
#include <stdarg.h>
/* CuString */
char* CuStrAlloc(int size);
char* CuStrCopy(const char* old);
#define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE)))
#define HUGE_STRING_LEN 8192
#define STRING_MAX 256
#define STRING_INC 256
typedef struct
{
int length;
int size;
char* buffer;
} CuString;
void CuStringInit(CuString* str);
CuString* CuStringNew(void);
void CuStringRead(CuString* str, const char* path);
void CuStringAppend(CuString* str, const char* text);
void CuStringAppendChar(CuString* str, char ch);
void CuStringAppendFormat(CuString* str, const char* format, ...);
void CuStringInsert(CuString* str, const char* text, int pos);
void CuStringResize(CuString* str, int newSize);
/* CuTest */
typedef struct CuTest CuTest;
typedef void (*TestFunction)(CuTest *);
struct CuTest
{
const char* name;
TestFunction function;
int failed;
int ran;
const char* message;
jmp_buf *jumpBuf;
};
void CuTestInit(CuTest* t, const char* name, TestFunction function);
CuTest* CuTestNew(const char* name, TestFunction function);
void CuTestRun(CuTest* tc);
/* Internal versions of assert functions -- use the public versions */
void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message);
void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition);
void CuAssertStrEquals_LineMsg(CuTest* tc,
const char* file, int line, const char* message,
const char* expected, const char* actual);
void CuAssertIntEquals_LineMsg(CuTest* tc,
const char* file, int line, const char* message,
int expected, int actual);
void CuAssertDblEquals_LineMsg(CuTest* tc,
const char* file, int line, const char* message,
double expected, double actual, double delta);
void CuAssertPtrEquals_LineMsg(CuTest* tc,
const char* file, int line, const char* message,
void* expected, void* actual);
/* public assert functions */
#define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms))
#define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond))
#define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond))
#define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
#define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
#define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
#define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
#define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl))
#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl))
#define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
#define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
#define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL))
#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL))
/* CuSuite */
#define MAX_TEST_CASES 1024
#define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST))
typedef struct
{
int count;
CuTest* list[MAX_TEST_CASES];
int failCount;
} CuSuite;
void CuSuiteInit(CuSuite* testSuite);
CuSuite* CuSuiteNew(void);
void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase);
void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2);
void CuSuiteRun(CuSuite* testSuite);
void CuSuiteSummary(CuSuite* testSuite, CuString* summary);
void CuSuiteDetails(CuSuite* testSuite, CuString* details);
#endif /* CU_TEST_H */
CONTRIB_DIR = ..
HASHMAP_DIR = $(CONTRIB_DIR)/CHashMapViaLinkedList
BITSTREAM_DIR = $(CONTRIB_DIR)/CBitstream
LLQUEUE_DIR = $(CONTRIB_DIR)/CLinkedListQueue
GCOV_OUTPUT = *.gcda *.gcno *.gcov
GCOV_CCFLAGS = -fprofile-arcs -ftest-coverage
SHELL = /bin/bash
CC = gcc
#CCFLAGS = -g -O2 -Wall -Werror -Werror=return-type -Werror=uninitialized -Wcast-align -fno-omit-frame-pointer -fno-common -fsigned-char $(GCOV_CCFLAGS) -I$(HASHMAP_DIR) -I$(BITSTREAM_DIR) -I$(LLQUEUE_DIR)
CCFLAGS = -g -O2 -Werror -Werror=return-type -Werror=uninitialized -Wcast-align -fno-omit-frame-pointer -fno-common -fsigned-char $(GCOV_CCFLAGS) -I$(HASHMAP_DIR) -I$(BITSTREAM_DIR) -I$(LLQUEUE_DIR)
all: tests_main
chashmap:
mkdir -p $(HASHMAP_DIR)/.git
git --git-dir=$(HASHMAP_DIR)/.git init
pushd $(HASHMAP_DIR); git pull git@github.com:willemt/CHashMapViaLinkedList.git; popd
cbitstream:
mkdir -p $(BITSTREAM_DIR)/.git
git --git-dir=$(BITSTREAM_DIR)/.git init
pushd $(BITSTREAM_DIR); git pull git@github.com:willemt/CBitstream.git; popd
clinkedlistqueue:
mkdir -p $(LLQUEUE_DIR)/.git
git --git-dir=$(LLQUEUE_DIR)/.git init
pushd $(LLQUEUE_DIR); git pull git@github.com:willemt/CLinkedListQueue.git; popd
download-contrib: chashmap cbitstream clinkedlistqueue
main_test.c:
if test -d $(HASHMAP_DIR); \
then echo have contribs; \
else make download-contrib; \
fi
sh make-tests.sh "test_*.c" > main_test.c
tests_main: main_test.c raft_server.c raft_candidate.c raft_follower.c raft_leader.c test_server.c test_server_appendentries.c test_server_request_vote.c test_follower.c test_candidate.c test_leader.c mock_send_functions.c CuTest.c $(HASHMAP_DIR)/linked_list_hashmap.c $(LLQUEUE_DIR)/linked_list_queue.c
$(CC) $(CCFLAGS) -o $@ $^
./tests_main
clean:
rm -f main_test.c *.o tests
#!/bin/bash
# Auto generate single AllTests file for CuTest.
# Searches through all *.c files in the current directory.
# Prints to stdout.
# Author: Asim Jalis
# Date: 01/08/2003
FILES=$1
#if test $# -eq 0 ; then FILES=*.c ; else FILES=$* ; fi
echo '
/* This is auto-generated code. Edit at your own peril. */
#include <stdio.h>
#include "CuTest.h"
'
cat $FILES | grep '^void Test' |
sed -e 's/(.*$//' \
-e 's/$/(CuTest*);/' \
-e 's/^/extern /'
echo \
'
void RunAllTests(void)
{
CuString *output = CuStringNew();
CuSuite* suite = CuSuiteNew();
'
cat $FILES | grep '^void Test' |
sed -e 's/^void //' \
-e 's/(.*$//' \
-e 's/^/ SUITE_ADD_TEST(suite, /' \
-e 's/$/);/'
echo \
'
CuSuiteRun(suite);
CuSuiteSummary(suite, output);
CuSuiteDetails(suite, output);
printf("%s\\n", output->buffer);
}
int main()
{
RunAllTests();
return 0;
}
'
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdbool.h>
#include <assert.h>
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "CuTest.h"
#include "linked_list_queue.h"
#include "raft.h"
typedef struct {
void* inbox;
} sender_t;
int sender_send(void* caller, void* udata, int peer, const unsigned char* data, int len)
{
sender_t* me = udata;
void* n;
n = malloc(len);
memcpy(n,data,len);
llqueue_offer(me->inbox,(void*)data);
return 0;
}
void* sender_new()
{
sender_t* me;
me = malloc(sizeof(sender_t));
me->inbox = llqueue_new();
return me;
}
void* sender_poll_msg(void* s)
{
return NULL;
}
int sender_send(void* caller, void* udata, const int peer,
const unsigned char* data, const int len);
void* sender_new();
void* sender_poll_msg(void* s);
enum {
RAFT_STATE_FOLLOWER,
RAFT_STATE_CANDIDATE,
RAFT_STATE_LEADER
};
/* messages */
enum {
MSG_RequestVote,
MSG_RequestVoteResponse,
MSG_AppendEntries,
MSG_AppendEntriesResponse
};
typedef struct {
/* term candidate's term */
int term;
/* candidateId candidate requesting vote */
int candidateID;
/* index of candidate's last log entry */
int lastLogIndex;
/* term of candidate's last log entry */
int lastLogTerm;
} msg_requestvote_t;
typedef struct {
unsigned int id;
unsigned char* data;
unsigned int len;
} msg_command_t;
typedef struct {
/* currentTerm, for candidate to update itself */
int term;
/* true means candidate received vote */
int voteGranted;
} msg_requestvote_response_t;
typedef struct {
int term;
int leaderID;
int prevLogIndex;
int prevLogTerm;
int n_entries;
void* entries;
int leaderCommit;
} msg_appendentries_t;
typedef struct {
/* currentTerm, for leader to update itself */
int term;
/* success true if follower contained entry matching
* prevLogIndex and prevLogTerm */
int success;
} msg_appendentries_response_t;
typedef int (
*func_send_f
) (
void *caller,
void *udata,
const int peer,
const unsigned char *send_data,
const int len
);
#ifndef HAVE_FUNC_LOG
#define HAVE_FUNC_LOG
typedef void (
*func_log_f
) (
void *udata,
void *src,
// bt_peer_t * peer,
const char *buf,
...
);
#endif
typedef struct {
func_send_f send;
func_log_f log;
} raft_external_functions_t;
typedef struct {
int pass;
// recv_appendentries_f recv_appendentries,
// recv_requestvote_f recv_requestvote,
} raft_functions_t;
typedef struct {
/* Persistent state: */
/* the server's best guess of what the current term is
* starts at zero */
int currentTerm;
/* The candidate the server voted for in its current term,
* or Nil if it hasn't voted for any. */
int votedFor;
/* the log which is replicated */
void* log;
/* Volatile state: */
/* Index of highest log entry known to be committed */
int commitIndex;
/* Index of highest log entry applied to state machine */
int lastApplied;
/* follower/leader/candidate indicator */
int state;
raft_functions_t *func;
/* callbacks */
raft_external_functions_t *ext_func;
void* caller;
int logSize;
} raft_server_t;
void* raft_new();
void raft_set_external_functions(void* r, raft_external_functions_t* funcs, void* caller);
void raft_election_start(void* r);
void raft_become_leader(raft_server_t* me);
void raft_become_candidate(raft_server_t* me);
int raft_receive_append_entries(raft_server_t* me, msg_appendentries_t* ae);
int raft_periodic(void* me_);
int raft_recv_appendentries(void* me_, int peer, msg_appendentries_t* ae);
int raft_recv_requestvote(void* me_, int peer, msg_requestvote_t* vr);
void raft_execute_command(void* me_);
void raft_set_election_timeout(void* me_, int millisec);
int raft_vote(void* me_, int peer);
int raft_add_peer(void* me_, void* peer_udata);
int raft_remove_peer(void* me_, int peer);
int raft_get_num_peers(void* me_);
int raft_recv_command(void* me_, int peer, msg_command_t* cmd);
int raft_get_log_size(void* me_);
void raft_set_current_term(void* me_,int term);
void raft_set_current_index(void* me_,int idx);
int raft_get_current_term(void* me_);
void raft_set_current_index(void* me_,int idx);
int raft_get_current_index(void* me_);
int raft_is_follower(void* me_);
int raft_is_leader(void* me_);
int raft_is_candidate(void* me_);
int raft_send_requestvote(void* me_, int peer);
/**
* @file
* @brief
* @author Willem Thiart himself@willemthiart.com
* @version 0.1
*
* @section LICENSE
* Copyright (c) 2011, Willem-Hendrik Thiart
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL WILLEM-HENDRIK THIART BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "raft.h"
typedef struct {
/* The set of servers from which the candidate has
* received a RequestVote response in this term. */
//int votesResponded;
/* The set of servers from which the candidate has received a vote in this term. */
//int votesGranted;
} candidate_t;
void raft_candidate_periodic(raft_server_t* me)
{
// leader(me)->
}
typedef struct
{
uint32_t piece_idx;
uint32_t block_byte_offset;
uint32_t block_len;
} bt_block_t;
typedef void *(*func_getpiece_f)( void *udata, unsigned int piece);
typedef void (*func_write_block_to_stream_f)(
void* pce, bt_block_t * blk, unsigned char ** msg);
#ifndef HAVE_FUNC_LOG
#define HAVE_FUNC_LOG
typedef void (
*func_log_f
) (
void *udata,
void *src,
// bt_peer_t * peer,
const char *buf,
...
);
#endif
typedef int (
*func_pollblock_f
) (
void *udata,
void * peers_bitfield,
bt_block_t * blk
);
typedef int (
*func_pushblock_f
) (
void *udata,
void * peer,
bt_block_t * block,
const void *data
);
typedef int (
*func_send_f
) (
void *udata,
const void * peer,
const void *send_data,
const int len
);
typedef int (
*func_disconnect_f
) (
void *udata,
void * peer,
char *reason
);
#ifndef HAVE_FUNC_GET_INT
#define HAVE_FUNC_GET_INT
typedef int (
*func_get_int_f
) (
void *,
void *pr
);
#endif
#define PC_NONE ((unsigned int)0)
#define PC_HANDSHAKE_SENT ((unsigned int)1<<0)
#define PC_HANDSHAKE_RECEIVED ((unsigned int)1<<1)
#define PC_DISCONNECTED ((unsigned int)1<<2)
#define PC_BITFIELD_RECEIVED ((unsigned int)1<<3)
/* connected to peer */
#define PC_CONNECTED ((unsigned int)1<<4)
/* we can't communicate with the peer */
#define PC_UNCONTACTABLE_PEER ((unsigned int)1<<5)
#define PC_IM_CHOKING ((unsigned int)1<<6)
#define PC_IM_INTERESTED ((unsigned int)1<<7)
#define PC_PEER_CHOKING ((unsigned int)1<<8)
#define PC_PEER_INTERESTED ((unsigned int)1<<9)
typedef enum
{
PWP_MSGTYPE_CHOKE = 0,
PWP_MSGTYPE_UNCHOKE = 1,
PWP_MSGTYPE_INTERESTED = 2,
PWP_MSGTYPE_UNINTERESTED = 3,
PWP_MSGTYPE_HAVE = 4,
PWP_MSGTYPE_BITFIELD = 5,
PWP_MSGTYPE_REQUEST = 6,
PWP_MSGTYPE_PIECE = 7,
PWP_MSGTYPE_CANCEL = 8,
} pwp_msg_type_e;
/* peer wire protocol configuration */
typedef struct
{
int max_pending_requests;
} bt_pwp_cfg_t;
void *pwp_conn_get_peer(void *pco);
void *pwp_conn_new();
void pwp_conn_set_active(void *pco, int opt);
int pwp_conn_peer_is_interested(void *pco);
int pwp_conn_is_active(void *pco);
void pwp_conn_set_my_peer_id(void *pco, const char *peer_id);
void pwp_conn_set_their_peer_id(void *pco, const char *peer_id);
void pwp_conn_set_infohash(void *pco, const char *infohash);
void pwp_conn_set_peer(void *pco, void * peer);
int pwp_conn_peer_is_interested(void *pco);
int pwp_conn_peer_is_choked(void *pco);
int pwp_conn_im_choked(void *pco);
int pwp_conn_im_interested(void *pco);
void pwp_conn_choke(void * pc);
void pwp_conn_unchoke(void * pco);
int pwp_conn_get_download_rate(const void * pco);
int pwp_conn_get_upload_rate(const void * pco);
int pwp_conn_send_statechange(void * pco, const unsigned char msg_type);
void pwp_conn_send_piece(void *pco, bt_block_t * req);
int pwp_conn_send_have(void *pco, const int piece_idx);
void pwp_conn_send_request(void *pco, const bt_block_t * request);
void pwp_conn_send_cancel(void *pco, bt_block_t * cancel);
void pwp_conn_send_bitfield(void *pco);
int pwp_conn_recv_handshake(void *pco, const char *info_hash);
int pwp_conn_send_handshake(void *pco);
void pwp_conn_set_piece_info(void *pco, int num_pieces, int piece_len);
void pwp_conn_set_state(void *pco, const int state);
int pwp_conn_get_state(void *pco);
int pwp_conn_mark_peer_has_piece(void *pco, const int piece_idx);
int pwp_conn_process_request(void * pco, bt_block_t * request);
int pwp_conn_process_msg(void *pco);
int pwp_conn_get_npending_requests(const void * pco);
int pwp_conn_get_npending_peer_requests(const void* pco);
void pwp_conn_request_block_from_peer(void * pco, bt_block_t * blk);
void pwp_conn_step(void *pco);
int pwp_conn_peer_has_piece(void *pco, const int piece_idx);
typedef struct {
/** send data to peer */
func_send_f send;
/* drop the connect.
* Most likely because we detected an error with the peer's processing */
func_disconnect_f disconnect;
/* manage piece related operations */
func_write_block_to_stream_f write_block_to_stream;
func_get_int_f piece_is_complete;
func_getpiece_f getpiece;
/**
* Ask our caller if they have an idea of what block they would like.
* We're able to request a block from the peer now.
*
* @return 0 on success; otherwise -1 on failure*/
func_pollblock_f pollblock;
/* We've just downloaded the block and want to allocate it. */
func_pushblock_f pushblock;
/* logging */
func_log_f log;
} pwp_connection_functions_t;
typedef struct {
bt_block_t block;
const void* data;
} msg_piece_t;
typedef struct {
uint32_t piece_idx;
} msg_have_t;
typedef struct {
bitfield_t bf;
} msg_bitfield_t;
void pwp_conn_choke_peer(void * pco);
void pwp_conn_unchoke_peer(void * pco);
void pwp_conn_keepalive(void* pco);
void pwp_conn_choke(void* pco);
void pwp_conn_unchoke(void* pco);
void pwp_conn_interested(void* pco);
void pwp_conn_uninterested(void* pco);
void pwp_conn_have(void* pco, msg_have_t* have);
void pwp_conn_bitfield(void* pco, msg_bitfield_t* bitfield);
int pwp_conn_request(void* pco, bt_block_t *request);
void pwp_conn_cancel(void* pco, bt_block_t *cancel);
int pwp_conn_piece(void* pco, msg_piece_t *piece);
void pwp_conn_set_functions(void *pco, pwp_connection_functions_t* funcs, void* caller);
int pwp_conn_flag_is_set(void *pco, const int flag);
void pwp_conn_connected(void* pco);
void pwp_conn_connect_failed(void *pco);
/**
* @file
* @brief
* @author Willem Thiart himself@willemthiart.com
* @version 0.1
*
* @section LICENSE
* Copyright (c) 2011, Willem-Hendrik Thiart
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL WILLEM-HENDRIK THIART BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "raft.h"
/**
* Client sends command to leader to be added to log.
* We aren't the leader so redirect to leader*/
void raft_client_recv_command(raft_server_t* me, unsigned char* cmd, int len)
{
}
/**
* @file
* @brief
* @author Willem Thiart himself@willemthiart.com
* @version 0.1
*
* @section LICENSE
* Copyright (c) 2011, Willem-Hendrik Thiart
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL WILLEM-HENDRIK THIART BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "raft.h"
typedef struct {
/* Array: For each server, index of the next log entry to send to
* that server (initialized to leader last log index +1) */
int *nextIndex;
/* Array: for each server, index of highest log entry known to be
* replicated on server (initialized to 0, increases monotonically) */
int *matchIndex;
#if 0
/* The latest entry that each follower has acknowledged is the same as
* the leader's. This is used to calculate commitIndex on the leader. */
int last_agree_index;
#endif
} leader_t;
void raft_leader_periodic(raft_server_t* me)
{
// leader(me)->
}
/**
* Client sends command to leader to be added to log */
void raft_leader_recv_command(raft_server_t* me)
{
}
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
/* for uint32_t */
#include <stdint.h>
#include <assert.h>
#include "bitfield.h"
#include "pwp_connection.h"
#include "pwp_msghandler.h"
typedef struct {
uint32_t len;
unsigned char id;
unsigned int bytes_read;
unsigned int tok_bytes_read;
union {
msg_have_t have;
msg_bitfield_t bitfield;
bt_block_t block;
msg_piece_t piece;
};
} msg_t;
typedef struct {
/* current message we are reading */
msg_t msg;
/* peer connection */
void* pc;
} raft_connection_event_handler_t;
static void __endmsg(msg_t* msg)
{
msg->bytes_read = 0;
msg->id = 0;
msg->tok_bytes_read = 0;
msg->len = 0;
}
static int __read_uint32(
uint32_t* in,
msg_t *msg,
const unsigned char** buf,
unsigned int *len)
{
while (1)
{
if (msg->tok_bytes_read == 4)
{
msg->tok_bytes_read = 0;
return 1;
}
else if (*len == 0)
{
return 0;
}
*((unsigned char*)in + msg->tok_bytes_read) = **buf;
msg->tok_bytes_read += 1;
msg->bytes_read += 1;
*buf += 1;
*len -= 1;
}
}
static int __read_byte(
unsigned char* in,
unsigned int *tot_bytes_read,
const unsigned char** buf,
unsigned int *len)
{
if (*len == 0)
return 0;
*in = **buf;
*tot_bytes_read += 1;
*buf += 1;
*len -= 1;
return 1;
}
/**
* create a new msg handler */
void* raft_msghandler_new(void *pc)
{
raft_connection_event_handler_t* me;
me = calloc(1,sizeof(raft_connection_event_handler_t));
me->pc = pc;
return me;
}
/**
* Receive this much data on this step. */
void raft_msghandler_dispatch_from_buffer(void *mh, const unsigned char* buf, unsigned int len)
{
raft_connection_event_handler_t* me = mh;
msg_t* msg = &me->msg;
while (0 < len)
{
/* read length of message (int) */
if (msg->bytes_read < 4)
{
if (1 == __read_uint32(&msg->len, &me->msg, &buf, &len))
{
/* it was a keep alive message */
if (0 == msg->len)
{
pwp_conn_keepalive(me->pc);
__endmsg(&me->msg);
}
}
}
/* get message ID */
else if (msg->bytes_read == 4)
{
__read_byte(&msg->id, &msg->bytes_read,&buf,&len);
if (msg->len != 1) continue;
switch (msg->id)
{
case PWP_MSGTYPE_CHOKE:
pwp_conn_choke(me->pc);
break;
case PWP_MSGTYPE_UNCHOKE:
pwp_conn_unchoke(me->pc);
break;
case PWP_MSGTYPE_INTERESTED:
pwp_conn_interested(me->pc);
break;
case PWP_MSGTYPE_UNINTERESTED:
pwp_conn_uninterested(me->pc);
break;
default: assert(0); break;
}
__endmsg(&me->msg);
}
else
{
switch (msg->id)
{
case PWP_MSGTYPE_HAVE:
if (1 == __read_uint32(&msg->have.piece_idx,
&me->msg, &buf,&len))
{
pwp_conn_have(me->pc,&msg->have);
__endmsg(&me->msg);
continue;
}
break;
case PWP_MSGTYPE_BITFIELD:
{
unsigned char val;
unsigned int ii;
if (msg->bytes_read == 1 + 4)
{
bitfield_init(&msg->bitfield.bf, (msg->len - 1) * 8);
}
__read_byte(&val, &msg->bytes_read,&buf,&len);
/* mark bits from byte */
for (ii=0; ii<8; ii++)
{
if (0x1 == ((unsigned char)(val<<ii) >> 7))
{
bitfield_mark(&msg->bitfield.bf,
(msg->bytes_read - 5 - 1) * 8 + ii);
}
}
/* done reading bitfield */
if (msg->bytes_read == 4 + msg->len)
{
pwp_conn_bitfield(me->pc, &msg->bitfield);
__endmsg(&me->msg);
}
}
break;
case PWP_MSGTYPE_REQUEST:
if (msg->bytes_read < 1 + 4 + 4)
{
__read_uint32(&msg->block.piece_idx,
&me->msg, &buf,&len);
}
else if (msg->bytes_read < 1 + 4 + 4 + 4)
{
__read_uint32(&msg->block.block_byte_offset,
&me->msg,&buf,&len);
}
else if (1 == __read_uint32(&msg->block.block_len,
&me->msg, &buf,&len))
{
pwp_conn_request(me->pc, &msg->block);
__endmsg(&me->msg);
}
break;
case PWP_MSGTYPE_CANCEL:
if (msg->bytes_read < 1 + 4 + 4)
{
__read_uint32(&msg->block.piece_idx,
&me->msg, &buf,&len);
}
else if (msg->bytes_read < 1 + 4 + 4 + 4)
{
__read_uint32(&msg->block.block_byte_offset,
&me->msg,&buf,&len);
}
else if (1 == __read_uint32(&msg->block.block_len,
&me->msg, &buf,&len))
{
pwp_conn_cancel(me->pc, &msg->block);
__endmsg(&me->msg);
}
break;
case PWP_MSGTYPE_PIECE:
if (msg->bytes_read < 1 + 4 + 4)
{
__read_uint32(&msg->piece.block.piece_idx,
&me->msg, &buf,&len);
}
else if (msg->bytes_read < 9 + 4)
{
__read_uint32(&msg->piece.block.block_byte_offset,
&me->msg,&buf,&len);
}
else
{
int size;
size = len;
/* check it isn't bigger than what the message tells
* us we should be expecting */
if (size > msg->len - 1 - 4 - 4)
{
size = msg->len - 1 - 4 - 4;
}
msg->piece.data = buf;
msg->piece.block.block_len = size;
pwp_conn_piece(me->pc, &msg->piece);
/* if we haven't received the full piece, why don't we
* just split it virtually? */
/* shorten the message */
msg->len -= size;
msg->piece.block.block_byte_offset += size;
/* if we received the whole message we're done */
if (msg->len == 9)
__endmsg(&me->msg);
len -= size;
buf += size;
}
break;
default:
assert(0); break;
}
}
}
}
void* pwp_msghandler_new(void *pc);
void pwp_msghandler_dispatch_from_buffer(void *mh, const unsigned char* buf, unsigned int len);
/**
* @file
* @brief
* @author Willem Thiart himself@willemthiart.com
* @version 0.1
*
* @section LICENSE
* Copyright (c) 2011, Willem-Hendrik Thiart
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL WILLEM-HENDRIK THIART BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "raft.h"
void* raft_new()
{
raft_server_t* me;
me = calloc(1,sizeof(raft_server_t));
return me;
}
void raft_free(void* me_)
{
raft_server_t* me = me_;
free(me);
}
void raft_set_state(void* me_)
{
raft_server_t* me = me_;
}
int raft_get_state(void* me_)
{
raft_server_t* me = me_;
return 0;
}
void raft_set_external_functions(void* r, raft_external_functions_t* funcs, void* caller)
{
}
void raft_election_start(void* r)
{
}
/**
* Candidate i transitions to leader. */
void raft_become_leader(raft_server_t* me)
{
}
void raft_become_candidate(raft_server_t* me)
{
}
/**
* Convert to candidate if election timeout elapses without either
* Receiving valid AppendEntries RPC, or
* Granting vote to candidate
*/
#if 0
int raft_election_timeout_elapsed(void* me_)
{
raft_server_t* me = me_;
if (nvalid_AEs_since_election == 0 || votes_granted_to_candidate_since_election == 0)
{
raft_become_candidate(me);
}
}
#endif
int raft_periodic(void* me_)
{
raft_server_t* me = me_;
return 0;
}
/**
* Invoked by leader to replicate log entries (§5.3); also used as heartbeat (§5.2). */
int raft_recv_appendentries(void* me_, int peer, msg_appendentries_t* ae)
{
return 0;
}
int raft_recv_appendentries_response(void* me_, int peer, msg_appendentries_response_t* ae)
{
return 0;
}
int raft_recv_requestvote(void* me_, int peer, msg_requestvote_t* vr)
{
return 0;
}
int raft_recv_requestvote_response(void* me_, int peer, msg_requestvote_response_t* r)
{
return 0;
}
void raft_execute_command(void* me_)
{
}
void raft_set_election_timeout(void* me_, int millisec)
{
}
int raft_vote(void* me_, int peer)
{
return 0;
}
#if 0
void raft_set_configuration(raft_server_t* me)
{
return 0;
}
#endif
int raft_add_peer(void* me_, void* peer_udata)
{
return 0;
}
int raft_remove_peer(void* me_, int peer)
{
return 0;
}
int raft_get_num_peers(void* me_)
{
return 0;
}
int raft_recv_command(void* me_, int peer, msg_command_t* cmd)
{
return 0;
}
int raft_get_log_size(void* me_)
{
return 0;
}
void raft_set_current_term(void* me_,int term)
{
}
int raft_get_current_term(void* me_)
{
return 0;
}
void raft_set_current_index(void* me_,int idx)
{
}
int raft_get_current_index(void* me_)
{
return 0;
}
int raft_is_follower(void* me_)
{
return 0;
}
int raft_is_leader(void* me_)
{
return 0;
}
int raft_is_candidate(void* me_)
{
return 0;
}
int raft_send_requestvote(void* me_, int peer)
{
return 0;
}
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "CuTest.h"
#include "raft.h"
#include "mock_send_functions.h"
/* Candidate 5.2 */
void TestRaft_follower_becoming_candidate_increments_current_term(CuTest * tc)
{
void *r;
r = raft_new();
CuAssertTrue(tc, 0 == raft_get_current_term(r));
raft_become_candidate(r);
CuAssertTrue(tc, 1 == raft_get_current_term(r));
}
/* Candidate 5.2 */
void TestRaft_follower_becoming_candidate_votes_for_self(CuTest * tc)
{
void *r;
r = raft_new();
CuAssertTrue(tc, 0 == raft_get_current_term(r));
raft_become_candidate(r);
CuAssertTrue(tc, 1 == raft_get_current_term(r));
}
/* Candidate 5.2 */
void TestRaft_follower_becoming_candidate_resets_election_timeout(CuTest * tc)
{
void *r;
r = raft_new();
CuAssertTrue(tc, 0 == raft_get_current_term(r));
raft_become_candidate(r);
CuAssertTrue(tc, 1 == raft_get_current_term(r));
}
/* Candidate 5.2 */
void TestRaft_follower_becoming_candidate_requests_votes_from_other_server(CuTest * tc)
{
void *r;
void *sender;
void *msg;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
sender = sender_new();
r = raft_new();
raft_set_external_functions(r,&funcs,sender);
raft_become_candidate(r);
msg = sender_poll_msg(sender);
// CuAssertTrue(tc, 1 == sender_msg_is_reqestvote(msg));
}
/* Candidate 5.2 */
void TestRaft_candidate_election_timeout_and_no_leader_results_in_new_election(CuTest * tc)
{
void *r;
void *sender;
void *msg;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
msg_requestvote_response_t vr;
memset(&vr,0,sizeof(msg_requestvote_response_t));
vr.term = 1;
vr.voteGranted = 1;
sender = sender_new();
r = raft_new();
/* three nodes */
raft_add_peer(r,(void*)1);
raft_add_peer(r,(void*)2);
raft_set_external_functions(r,&funcs,sender);
raft_set_current_term(r,1);
raft_set_state(r,RAFT_STATE_CANDIDATE);
raft_periodic(r);
raft_recv_requestvote_response(r,&vr);
CuAssertTrue(tc, 0 == raft_is_leader(r));
/* now has majority */
raft_recv_requestvote_response(r,&vr);
CuAssertTrue(tc, 1 == raft_is_leader(r));
}
/* Candidate 5.2 */
void TestRaft_candidate_dont_grant_vote_if_candidate_has_a_less_complete_log(CuTest * tc)
{
}
/* Candidate 5.2 */
void TestRaft_candidate_receives_majority_of_votes_becomes_leader(CuTest * tc)
{
void *r;
void *sender;
void *msg;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
msg_requestvote_response_t vr;
memset(&vr,0,sizeof(msg_requestvote_response_t));
vr.term = 1;
vr.voteGranted = 1;
sender = sender_new();
r = raft_new();
/* three nodes */
raft_add_peer(r,(void*)1);
raft_add_peer(r,(void*)2);
raft_set_external_functions(r,&funcs,sender);
raft_set_current_term(r,1);
raft_set_state(r,RAFT_STATE_CANDIDATE);
raft_recv_requestvote_response(r,&vr);
CuAssertTrue(tc, 0 == raft_is_leader(r));
/* now has majority */
raft_recv_requestvote_response(r,&vr);
CuAssertTrue(tc, 1 == raft_is_leader(r));
}
/* Candidate 5.2 */
void TestRaft_candidate_will_not_respond_to_voterequest_if_it_has_already_voted(CuTest * tc)
{
void *r;
void *sender;
void *msg;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
msg_appendentries_t ae;
memset(&ae,0,sizeof(msg_appendentries_t));
msg_requestvote_t rv;
memset(&rv,0,sizeof(msg_requestvote_t));
sender = sender_new();
r = raft_new();
/* three nodes */
raft_add_peer(r,(void*)1);
raft_add_peer(r,(void*)2);
raft_set_external_functions(r,&funcs,sender);
raft_set_current_term(r,1);
raft_set_state(r,RAFT_STATE_CANDIDATE);
//raft_recv_requestvote(
CuAssertTrue(tc, 0 == raft_is_follower(r));
raft_periodic(r);
raft_recv_appendentries(r,1,&ae);
CuAssertTrue(tc, 1 == raft_is_follower(r));
}
/* Candidate 5.2 */
void TestRaft_candidate_will_reject_requestvote_if_its_log_is_more_complete(CuTest * tc)
{
void *r;
void *sender;
void *msg;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
msg_requestvote_t rv;
memset(&rv,0,sizeof(msg_requestvote_t));
rv.lastLogTerm = 2;
rv.lastLogIndex = 2;
sender = sender_new();
r = raft_new();
/* three nodes */
raft_add_peer(r,(void*)1);
raft_add_peer(r,(void*)2);
raft_set_external_functions(r,&funcs,sender);
raft_set_current_term(r,5);
raft_set_current_index(r,3);
raft_set_state(r,RAFT_STATE_CANDIDATE);
// raft_recv_requestvote(r,
CuAssertTrue(tc, 0 == raft_is_follower(r));
raft_periodic(r);
// raft_recv_appendentries(r,1,&ae);
// CuAssertTrue(tc, 1 == raft_is_follower(r));
}
/* Candidate 5.2 */
void TestRaft_candidate_requestvote_includes_loginfo(CuTest * tc)
{
void *r;
void *sender;
void *msg;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
sender = sender_new();
r = raft_new();
/* three nodes */
raft_add_peer(r,(void*)1);
raft_add_peer(r,(void*)2);
raft_set_external_functions(r,&funcs,sender);
raft_set_current_term(r,5);
raft_set_current_index(r,3);
raft_set_state(r,RAFT_STATE_CANDIDATE);
raft_send_requestvote(r,1);
msg = sender_poll_msg(sender);
// CuAssertTrue(tc, msg_is_requestvote(msg));
// CuAssertTrue(tc, 3 == msg_requestvote_get_index(msg));
// CuAssertTrue(tc, 5 == msg_requestvote_get_term(msg));
}
/* Candidate 5.2 */
void TestRaft_candidate_recv_appendentries_frm_leader_results_in_follower(CuTest * tc)
{
void *r;
void *sender;
void *msg;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
msg_appendentries_t ae;
memset(&ae,0,sizeof(msg_appendentries_t));
sender = sender_new();
r = raft_new();
/* three nodes */
raft_add_peer(r,(void*)1);
raft_add_peer(r,(void*)2);
raft_set_external_functions(r,&funcs,sender);
raft_set_current_term(r,1);
raft_set_state(r,RAFT_STATE_CANDIDATE);
CuAssertTrue(tc, 0 == raft_is_follower(r));
raft_periodic(r);
raft_recv_appendentries(r,1,&ae);
CuAssertTrue(tc, 1 == raft_is_follower(r));
}
/* Candidate 5.2 */
void TestRaft_candidate_recv_appendentries_frm_invalid_leader_doesnt_result_in_follower(CuTest * tc)
{
}
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "CuTest.h"
#include "raft.h"
#include "mock_send_functions.h"
void TestRaft_follower_increases_log_after_appendentry(CuTest * tc)
{
void *r;
msg_appendentries_t ae;
memset(&ae,0,sizeof(msg_appendentries_t));
r = raft_new();
/* three nodes */
raft_add_peer(r,(void*)1);
raft_add_peer(r,(void*)2);
raft_set_current_term(r,1);
raft_set_state(r,RAFT_STATE_FOLLOWER);
CuAssertTrue(tc, 0 == raft_get_log_size(r));
raft_recv_appendentries(r,1,&ae);
CuAssertTrue(tc, 1 == raft_get_log_size(r));
}
void TestRaft_follower_rejects_appendentries_if_idx_and_term_dont_match_preceding_ones(CuTest * tc)
{
void *r;
msg_appendentries_t ae;
memset(&ae,0,sizeof(msg_appendentries_t));
r = raft_new();
/* three nodes */
raft_add_peer(r,(void*)1);
raft_add_peer(r,(void*)2);
raft_set_current_term(r,1);
raft_set_state(r,RAFT_STATE_FOLLOWER);
CuAssertTrue(tc, 0 == raft_get_log_size(r));
raft_recv_appendentries(r,1,&ae);
CuAssertTrue(tc, 1 == raft_get_log_size(r));
}
void TestRaft_follower_deletes_logentries_if_revealed_to_be_extraneous_by_new_appendentries(CuTest * tc)
{
}
void TestRaft_follower_resends_command_if_request_from_leader_times_out(CuTest * tc)
{
}
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "CuTest.h"
#include "raft.h"
#include "mock_send_functions.h"
/* 5.2 */
void TestRaft_leader_when_it_becomes_a_leader_sends_empty_appendentries(CuTest * tc)
{
void *r;
void *sender;
void *msg;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
msg_requestvote_response_t vr;
memset(&vr,0,sizeof(msg_requestvote_response_t));
vr.term = 1;
vr.voteGranted = 1;
sender = sender_new();
r = raft_new();
/* three nodes */
raft_add_peer(r,(void*)1);
raft_add_peer(r,(void*)2);
raft_set_external_functions(r,&funcs,sender);
raft_set_current_term(r,1);
raft_set_state(r,RAFT_STATE_CANDIDATE);
raft_become_leader(r);
}
/* 5.2 */
void TestRaft_leader_responds_to_command_msg_when_command_is_committed(CuTest * tc)
{
}
/* 5.3 */
void TestRaft_leader_sends_appendentries_with_NextIdx_when_PrevIdx_gt_NextIdx(CuTest * tc)
{
}
/* 5.3 */
void TestRaft_leader_retries_appendentries_with_decremented_NextIdx_log_inconsistency(CuTest * tc)
{
}
/*
If there exists an N such that N > commitIndex, a majority
of matchIndex[i] = N, and log[N].term == currentTerm:
set commitIndex = N (5.2, 5.4).
*/
void TestRaft_leader_append_command_to_log_increases_idxno(CuTest * tc)
{
void *r;
msg_command_t cmd;
cmd.id = 1;
cmd.data = "command";
cmd.len = strlen("command");
r = raft_new();
raft_set_state(r,RAFT_STATE_LEADER);
CuAssertTrue(tc, 0 == raft_get_log_size(r));
raft_recv_command(r,1,&cmd);
CuAssertTrue(tc, 1 == raft_get_log_size(r));
}
void TestRaft_leader_doesnt_append_command_if_unique_id_is_duplicate(CuTest * tc)
{
void *r;
msg_command_t cmd;
cmd.id = 1;
cmd.data = "command";
cmd.len = strlen("command");
r = raft_new();
raft_set_state(r,RAFT_STATE_LEADER);
CuAssertTrue(tc, 0 == raft_get_log_size(r));
raft_recv_command(r,1,&cmd);
CuAssertTrue(tc, 1 == raft_get_log_size(r));
raft_recv_command(r,1,&cmd);
CuAssertTrue(tc, 1 == raft_get_log_size(r));
}
void TestRaft_leader_increase_commitno_when_majority_have_entry_and_atleast_one_newer_entry(CuTest * tc)
{
}
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "CuTest.h"
#include "raft.h"
void TestRaft_server_idx_starts_at_1(CuTest * tc)
{
void *r;
r = raft_new();
CuAssertTrue(tc, 1 == raft_get_current_index(r));
}
void TestRaft_server_set_currentterm_sets_term(CuTest * tc)
{
void *r;
r = raft_new();
CuAssertTrue(tc, 0 == raft_get_current_term(r));
raft_set_current_term(r,5);
CuAssertTrue(tc, 5 == raft_get_current_term(r));
}
void TestRaft_election_start_increments_term(CuTest * tc)
{
void *r;
r = raft_new();
raft_set_current_term(r,1);
raft_election_start(r);
CuAssertTrue(tc, 2 == raft_get_current_term(r));
}
void TestRaft_add_peer(CuTest * tc)
{
void *r;
r = raft_new();
CuAssertTrue(tc, 0 == raft_get_num_peers(r));
raft_add_peer(r,(void*)1);
CuAssertTrue(tc, 1 == raft_get_num_peers(r));
}
void TestRaft_remove_peer(CuTest * tc)
{
void *r;
int peer;
r = raft_new();
peer = raft_add_peer(r,(void*)1);
raft_remove_peer(r,peer);
CuAssertTrue(tc, 0 == raft_get_num_peers(r));
}
void TestRaft_set_state(CuTest * tc)
{
void *r;
r = raft_new();
raft_set_state(r,RAFT_STATE_LEADER);
CuAssertTrue(tc, RAFT_STATE_LEADER == raft_get_state(r));
}
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "CuTest.h"
#include "raft.h"
#include "mock_send_functions.h"
/* 5.1 */
void TestRaft_server_recv_appendentries_reply_false_when_term_less_than_currentterm(CuTest * tc)
{
void *r;
void *sender;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
msg_appendentries_t ae;
msg_appendentries_response_t *aer;
memset(&ae,0,sizeof(msg_appendentries_t));
ae.term = 1;
sender = sender_new();
r = raft_new();
/* higher current term */
raft_set_current_term(r,5);
raft_set_external_functions(r,&funcs,sender);
raft_recv_appendentries(r,1,&ae);
/* response is false */
aer = sender_poll_msg(sender);
CuAssertTrue(tc, NULL != aer);
CuAssertTrue(tc, 0 == aer->success);
}
//Reply false if log doesnt contain an entry at prevLogIndex
//whose term matches prevLogTerm
// TODO
/* 5.3 */
void TestRaft_server_recv_appendentries_reply_false_if_log_does_not_contain_entry_at_prevLogIndex(CuTest * tc)
{
void *r;
void *sender;
void *msg;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
msg_appendentries_t ae;
msg_appendentries_response_t *aer;
memset(&ae,0,sizeof(msg_appendentries_t));
ae.term = 5;
ae.prevLogIndex = 5;
sender = sender_new();
r = raft_new();
raft_set_current_term(r,5);
raft_set_external_functions(r,&funcs,sender);
raft_recv_appendentries(r,1,&ae);
aer = sender_poll_msg(sender);
CuAssertTrue(tc, NULL != aer);
CuAssertTrue(tc, 0 == aer->success);
}
/* 5.3 */
void TestRaft_server_recv_appendentries_delete_entries_if_conflict_with_new_entries(CuTest * tc)
{
void *r;
msg_appendentries_t ae;
memset(&ae,0,sizeof(msg_appendentries_t));
ae.term = 2;
r = raft_new();
raft_set_current_term(r,1);
raft_recv_appendentries(r,1,&ae);
}
void TestRaft_server_recv_appendentries_add_new_entries_not_already_in_log(CuTest * tc)
{
void *r;
void *sender;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
msg_appendentries_t ae;
memset(&ae,0,sizeof(msg_appendentries_t));
ae.term = 2;
sender = sender_new();
r = raft_new();
raft_set_current_term(r,1);
raft_set_external_functions(r,&funcs,sender);
raft_recv_appendentries(r,1,&ae);
// msg = sender_poll_msg(sender);
// CuAssertTrue(tc, aer);
// CuAssertTrue(tc, 1 == sender_msg_is_appendentries(msg));
// CuAssertTrue(tc, 1 == sender_msg_is_false(msg));
}
//If leaderCommit > commitIndex, set commitIndex =
//min(leaderCommit, last log index)
void TestRaft_server_recv_appendentries_set_commitindex(CuTest * tc)
{
void *r;
void *sender;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
msg_appendentries_t ae;
memset(&ae,0,sizeof(msg_appendentries_t));
ae.term = 2;
sender = sender_new();
r = raft_new();
raft_set_current_term(r,1);
raft_set_external_functions(r,&funcs,sender);
raft_recv_appendentries(r,1,&ae);
// msg = sender_poll_msg(sender);
// CuAssertTrue(tc, aer);
// CuAssertTrue(tc, 1 == sender_msg_is_appendentries(msg));
// CuAssertTrue(tc, 1 == sender_msg_is_false(msg));
}
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "CuTest.h"
#include "raft.h"
#include "mock_send_functions.h"
/* If term > currentTerm, set currentTerm to term (step down if candidate or leader) */
//void TestRaft_when_recv_requestvote_step_down_if_term_is_greater(CuTest * tc)
// Reply false if term < currentTerm (5.1)
void TestRaft_server_recv_requestvote_reply_false_if_term_less_than_current_term(
CuTest * tc
)
{
void *r;
void *sender;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
msg_requestvote_t rv;
msg_requestvote_response_t *rvr;
memset(&rv,0,sizeof(msg_requestvote_t));
rv.term = 2;
sender = sender_new();
r = raft_new();
raft_set_current_term(r,1);
raft_set_external_functions(r,&funcs,sender);
raft_recv_requestvote(r,1,&rv);
rvr = sender_poll_msg(sender);
CuAssertTrue(tc, NULL != rvr);
CuAssertTrue(tc, 0 == rvr->voteGranted);
}
// If votedFor is null or candidateId, and candidate's log is at
// least as up-to-date as local log, grant vote (5.2, 5.4)
void TestRaft_server_dont_grant_vote_if_we_didnt_vote_for_this_candidate(
CuTest * tc
)
{
void *r;
void *sender;
void *msg;
raft_external_functions_t funcs = {
.send = sender_send,
.log = NULL
};
msg_requestvote_t rv;
msg_requestvote_response_t *rvr;
memset(&rv,0,sizeof(msg_requestvote_response_t));
rv.term = 1;
sender = sender_new();
r = raft_new();
raft_set_external_functions(r,&funcs,sender);
raft_set_current_term(r,1);
raft_vote(r,2);
raft_recv_requestvote(r,1,&rv);
rvr = sender_poll_msg(sender);
CuAssertTrue(tc, NULL != rvr);
CuAssertTrue(tc, 0 == rvr->voteGranted);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment