/* This file is part of libbrandt.
* Copyright (C) 2016 GNUnet e.V.
*
* libbrandt is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* libbrandt is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* libbrandt. If not, see .
*/
/**
* @file test_brandt.c
* @brief testing API functions.
* @author Markus Teich
*/
#include "platform.h"
#include
#include "brandt.h"
#include "crypto.h"
#include "test.h"
#include "util.h"
struct msg {
uint16_t sender;
uint16_t receiver;
void *buf;
size_t buf_len;
};
struct test {
uint16_t ret;
uint16_t m;
uint16_t outcome_public;
};
static uint16_t *id;
static uint16_t *result_called;
static struct BRANDT_Auction **ad;
static uint16_t unexpected_result;
/* TEST CONFIGURATION */
static const uint16_t bidders = 4;
static const uint16_t prizes = 3;
static const uint16_t bids[] = { 1, 2, 0, 2 };
static struct BRANDT_Result *
expected_outcome (uint16_t m, uint16_t outcome_public, uint16_t i)
{
int32_t highest_bidder = -1;
int32_t highest_bid = -1;
struct BRANDT_Result *ret;
for (uint16_t i = 0; i < bidders; i++)
{
if (bids[i] > highest_bid)
{
highest_bid = bids[i];
highest_bidder = i;
}
}
if (!outcome_public && !(i == highest_bidder || i == bidders))
return NULL;
ret = GNUNET_new (struct BRANDT_Result);
ret->bidder = highest_bidder;
ret->price = highest_bid;
ret->status = BRANDT_bidder_won;
return ret;
}
static void
bidder_start (void *arg)
{
uint16_t i = *(uint16_t *)arg;
weprintf ("starting bidder %d", i);
BRANDT_bidder_start (ad[i], i, bidders);
}
static void
transfer_message (void *arg)
{
struct msg *m = (struct msg *)arg;
struct msg_head *h = (struct msg_head *)m->buf;
weprintf ("xfer msg %d %x from %d to %d", ntohl (
h->msg_type), arg, m->sender, m->receiver);
BRANDT_got_message (ad[m->receiver], m->sender, m->buf, m->buf_len);
free (arg);
}
static uint16_t
cb_start (void *auction_closure)
{
uint16_t *s = (uint16_t *)auction_closure;
if (!s || bidders != *s)
{
weprintf ("start callback called from bidder");
_exit (1);
}
for (uint16_t i = 0; i < bidders; i++)
GNUNET_SCHEDULER_add_now (&bidder_start, &id[i]);
return bidders;
}
static int
cb_broadcast (void *auction_closure,
const void *msg,
size_t msg_len)
{
uint16_t *s = (uint16_t *)auction_closure;
struct msg *m;
for (uint16_t i = 0; i <= bidders; i++)
{
if (i == *s)
continue;
m = GNUNET_new (struct msg);
m->sender = *s;
m->receiver = i;
m->buf = GNUNET_new_array (msg_len, unsigned char);
memcpy (m->buf, msg, msg_len);
m->buf_len = msg_len;
GNUNET_SCHEDULER_add_now (&transfer_message, m);
}
return 0;
}
static int
cb_unicast (void *auction_closure,
const void *msg,
size_t msg_len)
{
uint16_t *s = (uint16_t *)auction_closure;
struct msg *m;
m = GNUNET_new (struct msg);
m->sender = *s;
m->receiver = bidders; /* == seller */
m->buf = GNUNET_new_array (msg_len, unsigned char);
memcpy (m->buf, msg, msg_len);
m->buf_len = msg_len;
GNUNET_SCHEDULER_add_now (&transfer_message, m);
return 0;
}
static void
cb_result (void *auction_closure,
struct BRANDT_Result results[],
uint16_t results_len)
{
uint16_t *s = (uint16_t *)auction_closure;
struct BRANDT_Result *must = expected_outcome (ad[*s]->m,
ad[*s]->outcome_public,
*s);
if (0 == results_len)
{
weprintf ("result from agent %d: %p", *s, must);
weprintf ("expected result is: (nil)");
if (NULL != must)
unexpected_result = 1;
}
for (uint16_t i = 0; i < results_len; i++)
{
weprintf ("result from agent %d: bidder %d got status %d with price %d",
*s,
results[i].bidder,
results[i].status,
results[i].price);
weprintf ("expected result is: bidder %d got status %d with price %d",
must[i].bidder,
must[i].status,
must[i].price);
if (NULL == must ||
must[i].bidder != results[i].bidder ||
must[i].status != results[i].status ||
must[i].price != results[i].price)
unexpected_result = 1;
}
result_called[*s] = 1;
}
static void
run_auction (void *arg)
{
struct test *asetup = arg;
const char description[] = "test description for test_auctions";
void *desc;
size_t desc_len;
ad = GNUNET_new_array (bidders + 1, struct BRANDT_Auction *);
ad[bidders] = BRANDT_new (&cb_result,
&cb_broadcast,
&cb_start,
&id[bidders],
&desc,
&desc_len,
description,
sizeof (description),
GNUNET_TIME_absolute_get (),
GNUNET_TIME_UNIT_MINUTES,
prizes, /* number of prizes */
asetup->m, /* m */
asetup->outcome_public); /* outcome public */
if (!ad[bidders])
{
weprintf ("BRANDT_new() failed.");
_exit (1);
}
for (uint16_t i = 0; i < bidders; i++)
{
ad[i] = BRANDT_join (&cb_result,
&cb_broadcast,
&cb_unicast,
&id[i],
desc,
desc_len,
description,
sizeof (description),
bids[i]); /* bid */
if (!ad[i])
{
weprintf ("BRANDT_join() failed.");
_exit (1);
}
if (ad[bidders]->k != ad[i]->k ||
ad[bidders]->m != ad[i]->m ||
ad[bidders]->outcome_public != ad[i]->outcome_public ||
ad[bidders]->time_start.abs_value_us
!= ad[i]->time_start.abs_value_us ||
ad[bidders]->time_round.rel_value_us
!= ad[i]->time_round.rel_value_us ||
!ad[bidders]->seller_mode || /* todo: split out */
ad[i]->seller_mode)
{
weprintf ("error/mismatch in basic auction data");
_exit (1);
}
}
}
static int
test_auctions ()
{
id = GNUNET_new_array (bidders + 1, uint16_t);
for (uint16_t i = 0; i <= bidders; i++)
id[i] = i;
for (size_t atype = 0; atype < auction_last; atype++)
{
if (auction_firstPrice != atype) /* others not yet implemented */
continue;
for (size_t oc = 0; oc < outcome_last; oc++)
{
struct test asetup;
result_called = GNUNET_new_array (bidders + 1, uint16_t);
unexpected_result = 0;
asetup.ret = 0;
asetup.m = atype;
asetup.outcome_public = oc;
GNUNET_SCHEDULER_run (&run_auction, &asetup);
for (uint16_t i = 0; i <= bidders; i++)
{
BRANDT_destroy (ad[i]);
if (!result_called[i])
{
weprintf ("result callback not called for bidder %d", i);
unexpected_result = 1;
}
}
if (unexpected_result)
return 0;
}
}
return 1;
}
int
main (int argc, char *argv[])
{
struct GNUNET_CRYPTO_EccDlogContext *edc;
edc = GNUNET_CRYPTO_ecc_dlog_prepare (1024, 16);
BRANDT_init (edc);
RUN (test_auctions);
GNUNET_CRYPTO_ecc_dlog_release (edc);
return ret;
}