Merge branch 'master' into community_transfer_confirmation_email

This commit is contained in:
einhornimmond 2021-06-08 16:56:26 +02:00 committed by GitHub
commit 61501b2a78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
111 changed files with 3503 additions and 3151 deletions

View File

@ -44,19 +44,19 @@ jobs:
- name: Checkout code
uses: actions/checkout@v2
with:
submodules: recursive
submodules: true
##########################################################################
# BUILD LOGIN SERVER DOCKER IMAGE ########################################
##########################################################################
- name: login server | Build `test` image
- name: login server | Build `release` image
run: |
docker build --target login_server -t "gradido/login_server:test" -f ./login_server/Dockerfile login_server/
docker save "gradido/login_server:test" > /tmp/login_server.tar
- name: Upload Artifact
uses: actions/upload-artifact@v2
with:
name: docker-login-server-test
path: /tmp/login_server.tar
docker build --target release -t "gradido/login_server:release" -f ./login_server/Dockerfile login_server/
#docker save "gradido/login_server:test" > /tmp/login_server.tar
#- name: Upload Artifact
# uses: actions/upload-artifact@v2
#with:
# name: docker-login-server-test
#path: /tmp/login_server.tar
##############################################################################
# JOB: DOCKER BUILD TEST COMMUNITY SERVER ####################################
@ -102,7 +102,7 @@ jobs:
##########################################################################
- name: mariadb | Build `test` image
run: |
docker build -t "gradido/mariadb:test" -f ./mariadb/Dockerfile ./
docker build --target mariadb_server_test -t "gradido/mariadb:test" -f ./mariadb/Dockerfile ./
docker save "gradido/mariadb:test" > /tmp/mariadb.tar
- name: Upload Artifact
uses: actions/upload-artifact@v2
@ -212,9 +212,138 @@ jobs:
report_name: Coverage Frontend
type: lcov
result_path: ./coverage/lcov.info
min_coverage: 20
min_coverage: 21
token: ${{ github.token }}
##############################################################################
# JOB: UNIT TEST LOGIN-SERVER ###############################################
##############################################################################
unit_test_login_server:
name: Unit tests - Login-Server
runs-on: ubuntu-latest
needs: []
services:
mariadb:
image: gradido/mariadb:test
env:
MARIADB_ALLOW_EMPTY_PASSWORD: 1
MARIADB_USER: root
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping"
--health-interval=6s
--health-timeout=3s
--health-retries=4
steps:
- name: Debug service
run: echo "$(docker ps)"
- name: Debug container choosing script
run: echo "$(docker container ls | grep mariadb | awk '{ print $1 }')"
##########################################################################
# CHECKOUT CODE ##########################################################
##########################################################################
- name: Checkout code
uses: actions/checkout@v2
with:
submodules: true
##########################################################################
# Build Login-Server Test Docker image ###################################
##########################################################################
- name: login server | Build `test` image
run: |
docker build --target test -t "gradido/login_server:test" -f ./login_server/Dockerfile login_server/
##########################################################################
# UNIT TESTS BACKEND LOGIN-SERVER #######################################
##########################################################################
- name: Login-Server | Unit tests
run: |
docker run --network container:$(docker container ls | grep mariadb | awk '{ print $1 }') -v ~/coverage:/code/build_cov/coverage -v $(pwd)/configs/login_server:/etc/grd_login gradido/login_server:test
cp -r ~/coverage ./coverage
##########################################################################
# COVERAGE CHECK BACKEND LOGIN-SERVER ####################################
##########################################################################
- name: backend login | Coverage check
uses: webcraftmedia/coverage-check-action@master
with:
report_name: Coverage Backend
type: lcov
result_path: ./coverage/coverage.info
min_coverage: 6
token: ${{ github.token }}
##############################################################################
# JOB: UNIT TEST COMMUNITY-SERVER ###########################################
##############################################################################
unit_test_community_server:
name: Unit tests - Community Server
runs-on: ubuntu-latest
needs: [build_test_community_server]
services:
mariadb:
image: gradido/mariadb:test
env:
MARIADB_ALLOW_EMPTY_PASSWORD: 1
MARIADB_USER: root
# ports:
# - 3306:3306
options: --health-cmd="mysqladmin ping"
--health-interval=5s
--health-timeout=5s
--health-retries=3
steps:
- name: get mariadb container id
run: echo "::set-output name=id::$(docker container ls | grep mariadb | awk '{ print $1 }')"
id: mariadb_container
- name: show networks
run: echo "$(docker network ls)"
- name: get automatic created network
run: echo "::set-output name=id::$(docker network ls | grep github_network | awk '{ print $1 }')"
id: network
- name: Start Login-Server
run: docker run --network ${{ steps.network.outputs.id }} --name=login-server -d gradido/login_server:default
- name: get login-server container id
run: echo "::set-output name=id::$(docker container ls | grep login_server | awk '{ print $1 }')"
id: login_server_container
##########################################################################
# CHECKOUT CODE ##########################################################
##########################################################################
- name: Checkout code
uses: actions/checkout@v2
##########################################################################
# DOWNLOAD DOCKER IMAGE ##################################################
##########################################################################
- name: Download Docker Image (Community-Server)
uses: actions/download-artifact@v2
with:
name: docker-community-server-test
path: /tmp
- name: Load Docker Image
run: docker load < /tmp/community_server.tar
# for debugging login-server
- name: check login-server
run: docker logs ${{ steps.login_server_container.outputs.id }}
- name: check mariadb
run: docker logs ${{ steps.mariadb_container.outputs.id }}
##########################################################################
# UNIT TESTS BACKEND COMMUNITY-SERVER #######################################
##########################################################################
- name: community server | Unit tests
run: |
docker run --network ${{ steps.network.outputs.id }} -v ~/coverage:/var/www/cakephp/webroot/coverage gradido/community_server:test
cp -r ~/coverage ./coverage
#########################################################################
# COVERAGE CHECK BACKEND COMMUNITY-SERVER ####################################
##########################################################################
#- name: backend community simplecov | Coverage check
# uses: webcraftmedia/coverage-check-action@master
# with:
# report_name: Coverage Backend
# type: simplecov
# result_path: ./coverage/coverage.info
# min_coverage: 8
# token: ${{ github.token }}
#test:
# runs-on: ubuntu-latest
# steps:
@ -228,4 +357,4 @@ jobs:
# GN_INSTANCE_FOLDER: /tmp/gradio-node-instance
# GN_CONTAINER_NAME: gradido-node-build
# run: docker run gradido-node-test
# timeout-minutes: 2
# timeout-minutes: 2

View File

@ -1,8 +1,8 @@
FROM phpdockerio/php74-fpm
FROM phpdockerio/php74-fpm as community_server
# install php fpm
RUN apt-get update \
&& apt-get -y --no-install-recommends install curl unzip php7.4-curl php7.4-fpm php7.4-mbstring php7.4-intl php7.4-xml php7.4-pdo php7.4-mysql \
&& apt-get -y --no-install-recommends install curl unzip php7.4-curl php7.4-fpm php7.4-mbstring php7.4-intl php7.4-xml php7.4-pdo php7.4-mysql php7.4-xdebug \
&& apt-get clean; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
WORKDIR /var/www/cakephp
@ -13,5 +13,17 @@ COPY ./configs/community_server/app.php ./config/
RUN composer update
RUN composer dump-autoload
######### special for code coverage and testing
FROM community_server as test
RUN apt-get update \
&& apt-get -y --no-install-recommends install php7.4-xdebug \
&& apt-get clean; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
WORKDIR /var/www/cakephp
ENV XDEBUG_MODE=coverage
CMD ./vendor/bin/phpunit --coverage-text=./webroot/coverage/coverage.info

View File

@ -88,19 +88,8 @@ class AppController extends Controller
// load current balance
$session = $this->getRequest()->getSession();
$state_user_id = $session->read('StateUser.id');
if ($state_user_id) {
$stateBalancesTable = TableRegistry::getTableLocator()->get('stateBalances');
$stateBalanceQuery = $stateBalancesTable
->find('all')
->contain(false)
->where(['state_user_id' => $state_user_id]);
if ($stateBalanceQuery->count() == 1) {
//var_dump($stateBalanceEntry->first());
$session->write('StateUser.balance', $stateBalanceQuery->first()->decay);
//echo "stateUser.balance: " . $session->read('StateUser.balance');
}
}
// load error count
if ($state_user_id) {
$stateErrorsTable = TableRegistry::getTableLocator()->get('stateErrors');
@ -111,8 +100,6 @@ class AppController extends Controller
->where(['state_user_id' => $state_user_id]);
$session->write('StateUser.errorCount', $stateErrorQuery->count());
}
//echo "initialize";
// put current page into global for navi
$GLOBALS["passed"] = null;

View File

@ -276,7 +276,8 @@ class AppRequestsController extends AppController
$this->viewBuilder()->setLayout('ajax');
$login_result = $this->requestLogin($session_id, false);
if($login_result !== true) {
return $this->returnJson($login_result);
$this->set('body', $login_result);
return;
}
$session = $this->getRequest()->getSession();
$user = $session->read('StateUser');
@ -285,16 +286,24 @@ class AppRequestsController extends AppController
$state_balance = $state_balances_table->find()->where(['state_user_id' => $user['id']])->first();
if(!$state_balance) {
return $this->returnJson(['state' => 'success', 'balance' => 0]);
}
$now = new FrozenTime();
$body = [
'state' => 'success',
'balance' => $state_balance->amount,
'decay' => $state_balance->partDecay($now),
'decay_date' => $now
];
if(!$state_balance) {
$body = [
'state' => 'success',
'balance' => 0,
'decay' => 0
];
} else {
$body = [
'state' => 'success',
'balance' => $state_balance->amount,
'decay' => $state_balance->partDecay($now),
];
}
$body['decay_date'] = $now;
$this->set('body', $body);
}
@ -302,35 +311,31 @@ class AppRequestsController extends AppController
{
$this->viewBuilder()->setLayout('ajax');
$startTime = microtime(true);
$login_result = $this->requestLogin($session_id, false);
if($login_result !== true) {
return $this->returnJson($login_result);
}
$session = $this->getRequest()->getSession();
$user = $session->read('StateUser');
$stateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances');
$stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions');
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
$stateBalancesTable->updateBalances($user['id']);
$gdtSum = 0;
$gdtEntries = $this->JsonRequestClient->sendRequestGDT(['email' => $user['email']], 'GdtEntries' . DS . 'sumPerEmailApi');
if('success' == $gdtEntries['state'] && 'success' == $gdtEntries['data']['state']) {
$gdtSum = intval($gdtEntries['data']['sum']);
} else {
$this->addAdminError('StateBalancesController', 'overview', $gdtEntries, $user['id'] ? $user['id'] : 0);
}
$stateUserTransactions_total = $stateUserTransactionsTable
->find()
->select(['id'])
->where(['state_user_id' => $user['id']])
->contain([]);
$stateUserTransactionsQuery = $stateUserTransactionsTable
->find()
@ -343,17 +348,18 @@ class AppRequestsController extends AppController
$decay = true;
$transactions = [];
$transactions_from_db = $stateUserTransactionsQuery->toArray();
if($stateUserTransactionsQuery->count() > 0) {
if(count($transactions_from_db)) {
if($orderDirection == 'DESC') {
$transactions_from_db = array_reverse($transactions_from_db);
}
$transactions = $transactionsTable->listTransactionsHumanReadable($transactions_from_db, $user, $decay);
if($orderDirection == 'DESC') {
$transactions = array_reverse($transactions);
}
}
}
$state_balance = $stateBalancesTable->find()->where(['state_user_id' => $user['id']])->first();
@ -361,7 +367,7 @@ class AppRequestsController extends AppController
'state' => 'success',
'transactions' => $transactions,
'transactionExecutingCount' => $session->read('Transactions.executing'),
'count' => $stateUserTransactions_total->count(),
'count' => $stateUserTransactionsQuery->count(),
'gdtSum' => $gdtSum,
'timeUsed' => microtime(true) - $startTime
];
@ -375,8 +381,8 @@ class AppRequestsController extends AppController
$body['balance'] = $state_balance->amount;
$body['decay'] = $stateBalancesTable->calculateDecay($state_balance->amount, $state_balance->record_date, $now);
}
$this->set('body', $body);
$this->set('body', $body);
}
private function acquireAccessToken($session_id)

View File

@ -340,12 +340,13 @@ class JsonRequestHandlerController extends AppController {
return;
}
$transaction_body = $transaction->getTransactionBody();
$transaction_type_name = $transaction_body->getTransactionTypeName();
$senderUser = null;
if($transaction_type_name === 'transfer') {
$senderUser = $transaction_body->getSpecificTransaction()->getSenderUser();
} else if($transaction_type_name === 'creation') {
$senderUser = $transaction->getFirstSigningUser();
$senderUser = $transaction->getFirstSigningUser();
if($transaction_body != null) {
$transaction_type_name = $transaction_body->getTransactionTypeName();
if($transaction_type_name === 'transfer') {
$senderUser = $transaction_body->getSpecificTransaction()->getSenderUser();
}
}
// send notification email
$noReplyEmail = Configure::read('noReplyEmail');
@ -373,18 +374,21 @@ class JsonRequestHandlerController extends AppController {
private function putTransaction($transactionBase64) {
$transaction = new Transaction($transactionBase64);
//echo "after new transaction<br>";
if($transaction->hasErrors()) {
$this->sendEMailTransactionFailed($transaction, 'parse');
return $this->returnJson(['state' => 'error', 'msg' => 'error parsing transaction', 'details' => $transaction->getErrors()]);
}
//echo "after check on errors<br>";
if(!$transaction->validate()) {
//$transaction_details
$this->sendEMailTransactionFailed($transaction, 'validate');
return $this->returnJsonSaveError($transaction, ['state' => 'error', 'msg' => 'error validate transaction', 'details' => $transaction->getErrors()]);
return $this->returnJsonSaveError($transaction, [
'state' => 'error',
'msg' => 'error validate transaction',
'details' => $transaction->getErrors()
]);
}
//echo "after validate <br>";
if ($transaction->save()) {
$result = ['state' => 'success'];

View File

@ -151,35 +151,6 @@ class StateBalancesController extends AppController
$this->set('gdtSum', $gdtSum);
}
public function ajaxGetBalance($session_id = 0)
{
if(!$session_id) {
return $this->returnJson(['state' => 'error', 'msg' => 'invalid session id']);
}
$login_result = $this->requestLogin($session_id, false);
if($login_result !== true) {
return $this->returnJson($login_result);
}
$session = $this->getRequest()->getSession();
$user = $session->read('StateUser');
$this->StateBalances->updateBalances($user['id']);
$state_balance = $this->StateBalances->find()->where(['state_user_id' => $user['id']])->first();
if(!$state_balance) {
return $this->returnJson(['state' => 'success', 'balance' => 0]);
}
$now = new FrozenTime();
return $this->returnJson([
'state' => 'success',
'balance' => $state_balance->amount,
'decay' => $this->StateBalances->calculateDecay($state_balance->amount, $state_balance->record_date, $now),
'decay_date' => $now
]);
}
public function ajaxGdtOverview()
{

View File

@ -7,6 +7,7 @@ use Model\Transactions\Transaction;
use Model\Transactions\TransactionBody;
use Cake\Core\Configure;
use Cake\I18n\Time;
use Cake\ORM\TableRegistry;
/**
@ -24,7 +25,7 @@ class TransactionsController extends AppController
parent::initialize();
$this->loadComponent('GradidoNumber');
$this->loadComponent('JsonRpcRequestClient');
$this->Auth->allow(['decode']);
$this->Auth->allow(['decode', 'manualTransaction']);
}
/**
@ -170,6 +171,78 @@ class TransactionsController extends AppController
$this->set('transaction', $transaction);
}
public function manualTransaction()
{
if ($this->request->is('post')) {
$data = $this->request->getData();
$type = $data['type'];
$transaction = new \Proto\Gradido\GradidoTransaction();
$transactionBody = new \Proto\Gradido\TransactionBody();
$transactionBody->setMemo($data['memo']);
$created = new \Proto\Gradido\TimestampSeconds();
$now = new Time();
$created->setSeconds($now->getTimestamp());
$transactionBody->setCreated($created);
if($type == "creation") {
$creation = new \Proto\Gradido\GradidoCreation();
$target_date = new \Proto\Gradido\TimestampSeconds();
$target_time = new Time($data['target_date']);
$target_date->setSeconds($target_time->getTimestamp());
$creation->setTargetDate($target_date);
$receiver = new \Proto\Gradido\TransferAmount();
$receiver->setAmount(intval($data['amount']));
$receiver->setPubkey(hex2bin($data['target_public_key']));
$creation->setReceiver($receiver);
$transactionBody->setCreation($creation);
} else if($type == "transfer") {
$transfer = new \Proto\Gradido\GradidoTransfer();
$local_transfer = new \Proto\Gradido\LocalTransfer();
$sender = new \Proto\Gradido\TransferAmount();
$sender->setAmount(intval($data['amount']));
$sender->setPubkey(hex2bin($data['sender_public_key']));
$local_transfer->setSender($sender);
$local_transfer->setReceiver(hex2bin($data['receiver_public_key']));
$transfer->setLocal($local_transfer);
$transactionBody->setTransfer($transfer);
}
$body_bytes = $transactionBody->serializeToString();
$transaction->setBodyBytes($body_bytes);
$protoSigMap = new \Proto\Gradido\SignatureMap();
$sigPairs = $protoSigMap->getSigPair();
//echo "sigPairs: "; var_dump($sigPairs); echo "<br>";
//return null;
// sign with keys
//foreach($keys as $key) {
$sigPair = new \Proto\Gradido\SignaturePair();
$sigPair->setPubKey(hex2bin($data['signer_public_key']));
$signature = sodium_crypto_sign_detached($body_bytes, hex2bin($data['signer_private_key']));
echo "signature: " . bin2hex($signature). "<br>";
$sigPair->setEd25519($signature);
$sigPairs[] = $sigPair;
// SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
// SODIUM_BASE64_VARIANT_ORIGINAL
$transaction->setSigMap($protoSigMap);
//var_dump($protoSigMap);
$transaction_bin = $transaction->serializeToString();
// $url_safe = sodium_bin2base64($transaction_bin, sodium_base64_VARIANT_ORIGINAL);
$base64 = [
//'original' => sodium_bin2base64($transaction_bin, sodium_base64_VARIANT_ORIGINAL),
//'original_nopadding' => sodium_bin2base64($transaction_bin, sodium_base64_VARIANT_ORIGINAL_NO_PADDING),
//'urlsafe' => sodium_bin2base64($transaction_bin, sodium_base64_VARIANT_URLSAFE),
'urlsafe_nopadding' => sodium_bin2base64($transaction_bin, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING),
'php' => base64_encode($transaction_bin)
];
$this->set('base64', $base64);
}
}
public function decode()
{
$this->viewBuilder()->setLayout('frontend');

View File

@ -1,96 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: BasicTypes.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* Generated from protobuf message <code>model.messages.gradido.Key</code>
*/
class Key extends \Google\Protobuf\Internal\Message
{
protected $key;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type string $ed25519
* ed25519 signature (libsodium default)
* @type string $ed25519_ref10
* ed25519 ref10 signature
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\BasicTypes::initOnce();
parent::__construct($data);
}
/**
* ed25519 signature (libsodium default)
*
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
* @return string
*/
public function getEd25519()
{
return $this->readOneof(2);
}
/**
* ed25519 signature (libsodium default)
*
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
* @param string $var
* @return $this
*/
public function setEd25519($var)
{
GPBUtil::checkString($var, False);
$this->writeOneof(2, $var);
return $this;
}
/**
* ed25519 ref10 signature
*
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
* @return string
*/
public function getEd25519Ref10()
{
return $this->readOneof(3);
}
/**
* ed25519 ref10 signature
*
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
* @param string $var
* @return $this
*/
public function setEd25519Ref10($var)
{
GPBUtil::checkString($var, False);
$this->writeOneof(3, $var);
return $this;
}
/**
* @return string
*/
public function getKey()
{
return $this->whichOneof("key");
}
}

View File

@ -1,85 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: BasicTypes.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* Generated from protobuf message <code>model.messages.gradido.ReceiverAmount</code>
*/
class ReceiverAmount extends \Google\Protobuf\Internal\Message
{
/**
* Generated from protobuf field <code>bytes ed25519_receiver_pubkey = 1;</code>
*/
private $ed25519_receiver_pubkey = '';
/**
* Generated from protobuf field <code>sint64 amount = 2;</code>
*/
private $amount = 0;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type string $ed25519_receiver_pubkey
* @type int|string $amount
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\BasicTypes::initOnce();
parent::__construct($data);
}
/**
* Generated from protobuf field <code>bytes ed25519_receiver_pubkey = 1;</code>
* @return string
*/
public function getEd25519ReceiverPubkey()
{
return $this->ed25519_receiver_pubkey;
}
/**
* Generated from protobuf field <code>bytes ed25519_receiver_pubkey = 1;</code>
* @param string $var
* @return $this
*/
public function setEd25519ReceiverPubkey($var)
{
GPBUtil::checkString($var, False);
$this->ed25519_receiver_pubkey = $var;
return $this;
}
/**
* Generated from protobuf field <code>sint64 amount = 2;</code>
* @return int|string
*/
public function getAmount()
{
return $this->amount;
}
/**
* Generated from protobuf field <code>sint64 amount = 2;</code>
* @param int|string $var
* @return $this
*/
public function setAmount($var)
{
GPBUtil::checkInt64($var);
$this->amount = $var;
return $this;
}
}

View File

@ -1,119 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: BasicTypes.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* Generated from protobuf message <code>model.messages.gradido.SenderAmount</code>
*/
class SenderAmount extends \Google\Protobuf\Internal\Message
{
/**
* Generated from protobuf field <code>bytes ed25519_sender_pubkey = 1;</code>
*/
private $ed25519_sender_pubkey = '';
/**
* Generated from protobuf field <code>sint64 amount = 2;</code>
*/
private $amount = 0;
/**
* sender balance after transaction, including perishability
*
* Generated from protobuf field <code>sint64 senderFinalBalance = 3;</code>
*/
private $senderFinalBalance = 0;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type string $ed25519_sender_pubkey
* @type int|string $amount
* @type int|string $senderFinalBalance
* sender balance after transaction, including perishability
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\BasicTypes::initOnce();
parent::__construct($data);
}
/**
* Generated from protobuf field <code>bytes ed25519_sender_pubkey = 1;</code>
* @return string
*/
public function getEd25519SenderPubkey()
{
return $this->ed25519_sender_pubkey;
}
/**
* Generated from protobuf field <code>bytes ed25519_sender_pubkey = 1;</code>
* @param string $var
* @return $this
*/
public function setEd25519SenderPubkey($var)
{
GPBUtil::checkString($var, False);
$this->ed25519_sender_pubkey = $var;
return $this;
}
/**
* Generated from protobuf field <code>sint64 amount = 2;</code>
* @return int|string
*/
public function getAmount()
{
return $this->amount;
}
/**
* Generated from protobuf field <code>sint64 amount = 2;</code>
* @param int|string $var
* @return $this
*/
public function setAmount($var)
{
GPBUtil::checkInt64($var);
$this->amount = $var;
return $this;
}
/**
* sender balance after transaction, including perishability
*
* Generated from protobuf field <code>sint64 senderFinalBalance = 3;</code>
* @return int|string
*/
public function getSenderFinalBalance()
{
return $this->senderFinalBalance;
}
/**
* sender balance after transaction, including perishability
*
* Generated from protobuf field <code>sint64 senderFinalBalance = 3;</code>
* @param int|string $var
* @return $this
*/
public function setSenderFinalBalance($var)
{
GPBUtil::checkInt64($var);
$this->senderFinalBalance = $var;
return $this;
}
}

View File

@ -1,65 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: BasicTypes.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* Generated from protobuf message <code>model.messages.gradido.SignatureMap</code>
*/
class SignatureMap extends \Google\Protobuf\Internal\Message
{
/**
* Each signature pair corresponds to a unique Key required to sign the transaction.
*
* Generated from protobuf field <code>repeated .model.messages.gradido.SignaturePair sigPair = 1;</code>
*/
private $sigPair;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type \Model\Messages\Gradido\SignaturePair[]|\Google\Protobuf\Internal\RepeatedField $sigPair
* Each signature pair corresponds to a unique Key required to sign the transaction.
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\BasicTypes::initOnce();
parent::__construct($data);
}
/**
* Each signature pair corresponds to a unique Key required to sign the transaction.
*
* Generated from protobuf field <code>repeated .model.messages.gradido.SignaturePair sigPair = 1;</code>
* @return \Google\Protobuf\Internal\RepeatedField
*/
public function getSigPair()
{
return $this->sigPair;
}
/**
* Each signature pair corresponds to a unique Key required to sign the transaction.
*
* Generated from protobuf field <code>repeated .model.messages.gradido.SignaturePair sigPair = 1;</code>
* @param \Model\Messages\Gradido\SignaturePair[]|\Google\Protobuf\Internal\RepeatedField $var
* @return $this
*/
public function setSigPair($var)
{
$arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Model\Messages\Gradido\SignaturePair::class);
$this->sigPair = $arr;
return $this;
}
}

View File

@ -1,123 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: BasicTypes.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* Generated from protobuf message <code>model.messages.gradido.SignaturePair</code>
*/
class SignaturePair extends \Google\Protobuf\Internal\Message
{
/**
* Generated from protobuf field <code>bytes pubKey = 1;</code>
*/
private $pubKey = '';
protected $signature;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type string $pubKey
* @type string $ed25519
* ed25519 signature (libsodium default)
* @type string $ed25519_ref10
* ed25519 ref10 signature
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\BasicTypes::initOnce();
parent::__construct($data);
}
/**
* Generated from protobuf field <code>bytes pubKey = 1;</code>
* @return string
*/
public function getPubKey()
{
return $this->pubKey;
}
/**
* Generated from protobuf field <code>bytes pubKey = 1;</code>
* @param string $var
* @return $this
*/
public function setPubKey($var)
{
GPBUtil::checkString($var, False);
$this->pubKey = $var;
return $this;
}
/**
* ed25519 signature (libsodium default)
*
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
* @return string
*/
public function getEd25519()
{
return $this->readOneof(2);
}
/**
* ed25519 signature (libsodium default)
*
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
* @param string $var
* @return $this
*/
public function setEd25519($var)
{
GPBUtil::checkString($var, False);
$this->writeOneof(2, $var);
return $this;
}
/**
* ed25519 ref10 signature
*
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
* @return string
*/
public function getEd25519Ref10()
{
return $this->readOneof(3);
}
/**
* ed25519 ref10 signature
*
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
* @param string $var
* @return $this
*/
public function setEd25519Ref10($var)
{
GPBUtil::checkString($var, False);
$this->writeOneof(3, $var);
return $this;
}
/**
* @return string
*/
public function getSignature()
{
return $this->whichOneof("signature");
}
}

View File

@ -1,114 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: StateCreateGroup.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* need signature from this group and from parent (if it isn't zero)
*
* Generated from protobuf message <code>model.messages.gradido.StateCreateGroup</code>
*/
class StateCreateGroup extends \Google\Protobuf\Internal\Message
{
/**
* Generated from protobuf field <code>string name = 1;</code>
*/
private $name = '';
/**
* Generated from protobuf field <code>.model.messages.gradido.Key groupPublicKey = 2;</code>
*/
private $groupPublicKey = null;
/**
* Generated from protobuf field <code>.model.messages.gradido.Key parentGroupPublicKey = 3;</code>
*/
private $parentGroupPublicKey = null;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type string $name
* @type \Model\Messages\Gradido\Key $groupPublicKey
* @type \Model\Messages\Gradido\Key $parentGroupPublicKey
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\StateCreateGroup::initOnce();
parent::__construct($data);
}
/**
* Generated from protobuf field <code>string name = 1;</code>
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Generated from protobuf field <code>string name = 1;</code>
* @param string $var
* @return $this
*/
public function setName($var)
{
GPBUtil::checkString($var, True);
$this->name = $var;
return $this;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.Key groupPublicKey = 2;</code>
* @return \Model\Messages\Gradido\Key
*/
public function getGroupPublicKey()
{
return $this->groupPublicKey;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.Key groupPublicKey = 2;</code>
* @param \Model\Messages\Gradido\Key $var
* @return $this
*/
public function setGroupPublicKey($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\Key::class);
$this->groupPublicKey = $var;
return $this;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.Key parentGroupPublicKey = 3;</code>
* @return \Model\Messages\Gradido\Key
*/
public function getParentGroupPublicKey()
{
return $this->parentGroupPublicKey;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.Key parentGroupPublicKey = 3;</code>
* @param \Model\Messages\Gradido\Key $var
* @return $this
*/
public function setParentGroupPublicKey($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\Key::class);
$this->parentGroupPublicKey = $var;
return $this;
}
}

View File

@ -1,114 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: StateGroupChangeParent.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* need signature from this group and from both parents (if it isn't zero)
*
* Generated from protobuf message <code>model.messages.gradido.StateGroupChangeParent</code>
*/
class StateGroupChangeParent extends \Google\Protobuf\Internal\Message
{
/**
* Generated from protobuf field <code>.model.messages.gradido.Key groupPublicKey = 1;</code>
*/
private $groupPublicKey = null;
/**
* Generated from protobuf field <code>.model.messages.gradido.Key newParentGroupPublicKey = 2;</code>
*/
private $newParentGroupPublicKey = null;
/**
* Generated from protobuf field <code>.model.messages.gradido.Key oldParentGroupPublicKey = 3;</code>
*/
private $oldParentGroupPublicKey = null;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type \Model\Messages\Gradido\Key $groupPublicKey
* @type \Model\Messages\Gradido\Key $newParentGroupPublicKey
* @type \Model\Messages\Gradido\Key $oldParentGroupPublicKey
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\StateGroupChangeParent::initOnce();
parent::__construct($data);
}
/**
* Generated from protobuf field <code>.model.messages.gradido.Key groupPublicKey = 1;</code>
* @return \Model\Messages\Gradido\Key
*/
public function getGroupPublicKey()
{
return $this->groupPublicKey;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.Key groupPublicKey = 1;</code>
* @param \Model\Messages\Gradido\Key $var
* @return $this
*/
public function setGroupPublicKey($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\Key::class);
$this->groupPublicKey = $var;
return $this;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.Key newParentGroupPublicKey = 2;</code>
* @return \Model\Messages\Gradido\Key
*/
public function getNewParentGroupPublicKey()
{
return $this->newParentGroupPublicKey;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.Key newParentGroupPublicKey = 2;</code>
* @param \Model\Messages\Gradido\Key $var
* @return $this
*/
public function setNewParentGroupPublicKey($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\Key::class);
$this->newParentGroupPublicKey = $var;
return $this;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.Key oldParentGroupPublicKey = 3;</code>
* @return \Model\Messages\Gradido\Key
*/
public function getOldParentGroupPublicKey()
{
return $this->oldParentGroupPublicKey;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.Key oldParentGroupPublicKey = 3;</code>
* @param \Model\Messages\Gradido\Key $var
* @return $this
*/
public function setOldParentGroupPublicKey($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\Key::class);
$this->oldParentGroupPublicKey = $var;
return $this;
}
}

View File

@ -1,101 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: BasicTypes.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* An exact date and time. This is the same data structure as the protobuf Timestamp.proto (see the comments in https://github.com/google/protobuf/blob/master/src/google/protobuf/timestamp.proto)
*
* Generated from protobuf message <code>model.messages.gradido.Timestamp</code>
*/
class Timestamp extends \Google\Protobuf\Internal\Message
{
/**
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
*/
private $seconds = 0;
/**
* Number of nanoseconds since the start of the last second
*
* Generated from protobuf field <code>int32 nanos = 2;</code>
*/
private $nanos = 0;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type int|string $seconds
* Number of complete seconds since the start of the epoch
* @type int $nanos
* Number of nanoseconds since the start of the last second
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\BasicTypes::initOnce();
parent::__construct($data);
}
/**
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
* @return int|string
*/
public function getSeconds()
{
return $this->seconds;
}
/**
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
* @param int|string $var
* @return $this
*/
public function setSeconds($var)
{
GPBUtil::checkInt64($var);
$this->seconds = $var;
return $this;
}
/**
* Number of nanoseconds since the start of the last second
*
* Generated from protobuf field <code>int32 nanos = 2;</code>
* @return int
*/
public function getNanos()
{
return $this->nanos;
}
/**
* Number of nanoseconds since the start of the last second
*
* Generated from protobuf field <code>int32 nanos = 2;</code>
* @param int $var
* @return $this
*/
public function setNanos($var)
{
GPBUtil::checkInt32($var);
$this->nanos = $var;
return $this;
}
}

View File

@ -1,67 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: BasicTypes.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* An exact date and time, with a resolution of one second (no nanoseconds).
*
* Generated from protobuf message <code>model.messages.gradido.TimestampSeconds</code>
*/
class TimestampSeconds extends \Google\Protobuf\Internal\Message
{
/**
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
*/
private $seconds = 0;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type int|string $seconds
* Number of complete seconds since the start of the epoch
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\BasicTypes::initOnce();
parent::__construct($data);
}
/**
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
* @return int|string
*/
public function getSeconds()
{
return $this->seconds;
}
/**
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
* @param int|string $var
* @return $this
*/
public function setSeconds($var)
{
GPBUtil::checkInt64($var);
$this->seconds = $var;
return $this;
}
}

View File

@ -1,166 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: Transaction.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* Generated from protobuf message <code>model.messages.gradido.Transaction</code>
*/
class Transaction extends \Google\Protobuf\Internal\Message
{
/**
* Generated from protobuf field <code>uint64 id = 1;</code>
*/
private $id = 0;
/**
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds received = 2;</code>
*/
private $received = null;
/**
* Generated from protobuf field <code>.model.messages.gradido.SignatureMap sigMap = 3;</code>
*/
private $sigMap = null;
/**
* Generated from protobuf field <code>bytes txHash = 4;</code>
*/
private $txHash = '';
/**
* Generated from protobuf field <code>bytes bodyBytes = 5;</code>
*/
private $bodyBytes = '';
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type int|string $id
* @type \Model\Messages\Gradido\TimestampSeconds $received
* @type \Model\Messages\Gradido\SignatureMap $sigMap
* @type string $txHash
* @type string $bodyBytes
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\Transaction::initOnce();
parent::__construct($data);
}
/**
* Generated from protobuf field <code>uint64 id = 1;</code>
* @return int|string
*/
public function getId()
{
return $this->id;
}
/**
* Generated from protobuf field <code>uint64 id = 1;</code>
* @param int|string $var
* @return $this
*/
public function setId($var)
{
GPBUtil::checkUint64($var);
$this->id = $var;
return $this;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds received = 2;</code>
* @return \Model\Messages\Gradido\TimestampSeconds
*/
public function getReceived()
{
return $this->received;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds received = 2;</code>
* @param \Model\Messages\Gradido\TimestampSeconds $var
* @return $this
*/
public function setReceived($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\TimestampSeconds::class);
$this->received = $var;
return $this;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.SignatureMap sigMap = 3;</code>
* @return \Model\Messages\Gradido\SignatureMap
*/
public function getSigMap()
{
return $this->sigMap;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.SignatureMap sigMap = 3;</code>
* @param \Model\Messages\Gradido\SignatureMap $var
* @return $this
*/
public function setSigMap($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\SignatureMap::class);
$this->sigMap = $var;
return $this;
}
/**
* Generated from protobuf field <code>bytes txHash = 4;</code>
* @return string
*/
public function getTxHash()
{
return $this->txHash;
}
/**
* Generated from protobuf field <code>bytes txHash = 4;</code>
* @param string $var
* @return $this
*/
public function setTxHash($var)
{
GPBUtil::checkString($var, False);
$this->txHash = $var;
return $this;
}
/**
* Generated from protobuf field <code>bytes bodyBytes = 5;</code>
* @return string
*/
public function getBodyBytes()
{
return $this->bodyBytes;
}
/**
* Generated from protobuf field <code>bytes bodyBytes = 5;</code>
* @param string $var
* @return $this
*/
public function setBodyBytes($var)
{
GPBUtil::checkString($var, False);
$this->bodyBytes = $var;
return $this;
}
}

View File

@ -1,193 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: TransactionBody.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* Generated from protobuf message <code>model.messages.gradido.TransactionBody</code>
*/
class TransactionBody extends \Google\Protobuf\Internal\Message
{
/**
* max 150 chars
*
* Generated from protobuf field <code>string memo = 1;</code>
*/
private $memo = '';
/**
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds created = 2;</code>
*/
private $created = null;
protected $data;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type string $memo
* max 150 chars
* @type \Model\Messages\Gradido\TimestampSeconds $created
* @type \Model\Messages\Gradido\StateCreateGroup $createGroup
* @type \Model\Messages\Gradido\StateGroupChangeParent $groupChangeParent
* @type \Model\Messages\Gradido\Transfer $transfer
* @type \Model\Messages\Gradido\TransactionCreation $creation
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\TransactionBody::initOnce();
parent::__construct($data);
}
/**
* max 150 chars
*
* Generated from protobuf field <code>string memo = 1;</code>
* @return string
*/
public function getMemo()
{
return $this->memo;
}
/**
* max 150 chars
*
* Generated from protobuf field <code>string memo = 1;</code>
* @param string $var
* @return $this
*/
public function setMemo($var)
{
GPBUtil::checkString($var, True);
$this->memo = $var;
return $this;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds created = 2;</code>
* @return \Model\Messages\Gradido\TimestampSeconds
*/
public function getCreated()
{
return $this->created;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds created = 2;</code>
* @param \Model\Messages\Gradido\TimestampSeconds $var
* @return $this
*/
public function setCreated($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\TimestampSeconds::class);
$this->created = $var;
return $this;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.StateCreateGroup createGroup = 6;</code>
* @return \Model\Messages\Gradido\StateCreateGroup
*/
public function getCreateGroup()
{
return $this->readOneof(6);
}
/**
* Generated from protobuf field <code>.model.messages.gradido.StateCreateGroup createGroup = 6;</code>
* @param \Model\Messages\Gradido\StateCreateGroup $var
* @return $this
*/
public function setCreateGroup($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\StateCreateGroup::class);
$this->writeOneof(6, $var);
return $this;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.StateGroupChangeParent groupChangeParent = 7;</code>
* @return \Model\Messages\Gradido\StateGroupChangeParent
*/
public function getGroupChangeParent()
{
return $this->readOneof(7);
}
/**
* Generated from protobuf field <code>.model.messages.gradido.StateGroupChangeParent groupChangeParent = 7;</code>
* @param \Model\Messages\Gradido\StateGroupChangeParent $var
* @return $this
*/
public function setGroupChangeParent($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\StateGroupChangeParent::class);
$this->writeOneof(7, $var);
return $this;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.Transfer transfer = 8;</code>
* @return \Model\Messages\Gradido\Transfer
*/
public function getTransfer()
{
return $this->readOneof(8);
}
/**
* Generated from protobuf field <code>.model.messages.gradido.Transfer transfer = 8;</code>
* @param \Model\Messages\Gradido\Transfer $var
* @return $this
*/
public function setTransfer($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\Transfer::class);
$this->writeOneof(8, $var);
return $this;
}
/**
* Generated from protobuf field <code>.model.messages.gradido.TransactionCreation creation = 9;</code>
* @return \Model\Messages\Gradido\TransactionCreation
*/
public function getCreation()
{
return $this->readOneof(9);
}
/**
* Generated from protobuf field <code>.model.messages.gradido.TransactionCreation creation = 9;</code>
* @param \Model\Messages\Gradido\TransactionCreation $var
* @return $this
*/
public function setCreation($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\TransactionCreation::class);
$this->writeOneof(9, $var);
return $this;
}
/**
* @return string
*/
public function getData()
{
return $this->whichOneof("data");
}
}

View File

@ -1,136 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: TransactionCreation.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* need signature from group admin or
* percent of group users another than the receiver
*
* Generated from protobuf message <code>model.messages.gradido.TransactionCreation</code>
*/
class TransactionCreation extends \Google\Protobuf\Internal\Message
{
/**
* 40 Byte
*
* Generated from protobuf field <code>.model.messages.gradido.ReceiverAmount receiverAmount = 1;</code>
*/
private $receiverAmount = null;
/**
* 4 Byte
*
* Generated from protobuf field <code>sint32 ident_hash = 2;</code>
*/
private $ident_hash = 0;
/**
* 8 Byte
*
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds target_date = 3;</code>
*/
private $target_date = null;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type \Model\Messages\Gradido\ReceiverAmount $receiverAmount
* 40 Byte
* @type int $ident_hash
* 4 Byte
* @type \Model\Messages\Gradido\TimestampSeconds $target_date
* 8 Byte
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\TransactionCreation::initOnce();
parent::__construct($data);
}
/**
* 40 Byte
*
* Generated from protobuf field <code>.model.messages.gradido.ReceiverAmount receiverAmount = 1;</code>
* @return \Model\Messages\Gradido\ReceiverAmount
*/
public function getReceiverAmount()
{
return $this->receiverAmount;
}
/**
* 40 Byte
*
* Generated from protobuf field <code>.model.messages.gradido.ReceiverAmount receiverAmount = 1;</code>
* @param \Model\Messages\Gradido\ReceiverAmount $var
* @return $this
*/
public function setReceiverAmount($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\ReceiverAmount::class);
$this->receiverAmount = $var;
return $this;
}
/**
* 4 Byte
*
* Generated from protobuf field <code>sint32 ident_hash = 2;</code>
* @return int
*/
public function getIdentHash()
{
return $this->ident_hash;
}
/**
* 4 Byte
*
* Generated from protobuf field <code>sint32 ident_hash = 2;</code>
* @param int $var
* @return $this
*/
public function setIdentHash($var)
{
GPBUtil::checkInt32($var);
$this->ident_hash = $var;
return $this;
}
/**
* 8 Byte
*
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds target_date = 3;</code>
* @return \Model\Messages\Gradido\TimestampSeconds
*/
public function getTargetDate()
{
return $this->target_date;
}
/**
* 8 Byte
*
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds target_date = 3;</code>
* @param \Model\Messages\Gradido\TimestampSeconds $var
* @return $this
*/
public function setTargetDate($var)
{
GPBUtil::checkMessage($var, \Model\Messages\Gradido\TimestampSeconds::class);
$this->target_date = $var;
return $this;
}
}

View File

@ -1,85 +0,0 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: Transfer.proto
namespace Model\Messages\Gradido;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* Generated from protobuf message <code>model.messages.gradido.Transfer</code>
*/
class Transfer extends \Google\Protobuf\Internal\Message
{
/**
* Generated from protobuf field <code>repeated .model.messages.gradido.SenderAmount senderAmounts = 1;</code>
*/
private $senderAmounts;
/**
* Generated from protobuf field <code>repeated .model.messages.gradido.ReceiverAmount receiverAmounts = 2;</code>
*/
private $receiverAmounts;
/**
* Constructor.
*
* @param array $data {
* Optional. Data for populating the Message object.
*
* @type \Model\Messages\Gradido\SenderAmount[]|\Google\Protobuf\Internal\RepeatedField $senderAmounts
* @type \Model\Messages\Gradido\ReceiverAmount[]|\Google\Protobuf\Internal\RepeatedField $receiverAmounts
* }
*/
public function __construct($data = NULL) {
\GPBMetadata\Transfer::initOnce();
parent::__construct($data);
}
/**
* Generated from protobuf field <code>repeated .model.messages.gradido.SenderAmount senderAmounts = 1;</code>
* @return \Google\Protobuf\Internal\RepeatedField
*/
public function getSenderAmounts()
{
return $this->senderAmounts;
}
/**
* Generated from protobuf field <code>repeated .model.messages.gradido.SenderAmount senderAmounts = 1;</code>
* @param \Model\Messages\Gradido\SenderAmount[]|\Google\Protobuf\Internal\RepeatedField $var
* @return $this
*/
public function setSenderAmounts($var)
{
$arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Model\Messages\Gradido\SenderAmount::class);
$this->senderAmounts = $arr;
return $this;
}
/**
* Generated from protobuf field <code>repeated .model.messages.gradido.ReceiverAmount receiverAmounts = 2;</code>
* @return \Google\Protobuf\Internal\RepeatedField
*/
public function getReceiverAmounts()
{
return $this->receiverAmounts;
}
/**
* Generated from protobuf field <code>repeated .model.messages.gradido.ReceiverAmount receiverAmounts = 2;</code>
* @param \Model\Messages\Gradido\ReceiverAmount[]|\Google\Protobuf\Internal\RepeatedField $var
* @return $this
*/
public function setReceiverAmounts($var)
{
$arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Model\Messages\Gradido\ReceiverAmount::class);
$this->receiverAmounts = $arr;
return $this;
}
}

View File

@ -58,7 +58,7 @@ class TransactionTransfer extends TransactionBase {
//$this->addError('TransactionTransfer::validate', 'not implemented yet');
//return false;
//$time = microtime(true);
static $functionName = 'TransactionCreation::validate';
static $functionName = 'TransactionTransfer::validate';
$sigPubHexs = [];
foreach($sigPairs as $sigPair)

View File

@ -0,0 +1,63 @@
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
$this->loadHelper('Form', [
'templates' => 'horizontal_form',
]);
$now = new \DateTime;
?>
<?php if(isset($errors) && count($errors) > 0) : ?>
<div class="alert-color">
<ul>
<?php foreach($errors as $error) : ?>
<li>
<?= var_dump($error); ?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<div class="action-form">
<p class="form-header"><?= __('Creation Transaction') ?></p>
<div class="form-body">
<?= $this->Form->create() ?>
<?= $this->Form->control('type', ['type' => 'hidden', 'value' => 'creation']) ?>
<?= $this->Form->control('target_public_key', ['type'=> 'text']) ?>
<?= $this->Form->control('target_date', ['type'=> 'text', 'placeholder' => 'yyyy-mm-dd hh:ii:ss', 'default' => $now->format('Y-m-d H:i:s')]) ?>
<?= $this->Form->control('amount', ['type'=> 'number']) ?>
<?= $this->Form->control('memo', ['type'=> 'textarea', 'rows' => '8', 'cols' => 40]) ?>
<?= $this->Form->control('signer_public_key', ['type' => 'text']) ?>
<?= $this->Form->control('signer_private_key', ['type'=> 'text']) ?>
<?= $this->Form->submit(); ?>
<?= $this->Form->end() ?>
</div>
</div>
<div class="action-form">
<p class="form-header"><?= __('Transfer Transaction') ?></p>
<div class="form-body">
<?= $this->Form->create() ?>
<?= $this->Form->control('type', ['type' => 'hidden', 'value' => 'transfer']) ?>
<?= $this->Form->control('sender_public_key', ['type'=> 'text']) ?>
<?= $this->Form->control('receiver_public_key', ['type'=> 'text']) ?>
<?= $this->Form->control('amount', ['type'=> 'number']) ?>
<?= $this->Form->control('memo', ['type'=> 'textarea', 'rows' => '8', 'cols' => 40]) ?>
<?= $this->Form->control('signer_public_key', ['type' => 'text']) ?>
<?= $this->Form->control('signer_private_key', ['type'=> 'text']) ?>
<?= $this->Form->submit(); ?>
<?= $this->Form->end() ?>
</div>
</div>
<?php if(isset($base64)) : ?>
<div>
<ul>
<?php foreach($base64 as $name => $value) : ?>
<li><?= $name ?>: <?= $value ?></li>
<?php endforeach ?>
</ul>
</div>
<?php endif; ?>

View File

@ -23,8 +23,7 @@ class CommunityProfilesFixture extends TestFixture
'state_user_id' => ['type' => 'index', 'columns' => ['state_user_id'], 'length' => []],
],
'_constraints' => [
'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []],
'community_profiles_ibfk_1' => ['type' => 'foreign', 'columns' => ['state_user_id'], 'references' => ['state_users', 'id'], 'update' => 'restrict', 'delete' => 'restrict', 'length' => []],
'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []]
],
'_options' => [
'engine' => 'InnoDB',

View File

@ -0,0 +1,45 @@
<?php
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
/**
* MigrationsFixture
*/
class Migrations2Fixture extends TestFixture
{
/**
* Fields
*
* @var array
*/
// @codingStandardsIgnoreStart
public $fields = [
'id' => ['type' => 'integer', 'length' => 10, 'unsigned' => true, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null],
'db_version' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => true, 'default' => '0', 'comment' => '', 'precision' => null, 'autoIncrement' => null],
'_constraints' => [
'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []],
],
'_options' => [
'engine' => 'InnoDB',
'collation' => 'utf8mb4_unicode_ci'
],
];
// @codingStandardsIgnoreEnd
/**
* Init method
*
* @return void
*/
public function init()
{
$this->table = "migrations";
$this->records = [
[
'id' => 1,
'db_version' => 2,
],
];
parent::init();
}
}

View File

@ -6,7 +6,7 @@ use Cake\TestSuite\Fixture\TestFixture;
/**
* StateBalancesFixture
*/
class StateBalancesFixture extends TestFixture
class StateBalancesFixture extends BaseTestFixture
{
/**
* Fields
@ -36,8 +36,11 @@ class StateBalancesFixture extends TestFixture
*/
public function init()
{
$this->records = [
$sql = [
[4, 4, '2021-05-27 17:47:50', '2021-05-27 17:47:50', 28808497],
[5, 1, '2021-05-27 17:47:51', '2021-05-27 17:47:50', 9823963]
];
$this->records = $this->sqlEntrysToRecords($sql, $this->fields);
parent::init();
}
}

View File

@ -1,8 +1,6 @@
<?php
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
/**
* TransactionCreationsFixture
*/
@ -19,7 +17,6 @@ class TransactionCreationsFixture extends BaseTestFixture
'transaction_id' => ['type' => 'integer', 'length' => 10, 'unsigned' => true, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null],
'state_user_id' => ['type' => 'integer', 'length' => 10, 'unsigned' => true, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null],
'amount' => ['type' => 'biginteger', 'length' => 20, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null],
'ident_hash' => ['type' => 'binary', 'length' => 32, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null],
'target_date' => ['type' => 'timestamp', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null],
'_constraints' => [
'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []],
@ -37,9 +34,9 @@ class TransactionCreationsFixture extends BaseTestFixture
*/
public function init()
{
$sql = [
[2, 1, 4, 10000000, '0000000000000000000000000000000000000000000000000000000000000000', '2021-01-01 00:00:00'],
[3, 2, 1, 10000000, '0000000000000000000000000000000000000000000000000000000000000000', '2021-01-01 00:00:00']
$sql = [
[2, 1, 4, 10000000, '2021-01-01 00:00:00'],
[3, 2, 1, 10000000, '2021-01-01 00:00:00']
];
$this->records = $this->sqlEntrysToRecords($sql, $this->fields);
parent::init();

View File

@ -1,46 +0,0 @@
<?php
namespace App\Test\TestCase\Controller;
use App\Controller\AppController;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
/**
* App\Controller\DashboardController Test Case
*
* @uses \App\Controller\DashboardController
*/
class AppControllerTest extends TestCase
{
use IntegrationTestTrait;
/**
* Fixtures
*
* @var array
*/
public $fixtures = [
'app.StateBalances'
];
public function setUp()
{
parent::setUp();
}
/**
* Test initialize method
*
* @return void
*/
public function testInitialize()
{
$this->session(['StateUser.id' => 1]);
$this->get('/');
$this->assertSession(1200, 'StateUser.balance');
//$this->markTestIncomplete('Not implemented yet.');
}
}

View File

@ -0,0 +1,303 @@
<?php
namespace App\Test\TestCase\Controller;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
/**
* App\Controller\AppRequestsController Test Case
*
* @uses \App\Controller\AppRequestsController
*/
class AppRequestControllerTest extends TestCase
{
use IntegrationTestTrait;
/**
* Fixtures
*
* @var array
*/
public $fixtures = [
'app.TransactionCreations',
'app.Transactions',
'app.StateUsers',
'app.StateUserTransactions',
'app.StateErrors',
'app.TransactionSignatures',
'app.TransactionSendCoins',
'app.StateBalances',
'app.TransactionTypes',
'app.Migrations'
];
/*public function setUp() {
parent::setUp();
}
*/
/**
* Test ajaxGetBalance method
*
* @return void
*/
public function testGetBalance1()
{
$session_id = rand();
$this->session([
'session_id' => $session_id,
'Transaction' => ['pending' => 0, 'executing' => 0],
'StateUser' => [
'id' => 1,
'email_checked' => 1,
'public_hex' => 'f7f4a49a4ac10379f8b9ddcb731c4d9ec495e6edd16075f52672cd25e3179f0f'
]
]);
$response = $this->getAndParseWithoutCompare('/api/get-balance/' . $session_id);
$this->assertEquals('success', $response->state);
$this->assertEquals(9100000, $response->balance);
$this->assertLessThan(9100000, $response->decay);
}
public function testGetBalance2()
{
$session_id = rand();
$this->session([
'session_id' => $session_id,
'Transaction' => ['pending' => 0, 'executing' => 0],
'StateUser' => [
'id' => 3,
'email_checked' => 1,
'public_hex' => '131c7f68dd94b2be4c913400ff7ff4cdc03ac2bda99c2d29edcacb3b065c67e6'
]
]);
$response = $this->getAndParseWithoutCompare('/api/get-balance/' . $session_id);
$this->assertEquals('success', $response->state);
$this->assertEquals(0, $response->balance);
}
public function testGetBalance3()
{
$session_id = rand();
$this->session([
'session_id' => $session_id,
'Transaction' => ['pending' => 0, 'executing' => 0],
'StateUser' => [
'id' => 4,
'email_checked' => 1,
'public_hex' => 'e3369de3623ce8446d0424c4013e7a1d71a2671ae3d7bf1e798ebf0665d145f2'
]
]);
$response = $this->getAndParseWithoutCompare('/api/get-balance/' . $session_id);
$this->assertEquals('success', $response->state);
$this->assertEquals(10900000, $response->balance);
$this->assertLessThan(10900000, $response->decay);
}
public function testGetBalanceInvalidSession()
{
$session_id = rand();
$this->session([
'session_id' => $session_id,
'Transaction' => ['pending' => 0, 'executing' => 0],
'StateUser' => [
'email_checked' => 1,
'public_hex' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d'
]
]);
$this->getAndParse('/api/get-balance/' . 1211,
['state' => 'not found', 'msg' => 'invalid session']
);
}
public function testGetBalanceInvalidSessionId()
{
$session_id = rand();
$this->session([
'session_id' => $session_id,
'Transaction' => ['pending' => 0, 'executing' => 0],
'StateUser' => [
'email_checked' => 1,
'public_hex' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d'
]
]);
$this->getAndParse('/api/get-balance/' ,
['state' => 'not found', 'msg' => 'invalid session']
);
}
/**
* Test ajaxListTransactions method
*
* @return void
*/
public function testListTransactions()
{
//ajaxListTransactions
$session_id = rand();
$this->session([
'session_id' => $session_id,
'Transactions' => ['pending' => 0, 'executing' => 0],
'StateUser' => [
'id' => 1,
'first_name' => 'Dario',
'last_name' => 'Frodo',
'email_checked' => 1,
'email' => 'fördertest@gradido.org',
'public_hex' => '94ae135b93cd9f33752b4e55c41903a3faa13a75bb90bfd411ea1d4a1a5e711f'
]
]);
//echo "balance: $balance";
$expectedResult = '{
"state": "success",
"transactions": [
{
"name": "Gradido Akademie",
"type": "creation",
"transaction_id": 2,
"date": "2021-04-12T00:00:00+00:00",
"target_date": "2021-01-01T00:00:00+00:00",
"creation_amount": 10000000,
"balance": 10000000,
"memo": "AGE Januar 2021"
},
{
"name": "Samuel Schmied",
"email": "test3.yahoo.com",
"type": "send",
"transaction_id": 3,
"date": "2021-04-12T00:00:00+00:00",
"balance": 1000000,
"memo": "test",
"pubkey": "e3369de3623ce8446d0424c4013e7a1d71a2671ae3d7bf1e798ebf0665d145f2"
},
{
"name": "Samuel Schmied",
"email": "test3.yahoo.com",
"type": "send",
"transaction_id": 4,
"date": "2021-04-14T00:00:00+00:00",
"balance": 100000,
"memo": "test time",
"pubkey": "e3369de3623ce8446d0424c4013e7a1d71a2671ae3d7bf1e798ebf0665d145f2"
},
{
"name": "Samuel Schmied",
"email": "test3.yahoo.com",
"type": "send",
"transaction_id": 5,
"date": "2021-04-14T09:01:07+00:00",
"balance": 100000,
"memo": "test time",
"pubkey": "e3369de3623ce8446d0424c4013e7a1d71a2671ae3d7bf1e798ebf0665d145f2"
},
{
"name": "Samuel Schmied",
"email": "test3.yahoo.com",
"type": "receive",
"transaction_id": 6,
"date": "2021-04-14T09:02:28+00:00",
"balance": 100000,
"memo": "test time 3",
"pubkey": "0000000000000000000000000000000000000000000000000000000000000000"
},
{
"name": "Samuel Schmied",
"email": "test3.yahoo.com",
"type": "receive",
"transaction_id": 7,
"date": "2021-04-14T09:28:46+00:00",
"balance": 100000,
"memo": "test login crash",
"pubkey": "0000000000000000000000000000000000000000000000000000000000000000"
},
{
"name": "Samuel Schmied",
"email": "test3.yahoo.com",
"type": "receive",
"transaction_id": 8,
"date": "2021-04-14T09:31:28+00:00",
"balance": 100000,
"memo": "test login crash",
"pubkey": "0000000000000000000000000000000000000000000000000000000000000000"
}
],
"transactionExecutingCount": 0,
"count": 7,
"gdtSum": 180000,
"timeUsed": 0.5575470924377441,
"decay_date": "2021-05-28T09:35:02+00:00",
"balance": 9100000,
"decay": 9100000
}';
$this->getAndParse('/api/list-transactions/', json_decode($expectedResult, true));
}
private function getAndParse($path, $expected)
{
$this->configRequest([
'headers' => ['Accept' => 'application/json']
]);
$this->disableErrorHandlerMiddleware();
$this->get($path);
// Check that the response was in 2xx - 3xx
$this->assertResponseSuccess();
$json = (object)$this->viewVariable('body');
if(!$json) {
// Check that the response was a 200
$this->assertResponseOk();
$responseBodyString = (string)$this->_response->getBody();
$json = json_decode($responseBodyString);
$this->assertNotFalse($json);
} else {
$responseBodyString = json_encode($json);
}
if(is_array($expected)) {
$dynamic_fields = ['timeUsed', 'decay_date', 'decay', 'gdtSum'];
// copy timeUsed because this value will be variy always
foreach($dynamic_fields as $field) {
if(isset($expected[$field]) && isset($json->$field)) {
$expected[$field] = $json->$field;
}
}
$expected = json_encode($expected);
}
$this->assertEquals($expected, $responseBodyString);
}
private function getAndParseWithoutCompare($path)
{
$this->configRequest([
'headers' => ['Accept' => 'application/json']
]);
$this->disableErrorHandlerMiddleware();
$this->get($path);
// Check that the response was in 2xx - 3xx
$this->assertResponseSuccess();
$view_body = $this->viewVariable('body');
if($view_body) {
return (object)$view_body;
}
// Check that the response was a 200
$this->assertResponseOk();
$responseBodyString = (string)$this->_response->getBody();
$json = json_decode($responseBodyString, true);
$this->assertNotFalse($json);
return $json;
}
}

View File

@ -51,19 +51,7 @@ class JsonRequestClientComponentTest extends TestCase
$this->markTestIncomplete('Not implemented yet.');
}
/**
* Test getLoginServerUrl method
*
* @return void
*/
public function testGetLoginServerUrl()
{
//$this->markTestIncomplete('Not implemented yet.');
$serverUrl = $this->JsonRequestClientComponent->getLoginServerUrl();
$this->assertEquals($serverUrl, 'http://***REMOVED***');
}
/**
/**
* Test is_base64 method
*
* @return void

View File

@ -5,9 +5,9 @@ use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
/**
* App\Controller\TransactionJsonRequestHandlerController Test Case
* App\Controller\JsonRequestHandlerController Test Case
*
* @uses \App\Controller\TransactionJsonRequestHandlerController
* @uses \App\Controller\JsonRequestHandlerController
*/
class JsonRequestHandlerControllerTest extends TestCase
{
@ -22,6 +22,7 @@ class JsonRequestHandlerControllerTest extends TestCase
'app.TransactionCreations',
'app.Transactions',
'app.StateUsers',
'app.StateUserTransactions',
'app.StateErrors',
'app.TransactionSignatures',
'app.TransactionSendCoins',
@ -30,13 +31,12 @@ class JsonRequestHandlerControllerTest extends TestCase
];
public $transactions = [
'validCreation' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQJ8wF12eZo3hcMAlAKKJ9WLT-zuSkNmGh7D98UEqH4KoIysnCkXqEya9EBZl9o11_nJ8xmm_nOevuVjR-GfLMQ8qSQoOSGFsbG8gV2VsdCAxMjMSBgiZm4ruBUovCicKIJSuE1uTzZ8zdStOVcQZA6P6oTp1u5C_1BHqHUoaXnEfEKDakwEQtYntlgo',
'validCreation900' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQNVZ8Ae3Zbg3G0wZ840fzKan6N4KtTcSe0KYi17kQwFmsl18oFxXv8_s6j1xXFrIKjy1_1Olq0a7xYLErDMkjwYqORIGCNb5iu4FSi8KJwoglK4TW5PNnzN1K05VxBkDo_qhOnW7kL_UEeodShpecR8QgNHKCBC1ie2WCg',
'validCreation1200' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQEEey5QMAdldoOTP_jTETHgOQriGsixEY0cziQeRfT_J5YtbI_A6AizEYD-JcxmRmXzv1xjjTgsV39Y32ta2CQkqORIGCIeGi-4FSi8KJwoglK4TW5PNnzN1K05VxBkDo_qhOnW7kL_UEeodShpecR8QgOy4CxC1ie2WCg',
'validCreation' => 'CmYKZAog4zad42I86ERtBCTEAT56HXGiZxrj178eeY6_BmXRRfISQDnatUMvitiiP0-sY93JStYPhPKKPU4Vosv_EGrh77BVs48xhPgPj2QHWC3oyuuMh6nN8YNjBQZx20rKvdQ4uwMSRwoMQUdFIE1haSAyMDIxEgYI_c3ChQY6LwolCiD39KSaSsEDefi53ctzHE2exJXm7dFgdfUmcs0l4xefDxDQDxoGCPqbtIQG',
'validCreation900' => 'CmYKZAog9_SkmkrBA3n4ud3LcxxNnsSV5u3RYHX1JnLNJeMXnw8SQCaZHmvmvJOt336E3qst3rn1pptdAR5ZPzePaUT10x0_Yky8FnEiQtMGNy1yT94QErzwQudJZjJwDY2uyK4cTgkSOxIGCKb1vYUGOjEKJwog4zad42I86ERtBCTEAT56HXGiZxrj178eeY6_BmXRRfIQgNHKCBoGCIDMuf8F',
'validCreation1200' => 'CmYKZAog9_SkmkrBA3n4ud3LcxxNnsSV5u3RYHX1JnLNJeMXnw8SQF8jptIrosEyVmCf3WEIGVOK0NR8YCcO0j-s8v2yUyR5BKus0ciT6B7IA5LDtn7eQX6zHjg1v5WlsTiZuOpuNgwSRAoHVG8gbXVjaBIGCL3Jv4UGOjEKJwog4zad42I86ERtBCTEAT56HXGiZxrj178eeY6_BmXRRfIQgOy4CxoGCOG5toQG',
'notBase64' => 'CgpIYWxsbyBXZW-0EgYIyfSG7gV_LwonCiCboKikqwjZfes9xuqgthFH3',
'validTransfer' => 'GmYKZAoggZC9pYXuXx2fv30G6B5p7BjhM3YQTP9Ut0V-t9PvcQ0SQDddHyKzAX3LBV0PuDiPc6lxkUipss5tyuLRpMtFJQnT30tsbYIkA1FXimjMKOoiuLswf4OLLV3bAIYehW-b9AgqYQoFSGFsbG8SBgiJlaPvBUJQCiYKIIGQvaWF7l8dn799BugeaewY4TN2EEz_VLdFfrfT73ENEICfSRImCiDtdleSLxhUgEbMW9DpqIwsykFj3-z_enKEOuGnXrmW8xCAn0k',
'errornusTransfer' => 'ClxGcm9oZXMgTmV1ZXMgSmFociB1bmQgREFOS0UsIGRhc3MgZHUgZGljaCBzbyBlaW5zZXR6dCBmw7xyIEdyYWRpZG8hIEhlcnpsaWNoZSBHcsO8w59lIFRlcmVzYRIGCPjjgvEFQlAKJgogUQwFYeVlGlfWDrkXNN7rHwejoCDJKt+YkYJfbJVyj3EQwIQ9EiYKIPXIRnUhVJ/zCs5+y/VaTBjTIoYizJNwS+JC//xsbQrHEMCEPQ==',
'creationValid' => 'GmYKZAogLtKKHPXhFtg2FUBrxXcVIiHC93SlZW9moOdUD3V21xsSQHpXYAGiVmSfhjB3o7OPx0ZJuPXrDk5eu1_AOhQBODU3KpUqBRA9yMX54S_mvGijGubCNRcMLcm7wiYbyAG-3AkqSwoQZWluIE1vbmF0c2dlaGFsdBIGCKqs5vEFSi8KJwoggZC9pYXuXx2fv30G6B5p7BjhM3YQTP9Ut0V-t9PvcQ0QgNrECRDKyd3uAQ'
'validTransfer' => 'CmYKZAog9_SkmkrBA3n4ud3LcxxNnsSV5u3RYHX1JnLNJeMXnw8SQA0ZVQ9T1qBabzmgDO1NAWNy2J6mlv0YjMP99CiV7bSR0zemt5XoM-kTviR1aTqKggzpSYSyTN5T6gIx2xa-hgkSYwoLTXkgQmlydGhkYXkSBgie0L-FBjJMCkoKJgog9_SkmkrBA3n4ud3LcxxNnsSV5u3RYHX1JnLNJeMXnw8QgIl6EiDjNp3jYjzoRG0EJMQBPnodcaJnGuPXvx55jr8GZdFF8g',
'errornusTransfer' => 'ClxGcm9oZXMgTmV1ZXMgSmFociB1bmQgREFOS0UsIGRhc3MgZHUgZGljaCBzbyBlaW5zZXR6dCBmw7xyIEdyYWRpZG8hIEhlcnpsaWNoZSBHcsO8w59lIFRlcmVzYRIGCPjjgvEFQlAKJgogUQwFYeVlGlfWDrkXNN7rHwejoCDJKt+YkYJfbJVyj3EQwIQ9EiYKIPXIRnUhVJ/zCs5+y/VaTBjTIoYizJNwS+JC//xsbQrHEMCEPQ=='
];
/*public function setUp() {
@ -51,7 +51,7 @@ class JsonRequestHandlerControllerTest extends TestCase
$this->get('/JsonRequestHandler');
$this->assertResponseOk();
$expected = json_encode(['state' => 'error', 'msg' => 'no post']);
$expected = json_encode(['state' => 'error', 'msg' => 'unknown method for get', 'details' => null]);
$this->assertEquals($expected, (string)$this->_response->getBody());
}
@ -87,7 +87,7 @@ class JsonRequestHandlerControllerTest extends TestCase
//$this->post('/TransactionJsonRequestHandler', ['method' => 'putTransaction', 'transaction' => 'CgpIYWxsbyBXZWx0EgYIyfSG7gVKLwonCiCboKikqwjZfes9xuqgthFH3/cHHaWchkUhWiGhQjB23xCg2pMBELWJ7ZYK']);
$this->postAndParse(
['method' => 'foobar', 'transaction' => $this->transactions['validCreation']],
['state' => 'error', 'msg' => 'unknown method', 'details' => 'foobar']
['state' => 'error', 'msg' => 'unknown method for post', 'details' => 'foobar']
);
}
@ -97,7 +97,8 @@ class JsonRequestHandlerControllerTest extends TestCase
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['notBase64']],
['state' => 'error', 'msg' => 'error parsing transaction', 'details' => [
['Transaction' => 'invalid base64 string']
['Transaction' => 'invalid base64 string'],
['base64' => 'CgpIYWxsbyBXZW-0EgYIyfSG7gV_LwonCiCboKikqwjZfes9xuqgthFH3']
]]
);
}
@ -114,9 +115,10 @@ class JsonRequestHandlerControllerTest extends TestCase
public function testToLargeCreationSum()
{
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation900']],
'{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1000 gr per Month not allowed"}]}'
'{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1.000 GDD per Month for in target_date not allowed"}]}'
);
}
@ -124,49 +126,36 @@ class JsonRequestHandlerControllerTest extends TestCase
{
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation1200']],
'{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1000 gr per Month not allowed"}]}'
'{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1.000 GDD per Month for in target_date not allowed"}]}'
);
}
public function testValidTransfer()
{
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['validTransfer']],
['state' => 'success']
);
}
/*public function testMissingPreviousTransaction()
{
}*/
public function testValidTransaction()
{
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation']],
['state' => 'success']
{
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['validTransfer']],
['state' => 'success']
);
}
public function testValidCreation()
{
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['creationValid']],
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation']],
['state' => 'success']
);
}
private function postAndParse($params, $expected)
{
//$this->enableCsrfToken();
$this->enableCsrfToken();
//$this->enableSecurityToken();
$token = 'my-csrf-token';
$this->cookie('csrfToken', $token);
//$token = 'my-csrf-token';
//$this->cookie('csrfToken', $token);
$this->configRequest([
'headers' => ['Accept' => 'application/json', 'X-CSRF-Token' => $token]
'headers' => ['Accept' => 'application/json']//, 'X-CSRF-Token' => $token]
]);
$this->disableErrorHandlerMiddleware();

View File

@ -27,6 +27,10 @@ use Cake\View\Exception\MissingTemplateException;
*/
class PagesControllerTest extends IntegrationTestCase
{
public $fixtures = [
'app.Migrations2'
];
/**
* testMultipleGet method
*
@ -35,9 +39,12 @@ class PagesControllerTest extends IntegrationTestCase
public function testMultipleGet()
{
$this->get('/');
$this->assertRedirect('account/');
$locations = $this->_response->getHeader('Location');
$this->assertRegExp('%.*/account/$%', $locations[0]);
$this->get('/');
$this->assertRedirect('account/');
$locations = $this->_response->getHeader('Location');
$this->assertRegExp('%.*/account/$%', $locations[0]);
}
/**
@ -64,7 +71,7 @@ class PagesControllerTest extends IntegrationTestCase
$this->get('/pages/not_existing');
$this->assertResponseError();
$this->assertResponseContains('Error');
$this->assertResponseContains('Not Found');
}
/**
@ -78,8 +85,7 @@ class PagesControllerTest extends IntegrationTestCase
$this->get('/pages/not_existing');
$this->assertResponseFailure();
$this->assertResponseContains('Missing Template');
$this->assertResponseContains('Stacktrace');
$this->assertResponseContains('Template file \u0022Pages\/not_existing.ctp\u0022 is missing.');
$this->assertResponseContains('not_existing.ctp');
}

View File

@ -69,142 +69,7 @@ class StateBalancesControllerTest extends TestCase
$this->markTestIncomplete('Not implemented yet.');
}
/**
* Test ajaxGetBalance method
*
* @return void
*/
public function testAjaxGetBalance1()
{
$session_id = rand();
$this->session([
'session_id' => $session_id,
'Transaction' => ['pending' => 0, 'executing' => 0],
'StateUser' => [
'id' => 1,
'email_checked' => 1,
'public_hex' => 'f7f4a49a4ac10379f8b9ddcb731c4d9ec495e6edd16075f52672cd25e3179f0f'
]
]);
$response = $this->getAndParseWithoutCompare('/state-balances/ajaxGetBalance/' . $session_id);
$this->assertEquals('success', $response->state);
$this->assertEquals(7321825, $response->balance);
$this->assertLessThan(7321825, $response->decay);
}
public function testAjaxGetBalance2()
{
$session_id = rand();
$this->session([
'session_id' => $session_id,
'Transaction' => ['pending' => 0, 'executing' => 0],
'StateUser' => [
'id' => 3,
'email_checked' => 1,
'public_hex' => '131c7f68dd94b2be4c913400ff7ff4cdc03ac2bda99c2d29edcacb3b065c67e6'
]
]);
$response = $this->getAndParseWithoutCompare('/state-balances/ajaxGetBalance/' . $session_id);
$this->assertEquals('success', $response->state);
$this->assertEquals(0, $response->balance);
}
public function testAjaxGetBalance3()
{
$session_id = rand();
$this->session([
'session_id' => $session_id,
'Transaction' => ['pending' => 0, 'executing' => 0],
'StateUser' => [
'id' => 4,
'email_checked' => 1,
'public_hex' => 'e3369de3623ce8446d0424c4013e7a1d71a2671ae3d7bf1e798ebf0665d145f2'
]
]);
$response = $this->getAndParseWithoutCompare('/state-balances/ajaxGetBalance/' . $session_id);
$this->assertEquals('success', $response->state);
$this->assertEquals(9112592, $response->balance);
$this->assertLessThan(9112592, $response->decay);
}
public function testAjaxGetBalanceInvalidSession()
{
$session_id = rand();
$this->session([
'session_id' => $session_id,
'Transaction' => ['pending' => 0, 'executing' => 0],
'StateUser' => [
'email_checked' => 1,
'public_hex' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d'
]
]);
//echo "balance: $balance";
$this->getAndParse('/state-balances/ajaxGetBalance/' . 1211,
['state' => 'not found', 'msg' => 'invalid session']
);
}
public function testAjaxGetBalanceInvalidSessionId()
{
$session_id = rand();
$this->session([
'session_id' => $session_id,
'Transaction' => ['pending' => 0, 'executing' => 0],
'StateUser' => [
'email_checked' => 1,
'public_hex' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d'
]
]);
//echo "balance: $balance";
$this->getAndParse('/state-balances/ajaxGetBalance' ,
['state' => 'error', 'msg' => 'invalid session id']
);
}
/**
* Test ajaxListTransactions method
*
* @return void
*/
public function testAjaxListTransactions()
{
//ajaxListTransactions
$session_id = rand();
$this->session([
'session_id' => $session_id,
'Transaction' => ['pending' => 0, 'executing' => 0],
'StateUser' => [
'id' => 1,
'first_name' => 'Dario',
'last_name' => 'Frodo',
'email_checked' => 1,
'email' => 'fördertest@gradido.org',
'public_hex' => '94ae135b93cd9f33752b4e55c41903a3faa13a75bb90bfd411ea1d4a1a5e711f'
]
]);
//echo "balance: $balance";
$this->getAndParse('/state-balances/ajaxListTransactions/' . $session_id,
[
'state' => 'success', 'transactions' => [[
'name' => 'Dario Frodo',
'email'=> 'dariofrodo@gmx.de',
'type'=> '',
'transaction_id' => 4,
'date' => '2021-02-19T13:27:14+00:00',
'balance' => 150000001,
'memo' => ''
]],
'transactionExecutingCount' => 0,
'count' => 1,
'gdtSum' => 0,
'timeUsed' => 0.03168010711669922
]
);
}
/**
* Test overviewGdt method

View File

@ -1,174 +0,0 @@
<?php
namespace App\Test\TestCase\Controller;
use App\Controller\JsonRequestHandlerController;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
/**
* App\Controller\TransactionJsonRequestHandlerController Test Case
*
* @uses \App\Controller\TransactionJsonRequestHandlerController
*/
class TransactionJsonRequestHandlerControllerTest extends TestCase
{
use IntegrationTestTrait;
/**
* Fixtures
*
* @var array
*/
public $fixtures = [
'app.TransactionCreations',
'app.Transactions',
'app.StateUsers',
'app.StateErrors',
'app.TransactionSignatures',
'app.TransactionSendCoins',
'app.StateBalances',
'app.TransactionTypes'
];
public $transactions = [
'validCreation' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQJ8wF12eZo3hcMAlAKKJ9WLT-zuSkNmGh7D98UEqH4KoIysnCkXqEya9EBZl9o11_nJ8xmm_nOevuVjR-GfLMQ8qSQoOSGFsbG8gV2VsdCAxMjMSBgiZm4ruBUovCicKIJSuE1uTzZ8zdStOVcQZA6P6oTp1u5C_1BHqHUoaXnEfEKDakwEQtYntlgo',
'validCreation900' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQNVZ8Ae3Zbg3G0wZ840fzKan6N4KtTcSe0KYi17kQwFmsl18oFxXv8_s6j1xXFrIKjy1_1Olq0a7xYLErDMkjwYqORIGCNb5iu4FSi8KJwoglK4TW5PNnzN1K05VxBkDo_qhOnW7kL_UEeodShpecR8QgNHKCBC1ie2WCg',
'validCreation1200' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQEEey5QMAdldoOTP_jTETHgOQriGsixEY0cziQeRfT_J5YtbI_A6AizEYD-JcxmRmXzv1xjjTgsV39Y32ta2CQkqORIGCIeGi-4FSi8KJwoglK4TW5PNnzN1K05VxBkDo_qhOnW7kL_UEeodShpecR8QgOy4CxC1ie2WCg',
'notBase64' => 'CgpIYWxsbyBXZW-0EgYIyfSG7gV_LwonCiCboKikqwjZfes9xuqgthFH3',
'validTransfer' => 'GmYKZAoggZC9pYXuXx2fv30G6B5p7BjhM3YQTP9Ut0V-t9PvcQ0SQDddHyKzAX3LBV0PuDiPc6lxkUipss5tyuLRpMtFJQnT30tsbYIkA1FXimjMKOoiuLswf4OLLV3bAIYehW-b9AgqYQoFSGFsbG8SBgiJlaPvBUJQCiYKIIGQvaWF7l8dn799BugeaewY4TN2EEz_VLdFfrfT73ENEICfSRImCiDtdleSLxhUgEbMW9DpqIwsykFj3-z_enKEOuGnXrmW8xCAn0k',
'errornusTransfer' => 'ClxGcm9oZXMgTmV1ZXMgSmFociB1bmQgREFOS0UsIGRhc3MgZHUgZGljaCBzbyBlaW5zZXR6dCBmw7xyIEdyYWRpZG8hIEhlcnpsaWNoZSBHcsO8w59lIFRlcmVzYRIGCPjjgvEFQlAKJgogUQwFYeVlGlfWDrkXNN7rHwejoCDJKt+YkYJfbJVyj3EQwIQ9EiYKIPXIRnUhVJ/zCs5+y/VaTBjTIoYizJNwS+JC//xsbQrHEMCEPQ=='
];
/*public function setUp() {
parent::setUp();
}
*/
public function testWrongMethod()
{
$this->configRequest([
'headers' => ['Accept' => 'application/json']
]);
$this->get('/TransactionJsonRequestHandler');
$this->assertResponseOk();
$expected = json_encode(['state' => 'error', 'msg' => 'no post']);
$this->assertEquals($expected, (string)$this->_response->getBody());
}
public function testInvalidJson()
{
$this->configRequest([
'headers' => ['Accept' => 'application/json']
]);
$this->post('/TransactionJsonRequestHandler', '{This isn\'t valid json}');
$this->assertResponseOk();
$expected = json_encode(['state' => 'error', 'msg' => 'parameter error']);
$this->assertEquals($expected, (string)$this->_response->getBody());
}
public function testNotSetTransaction()
{
$this->postAndParse(
['method' => 'putTransaction'],
['state' => 'error', 'msg' => 'parameter error']
);
}
public function testNotSetMethod()
{
$this->postAndParse(
['transaction' => $this->transactions['validCreation']],
['state' => 'error', 'msg' => 'parameter error']
);
}
public function testUnknownMethod()
{
//$this->post('/TransactionJsonRequestHandler', ['method' => 'putTransaction', 'transaction' => 'CgpIYWxsbyBXZWx0EgYIyfSG7gVKLwonCiCboKikqwjZfes9xuqgthFH3/cHHaWchkUhWiGhQjB23xCg2pMBELWJ7ZYK']);
$this->postAndParse(
['method' => 'foobar', 'transaction' => $this->transactions['validCreation']],
['state' => 'error', 'msg' => 'unknown method', 'details' => 'foobar']
);
}
public function testInvalidEncodedTransaction() {
//"msg":"error parsing transaction","details":[{"Transaction":"base64 decode error"}]
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['notBase64']],
['state' => 'error', 'msg' => 'error parsing transaction', 'details' => [
['Transaction' => 'invalid base64 string']
]]
);
}
public function testInvalidTransaction() {
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => base64_encode('Hallo Miau Welt')],
['state' => 'error', 'msg' => 'error parsing transaction', 'details' => [
['Transaction' => 'Error occurred during parsing: Unexpected wire type.']
]]
);
}
public function testToLargeCreationSum()
{
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation900']],
'{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1000 gr per Month not allowed"}]}'
);
}
public function testToLargeCreation()
{
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation1200']],
'{"state":"error","msg":"error validate transaction","details":[{"TransactionCreation::validate":"Creation more than 1000 gr per Month not allowed"}]}'
);
}
public function testValidTransfer()
{
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['validTransfer']],
['state' => 'success']
);
}
/*public function testMissingPreviousTransaction()
{
}*/
public function testValidTransaction()
{
$this->postAndParse(
['method' => 'putTransaction', 'transaction' => $this->transactions['validCreation']],
['state' => 'success']
);
}
private function postAndParse($params, $expected)
{
$this->configRequest([
'headers' => ['Accept' => 'application/json']
]);
$this->disableErrorHandlerMiddleware();
$this->post('/TransactionJsonRequestHandler', json_encode($params));
// Check that the response was a 200
$this->assertResponseOk();
$responseBodyString = (string)$this->_response->getBody();
$json = json_decode($responseBodyString);
$this->assertNotFalse($json);
if(is_array($expected)) {
$expected = json_encode($expected);
}
$this->assertEquals($expected, $responseBodyString);
}
}

View File

@ -1,51 +0,0 @@
<?php
namespace App\Test\TestCase\Model\Entity;
use App\Model\Entity\Table;
use Cake\TestSuite\TestCase;
/**
* App\Model\Entity\Table Test Case
*/
class TableTest extends TestCase
{
/**
* Test subject
*
* @var \App\Model\Entity\Table
*/
public $Table;
/**
* setUp method
*
* @return void
*/
public function setUp()
{
parent::setUp();
$this->Table = new Table();
}
/**
* tearDown method
*
* @return void
*/
public function tearDown()
{
unset($this->Table);
parent::tearDown();
}
/**
* Test initial setup
*
* @return void
*/
public function testInitialization()
{
$this->markTestIncomplete('Not implemented yet.');
}
}

View File

@ -30,84 +30,12 @@ class TransactionCreationTest extends TestCase
parent::setUp();
}
public function testHashingFunction()
public function testDummy()
{
$pairs = [
"a" => 97,
"b" => 98,
"c" => 99,
"d" => 100,
"aa" => 12513,
"ab" => 12514,
"@" => 64,
".d" => 5988,
"gmx" => 1701624,
"@gmx" => 135919352,
"@gmx.de" => 3742152099,
"***REMOVED***" => 2928827813,
"***REMOVED***" => 1899591683,
"***REMOVED***" => 2089074830,
"maximilian.muster@gradido.net" => 793144931,
"coin-info5@gradido.net" => 1829129963,
"coin-info6@gradido.net" => 1830178539,
"coin-info8@gradido.net" => 1832275691,
"coin-info9@gradido.net" => 1833324267,
"coin-info10@gradido.net" => 3877298078,
"coin-info11@gradido.net" => 3878346654,
"coin-info12@gradido.net" => 3879395230,
"***REMOVED***" => 2089074830,
"***REMOVED***" => 3996757473,
"***REMOVED***" => 3788634614,
"***REMOVED***" => 807797884,
"***REMOVED***" => 1640973721,
"***REMOVED***" => 2025729173,
"***REMOVED***" => 1961122507,
"***REMOVED***" => 362466358,
"***REMOVED***" => 3796728871,
"***REMOVED***" => 807797884,
"***REMOVED***" => 3794905967,
"***REMOVED***" => 3077694284,
"***REMOVED***" => 3246159770,
"***REMOVED***" => 3123402690,
"testneu-11-12-3@gradido.net" => 4092403827,
"***REMOVED***" => 3151414199,
"***REMOVED***" => 3526188273,
"***REMOVED***" => 966804823,
"***REMOVED***" => 1309273258,
"***REMOVED***" => 995978784,
"***REMOVED***" => 310113324,
"***REMOVED***" => 1309273258,
"***REMOVED***" => 530108573,
"***REMOVED***" => 1734855679,
"***REMOVED***" => 767779182,
"***REMOVED***" => 2247491519,
"***REMOVED***" => 3248626267,
"***REMOVED***" => 3516649930,
"***REMOVED***" => 231214190,
"***REMOVED***" => 4247461928,
"***REMOVED***" => 324829839,
"***REMOVED***" => 3046147747,
"***REMOVED***" => 3207307415,
"***REMOVED***" => 728893500,
"***REMOVED***" => 3905254663,
"***REMOVED***" => 3207307415,
"***REMOVED***" => 1155733239,
"***REMOVED***" => 2013046423,
"***REMOVED***" => 4033835283,
"***REMOVED***" => 1945541625,
"***REMOVED***" => 2310715309,
"***REMOVED***" => 1221362064,
"***REMOVED***" => 4161339877
];
foreach($pairs as $email => $cpp_hash) {
$php_hash = TransactionCreation::DRMakeStringHash($email);
// assertEquals(mixed $expected, mixed $actual[, string $message = ''])
if($php_hash != $cpp_hash) {
$this->assertEquals($cpp_hash, $php_hash, "hashes for $email don't match");
}
}
$this->assertEquals(true, true);
}
}

View File

@ -0,0 +1,57 @@
HTTPServer.port = 1200
JSONServer.port = 1201
Gradido.group_id = 1
crypto.server_admin_public = f909a866baec97c5460b8d7a93b72d3d4d20cc45d9f15d78bd83944eb9286b7f
crypto.server_key = a51ef8ac7ef1abf162fb7a65261acd7a
# TODO auto-generate in docker build step
crypto.app_secret = 21ffbbc616fe
# Server admin Passphrase
# nerve execute merit pool talk hockey basic win cargo spin disagree ethics swear price purchase say clutch decrease slow half forest reform cheese able
#
phpServer.url = http://localhost/
phpServer.host = nginx
loginServer.path = http://localhost/account
loginServer.default_locale = de
loginServer.db.host = mariadb
loginServer.db.name = gradido_login_test
loginServer.db.user = root
loginServer.db.password =
loginServer.db.port = 3306
frontend.checkEmailPath = http://localhost/reset
email.disable = true
#email.username =
#email.sender =
#email.admin_receiver =
#email.password =
#email.smtp.url =
#email.smtp.port =
# binary is default, for debugging also json is possible
#hedera.consensus.message_format = json
# TESTNET or MAINNET, TESTNET is default
hedera.nettype = TESTNET
# server setup types: test, staging or production
ServerSetupType=test
dev.default_group = docker
# Session timeout in minutes
#
session.timeout = 15
# Disabling security features for faster develop and testing
unsecure.allow_passwort_via_json_request = 1
unsecure.allow_auto_sign_transactions = 1
unsecure.allow_cors_all = 1
# default disable, passwords must contain a number, a lower character, a high character, special character, and be at least 8 characters long
unsecure.allow_all_passwords = 1

View File

@ -38,7 +38,7 @@ services:
- ./login_server/dependencies:/code/dependencies
- ./login_server/scripts:/code/scripts
- ./configs/login_server:/etc/grd_login
- login_build_3:/code/build
- login_build_3.1:/code/build
#########################################################
@ -47,11 +47,8 @@ services:
community-server:
build:
context: .
target: community_server
dockerfile: ./community_server/Dockerfile
environment:
- DB_PASSWORD=''
- DB_USER='root'
- DB_DATABASE='gradido_community'
depends_on:
- mariadb
networks:
@ -103,4 +100,4 @@ services:
volumes:
frontend_node_modules:
login_build_3:
login_build_3.1:

99
docker-compose.test.yml Normal file
View File

@ -0,0 +1,99 @@
version: "3.4"
services:
#########################################################
## MARIADB ##############################################
#########################################################
mariadb:
build:
context: .
dockerfile: ./mariadb/Dockerfile
target: mariadb_server_test
environment:
- MARIADB_ALLOW_EMPTY_PASSWORD=1
- MARIADB_USER=root
networks:
- internal-net
ports:
- 3306:3306
volumes:
- db_test_vol:/var/lib/mysql
#########################################################
## LOGIN SERVER #########################################
#########################################################
login-server:
build:
context: ./login_server/
target: test
security_opt:
- seccomp:unconfined
cap_add:
- SYS_PTRACE
depends_on:
- mariadb
networks:
- internal-net
volumes:
- ./logs:/var/log/grd_login
- ./login_server/src:/code/src
- ./configs/login_server:/etc/grd_login
- login_build_cov:/code/build_cov
- ./coverage/login:/code/build_cov/coverage_html
#########################################################
## COMMUNITY SERVER (cakephp with php-fpm) ##############
#########################################################
community-server:
build:
context: .
target: test
dockerfile: ./community_server/Dockerfile
depends_on:
- mariadb
networks:
- internal-net
volumes:
- ./community_server/config/php-fpm/php-ini-overrides.ini:/etc/php/7.4/fpm/conf.d/99-overrides.ini
- ./community_server/src:/var/www/cakephp/src
- ./coverage/community:/var/www/cakephp/webroot/coverage
#########################################################
## PHPMYADMIN ###########################################
#########################################################
phpmyadmin:
image: phpmyadmin
environment:
- PMA_ARBITRARY=1
#restart: always
ports:
- 8074:80
networks:
- internal-net
- external-net
volumes:
- /sessions
#########################################################
## skeema for updating dbs if changes happend ###########
#########################################################
skeema:
build:
context: .
dockerfile: ./skeema/Dockerfile
target: skeema_run
depends_on:
- mariadb
networks:
- internal-net
networks:
external-net:
internal-net:
internal: true
volumes:
db_test_vol:
login_build_cov:

View File

@ -38,7 +38,7 @@ services:
build:
context: .
dockerfile: ./mariadb/Dockerfile
target: mariadb_server
target: mariadb_server_test
environment:
- MARIADB_ALLOW_EMPTY_PASSWORD=1
- MARIADB_USER=root
@ -47,7 +47,7 @@ services:
ports:
- 3306:3306
volumes:
- db_vol:/var/lib/mysql
- db_vol:/var/lib/mysql
#########################################################
## LOGIN SERVER #########################################
@ -80,6 +80,7 @@ services:
depends_on:
- community-server
- login-server
- frontend
ports:
- 80:80
@ -89,6 +90,7 @@ services:
community-server:
build:
context: .
target: community_server
dockerfile: ./community_server/Dockerfile
environment:
- DB_PASSWORD=''

View File

@ -89,6 +89,56 @@ In case of success returns:
nginx was wrong configured.
- `session_id`: can be also negative
## Check username
### Request
`GET http://localhost/login_api/checkUsername?username=<username>&group_id=<group_id>`
`POST http://localhost/login_api/checkUsername`
with
```json
{
"username": "Maxilein",
"group_id": 1,
"group_alias": "gdd1"
}
```
group_id or group_alias, one of both is enough.
group_id is better, because one db request less
### Response
If username is not already taken
```json
{
"state":"success"
}
```
If username is already taken
```json
{
"state":"warning",
"msg":"username already in use"
}
```
If only group_alias was given and group with that alias was found in db
```json
{
"state":"success",
"group_id": 1
}
```
If group_id or group_alias unknown
```json
{
"state":"error",
"msg": "unknown group"
}
```
## Create user
Register a new User

View File

@ -35,7 +35,7 @@ const communityAPI = {
balance: async (sessionId) => {
return apiGet(CONFIG.COMMUNITY_API_URL + 'getBalance/' + sessionId)
},
transactions: async (sessionId, firstPage = 1, items = 1000, order = 'DESC') => {
transactions: async (sessionId, firstPage = 1, items = 5, order = 'DESC') => {
return apiGet(
`${CONFIG.COMMUNITY_API_URL}listTransactions/${firstPage}/${items}/${order}/${sessionId}`,
)

View File

@ -78,6 +78,27 @@ const loginAPI = {
CONFIG.LOGIN_API_URL + 'loginViaEmailVerificationCode?emailVerificationCode=' + optin,
)
},
getUserInfos: async (sessionId, email) => {
const payload = {
session_id: sessionId,
email: email,
ask: ['user.first_name', 'user.last_name'],
}
return apiPost(CONFIG.LOGIN_API_URL + 'getUserInfos', payload)
},
updateUserInfos: async (sessionId, email, data) => {
const payload = {
session_id: sessionId,
email,
update: {
'User.first_name': data.firstName,
'User.last_name': data.lastName,
'User.description': data.description,
},
}
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
},
changePassword: async (sessionId, email, password) => {
const payload = {
session_id: sessionId,
@ -88,6 +109,27 @@ const loginAPI = {
}
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
},
changePasswordProfile: async (sessionId, email, password, passwordNew) => {
const payload = {
session_id: sessionId,
email,
update: {
'User.password': password,
'User.passwordNew': passwordNew,
},
}
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
},
changeUsernameProfile: async (sessionId, email, usernameNew) => {
const payload = {
session_id: sessionId,
email,
update: {
'User.usernameNew': usernameNew,
},
}
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
},
updateLanguage: async (sessionId, email, language) => {
const payload = {
session_id: sessionId,

View File

@ -0,0 +1,53 @@
import { mount } from '@vue/test-utils'
import PaginationButtons from './PaginationButtons'
const localVue = global.localVue
describe('PaginationButtons', () => {
let wrapper
const Wrapper = () => {
return mount(PaginationButtons, { localVue })
}
describe('mount', () => {
beforeEach(() => {
wrapper = Wrapper()
})
it('renders the component', () => {
expect(wrapper.find('div.pagination-buttons').exists()).toBeTruthy()
})
it('has previous page button disabled by default', () => {
expect(wrapper.find('button.previous-page').attributes('disabled')).toBe('disabled')
})
it('has bext page button disabled by default', () => {
expect(wrapper.find('button.next-page').attributes('disabled')).toBe('disabled')
})
it('shows the text "1 / 1" by default"', () => {
expect(wrapper.find('p.text-center').text()).toBe('1 / 1')
})
describe('with active buttons', () => {
beforeEach(async () => {
await wrapper.setProps({
hasNext: true,
hasPrevious: true,
})
})
it('emits show-previous when previous page button is clicked', () => {
wrapper.find('button.previous-page').trigger('click')
expect(wrapper.emitted('show-previous')).toBeTruthy()
})
it('emits show-next when next page button is clicked', () => {
wrapper.find('button.next-page').trigger('click')
expect(wrapper.emitted('show-next')).toBeTruthy()
})
})
})
})

View File

@ -0,0 +1,30 @@
<template>
<div class="pagination-buttons">
<b-row class="m-4">
<b-col class="text-right">
<b-button class="previous-page" :disabled="!hasPrevious" @click="$emit('show-previous')">
<b-icon icon="chevron-left" variant="primary"></b-icon>
</b-button>
</b-col>
<b-col cols="2">
<p class="text-center pt-2">{{ currentPage }} / {{ totalPages }}</p>
</b-col>
<b-col>
<b-button class="next-page" :disabled="!hasNext" @click="$emit('show-next')">
<b-icon icon="chevron-right" variant="primary"></b-icon>
</b-button>
</b-col>
</b-row>
</div>
</template>
<script>
export default {
name: 'PaginationButtons',
props: {
hasNext: { type: Boolean, default: false },
hasPrevious: { type: Boolean, default: false },
totalPages: { type: Number, default: 1 },
currentPage: { type: Number, default: 1 },
},
}
</script>

View File

@ -20,17 +20,25 @@
},
"decay": "Vergänglichkeit",
"form": {
"cancel":"Abbrechen",
"cancel": "Abbrechen",
"reset": "Zurücksetzen",
"close":"schließen",
"close": "schließen",
"edit": "bearbeiten",
"save": "speichern",
"receiver":"Empfänger",
"sender":"Absender",
"username":"Username",
"firstname":"Vorname",
"lastname":"Nachname",
"description": "Beschreibung",
"email":"E-Mail",
"email_repeat":"eMail wiederholen",
"password":"Passwort",
"password_repeat":"Passwort wiederholen",
"password_old":"altes Passwort",
"password_new":"neues Passwort",
"password_new_repeat":"neues Passwort wiederholen",
"change": "ändern",
"amount":"Betrag",
"memo":"Nachricht für den Empfänger",
"message":"Nachricht",
@ -49,8 +57,9 @@
"send_transaction_error":"Leider konnte die Transaktion nicht ausgeführt werden!",
"validation": {
"double": "Das Feld {field} muss eine Dezimalzahl mit zwei Nachkommastellen sein",
"is-not": "Du kannst dir selbst keine Gradidos überweisen"
}
"is-not": "Du kannst Dir selbst keine Gradidos überweisen"
},
"change_username_info": "Das ändern des Usernamens bedarf mehrerer Schritte."
},
"error": {
"error":"Fehler"
@ -96,7 +105,6 @@
"add_work":"neuer Gemeinschaftsbeitrag"
},
"profil": {
"transactions":"transactions",
"activity": {
"chart":"Gemeinschaftsstunden Chart",
"new":"Neue Gemeinschaftsstunden eintragen",

View File

@ -1,7 +1,7 @@
{
"message": "hello gradido !!",
"welcome":"Welcome!",
"community": "Gemeinschaft",
"community": "Community",
"logout":"Logout",
"login":"Login",
"signup": "Sign up",
@ -23,14 +23,22 @@
"cancel":"Cancel",
"reset": "Reset",
"close":"Close",
"edit": "Edit",
"save": "save",
"receiver":"Receiver",
"sender":"Sender",
"username":"Username",
"firstname":"Firstname",
"lastname":"Lastname",
"description": "Description",
"email":"Email",
"email_repeat":"Repeat Email",
"password":"Password",
"password_repeat":"Repeat password",
"password_old":"Old password",
"password_new":"New password",
"password_new_repeat":"Repeat new password",
"change": "change",
"amount":"Amount",
"memo":"Message for the recipient",
"message":"Message",
@ -50,7 +58,8 @@
"validation": {
"double": "The {field} field must be a decimal with two digits",
"is-not": "You cannot send Gradidos to yourself"
}
},
"change_username_info": "Changing the username requires several steps."
},
"error": {
"error":"Error"

View File

@ -16,25 +16,11 @@ const routes = [
},
{
path: '/profile',
component: () => import('../views/Pages/UserProfile.vue'),
component: () => import('../views/Pages/UserProfileOverview.vue'),
meta: {
requiresAuth: true,
},
},
// {
// path: '/profileedit',
// component: () => import('../views/Pages/UserProfileEdit.vue'),
// meta: {
// requiresAuth: true,
// },
// },
// {
// path: '/activity',
// component: () => import('../views/Pages/UserProfileActivity.vue'),
// meta: {
// requiresAuth: true,
// },
// },
{
path: '/transactions',
component: () => import('../views/Pages/UserProfileTransactionList.vue'),

View File

@ -13,6 +13,18 @@ export const mutations = {
sessionId: (state, sessionId) => {
state.sessionId = sessionId
},
username: (state, username) => {
state.username = username
},
firstName: (state, firstName) => {
state.firstName = firstName
},
lastName: (state, lastName) => {
state.lastName = lastName
},
description: (state, description) => {
state.description = description
},
}
export const actions = {
@ -20,10 +32,18 @@ export const actions = {
commit('sessionId', data.sessionId)
commit('email', data.user.email)
commit('language', data.user.language)
commit('username', data.user.username)
commit('firstName', data.user.first_name)
commit('lastName', data.user.last_name)
commit('description', data.user.description)
},
logout: ({ commit, state }) => {
commit('sessionId', null)
commit('email', null)
commit('username', '')
commit('firstName', '')
commit('lastName', '')
commit('description', '')
sessionStorage.clear()
},
}
@ -39,6 +59,10 @@ export const store = new Vuex.Store({
email: '',
language: null,
modals: false,
firstName: '',
lastName: '',
username: '',
description: '',
},
getters: {},
// Syncronous mutation of the state

View File

@ -40,7 +40,7 @@ describe('Vuex store', () => {
{ commit, state },
{ sessionId: 1234, user: { email: 'someone@there.is', language: 'en' } },
)
expect(commit).toHaveBeenCalledTimes(3)
expect(commit).toHaveBeenCalledTimes(7)
})
it('commits sessionId', () => {
@ -74,7 +74,7 @@ describe('Vuex store', () => {
it('calls two commits', () => {
logout({ commit, state })
expect(commit).toHaveBeenCalledTimes(2)
expect(commit).toHaveBeenCalledTimes(6)
})
it('commits sessionId', () => {

View File

@ -78,7 +78,7 @@ describe('DashboardLayoutGdd', () => {
})
it('has five items in the navbar', () => {
expect(navbar.findAll('ul > a')).toHaveLength(2)
expect(navbar.findAll('ul > a')).toHaveLength(3)
})
it('has first item "send" in navbar', () => {
@ -103,21 +103,21 @@ describe('DashboardLayoutGdd', () => {
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/transactions')
})
// it('has tree items in the navbar', () => {
// expect(navbar.findAll('ul > li')).toHaveLength(3)
// })
//
// it('has third item "My profile" in navbar', () => {
// expect(navbar.findAll('ul > li').at(2).text()).toEqual('site.navbar.my-profil')
// })
//
// it.skip('has third item "My profile" linked to profile in navbar', async () => {
// navbar.findAll('ul > li > a').at(2).trigger('click')
// await flushPromises()
// await jest.runAllTimers()
// await flushPromises()
// expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/profile')
// })
it('has tree items in the navbar', () => {
expect(navbar.findAll('ul > a')).toHaveLength(3)
})
it('has third item "My profile" in navbar', () => {
expect(navbar.findAll('ul > a').at(2).text()).toEqual('site.navbar.my-profil')
})
it.skip('has third item "My profile" linked to profile in navbar', async () => {
navbar.findAll('ul > a').at(2).trigger('click')
await flushPromises()
await jest.runAllTimers()
await flushPromises()
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/profile')
})
// it('has fourth item "Settigs" in navbar', () => {
// expect(navbar.findAll('ul > li').at(3).text()).toEqual('site.navbar.settings')

View File

@ -1,5 +1,5 @@
<template>
<div class="wrapper">
<div>
<side-bar @logout="logout" :balance="balance" :pending="pending">
<template slot="links">
<sidebar-item
@ -14,18 +14,12 @@
path: '/transactions',
}"
></sidebar-item>
<!--
<b-nav-item href="#!" to="/profile">
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.my-profil') }}</b-nav-text>
</b-nav-item>
<b-nav-item href="#!" to="/profileedit">
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.settings') }}</b-nav-text>
</b-nav-item>
<b-nav-item href="#!" to="/activity">
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.activity') }}</b-nav-text>
</b-nav-item>
-->
<sidebar-item
:link="{
name: $t('site.navbar.my-profil'),
path: '/profile',
}"
></sidebar-item>
</template>
</side-bar>
<div class="main-content">
@ -39,6 +33,7 @@
:transactions="transactions"
:transactionCount="transactionCount"
:pending="pending"
:UserProfileTestData="UserProfileTestData"
@update-balance="updateBalance"
@update-transactions="updateTransactions"
></router-view>
@ -90,6 +85,11 @@ export default {
bookedBalance: 0,
transactionCount: 0,
pending: true,
UserProfileTestData: {
username: 'Mustermax',
desc:
'Max Mustermann seine Beschreibung. Max Mustermann seine Beschreibung. Max Mustermann seine Beschreibung. Max Mustermann seine Beschreibung. ',
},
}
},
methods: {
@ -106,9 +106,13 @@ export default {
this.$store.dispatch('logout')
this.$router.push('/login')
},
async updateTransactions() {
async updateTransactions(pagination) {
this.pending = true
const result = await communityAPI.transactions(this.$store.state.sessionId)
const result = await communityAPI.transactions(
this.$store.state.sessionId,
pagination.firstPage,
pagination.items,
)
if (result.success) {
this.GdtBalance = Number(result.result.data.gdtSum)
this.transactions = result.result.data.transactions
@ -129,7 +133,7 @@ export default {
this.initScrollbar()
},
created() {
this.updateTransactions()
this.updateTransactions({ firstPage: 1, items: 5 })
},
}
</script>

View File

@ -1,7 +1,7 @@
<template>
<base-nav
container-classes="container-fluid"
class="navbar-top navbar-expand"
class="navbar-expand"
:class="{ 'navbar-dark': type === 'default' }"
>
<!-- Navbar links -->
@ -15,7 +15,7 @@
<span class="pb-2 text-lg font-weight-bold">
{{ $store.state.email }}
</span>
<b-media-body class="ml-2 d-none d-lg-block d-md-block">
<b-media-body class="ml-2">
<span class="avatar">
<vue-qrcode :value="$store.state.email" type="image/png"></vue-qrcode>
</span>

View File

@ -1,6 +1,6 @@
<template>
<div>
<b-container fluid class="p-lg-2 mt-lg-1">
<b-container fluid>
<gdd-status
v-if="showContext"
:pending="pending"
@ -31,10 +31,10 @@
<gdd-transaction-list
v-if="showContext"
:transactions="transactions"
:max="5"
:page-size="5"
:timestamp="timestamp"
:transactionCount="transactionCount"
@update-transactions="$emit('update-transactions')"
:transaction-count="transactionCount"
@update-transactions="updateTransactions"
/>
<gdd-transaction-list-footer v-if="showContext" :count="transactionCount" />
</b-container>
@ -116,6 +116,9 @@ export default {
this.transactionData = EMPTY_TRANSACTION_DATA
this.currentTransactionStep = 0
},
updateTransactions(pagination) {
this.$emit('update-transactions', pagination)
},
},
}
</script>

View File

@ -202,16 +202,6 @@ describe('GddTransactionList', () => {
expect(transaction.findAll('div').at(3).text()).toBe('decay')
})
})
describe('max property set to 2', () => {
beforeEach(async () => {
await wrapper.setProps({ max: 2 })
})
it('shows only 2 transactions', () => {
expect(wrapper.findAll('div.gdd-transaction-list-item')).toHaveLength(2)
})
})
})
describe('with invalid transaction type', () => {
@ -234,5 +224,69 @@ describe('GddTransactionList', () => {
expect(errorHandler).toHaveBeenCalled()
})
})
describe('pagination buttons', () => {
const transactions = Array.from({ length: 42 }, (_, idx) => {
return {
balance: '3.14',
date: '2021-04-29T17:26:40+00:00',
memo: 'Kreiszahl PI',
name: 'Euklid',
transaction_id: idx + 1,
type: 'receive',
}
})
let paginationButtons
beforeEach(async () => {
await wrapper.setProps({
transactions,
transactionCount: 42,
showPagination: true,
})
paginationButtons = wrapper.find('div.pagination-buttons')
})
it('shows the pagination buttons', () => {
expect(paginationButtons.exists()).toBeTruthy()
})
it('has the previous button disabled', () => {
expect(paginationButtons.find('button.previous-page').attributes('disabled')).toBe(
'disabled',
)
})
it('shows the text "1 / 2"', () => {
expect(paginationButtons.find('p.text-center').text()).toBe('1 / 2')
})
it('emits update-transactions when next button is clicked', async () => {
paginationButtons.find('button.next-page').trigger('click')
await wrapper.vm.$nextTick()
expect(wrapper.emitted('update-transactions')[1]).toEqual([{ firstPage: 2, items: 25 }])
})
it('shows text "2 / 2" when next button is clicked', async () => {
paginationButtons.find('button.next-page').trigger('click')
await wrapper.vm.$nextTick()
expect(paginationButtons.find('p.text-center').text()).toBe('2 / 2')
})
it('has next-button disabled when next button is clicked', async () => {
paginationButtons.find('button.next-page').trigger('click')
await wrapper.vm.$nextTick()
expect(paginationButtons.find('button.next-page').attributes('disabled')).toBe('disabled')
})
it('emits update-transactions when preivous button is clicked after next buton', async () => {
paginationButtons.find('button.next-page').trigger('click')
await wrapper.vm.$nextTick()
paginationButtons.find('button.previous-page').trigger('click')
await wrapper.vm.$nextTick()
expect(wrapper.emitted('update-transactions')[2]).toEqual([{ firstPage: 1, items: 25 }])
})
})
})
})

View File

@ -2,7 +2,7 @@
<div class="gdd-transaction-list">
<b-list-group>
<b-list-group-item
v-for="item in transactions.slice(0, max)"
v-for="item in transactions"
:key="item.id"
style="background-color: #ebebeba3 !important"
>
@ -66,6 +66,15 @@
</b-card>
</b-collapse>
</b-list-group-item>
<pagination-buttons
v-if="showPagination && transactionCount > pageSize"
:has-next="hasNext"
:has-previous="hasPrevious"
:total-pages="totalPages"
:current-page="currentPage"
@show-next="showNext"
@show-previous="showPrevious"
></pagination-buttons>
<div v-if="transactions.length === 0" class="mt-4 text-center">
<span>{{ $t('transaction.nullTransactions') }}</span>
</div>
@ -74,6 +83,8 @@
</template>
<script>
import PaginationButtons from '../../../components/PaginationButtons'
const iconsByType = {
send: { icon: 'arrow-left-circle', classes: 'text-danger', operator: '-' },
receive: { icon: 'arrow-right-circle', classes: 'gradido-global-color-accent', operator: '+' },
@ -83,11 +94,20 @@ const iconsByType = {
export default {
name: 'gdd-transaction-list',
components: {
PaginationButtons,
},
data() {
return {
currentPage: 1,
}
},
props: {
transactions: { default: () => [] },
max: { type: Number, default: 1000 },
pageSize: { type: Number, default: 25 },
timestamp: { type: Number, default: 0 },
transactionCount: { type: Number, default: 0 },
showPagination: { type: Boolean, default: false },
},
watch: {
timestamp: {
@ -95,9 +115,23 @@ export default {
handler: 'updateTransactions',
},
},
computed: {
hasNext() {
return this.currentPage * this.pageSize < this.transactionCount
},
hasPrevious() {
return this.currentPage > 1
},
totalPages() {
return Math.ceil(this.transactionCount / this.pageSize)
},
},
methods: {
updateTransactions() {
this.$emit('update-transactions')
this.$emit('update-transactions', {
firstPage: this.currentPage,
items: this.pageSize,
})
},
getProperties(item) {
const type = iconsByType[item.type]
@ -112,6 +146,14 @@ export default {
throwError(msg) {
throw new Error(msg)
},
showNext() {
this.currentPage++
this.updateTransactions()
},
showPrevious() {
this.currentPage--
this.updateTransactions()
},
},
}
</script>

View File

@ -1,32 +0,0 @@
<template>
<div>
<!-- Header -->
<div class="header bg-gradient-info py-7 py-lg-3 pt-lg-2">
<b-container>
<div class="header-body text-center mb-7">
<p class="h1">GDD</p>
<p class="h4">Explorer</p>
</div>
</b-container>
<div class="separator separator-bottom separator-skew zindex-100">
<svg
x="0"
y="0"
viewBox="0 0 2560 100"
preserveAspectRatio="none"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
>
<polygon class="fill-default" points="2560 0 2560 100 0 100"></polygon>
</svg>
</div>
</div>
<!-- Page content -->
<div>
<b-card>
<b-card-body>This is some text within a card body.</b-card-body>
</b-card>
</div>
</div>
</template>

View File

@ -1,134 +0,0 @@
<template>
<card style="background-color: #ebebeba3 !important">
<b-form @submit.prevent="updateProfile">
<h6 class="heading-small text-muted mb-4">User information</h6>
<div class="pl-lg-4">
<b-row>
<b-col lg="6">
<base-input
type="text"
label="Username"
placeholder="Username"
v-model="user.username"
></base-input>
</b-col>
<b-col lg="6">
<base-input
type="email"
label="Email address"
placeholder="mike@email.com"
v-model="user.email"
></base-input>
</b-col>
</b-row>
<b-row>
<b-col lg="6">
<base-input
type="text"
label="First Name"
placeholder="First Name"
v-model="user.firstName"
></base-input>
</b-col>
<b-col lg="6">
<base-input
type="text"
label="Last Name"
placeholder="Last Name"
v-model="user.lastName"
></base-input>
</b-col>
</b-row>
</div>
<hr class="my-4" />
<!-- Address -->
<h6 class="heading-small text-muted mb-4">Contact information</h6>
<div class="pl-lg-4">
<b-row>
<b-col md="12">
<base-input
type="text"
label="Address"
placeholder="Home Address"
v-model="user.address"
></base-input>
</b-col>
</b-row>
<b-row>
<b-col lg="4">
<base-input
type="text"
label="City"
placeholder="City"
v-model="user.city"
></base-input>
</b-col>
<b-col lg="4">
<base-input
type="text"
label="Country"
placeholder="Country"
v-model="user.country"
></base-input>
</b-col>
<b-col lg="4">
<base-input
label="Postal Code"
placeholder="ZIP Code"
v-model="user.postalCode"
></base-input>
</b-col>
</b-row>
</div>
<hr class="my-4" />
<!-- Description -->
<h6 class="heading-small text-muted mb-4">About me</h6>
<div class="pl-lg-4">
<b-form-group
label="About Me"
label-class="form-control-label"
class="mb-0"
label-for="about-form-textaria"
>
<!-- <label class="form-control-label">About Me</label> -->
<b-form-textarea
rows="4"
value="A beautiful premium dashboard for BootstrapVue."
id="about-form-textaria"
placeholder="A few words about you ..."
></b-form-textarea>
</b-form-group>
</div>
</b-form>
</card>
</template>
<script>
export default {
data() {
return {
user: {
company: 'Creative Code Inc.',
username: 'michael23',
email: '',
firstName: 'Mike',
lastName: 'Andrew',
address: 'Bld Mihail Kogalniceanu, nr. 8 Bl 1, Sc 1, Ap 09',
city: 'New York',
country: 'USA',
postalCode: '',
aboutMe: `Lamborghini Mercy, Your chick she so thirsty, I'm in that two seat Lambo.`,
},
}
},
methods: {
updateProfile() {
alert('Your data: ' + JSON.stringify(this.user))
},
},
}
</script>
<style></style>

View File

@ -1,72 +0,0 @@
<template>
<div>
<!-- slot for parent component to activate the file changer -->
<div @click="launchFilePicker()">
<slot name="activator"></slot>
</div>
<!-- image input: style is set to hidden and assigned a ref so that it can be triggered -->
<input
type="file"
ref="file"
:name="uploadFieldName"
@change="onFileChange($event.target.name, $event.target.files)"
style="display: none"
/>
<!-- error dialog displays any potential errors -->
<v-dialog v-model="errorDialog" max-width="300">
<v-card>
<v-card-text class="subheading">{{ errorText }}</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn @click="errorDialog = false" flat>Got it!</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script>
export default {
name: 'avatar-uploader',
data: () => ({
errorDialog: null,
errorText: '',
uploadFieldName: 'file',
maxSize: 1024,
}),
props: {
// Use "value" here to enable compatibility with v-model
value: Object,
},
methods: {
launchFilePicker() {
this.$refs.file.click()
},
onFileChange(fieldName, file) {
const { maxSize } = this
const imageFile = file[0]
// check if user actually selected a file
if (file.length > 0) {
const size = imageFile.size / maxSize / maxSize
if (!imageFile.type.match('image.*')) {
// check whether the upload is an image
this.errorDialog = true
this.errorText = 'Please choose an image file'
} else if (size > 1) {
// check whether the size is greater than the size limit
this.errorDialog = true
this.errorText = 'Your file is too big! Please select an image under 1MB'
} else {
// Append file into FormData & turn file into image URL
const formData = new FormData()
const imageURL = URL.createObjectURL(imageFile)
formData.append(fieldName, imageFile)
// Emit FormData & image URL to the parent component
this.$emit('input', { formData, imageURL })
}
}
},
},
}
</script>
<style></style>

View File

@ -1,67 +1,41 @@
<template>
<b-card
no-body
class="card-profile"
alt="Image placeholder"
img-top
style="background-color: #ebebeba3 !important"
>
<b-row class="justify-content-center">
<b-col lg="3" class="order-lg-2">
<div class="card-profile-image">
<a href="#">
<vue-qrcode :value="$store.state.email" type="image/png"></vue-qrcode>
</a>
<b-card class="bg-transparent">
<div class="w-100 text-center">
<vue-qrcode :value="$store.state.email" type="image/png"></vue-qrcode>
</div>
<b-row>
<b-col>
<div class="card-profile-stats d-flex justify-content-center mt-md-5">
<div>
<span class="heading">
{{ $n(balance) }}
</span>
<span class="description">GDD</span>
</div>
<div>
<span class="heading">{{ transactionCount }}</span>
<span class="description">{{ $t('transactions') }}</span>
</div>
<div>
<span class="heading">--</span>
<span class="description">{{ $t('community') }}</span>
</div>
</div>
</b-col>
</b-row>
<b-card-header class="text-center border-0 pt-8 pt-md-4 pb-0 pb-md-4">
<div class="d-flex justify-content-between">
<br />
</div>
</b-card-header>
<b-card-body class="pt-0">
<b-row>
<b-col>
<div class="card-profile-stats d-flex justify-content-center mt-md-5">
<div>
<span class="heading">--</span>
<span class="description">Transactions</span>
</div>
<div>
<span class="heading">--</span>
<span class="description">Community</span>
</div>
<div>
<span class="heading">
{{ $n(balance, 'decimal') }}
</span>
<span class="description">GDD</span>
</div>
</div>
</b-col>
</b-row>
<div class="text-center">
<h5 class="h3">
{{ this.$store.state.email }}
<span class="font-weight-light"></span>
</h5>
</div>
</b-card-body>
</b-card>
</template>
<script>
import VueQrcode from 'vue-qrcode'
export default {
name: 'profilecard',
name: 'UserCard',
components: {
VueQrcode,
},
props: {
balance: { type: Number, default: 0 },
transactionCount: { type: Number, default: 0 },
},
}
</script>

View File

@ -0,0 +1,108 @@
<template>
<div class="userdata_form">
<b-card
id="userdata_form"
class="bg-transparent"
style="background-color: #ebebeba3 !important"
>
<b-container>
<b-row class="mb-4 text-right">
<b-col class="text-right">
<a href="#userdata_form" v-if="editUserdata" @click="editUserdata = !editUserdata">
<span>{{ $t('form.edit') }}</span>
</a>
<div v-else>
<a href="#userdata_form" @click="onSubmit">
<span class="mr-4 text-success display-4">{{ $t('form.save') }}</span>
</a>
<a href="#userdata_form" @click="editUserdata = !editUserdata">
<span>
<b>{{ $t('form.cancel') }}</b>
</span>
</a>
</div>
</b-col>
</b-row>
<div>
<b-row class="mb-3">
<b-col class="col-lg-3 col-md-12 col-sm-12 text-md-left text-lg-right">
<small>{{ $t('form.firstname') }}</small>
</b-col>
<b-col v-if="editUserdata" class="col-md-9 col-sm-10">
{{ form.firstName }}
</b-col>
<b-col v-else class="col-md-9 col-sm-10">
<b-input type="text" v-model="form.firstName"></b-input>
</b-col>
</b-row>
<b-row class="mb-3">
<b-col class="col-lg-3 col-md-12 col-sm-12 text-md-left text-lg-right">
<small>{{ $t('form.lastname') }}</small>
</b-col>
<b-col v-if="editUserdata" class="col-md-9 col-sm-10">
{{ form.lastName }}
</b-col>
<b-col v-else class="col-md-9 col-sm-10">
<b-input type="text" v-model="form.lastName"></b-input>
</b-col>
</b-row>
<b-row class="mb-3">
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
<small>{{ $t('form.description') }}</small>
</b-col>
<b-col v-if="editUserdata" class="col-md-9 col-sm-10">
{{ form.description }}
</b-col>
<b-col v-else class="col-md-9 col-sm-10">
<b-textarea rows="3" max-rows="6" v-model="form.description"></b-textarea>
</b-col>
</b-row>
</div>
</b-container>
</b-card>
</div>
</template>
<script>
import loginAPI from '../../../apis/loginAPI'
export default {
name: 'FormUserData',
props: {
UserProfileTestData: { type: Object },
},
data() {
return {
editUserdata: true,
sessionId: this.$store.state.sessionId,
form: {
firstName: this.$store.state.firstName,
lastName: this.$store.state.lastName,
description: this.$store.state.description,
},
}
},
methods: {
async onSubmit() {
const result = await loginAPI.updateUserInfos(
this.$store.state.sessionId,
this.$store.state.email,
{
firstName: this.form.firstName,
lastName: this.form.lastName,
description: this.form.description,
},
)
if (result.success) {
this.$store.commit('firstName', this.form.firstName)
this.$store.commit('lastName', this.form.lastName)
this.$store.commit('description', this.form.description)
this.editUserdata = true
} else {
alert(result.result.message)
}
},
},
}
</script>
<style></style>

View File

@ -0,0 +1,62 @@
<template>
<b-card id="formusermail" class="bg-transparent" style="background-color: #ebebeba3 !important">
<b-container>
<b-row class="mb-4 text-right">
<b-col class="text-right">
<a href="#formusermail" v-if="edit_email" @click="edit_email = !edit_email">
<span>E-Mail {{ $t('form.change') }}</span>
</a>
<div v-else>
<a href="#formusermail" @click="onSubmit">
<span class="mr-4 text-success display-4">{{ $t('form.save') }}</span>
</a>
<a href="#formusermail" @click="edit_email = !edit_email">
<span>
<b>{{ $t('form.cancel') }}</b>
</span>
</a>
</div>
</b-col>
</b-row>
<b-row class="mb-3">
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
<small>E-Mail</small>
</b-col>
<b-col v-if="edit_email" class="col-md-9 col-sm-10">{{ $store.state.email }}</b-col>
<b-col v-else class="col-md-9 col-sm-10">
<b-input type="text" v-model="newEmail"></b-input>
</b-col>
</b-row>
</b-container>
</b-card>
</template>
<script>
import loginAPI from '../../../apis/loginAPI'
export default {
name: 'FormUserMail',
data() {
return {
edit_email: true,
newEmail: '',
}
},
methods: {
async onSubmit() {
// console.log(this.data)
const result = await loginAPI.changeEmailProfil(
this.$store.state.sessionId,
this.email,
this.newEmail,
)
if (result.success) {
alert('changePassword success')
} else {
alert(result.result.message)
}
},
},
}
</script>
<style></style>

View File

@ -0,0 +1,95 @@
<template>
<b-card id="change_pwd" class="bg-transparent" style="background-color: #ebebeba3 !important">
<b-container>
<b-row class="mb-4 text-right">
<b-col class="text-right">
<a href="#change_pwd" v-if="edit_pwd" @click="edit_pwd = !edit_pwd">
<span>{{ $t('form.password') }} {{ $t('form.change') }}</span>
</a>
<div v-else>
<a href="#change_pwd" @click="onSubmit">
<span class="mr-4 text-success display-4">{{ $t('form.save') }}</span>
</a>
<a href="#change_pwd" @click="edit_pwd = !edit_pwd">
<span>
<b>{{ $t('form.cancel') }}</b>
</span>
</a>
</div>
</b-col>
</b-row>
<div v-if="!edit_pwd">
<b-row class="mb-3">
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
<small>{{ $t('form.password_old') }}</small>
</b-col>
<b-col class="col-md-9 col-sm-10">
<b-input
type="text"
:placeholder="$t('form.password_old')"
v-model="password"
></b-input>
</b-col>
</b-row>
<b-row class="mb-3">
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
<small>{{ $t('form.password_new') }}</small>
</b-col>
<b-col class="col-md-9 col-sm-10">
<b-input
type="text"
:placeholder="$t('form.password_new')"
v-model="passwordNew"
></b-input>
</b-col>
</b-row>
<b-row class="mb-3">
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
<small>{{ $t('form.password_new_repeat') }}</small>
</b-col>
<b-col class="col-md-9 col-sm-10">
<b-input
type="text"
:placeholder="$t('form.password_new_repeat')"
v-model="passwordNew2"
></b-input>
</b-col>
</b-row>
</div>
</b-container>
</b-card>
</template>
<script>
import loginAPI from '../../../apis/loginAPI'
export default {
name: 'FormUserPasswort',
data() {
return {
edit_pwd: true,
email: null,
password: '',
passwordNew: '',
passwordNew2: '',
}
},
methods: {
async onSubmit() {
// console.log(this.data)
const result = await loginAPI.changePasswordProfile(
this.$store.state.sessionId,
this.email,
this.password,
this.passwordNew,
)
if (result.success) {
alert('changePassword success')
} else {
alert(result.result.message)
}
},
},
}
</script>
<style></style>

View File

@ -0,0 +1,67 @@
<template>
<b-card id="formusername" class="bg-transparent" style="background-color: #ebebeba3 !important">
<b-container>
<b-row class="mb-4 text-right">
<b-col class="text-right">
<a href="#formusername" v-if="edit_username" @click="edit_username = !edit_username">
<span>{{ $t('form.username') }} {{ $t('form.change') }}</span>
</a>
<div v-else>
<a href="#formusername" @click="edit_username = !edit_username">
<span>
<b>{{ $t('form.cancel') }}</b>
</span>
</a>
</div>
</b-col>
</b-row>
<b-row class="mb-3">
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
<small>{{ $t('form.username') }}</small>
</b-col>
<b-col v-if="edit_username" class="col-md-9 col-sm-10">@{{ $store.state.username }}</b-col>
<b-col v-else class="col-md-9 col-sm-10">
<validation-observer v-slot="{ handleSubmit }" ref="formValidator">
<b-form role="form" @submit.prevent="handleSubmit(onSubmit)">
<b-form-input v-model="username" :placeholder="$store.state.username"></b-form-input>
<div>
{{ $t('form.change_username_info') }}
</div>
<div class="text-center" ref="submitButton">
<b-button type="submit" class="mt-4">
{{ $t('form.save') }}
</b-button>
</div>
</b-form>
</validation-observer>
</b-col>
</b-row>
</b-container>
</b-card>
</template>
<script>
import loginAPI from '../../../apis/loginAPI'
export default {
name: 'FormUsername',
data() {
return {
edit_username: true,
username: '',
}
},
methods: {
async onSubmit() {
// console.log(this.data)
const result = await loginAPI.changeUsernameProfile(this.username)
if (result.success) {
alert('changeUsername success')
} else {
alert(result.result.message)
}
},
},
}
</script>
<style></style>

View File

@ -1,71 +0,0 @@
<template>
<div>
<div class="header pb-7 pt-5"></div>
<b-container fluid class="mt--6">
<div class="display-4 mb-3">{{ $t('site.profil.activity.chart') }}</div>
<b-row>
<b-col>
<div class="chart">
<line-chart :height="350" :chart-data="bigLineChart.chartData"></line-chart>
</div>
</b-col>
</b-row>
<hr />
<div class="display-4 mt-6">{{ $t('site.profil.activity.new') }}</div>
<b-row>
<b-col>
<gdd-add-work-2 />
</b-col>
</b-row>
<hr />
<div class="display-4 mb-3">{{ $t('site.profil.activity.list') }}</div>
<b-row>
<b-col class="mb-5">
{{ $t('community') }}
<gdd-work-table></gdd-work-table>
</b-col>
</b-row>
</b-container>
</div>
</template>
<script>
import GddWorkTable from '../../views/Pages/AccountOverview/GddWorkTable.vue'
import GddAddWork2 from '../../views/Pages/AccountOverview/GddAddWork2.vue'
import * as chartConfigs from '@/components/Charts/config'
import LineChart from '@/components/Charts/LineChart'
export default {
components: {
GddWorkTable,
LineChart,
GddAddWork2,
},
data() {
return {
bigLineChart: {
allData: [
[0, 20, 10, 30, 15, 40, 20, 60, 60],
[0, 20, 5, 25, 10, 30, 35, 60, 40],
[0, 2, 5, 7, 10, 30, 15, 9, 10],
[0, 2, 5, 7, 10, 14, 29, 78, 120],
],
activeIndex: 0,
chartData: {
datasets: [
{
label: 'Gemeinschaftsstunden',
data: [30, 20, 10, 30, 65, 40, 20, 60, 70],
},
],
labels: ['2020 Aug', 'Sep', 'Okt', 'Nov', 'Dez', 'Jan', 'Feb', 'Mär 2021'],
},
extraOptions: chartConfigs.blueChartOptions,
},
}
},
}
</script>
<style></style>

View File

@ -1,23 +0,0 @@
<template>
<div>
<div class="header pb-8 pt-5 pt-lg-8 d-flex align-items-center profile-header"></div>
<b-container fluid class="mt--6">
<b-row>
<b-col xl="12" class="order-xl-1">
<edit-profile-form></edit-profile-form>
</b-col>
</b-row>
</b-container>
</div>
</template>
<script>
import EditProfileForm from './UserProfile/EditProfileForm.vue'
export default {
components: {
EditProfileForm,
},
}
</script>
<style></style>

View File

@ -0,0 +1,29 @@
<template>
<b-container fluid>
<user-card :balance="balance" :transactionCount="transactionCount"></user-card>
<form-user-data :UserProfileTestData="UserProfileTestData" />
<form-username />
<form-user-passwort />
</b-container>
</template>
<script>
import UserCard from './UserProfile/UserCard.vue'
import FormUserData from './UserProfile/UserCard_FormUserData.vue'
import FormUsername from './UserProfile/UserCard_FormUsername.vue'
import FormUserPasswort from './UserProfile/UserCard_FormUserPasswort.vue'
export default {
components: {
UserCard,
FormUserData,
FormUsername,
FormUserPasswort,
},
props: {
balance: { type: Number, default: 0 },
transactionCount: { type: Number, default: 0 },
UserProfileTestData: { type: Object },
},
}
</script>
<style></style>

View File

@ -1,16 +1,18 @@
<template>
<div>
<div
class="header pb-sm-1 pb-md-7 d-flex align-items-center profile-header"
style="max-height: 200px"
></div>
<gdd-transaction-list
:timestamp="timestamp"
:transactionCount="transactionCount"
:transactions="transactions"
@update-transactions="updateTransactions"
/>
<b-container fluid>
<b-row>
<b-col class="order-xl-1">
<gdd-transaction-list
:timestamp="timestamp"
:transactionCount="transactionCount"
:transactions="transactions"
:show-pagination="true"
@update-transactions="updateTransactions"
/>
</b-col>
</b-row>
</b-container>
</div>
</template>
<script>
@ -32,8 +34,8 @@ export default {
}
},
methods: {
updateTransactions() {
this.$emit('update-transactions')
updateTransactions(pagination) {
this.$emit('update-transactions', pagination)
},
},
}

View File

@ -170,6 +170,7 @@ FILE(GLOB TEST_CRYPTO "src/cpp/test/crypto/*.cpp" "src/cpp/test/crypto/*.h")
FILE(GLOB TEST_MODEL "src/cpp/test/model/*.cpp" "src/cpp/test/model/*.h")
FILE(GLOB TEST_MODEL_TABLE "src/cpp/test/model/table/*.cpp" "src/cpp/test/model/table/*.h")
FILE(GLOB TEST_CONTROLLER "src/cpp/test/controller/*.cpp" "src/cpp/test/controller/*.h")
FILE(GLOB TEST_JSON_INTERFACE "src/cpp/test/JSONInterface/*.cpp" "src/cpp/test/JSONInterface/*.h")
SET(LOCAL_SRCS
${CONTROLLER} ${TINF} ${MAIN} ${HTTPInterface} ${COMPILED_PAGES}
@ -179,7 +180,7 @@ SET(LOCAL_SRCS
${PROTO_GRADIDO}
)
SET(LOCAL_TEST_SRC
${TEST} ${TEST_CRYPTO} ${TEST_MODEL} ${TEST_MODEL_TABLE} ${TEST_CONTROLLER}
${TEST} ${TEST_CRYPTO} ${TEST_MODEL} ${TEST_MODEL_TABLE} ${TEST_CONTROLLER} ${TEST_JSON_INTERFACE}
)
aux_source_directory("src/cpp" LOCAL_SRCS)
@ -204,6 +205,7 @@ if(MSVC)
source_group("Test\\model\\table" FILES ${TEST_MODEL_TABLE})
source_group("Test\\model" FILES ${TEST_MODEL})
source_group("Test\\controller" FILES ${TEST_CONTROLLER})
source_group("Test\\Json-Interface" FILES ${TEST_JSON_INTERFACE})
source_group("Test" FILES ${TEST})
endif()
@ -274,12 +276,66 @@ install(DIRECTORY src/LOCALE DESTINATION /etc/grd_login/
endif(UNIX)
# ---------------------- Test -----------------------------------------
enable_testing()
# ---------------------- Test -----------------------------------------
#project(Gradido_LoginServer_Test C CXX)
option(COLLECT_COVERAGE_DATA "Use cov to collect coverage informations" OFF)
set(COVERAGE_TOOL "Coverage Tool (gcovr|lcov|fastcov)" CACHE STRING "gcovr")
if(COLLECT_COVERAGE_DATA)
include(cmake/CodeCoverage.cmake)
append_coverage_compiler_flags()
set(EXCLUDE_FOR_HTML_COV
"${CMAKE_CURRENT_SOURCE_DIR}/build/proto/*"
"${CMAKE_CURRENT_SOURCE_DIR}/dependencies/*"
"${CMAKE_CURRENT_SOURCE_DIR}/src/cpp/test/*"
"${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest/include/gtest/internal/*"
"${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest/src/"
)
if("${COVERAGE_TOOL}" STREQUAL "gcovr")
setup_target_for_coverage_gcovr_html(
NAME coverage
EXECUTABLE Gradido_LoginServer_Test
EXCLUDE ${EXCLUDE_FOR_HTML_COV}
GCOVR_ADDITIONAL_ARGS "--txt "
#DEPENDENCIES lib/libmariadb.so.3
)
endif()
set(EXCLUDE_FOR_COV
${EXCLUDE_FOR_HTML_COV}
"/usr/include/*"
)
if("${COVERAGE_TOOL}" STREQUAL "lcov")
setup_target_for_coverage_lcov(
NAME coverage
EXECUTABLE Gradido_LoginServer_Test
EXCLUDE "${EXCLUDE_FOR_COV}"
#DEPENDENCIES lib/libmariadb.so.3
)
endif()
if("${COVERAGE_TOOL}" STREQUAL "fastcov")
setup_target_for_coverage_fastcov(
NAME coverage # New target name
EXECUTABLE Gradido_LoginServer_Test -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
#BASE_DIRECTORY "../" # Base directory for report
# (defaults to PROJECT_SOURCE_DIR)
EXCLUDE "${EXCLUDE_FOR_COV}" # Patterns to exclude.
NO_DEMANGLE # Don't demangle C++ symbols
# even if c++filt is found
SKIP_HTML # Don't create html report
)
endif()
endif()
project(Gradido_LoginServer_Test C CXX)
#_TEST_BUILD
#find_package(gtest)
#find_package(GTest CONFIG REQUIRED)
#add_subdirectory("dependencies/protobuf/third_party/googletest")
add_executable(Gradido_LoginServer_Test ${LOCAL_SRCS} ${LOCAL_TEST_SRC})
target_compile_definitions(Gradido_LoginServer_Test PUBLIC "_TEST_BUILD")
@ -287,12 +343,12 @@ target_compile_definitions(Gradido_LoginServer_Test PUBLIC "_TEST_BUILD")
target_link_libraries(Gradido_LoginServer_Test ${GRPC_LIBS} )
if(WIN32)
target_link_libraries(Gradido_LoginServer_Test ${CONAN_LIBS} )
target_link_libraries(Gradido_LoginServer_Test ${CONAN_LIBS} libmariadb libprotobuf)
#TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test optimized ${MYSQL_LIBRARIES} Shlwapi)
#TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi)
#TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${GRPC_LIBS} ${PROTOBUF_DEBUG_LIBS})
else()
target_link_libraries(Gradido_LoginServer_Test ${POCO_LIBS} libmariadb sodium)
target_link_libraries(Gradido_LoginServer_Test ${POCO_LIBS} libmariadb sodium gtest)
endif()
add_test(NAME main COMMAND Gradido_LoginServer_Test)

View File

@ -30,22 +30,16 @@ include_directories(
find_package(Protobuf REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
FIND_PACKAGE(gRPC CONFIG REQUIRED)
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin)
set(PROTOBUF_LIBS protobuf::libprotobuf protobuf::libprotobuf-lite protobuf::libprotoc)
############################## parse proto files ###################################
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/proto GRADIDO_PROTO_MODEL_PATH)
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/proto/hedera/hedera-protobuf/src/main/proto HEDERA_PROTO_MODEL_PATH)
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/proto PROTOBINDING_PATH)
file(MAKE_DIRECTORY ${PROTOBINDING_PATH})
file(MAKE_DIRECTORY ${PROTOBINDING_PATH}/gradido)
file(MAKE_DIRECTORY ${PROTOBINDING_PATH}/hedera)
FILE(GLOB DATAMODEL_GRADIDO_PROTOS "${GRADIDO_PROTO_MODEL_PATH}/gradido/*.proto")
FILE(GLOB DATAMODEL_HEDERA_PROTOS "${HEDERA_PROTO_MODEL_PATH}/*.proto")
FOREACH(proto ${DATAMODEL_GRADIDO_PROTOS})
FILE(TO_NATIVE_PATH ${proto} proto_native)
@ -71,31 +65,6 @@ FOREACH(proto ${DATAMODEL_GRADIDO_PROTOS})
ENDFOREACH(proto)
FOREACH(proto ${DATAMODEL_HEDERA_PROTOS})
FILE(TO_NATIVE_PATH ${proto} proto_native)
get_filename_component(proto_parsed ${proto} NAME_WLE)
FILE(TO_NATIVE_PATH ${PROTOBINDING_PATH}/hedera/${proto_parsed}.pb.h proto_parsed_native)
IF(${proto_native} IS_NEWER_THAN ${proto_parsed_native})
EXECUTE_PROCESS(
COMMAND
${PROTOBUF_PROTOC_EXECUTABLE}
--plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
--proto_path=${HEDERA_PROTO_MODEL_PATH}
--proto_path=${GOOGLE_PROTOBUF_INCLUDES}
--cpp_out=${PROTOBINDING_PATH}/hedera
--grpc_out ${PROTOBINDING_PATH}/hedera
${proto_native}
RESULT_VARIABLE rv
)
# Optional, but that can show the user if something have gone wrong with the proto generation
IF(${rv})
MESSAGE("Generation of data model returned ${rv} for proto ${proto_native}")
ELSE()
MESSAGE("Parsed: src/proto/hedera/hedera-protobuf/src/main/proto/${proto_parsed}.proto")
ENDIF()
ENDIF()
ENDFOREACH(proto)
############################## parse cpsp Files ####################################
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/cpsp GRADIDO_CPSP_PAGE_SRC_PATH)
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/http_pages GRADIDO_HTTP_PAGES_PATH)
@ -153,7 +122,6 @@ FILE(GLOB CRYPTO "src/cpp/Crypto/*.h" "src/cpp/Crypto/*.cpp")
FILE(GLOB MAIN "src/cpp/*.cpp" "src/cpp/*.c" "src/cpp/*.h")
FILE(GLOB MYSQL "src/cpp/MySQL/*.cpp" "src/cpp/MySQL/*.h" "src/cpp/MySQL/Poco/*.h")
FILE(GLOB PROTO_GRADIDO "${PROTOBINDING_PATH}/gradido/*.cc" "${PROTOBINDING_PATH}/gradido/*.h")
FILE(GLOB PROTO_HEDERA "${PROTOBINDING_PATH}/hedera/*.cc" "${PROTOBINDING_PATH}/hedera/*.h")
# used only for test project
FILE(GLOB TEST "src/cpp/test/*.cpp" "src/cpp/test/*.h")
@ -204,5 +172,83 @@ set(POCO_LIBS ${POCO_FOUNDATION_LIB} ${POCO_UTIL_LIB} ${POCO_NET_SSL_LIB} ${POCO
############################## build login server ###################################
target_link_libraries(Gradido_LoginServer gRPC::grpc++ ${PROTOBUF_LIBS} ${MYSQL_LIBRARIES} ${POCO_LIBS} sodium pthread)
target_link_libraries(Gradido_LoginServer ${PROTOBUF_LIBS} ${MYSQL_LIBRARIES} ${POCO_LIBS} sodium pthread)
############################## build login server test ###################################
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
project(Gradido_LoginServer_Test C CXX)
enable_testing()
option(COLLECT_COVERAGE_DATA "Use cov to collect coverage informations" OFF)
set(COVERAGE_TOOL "Coverage Tool (gcovr|lcov|fastcov)" CACHE STRING "gcovr")
if(COLLECT_COVERAGE_DATA)
include(cmake/CodeCoverage.cmake)
append_coverage_compiler_flags()
set(EXCLUDE_FOR_HTML_COV
"${CMAKE_CURRENT_SOURCE_DIR}/build/proto/*"
"${CMAKE_CURRENT_SOURCE_DIR}/dependencies/*"
"${CMAKE_CURRENT_SOURCE_DIR}/src/cpp/test/*"
"${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest/include/gtest/internal/*"
"${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest/src/"
)
if("${COVERAGE_TOOL}" STREQUAL "gcovr")
setup_target_for_coverage_gcovr_html(
NAME coverage
EXECUTABLE Gradido_LoginServer_Test
EXCLUDE ${EXCLUDE_FOR_HTML_COV}
GCOVR_ADDITIONAL_ARGS "--txt "
#DEPENDENCIES lib/libmariadb.so.3
)
endif()
set(EXCLUDE_FOR_COV
${EXCLUDE_FOR_HTML_COV}
"/usr/include/*"
)
if("${COVERAGE_TOOL}" STREQUAL "lcov")
setup_target_for_coverage_lcov(
NAME coverage
EXECUTABLE Gradido_LoginServer_Test
EXCLUDE "${EXCLUDE_FOR_COV}"
#DEPENDENCIES lib/libmariadb.so.3
)
endif()
if("${COVERAGE_TOOL}" STREQUAL "fastcov")
setup_target_for_coverage_fastcov(
NAME coverage # New target name
EXECUTABLE Gradido_LoginServer_Test -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
#BASE_DIRECTORY "coverage" # Base directory for report
# (defaults to PROJECT_SOURCE_DIR)
EXCLUDE "${EXCLUDE_FOR_COV}" # Patterns to exclude.
NO_DEMANGLE # Don't demangle C++ symbols
# even if c++filt is found
SKIP_HTML # Don't create html report
)
endif()
endif()
#_TEST_BUILD
add_subdirectory("googletest")
add_executable(Gradido_LoginServer_Test ${LOCAL_SRCS} ${LOCAL_TEST_SRC})
target_compile_definitions(Gradido_LoginServer_Test PUBLIC "_TEST_BUILD")
target_link_libraries(Gradido_LoginServer_Test ${GRPC_LIBS} )
if(WIN32)
target_link_libraries(Gradido_LoginServer_Test ${CONAN_LIBS} )
#TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test optimized ${MYSQL_LIBRARIES} Shlwapi)
#TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${COMPILED_MARIADB_CLIENT_DEBUG} Shlwapi)
#TARGET_LINK_LIBRARIES(Gradido_LoginServer_Test debug ${GRPC_LIBS} ${PROTOBUF_DEBUG_LIBS})
else()
target_link_libraries(Gradido_LoginServer_Test ${PROTOBUF_LIBS} ${MYSQL_LIBRARIES} ${POCO_LIBS} sodium pthread gtest)
endif()
add_test(NAME main COMMAND Gradido_LoginServer_Test)
ENDIF()

View File

@ -1,13 +1,96 @@
#########################################################################################################
# Prepare debug
#########################################################################################################
FROM gradido/login_dependencies:gcc9-debug-3 as prepare_debug
ENV DOCKER_WORKDIR="/code"
WORKDIR ${DOCKER_WORKDIR}
RUN echo '/usr/local/lib' >> /etc/ld.so.conf && ldconfig
COPY ./CMakeLists.txt.lib ./CMakeLists.txt
RUN ln -s /usr/local/googletest ./googletest
COPY ./src ./src
COPY ./cmake/CodeCoverage.cmake ./cmake/CodeCoverage.cmake
COPY ./dependencies/cmake-modules ./dependencies/cmake-modules
COPY ./dependencies/spirit-po ./dependencies/spirit-po
COPY ./dependencies/tinf ./dependencies/tinf
COPY ./scripts ./scripts
#########################################################################################################
# Install Coverage tool
#########################################################################################################
FROM prepare_debug as coverage
RUN apt-get update && \
apt-get install -y --no-install-recommends python3-pip && \
apt-get autoclean && \
apt-get autoremove && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN pip3 install gcovr setuptools wheel && \
pip3 install fastcov
#########################################################################################################
# Build test
#########################################################################################################
FROM coverage as test
ENV DOCKER_WORKDIR="/code"
WORKDIR ${DOCKER_WORKDIR}
RUN if [ ! -d "./build_cov" ] ; then mkdir build_cov; fi
RUN cd build_cov && \
cmake -DCMAKE_BUILD_TYPE=Debug -DCOLLECT_COVERAGE_DATA=ON -DCOVERAGE_TOOL=fastcov ..
#make -j$(nproc) Gradido_LoginServer_Test
#RUN chmod +x build_cov/bin/Gradido_LoginServer_Test
#CMD gdb -ex run ./build_cov/bin/Gradido_LoginServer_Test
#CMD ./build_cov/bin/Gradido_LoginServer_Test
#ENTRYPOINT make -C build_cov coverage
CMD cd build_cov && make -j$(nproc) Gradido_LoginServer_Test && make coverage && \
if [ ! -d "./coverage" ] ; then mkdir coverage; fi && \
cp coverage.info ./coverage/
#########################################################################################################
# Build debug
#########################################################################################################
FROM prepare_debug as debug
ENV DOCKER_WORKDIR="/code"
WORKDIR ${DOCKER_WORKDIR}
RUN mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Debug .. && \
make -j$(nproc) Gradido_LoginServer
RUN cd scripts && \
chmod +x compile_pot.sh && \
./compile_pot.sh
RUN chmod +x build/bin/Gradido_LoginServer
ENTRYPOINT ["build/bin/Gradido_LoginServer"]
#########################################################################################################
# Build release
#########################################################################################################
FROM gradido/login_dependencies:alpine-release-1 as release
FROM gradido/login_dependencies:alpine-release-3 as release
ENV DOCKER_WORKDIR="/code"
WORKDIR ${DOCKER_WORKDIR}
COPY ./CMakeLists.txt.lib ./CMakeLists.txt
COPY ./src ./src
RUN ln -s /usr/local/googletest ./googletest
COPY ./dependencies/cmake-modules ./dependencies/cmake-modules
COPY ./dependencies/spirit-po ./dependencies/spirit-po
COPY ./dependencies/tinf ./dependencies/tinf
@ -35,10 +118,11 @@ WORKDIR "/usr/bin"
COPY --from=release /code/build/bin/Gradido_LoginServer /usr/bin/
COPY --from=release /usr/local/lib/mariadb/libmariadb.so.3 /usr/local/lib/
COPY --from=release /usr/local/lib/libPoco* /usr/local/lib/
COPY --from=release /usr/lib/libsodium.so.23 /usr/lib/
COPY --from=release /usr/lib/libstdc++.so.6 /usr/lib/
COPY --from=release /usr/lib/libgcc_s.so.1 /usr/lib/
COPY --from=release /usr/local/lib/libPoco* /usr/local/lib/
COPY --from=release /usr/local/lib/libproto* /usr/local/lib/
COPY --from=release /usr/lib/libsodium.so.23 /usr/lib/
COPY --from=release /usr/lib/libstdc++.so.6 /usr/lib/
COPY --from=release /usr/lib/libgcc_s.so.1 /usr/lib/
RUN chmod +x /usr/bin/Gradido_LoginServer

View File

@ -1,4 +1,4 @@
FROM gradido/login_dependencies:alpine-debug-1 as login_server_alpine_debug
FROM gradido/login_dependencies:alpine-debug-3 as login_server_alpine_debug
ENV DOCKER_WORKDIR="/code"
@ -9,6 +9,8 @@ WORKDIR ${DOCKER_WORKDIR}
COPY ./CMakeLists.txt.lib ./CMakeLists.txt
COPY ./scripts ./scripts
COPY ./cmake ./cmake
RUN ln -s /usr/local/googletest ./googletest
CMD cd scripts; ./build_debug.sh; cd ..; ./build/bin/Gradido_LoginServer

View File

@ -1,60 +0,0 @@
#########################################################################################################
# cmake
#########################################################################################################
FROM gcc:9 as cmake-gcc-9
ENV DOCKER_WORKDIR="/code"
RUN mkdir -p ${DOCKER_WORKDIR}
WORKDIR ${DOCKER_WORKDIR}
USER root
RUN git clone https://github.com/Kitware/CMake.git --branch=v3.19.8 \
&& cd CMake \
&& ./bootstrap \
&& make -j$(nproc) \
&& make install
#########################################################################################################
# Build debug
#########################################################################################################
From gradido/login_dependencies:stage2 as debug
ENV DOCKER_WORKDIR="/code"
USER root
WORKDIR ${DOCKER_WORKDIR}
COPY . .
RUN cd scripts \
&& chmod +x ./prepare_build.sh \
&& ./prepare_build.sh
RUN ./compile_pot.sh
RUN ./unix_parse_proto.sh
#########################################################################################################
# run debug
#########################################################################################################
FROM debug as login_server_debug
ENV DOCKER_WORKDIR="/code"
#RUN apt-get update && \
# apt-get install -y --no-install-recommends gdb && \
# apt-get autoclean && \
# apt-get autoremove && \
# apt-get clean && \
# rm -rf /var/lib/apt/lists/*
VOLUME /var/log/grd_login
VOLUME /code/src
EXPOSE 1200
EXPOSE 1201
WORKDIR ${DOCKER_WORKDIR}
RUN chmod +x ./scripts/build_and_run.sh
CMD ./Dockerfiles/build_and_run.sh; ./build_vol/bin/Gradido_LoginServer

View File

@ -0,0 +1,58 @@
#########################################################################################################
# Build release
#########################################################################################################
FROM gradido/login_dependencies:alpine-release-3 as release_default
ENV DOCKER_WORKDIR="/code"
WORKDIR ${DOCKER_WORKDIR}
COPY ./login_server/CMakeLists.txt.lib ./CMakeLists.txt
COPY ./login_server/src ./src
COPY ./login_server/dependencies/cmake-modules ./dependencies/cmake-modules
COPY ./login_server/dependencies/spirit-po ./dependencies/spirit-po
COPY ./login_server/dependencies/tinf ./dependencies/tinf
COPY ./login_server/scripts ./scripts
RUN mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release .. && \
make -j$(nproc) Gradido_LoginServer
RUN cd scripts && \
chmod +x compile_pot.sh && \
./compile_pot.sh
#########################################################################################################
# run release with docker default config
#########################################################################################################
#From alpine:latest as login_server
FROM alpine:3.13.5 as login_server_default
USER root
WORKDIR "/usr/bin"
COPY --from=release_default /code/build/bin/Gradido_LoginServer /usr/bin/
COPY --from=release_default /usr/local/lib/mariadb/libmariadb.so.3 /usr/local/lib/
COPY --from=release_default /usr/local/lib/libPoco* /usr/local/lib/
COPY --from=release_default /usr/lib/libsodium.so.23 /usr/lib/
COPY --from=release_default /usr/lib/libstdc++.so.6 /usr/lib/
COPY --from=release_default /usr/lib/libgcc_s.so.1 /usr/lib/
COPY ./configs/login_server/grd_login.properties /etc/grd_login/
COPY ./configs/login_server/cacert.pem /etc/grd_login/
COPY ./configs/login_server/LOCALE /etc/grd_login/
EXPOSE 1200
EXPOSE 1201
RUN chmod +x /usr/bin/Gradido_LoginServer
ENTRYPOINT ["/usr/bin/Gradido_LoginServer"]
#CMD Gradido_LoginServer

View File

@ -1,11 +1,8 @@
#########################################################################################################
# gcc 9 with libssl
#########################################################################################################
FROM gcc:9 as gcc_9_libssl
USER root
##### BUILD-ENV #####
FROM gcc:9 as gcc9_build
RUN apt-get update && \
apt-get install -y --no-install-recommends libssl-dev libboost-dev && \
apt-get install -y --no-install-recommends libssl-dev libboost-dev gettext libsodium-dev lcov && \
apt-get autoclean && \
apt-get autoremove && \
apt-get clean && \
@ -15,79 +12,73 @@ RUN apt-get update && \
#########################################################################################################
# gcc 9 cmake
#########################################################################################################
FROM gcc_9_libssl as gcc_9_cmake
USER root
ENV DOCKER_WORKDIR="/code"
RUN mkdir -p ${DOCKER_WORKDIR}
WORKDIR ${DOCKER_WORKDIR}
FROM gcc9_build as gcc_9_cmake
RUN git clone https://github.com/Kitware/CMake.git --branch=v3.19.8 && \
cd CMake && \
./bootstrap --parallel=$(nproc) && \
make -j$(nproc) && \
make install && \
cd .. && \
rm -rf CMake
make install
######### BUILD grpc ##############
FROM gcc_9_cmake as gcc_9_protobuf
ARG BUILD_TYPE=Debug
RUN git clone https://github.com/protocolbuffers/protobuf.git --recursive -j4 && \
cd protobuf && \
./autogen.sh && \
./configure && \
make -j$(nproc) && \
make install && \
ldconfig
# protobuf libs missing after make install
#RUN cp grpc/build/third_party/protobuf/*.a /usr/local/lib/
######### BUILD poco ##############
FROM gcc_9_cmake as gcc_9_poco
ARG BUILD_TYPE=Debug
RUN git clone https://github.com/pocoproject/poco.git --recursive && \
cd poco && \
git checkout poco-1.9.4-release && \
mkdir cmake-build && cd cmake-build && \
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. && make -j$(nproc) && \
make install
######### BUILD mariadb ###########
FROM gcc_9_cmake as gcc_9_mariadb-connector
ARG BUILD_TYPE=Debug
RUN git clone https://github.com/mariadb-corporation/mariadb-connector-c.git && \
cd mariadb-connector-c && \
git checkout 159540f && \
mkdir build && cd build && \
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. && make -j$(nproc) && \
make install
#########################################################################################################
# debug build preparation
# builded libs and binaries
#########################################################################################################
FROM gcc_9_libssl as build_debug_dependencies
FROM gcc9_build as gcc9_libs
USER root
ENV DOCKER_WORKDIR="/code"
RUN echo '/usr/local/lib' >> /etc/ld.so.conf && ldconfig
RUN mkdir -p ${DOCKER_WORKDIR}
WORKDIR ${DOCKER_WORKDIR}
# copy CMake from last stage
# copy CMake from cmake stage
COPY --from=gcc_9_cmake /usr/local/bin/cmake /usr/local/bin/cmake
COPY --from=gcc_9_cmake /usr/local/share/cmake-3.19/Modules /usr/local/share/cmake-3.19/Modules
COPY --from=gcc_9_cmake /usr/local/share/cmake-3.19/Templates /usr/local/share/cmake-3.19/Templates
COPY ./dependencies ./dependencies
COPY ./scripts ./scripts
COPY ./CMakeLists.txt .
COPY ./src ./src
# copy from grpc
COPY --from=gcc_9_protobuf /usr/local /usr/local
COPY --from=gcc_9_protobuf /protobuf/third_party/googletest /usr/local/googletest
# COPY from poco
COPY --from=gcc_9_poco /usr/local /usr/local
RUN cd scripts && \
chmod +x ./prepare_build.sh && \
./prepare_build.sh && \
mkdir ../build && \
chmod +x ./build_debug.sh && \
./build_debug.sh
# remove unneccessary stuff
RUN rm -rf build/bin/Gradido_LoginServer
#########################################################################################################
# debug build
#########################################################################################################
FROM gcc_9_libssl as build_debug
USER root
ENV DOCKER_WORKDIR="/code"
RUN mkdir -p ${DOCKER_WORKDIR}
WORKDIR ${DOCKER_WORKDIR}
# copy CMake from last stage
COPY --from=build_debug_dependencies /usr/local/bin/cmake /usr/local/bin/cmake
COPY --from=build_debug_dependencies /usr/local/share/cmake-3.19 /usr/local/share/cmake-3.19
COPY --from=build_debug_dependencies /code/build/bin /code/build/bin
COPY --from=build_debug_dependencies /code/build/lib /code/build/lib
# grpc
COPY --from=build_debug_dependencies /code/build/dependencies/grpc/lib /build/dependencies/grpc/lib
COPY --from=build_debug_dependencies /code/build/dependencies/grpc/third_party/protobuf/lib /build/dependencies/grpc/third_party/protobuf/lib
COPY --from=build_debug_dependencies /code/build/dependencies/grpc/third_party/re2/lib /build/dependencies/grpc/third_party/re2/lib
COPY --from=build_debug_dependencies /code/build/dependencies/grpc/third_party/zlib/lib /build/dependencies/grpc/third_party/zlib/lib
COPY --from=build_debug_dependencies /code/build/dependencies/grpc/third_party/cares/cares/lib /build/dependencies/grpc/third_party/cares/cares/lib
COPY --from=build_debug_dependencies /code/build/dependencies/mariadb-connector-c/libmariadb/lib /build/dependencies/mariadb-connector-c/libmariadb/lib
# COPY from mariadb
COPY --from=gcc_9_mariadb-connector /usr/local /usr/local

View File

@ -2,8 +2,8 @@
##### BUILD-ENV #####
FROM alpine:3.13.5 as alpine-build
RUN apk add --update --no-cache icu-dev
RUN apk add --no-cache git openssl-dev make gcc musl-dev g++ linux-headers libintl gettext-dev boost-dev libsodium-dev
RUN apk add --update --no-cache icu-dev
RUN apk add --no-cache git openssl-dev make gcc musl-dev g++ linux-headers libintl gettext-dev boost-dev libsodium-dev
##### CMAKE #####
@ -16,21 +16,21 @@ RUN git clone https://github.com/Kitware/CMake.git --branch=v3.19.8 && \
make install
######### BUILD grpc ##############
FROM alpine-gxx-cmake as alpine-gxx-grpc
FROM alpine-gxx-cmake as alpine-gxx-protobuf
ARG BUILD_TYPE=Debug
RUN git clone https://github.com/grpc/grpc.git --branch=v1.37.0 --recursive -j4 && \
cd grpc && \
mkdir build && cd build && \
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. && make -j$(nproc) && \
make install
RUN apk add --no-cache autoconf automake libtool curl unzip
# abseil don't install themself correctly
RUN cp -r grpc/third_party/abseil-cpp/absl /usr/local/include/
RUN git clone https://github.com/protocolbuffers/protobuf.git --recursive -j4 && \
cd protobuf && \
./autogen.sh && \
./configure && \
make -j$(nproc) && \
make install
# protobuf libs missing after make install
RUN cp grpc/build/third_party/protobuf/*.a /usr/local/lib/
#RUN cp grpc/build/third_party/protobuf/*.a /usr/local/lib/
######### BUILD poco ##############
FROM alpine-gxx-cmake as alpine-gxx-poco
@ -67,8 +67,7 @@ COPY --from=alpine-gxx-cmake /usr/local/share/cmake-3.19/Modules /usr/local/shar
COPY --from=alpine-gxx-cmake /usr/local/share/cmake-3.19/Templates /usr/local/share/cmake-3.19/Templates
# copy from grpc
COPY --from=alpine-gxx-grpc /usr/local /usr/local
COPY --from=alpine-gxx-protobuf /usr/local /usr/local
# COPY from poco
COPY --from=alpine-gxx-poco /usr/local /usr/local
@ -76,4 +75,10 @@ COPY --from=alpine-gxx-poco /usr/local /usr/local
# COPY from mariadb
COPY --from=alpine-gxx-mariadb-connector /usr/local /usr/local
#########################################################################################################
# COPY Things only needed for testing
#########################################################################################################
FROM alpine-libs as alpine-libs-test
COPY --from=alpine-gxx-protobuf /protobuf/third_party/googletest /usr/local/googletest

View File

@ -1,30 +0,0 @@
#########################################################################################################
# Build protoc
#########################################################################################################
FROM gcc:7.5 as protoc3.9.1_build
RUN git clone --recurse-submodules https://github.com/protocolbuffers/protobuf.git
WORKDIR /protobuf
RUN git checkout v3.9.1
RUN ./autogen.sh
RUN ./configure --enable-static=yes
RUN make -j$(nproc)
#RUN make check
CMD ["./protobuf"]
#########################################################################################################
# Store protoc
#########################################################################################################
FROM alpine:3.10 as protoc
COPY --from=protoc3.9.1_build /protobuf/src/.libs/protoc /usr/bin/
COPY --from=protoc3.9.1_build /protobuf/src/.libs/libprotobuf.so.20.0.1 /usr/lib/libprotobuf.so.20
COPY --from=protoc3.9.1_build /protobuf/src/.libs/libprotoc.so.20.0.1 /usr/lib/libprotoc.so.20
COPY --from=protoc3.9.1_build /protobuf/src/google/protobuf/*.proto /usr/include/google/protobuf/
COPY --from=protoc3.9.1_build /protobuf/src/google/protobuf/*.h /usr/include/google/protobuf/
## build with:
# docker build . -f Dockefile.protoc -t gradido/protoc:3.9.1
## upload (login to docker hub on shell before):
# docker push gradido/protoc:3.9.1

View File

@ -0,0 +1,682 @@
# Copyright (c) 2012 - 2017, Lars Bilke
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. 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.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
#
# CHANGES:
#
# 2012-01-31, Lars Bilke
# - Enable Code Coverage
#
# 2013-09-17, Joakim Söderberg
# - Added support for Clang.
# - Some additional usage instructions.
#
# 2016-02-03, Lars Bilke
# - Refactored functions to use named parameters
#
# 2017-06-02, Lars Bilke
# - Merged with modified version from github.com/ufz/ogs
#
# 2019-05-06, Anatolii Kurotych
# - Remove unnecessary --coverage flag
#
# 2019-12-13, FeRD (Frank Dana)
# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor
# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments.
# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY
# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list
# - Set lcov basedir with -b argument
# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be
# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().)
# - Delete output dir, .info file on 'make clean'
# - Remove Python detection, since version mismatches will break gcovr
# - Minor cleanup (lowercase function names, update examples...)
#
# 2019-12-19, FeRD (Frank Dana)
# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets
#
# 2020-01-19, Bob Apthorpe
# - Added gfortran support
#
# 2020-02-17, FeRD (Frank Dana)
# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters
# in EXCLUDEs, and remove manual escaping from gcovr targets
#
# 2021-01-19, Robin Mueller
# - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run
# - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional
# flags to the gcovr command
#
# 2020-05-04, Mihchael Davis
# - Add -fprofile-abs-path to make gcno files contain absolute paths
# - Fix BASE_DIRECTORY not working when defined
# - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines
# USAGE:
#
# 1. Copy this file into your cmake modules path.
#
# 2. Add the following line to your CMakeLists.txt (best inside an if-condition
# using a CMake option() to enable it just optionally):
# include(CodeCoverage)
#
# 3. Append necessary compiler flags:
# append_coverage_compiler_flags()
#
# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
#
# 4. If you need to exclude additional directories from the report, specify them
# using full paths in the COVERAGE_EXCLUDES variable before calling
# setup_target_for_coverage_*().
# Example:
# set(COVERAGE_EXCLUDES
# '${PROJECT_SOURCE_DIR}/src/dir1/*'
# '/path/to/my/src/dir2/*')
# Or, use the EXCLUDE argument to setup_target_for_coverage_*().
# Example:
# setup_target_for_coverage_lcov(
# NAME coverage
# EXECUTABLE testrunner
# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*")
#
# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set
# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR)
# Example:
# set(COVERAGE_EXCLUDES "dir1/*")
# setup_target_for_coverage_gcovr_html(
# NAME coverage
# EXECUTABLE testrunner
# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src"
# EXCLUDE "dir2/*")
#
# 5. Use the functions described below to create a custom make target which
# runs your test executable and produces a code coverage report.
#
# 6. Build a Debug build:
# cmake -DCMAKE_BUILD_TYPE=Debug ..
# make
# make my_coverage_target
#
include(CMakeParseArguments)
option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE)
# Check prereqs
find_program( GCOV_PATH gcov )
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
find_program( FASTCOV_PATH NAMES fastcov fastcov.py )
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
find_program( CPPFILT_PATH NAMES c++filt )
if(NOT GCOV_PATH)
message(FATAL_ERROR "gcov not found! Aborting...")
endif() # NOT GCOV_PATH
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
list(GET LANGUAGES 0 LANG)
if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3)
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
endif()
elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang")
# Do nothing; exit conditional without error if true
elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
# Do nothing; exit conditional without error if true
else()
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
endif()
endif()
set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage"
CACHE INTERNAL "")
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-fprofile-abs-path HAVE_fprofile_abs_path)
if(HAVE_fprofile_abs_path)
set(COVERAGE_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
endif()
endif()
set(CMAKE_Fortran_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the Fortran compiler during coverage builds."
FORCE )
set(CMAKE_CXX_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C++ compiler during coverage builds."
FORCE )
set(CMAKE_C_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C compiler during coverage builds."
FORCE )
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used for linking binaries during coverage builds."
FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
FORCE )
mark_as_advanced(
CMAKE_Fortran_FLAGS_COVERAGE
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
link_libraries(gcov)
endif()
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# setup_target_for_coverage_lcov(
# NAME testrunner_coverage # New target name
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES testrunner # Dependencies to build first
# BASE_DIRECTORY "../" # Base directory for report
# # (defaults to PROJECT_SOURCE_DIR)
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
# # to BASE_DIRECTORY, with CMake 3.4+)
# NO_DEMANGLE # Don't demangle C++ symbols
# # even if c++filt is found
# )
function(setup_target_for_coverage_lcov)
set(options NO_DEMANGLE)
set(oneValueArgs BASE_DIRECTORY NAME)
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT LCOV_PATH)
message(FATAL_ERROR "lcov not found! Aborting...")
endif() # NOT LCOV_PATH
if(NOT GENHTML_PATH)
message(FATAL_ERROR "genhtml not found! Aborting...")
endif() # NOT GENHTML_PATH
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
if(DEFINED Coverage_BASE_DIRECTORY)
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
else()
set(BASEDIR ${PROJECT_SOURCE_DIR})
endif()
# Collect excludes (CMake 3.4+: Also compute absolute paths)
set(LCOV_EXCLUDES "")
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
if(CMAKE_VERSION VERSION_GREATER 3.4)
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
endif()
list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES LCOV_EXCLUDES)
# Conditional arguments
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
endif()
# Setting up commands which will be run to generate coverage data.
# Cleanup lcov
set(LCOV_CLEAN_CMD
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory .
-b ${BASEDIR} --zerocounters
)
# Create baseline to make sure untouched files show up in the report
set(LCOV_BASELINE_CMD
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b
${BASEDIR} -o ${Coverage_NAME}.base
)
# Run tests
set(LCOV_EXEC_TESTS_CMD
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
)
# Capturing lcov counters and generating report
set(LCOV_CAPTURE_CMD
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b
${BASEDIR} --capture --output-file ${Coverage_NAME}.capture
)
# add baseline counters
set(LCOV_BASELINE_COUNT_CMD
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base
-a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
)
# filter collected data to final coverage report
set(LCOV_FILTER_CMD
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove
${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
)
# Generate HTML output
set(LCOV_GEN_HTML_CMD
${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o
${Coverage_NAME} ${Coverage_NAME}.info
)
if(CODE_COVERAGE_VERBOSE)
message(STATUS "Executed command report")
message(STATUS "Command to clean up lcov: ")
string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}")
message(STATUS "${LCOV_CLEAN_CMD_SPACED}")
message(STATUS "Command to create baseline: ")
string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}")
message(STATUS "${LCOV_BASELINE_CMD_SPACED}")
message(STATUS "Command to run the tests: ")
string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}")
message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}")
message(STATUS "Command to capture counters and generate report: ")
string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}")
message(STATUS "${LCOV_CAPTURE_CMD_SPACED}")
message(STATUS "Command to add baseline counters: ")
string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}")
message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}")
message(STATUS "Command to filter collected data: ")
string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}")
message(STATUS "${LCOV_FILTER_CMD_SPACED}")
message(STATUS "Command to generate lcov HTML output: ")
string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}")
message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}")
endif()
# Setup target
add_custom_target(${Coverage_NAME}
COMMAND ${LCOV_CLEAN_CMD}
COMMAND ${LCOV_BASELINE_CMD}
COMMAND ${LCOV_EXEC_TESTS_CMD}
COMMAND ${LCOV_CAPTURE_CMD}
COMMAND ${LCOV_BASELINE_COUNT_CMD}
COMMAND ${LCOV_FILTER_CMD}
COMMAND ${LCOV_GEN_HTML_CMD}
# Set output files as GENERATED (will be removed on 'make clean')
BYPRODUCTS
${Coverage_NAME}.base
${Coverage_NAME}.capture
${Coverage_NAME}.total
${Coverage_NAME}.info
${Coverage_NAME}/index.html
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
VERBATIM # Protect arguments to commands
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
)
# Show where to find the lcov info report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # setup_target_for_coverage_lcov
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# setup_target_for_coverage_gcovr_xml(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# BASE_DIRECTORY "../" # Base directory for report
# # (defaults to PROJECT_SOURCE_DIR)
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
# # to BASE_DIRECTORY, with CMake 3.4+)
# )
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
# GCVOR command.
function(setup_target_for_coverage_gcovr_xml)
set(options NONE)
set(oneValueArgs BASE_DIRECTORY NAME)
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
if(DEFINED Coverage_BASE_DIRECTORY)
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
else()
set(BASEDIR ${PROJECT_SOURCE_DIR})
endif()
# Collect excludes (CMake 3.4+: Also compute absolute paths)
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
if(CMAKE_VERSION VERSION_GREATER 3.4)
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
endif()
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDE_ARGS "")
foreach(EXCLUDE ${GCOVR_EXCLUDES})
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
endforeach()
# Set up commands which will be run to generate coverage data
# Run tests
set(GCOVR_XML_EXEC_TESTS_CMD
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
)
# Running gcovr
set(GCOVR_XML_CMD
${GCOVR_PATH} --xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} ${GCOVR_EXCLUDE_ARGS}
--object-directory=${PROJECT_BINARY_DIR} -o ${Coverage_NAME}.xml
)
if(CODE_COVERAGE_VERBOSE)
message(STATUS "Executed command report")
message(STATUS "Command to run tests: ")
string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}")
message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}")
message(STATUS "Command to generate gcovr XML coverage data: ")
string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}")
message(STATUS "${GCOVR_XML_CMD_SPACED}")
endif()
add_custom_target(${Coverage_NAME}
COMMAND ${GCOVR_XML_EXEC_TESTS_CMD}
COMMAND ${GCOVR_XML_CMD}
BYPRODUCTS ${Coverage_NAME}.xml
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
VERBATIM # Protect arguments to commands
COMMENT "Running gcovr to produce Cobertura code coverage report."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
)
endfunction() # setup_target_for_coverage_gcovr_xml
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# setup_target_for_coverage_gcovr_html(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# BASE_DIRECTORY "../" # Base directory for report
# # (defaults to PROJECT_SOURCE_DIR)
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
# # to BASE_DIRECTORY, with CMake 3.4+)
# )
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
# GCVOR command.
function(setup_target_for_coverage_gcovr_html)
set(options NONE)
set(oneValueArgs BASE_DIRECTORY NAME)
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
if(DEFINED Coverage_BASE_DIRECTORY)
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
else()
set(BASEDIR ${PROJECT_SOURCE_DIR})
endif()
# Collect excludes (CMake 3.4+: Also compute absolute paths)
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
if(CMAKE_VERSION VERSION_GREATER 3.4)
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
endif()
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDE_ARGS "")
foreach(EXCLUDE ${GCOVR_EXCLUDES})
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
endforeach()
# Set up commands which will be run to generate coverage data
# Run tests
set(GCOVR_HTML_EXEC_TESTS_CMD
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
)
# Create folder
set(GCOVR_HTML_FOLDER_CMD
${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
)
# Running gcovr
set(GCOVR_HTML_CMD
${GCOVR_PATH} --html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
-o ${Coverage_NAME}/index.html
)
if(CODE_COVERAGE_VERBOSE)
message(STATUS "Executed command report")
message(STATUS "Command to run tests: ")
string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}")
message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}")
message(STATUS "Command to create a folder: ")
string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}")
message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}")
message(STATUS "Command to generate gcovr HTML coverage data: ")
string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}")
message(STATUS "${GCOVR_HTML_CMD_SPACED}")
endif()
add_custom_target(${Coverage_NAME}
COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD}
COMMAND ${GCOVR_HTML_FOLDER_CMD}
COMMAND ${GCOVR_HTML_CMD}
BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
VERBATIM # Protect arguments to commands
COMMENT "Running gcovr to produce HTML code coverage report."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # setup_target_for_coverage_gcovr_html
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# setup_target_for_coverage_fastcov(
# NAME testrunner_coverage # New target name
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES testrunner # Dependencies to build first
# BASE_DIRECTORY "../" # Base directory for report
# # (defaults to PROJECT_SOURCE_DIR)
# EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude.
# NO_DEMANGLE # Don't demangle C++ symbols
# # even if c++filt is found
# SKIP_HTML # Don't create html report
# )
function(setup_target_for_coverage_fastcov)
set(options NO_DEMANGLE SKIP_HTML)
set(oneValueArgs BASE_DIRECTORY NAME)
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT FASTCOV_PATH)
message(FATAL_ERROR "fastcov not found! Aborting...")
endif()
if(NOT GENHTML_PATH)
message(FATAL_ERROR "genhtml not found! Aborting...")
endif()
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
if(Coverage_BASE_DIRECTORY)
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
else()
set(BASEDIR ${PROJECT_SOURCE_DIR})
endif()
# Collect excludes (Patterns, not paths, for fastcov)
set(FASTCOV_EXCLUDES "")
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES})
list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES FASTCOV_EXCLUDES)
# Conditional arguments
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
endif()
# Set up commands which will be run to generate coverage data
set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS})
set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
--search-directory ${BASEDIR}
--process-gcno
--lcov
--output ${Coverage_NAME}.info
--exclude ${FASTCOV_EXCLUDES}
--exclude ${FASTCOV_EXCLUDES}
)
if(Coverage_SKIP_HTML)
set(FASTCOV_HTML_CMD ";")
else()
set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS}
-o ${Coverage_NAME} ${Coverage_NAME}.info
)
endif()
if(CODE_COVERAGE_VERBOSE)
message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):")
message(" Running tests:")
string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}")
message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}")
message(" Capturing fastcov counters and generating report:")
string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}")
message(" ${FASTCOV_CAPTURE_CMD_SPACED}")
if(NOT Coverage_SKIP_HTML)
message(" Generating HTML report: ")
string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}")
message(" ${FASTCOV_HTML_CMD_SPACED}")
endif()
endif()
# Setup target
add_custom_target(${Coverage_NAME}
# Cleanup fastcov
COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
--search-directory ${BASEDIR}
--zerocounters
COMMAND ${FASTCOV_EXEC_TESTS_CMD}
COMMAND ${FASTCOV_CAPTURE_CMD}
COMMAND ${FASTCOV_HTML_CMD}
# Set output files as GENERATED (will be removed on 'make clean')
BYPRODUCTS
${Coverage_NAME}.info
${Coverage_NAME}/index.html # report directory
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
VERBATIM # Protect arguments to commands
COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report."
)
set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info.")
if(NOT Coverage_SKIP_HTML)
string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.")
endif()
# Show where to find the fastcov info report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG}
)
endfunction() # setup_target_for_coverage_fastcov
function(append_coverage_compiler_flags)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
endfunction() # append_coverage_compiler_flags

View File

@ -0,0 +1,141 @@
# - Returns a version string from Git
#
# These functions force a re-configure on each git commit so that you can
# trust the values of the variables in your build system.
#
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
#
# Returns the refspec and sha hash of the current head revision
#
# git_describe(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the source tree, and adjusting
# the output so that it tests false if an error occurs.
#
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe --exact-match on the source tree,
# and adjusting the output so that it tests false if there was no exact
# matching tag.
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__get_git_revision_description)
return()
endif()
set(__get_git_revision_description YES)
# We must run the following at "include" time, not at function call time,
# to find the path to this module rather than the path to a calling list file
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
function(get_git_head_revision _refspecvar _hashvar)
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
# We have reached the root directory, we are not in git
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
return()
endif()
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
endwhile()
# check if this is a submodule
if(NOT IS_DIRECTORY ${GIT_DIR})
file(READ ${GIT_DIR} submodule)
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
if (IS_ABSOLUTE ${GIT_DIR_RELATIVE})
set(GIT_DIR ${GIT_DIR_RELATIVE})
else()
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
endif()
endif()
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
if(NOT EXISTS "${GIT_DATA}")
file(MAKE_DIRECTORY "${GIT_DATA}")
endif()
if(NOT EXISTS "${GIT_DIR}/HEAD")
return()
endif()
set(HEAD_FILE "${GIT_DATA}/HEAD")
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
"${GIT_DATA}/grabRef.cmake"
@ONLY)
include("${GIT_DATA}/grabRef.cmake")
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
endfunction()
function(git_describe _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
return()
endif()
# TODO sanitize
#if((${ARGN}" MATCHES "&&") OR
# (ARGN MATCHES "||") OR
# (ARGN MATCHES "\\;"))
# message("Please report the following error to the project!")
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
#endif()
#message(STATUS "Arguments to execute_process: ${ARGN}")
execute_process(COMMAND
${GIT_EXECUTABLE}
describe
${hash}
${ARGN}
WORKING_DIRECTORY
"${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_get_exact_tag _var)
git_describe(out --exact-match ${ARGN})
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_get_tag _var)
git_describe(out --tags ${ARGN})
set(${_var} "${out}" PARENT_SCOPE)
endfunction()

View File

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,72 @@
Additional CMake Modules
========================
Introduction
------------
This is a collection of additional CMake modules.
Most of them are from Ryan Pavlik (<http://academic.cleardefinition.com>).
How to Integrate
----------------
These modules are probably best placed wholesale into a "cmake" subdirectory
of your project source.
If you use Git, try installing [git-subtree][1],
so you can easily use this repository for subtree merges, updating simply.
For the initial checkout:
cd projectdir
git subtree add --squash --prefix=cmake git@github.com:bilke/cmake-modules.git master
For updates:
cd projectdir
git subtree pull --squash --prefix=cmake git@github.com:bilke/cmake-modules.git master
For pushing to upstream:
cd projectdir
git subtree push --prefix=cmake git@github.com:bilke/cmake-modules.git master
How to Use
----------
At the minimum, all you have to do is add a line like this near the top
of your root CMakeLists.txt file (but not before your project() call):
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
Licenses
--------
The modules that are written by Ryan Pavlik are all subject to this license:
> Copyright Iowa State University 2009-2011
>
> Distributed under the Boost Software License, Version 1.0.
>
> (See accompanying file `LICENSE_1_0.txt` or copy at
> <http://www.boost.org/LICENSE_1_0.txt>)
Modules based on those included with CMake as well as modules added by me (Lars
Bilke) are under the OSI-approved **BSD** license, which is included in each of
those modules. A few other modules are modified from other sources - when in
doubt, look at the .cmake.
Important License Note!
-----------------------
If you find this file inside of another project, rather at the top-level
directory, you're in a separate project that is making use of these modules.
That separate project can (and probably does) have its own license specifics.
[1]: http://github.com/apenwarr/git-subtree "Git Subtree master"

View File

@ -2,6 +2,7 @@
Poco/1.9.4@pocoproject/stable
libsodium/1.0.18@bincrafters/stable
boost/1.71.0@conan/stable
gtest/1.10.0
[options]
Poco:enable_pagecompiler=True

View File

@ -11,5 +11,10 @@ cd build
cmake -DWITH_SSL=OFF ..
cd ../../
if [! -d "./build" ] ; then
mkdir build
fi
cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
make -j$(nproc) protoc PageCompiler
cmake ..

View File

@ -179,8 +179,8 @@ Poco::AutoPtr<Passphrase> Passphrase::create(const Poco::UInt16 wordIndices[PHRA
return new Passphrase(clearPassphrase, wordSource);
}
Poco::AutoPtr<Passphrase> Passphrase::generate(const Mnemonic* wordSource)
{
Poco::AutoPtr<Passphrase> Passphrase::generate(const Mnemonic* wordSource)
{
auto em = ErrorManager::getInstance();
auto mm = MemoryManager::getInstance();
auto word_indices = mm->getFreeMemory(PHRASE_WORD_COUNT * sizeof(Poco::UInt16));
@ -266,7 +266,7 @@ bool Passphrase::createWordIndices()
return false;
}
//DHASH key = DRMakeStringHash(passphrase);
size_t pass_phrase_size = mPassphraseString.size();
@ -352,9 +352,9 @@ const Mnemonic* Passphrase::detectMnemonic(const std::string& passphrase, const
if (keyPair) {
user_public_key_hex = DataTypeConverter::pubkeyToHex(keyPair->getPublicKey());
printf("user public key hex: %s\n", user_public_key_hex.data());
//printf("user public key hex: %s\n", user_public_key_hex.data());
}
std::string last_words_not_found[ServerConfig::Mnemonic_Types::MNEMONIC_MAX];
for (int i = 0; i < ServerConfig::Mnemonic_Types::MNEMONIC_MAX; i++) {
Mnemonic& m = ServerConfig::g_Mnemonic_WordLists[i];
bool existAll = true;
@ -362,6 +362,8 @@ const Mnemonic* Passphrase::detectMnemonic(const std::string& passphrase, const
if (*it == "\0" || *it == "" || it->size() < 3) continue;
if (!m.isWordExist(*it)) {
existAll = false;
//printf("couldn't find word: %s\n", (*it).data());
last_words_not_found[i] = (*it);
// leave inner for-loop
break;
}
@ -372,10 +374,14 @@ const Mnemonic* Passphrase::detectMnemonic(const std::string& passphrase, const
test_passphrase->createWordIndices();
auto key_pair = KeyPairEd25519::create(test_passphrase);
if (key_pair) {
std::string current_key_pair = DataTypeConverter::pubkeyToHex(key_pair->getPublicKey());
printf("public key hex to compare: %s\n", current_key_pair.data());
if (*key_pair != *keyPair) {
#ifdef _TEST_BUILD // additional infos for debugging if error occure in test
printf("public key mismatch\n");
std::string generated_key_pair_hex = DataTypeConverter::pubkeyToHex(key_pair->getPublicKey());
std::string parameter_key_pair_hex = DataTypeConverter::pubkeyToHex(keyPair->getPublicKey());
printf("parameter: %s, generated: %s\n", parameter_key_pair_hex.data(), generated_key_pair_hex.data());
#endif
delete key_pair;
continue;
}
@ -386,6 +392,8 @@ const Mnemonic* Passphrase::detectMnemonic(const std::string& passphrase, const
}
return &ServerConfig::g_Mnemonic_WordLists[i];
}
//printf("last word not found: %s in %s\n", last_words_not_found[i].data(), ServerConfig::mnemonicTypeToString((ServerConfig::Mnemonic_Types)i));
}
return nullptr;
}
}

View File

@ -34,10 +34,12 @@ SecretKeyCryptography::ResultType SecretKeyCryptography::createKey(const std::st
assert(app_secret);
Profiler timeUsed;
std::unique_lock<std::shared_mutex> _lock(mWorkingMutex);
#ifndef _TEST_BUILD
if (timeUsed.millis() > 10) {
printf("[AuthenticatedEncryption::createKey] wait %s on getting lock\n", timeUsed.string().data());
printf("[SecretKeyCryptography::createKey] wait %s on getting lock\n", timeUsed.string().data());
timeUsed.reset();
}
#endif
// use hash512 because existing data where calculated with that, but could be also changed to hash256
auto hash512_salt = mm->getFreeMemory(crypto_hash_sha512_BYTES); // need at least crypto_pwhash_SALTBYTES 16U
@ -49,10 +51,12 @@ SecretKeyCryptography::ResultType SecretKeyCryptography::createKey(const std::st
crypto_hash_sha512_update(&state, *app_secret, app_secret->size());
crypto_hash_sha512_final(&state, *hash512_salt);
#ifndef _TEST_BUILD
if (timeUsed.millis() > 200) {
printf("[AuthenticatedEncryption::createKey] %s calculating sha512\n", timeUsed.string().data());
printf("[SecretKeyCryptography::createKey] %s calculating sha512\n", timeUsed.string().data());
timeUsed.reset();
}
#endif
//unsigned char* key = (unsigned char *)malloc(crypto_box_SEEDBYTES); // 32U
//ObfusArray* key = new ObfusArray(crypto_box_SEEDBYTES);
@ -68,9 +72,11 @@ SecretKeyCryptography::ResultType SecretKeyCryptography::createKey(const std::st
return AUTH_CREATE_ENCRYPTION_KEY_FAILED;
}
#ifndef _TEST_BUILD
if (timeUsed.millis() > 400) {
printf("[AuthenticatedEncryption::createKey] %s calculating pwd hash\n", timeUsed.string().data());
printf("[SecretKeyCryptography::createKey] %s calculating pwd hash\n", timeUsed.string().data());
}
#endif
// generate hash from key for compare
assert(sizeof(KeyHashed) >= crypto_shorthash_BYTES);
assert(ServerConfig::g_ServerCryptoKey);

View File

@ -0,0 +1,92 @@
#include "JsonCheckUsername.h"
#include "Poco/URI.h"
#include "controller/User.h"
#include "lib/DataTypeConverter.h"
Poco::JSON::Object* JsonCheckUsername::handle(Poco::Dynamic::Var params)
{
std::string username;
int group_id = 0;
std::string group_alias;
// if is json object
if (params.type() == typeid(Poco::JSON::Object::Ptr)) {
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
/// Throws a RangeException if the value does not fit
/// into the result variable.
/// Throws a NotImplementedException if conversion is
/// not available for the given type.
/// Throws InvalidAccessException if Var is empty.
auto username_obj = paramJsonObject->get("username");
auto group_id_obj = paramJsonObject->get("group_id");
auto group_alias_obj = paramJsonObject->get("group_alias");
try {
if (!username_obj.isEmpty()) {
username_obj.convert(username);
}
if (!group_id_obj.isEmpty()) {
group_id_obj.convert(group_id);
}
if (!group_alias_obj.isEmpty()) {
group_alias_obj.convert(group_alias);
}
}
catch (Poco::Exception& ex) {
return stateError("Poco Exception", ex.displayText());
}
}
else if (params.isVector()) {
const Poco::URI::QueryParameters queryParams = params.extract<Poco::URI::QueryParameters>();
for (auto it = queryParams.begin(); it != queryParams.end(); it++) {
if (it->first == "username") {
username = it->second;
}
else if (it->first == "group_id") {
DataTypeConverter::strToInt(it->second, group_id);
}
else if (it->first == "group_alias") {
group_alias = it->second;
}
}
}
else {
return stateError("format not implemented", std::string(params.type().name()));
}
if (!group_id && group_alias == "") {
return stateError("no group given");
}
if (!group_id) {
auto groups = controller::Group::load(group_alias);
if (groups.size() > 1) {
return stateError("group is ambiguous");
}
if (!groups.size()) {
return stateError("unknown group");
}
group_id = groups[0]->getModel()->getID();
}
auto group = controller::Group::load(group_id);
if (group.isNull()) {
return stateError("unknown group");
}
auto user = controller::User::create();
user->getModel()->setGroupId(group_id);
if (username == "") {
Poco::JSON::Object* result = new Poco::JSON::Object;
result->set("state", "success");
result->set("group_id", group_id);
return result;
}
if (user->isUsernameAlreadyUsed(username)) {
return stateWarning("username already in use");
}
return stateSuccess();
}

View File

@ -0,0 +1,16 @@
#ifndef __JSON_INTERFACE_JSON_CHECK_USERNAME_
#define __JSON_INTERFACE_JSON_CHECK_USERNAME_
#include "JsonRequestHandler.h"
class JsonCheckUsername : public JsonRequestHandler
{
public:
Poco::JSON::Object* handle(Poco::Dynamic::Var params);
protected:
};
#endif // __JSON_INTERFACE_JSON_CHECK_USERNAME_

View File

@ -7,6 +7,7 @@
#include "JsonAdminEmailVerificationResend.h"
#include "JsonCheckSessionState.h"
#include "JsonCheckUsername.h"
#include "JsonAppLogin.h"
#include "JsonAquireAccessToken.h"
#include "JsonCreateTransaction.h"
@ -74,6 +75,9 @@ Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(c
else if (url_first_part == "/checkSessionState") {
return new JsonCheckSessionState;
}
else if (url_first_part == "/checkUsername") {
return new JsonCheckUsername;
}
else if (url_first_part == "/createTransaction") {
return new JsonCreateTransaction;
}

View File

@ -58,31 +58,37 @@ Poco::JSON::Object* JsonUnsecureLogin::handle(Poco::Dynamic::Var params)
}
auto user = controller::User::create();
std::string message;
std::string details;
if (email.size()) {
if (!sm->isValid(email, VALIDATE_EMAIL)) {
return stateError("invalid email");
message = "invalid email";
}
if (1 != user->load(email)) {
return stateError("user with email not found", email);
message = "user with email not found";
details = email;
}
}
else if (username.size() > 0) {
if (1 != user->load(username)) {
return stateError("user with username not found", username);
message = "user with username not found";
details = username;
}
email = user->getModel()->getEmail();
}
if (message.size()) {
Poco::Thread::sleep(ServerConfig::g_FakeLoginSleepTime);
return stateError(message.data(), details);
}
NotificationList pwd_errors;
Poco::JSON::Object* result = new Poco::JSON::Object;
if (!password.size() || !sm->checkPwdValidation(password, &pwd_errors, LanguageManager::getInstance()->getFreeCatalog(LANG_EN))) {
Poco::Thread::sleep(ServerConfig::g_FakeLoginSleepTime);
result->set("state", "error");
result->set("msg", pwd_errors.getLastError()->getString(false));
if (pwd_errors.errorCount()) {
result->set("details", pwd_errors.getLastError()->getString(false));
}
result->set("msg", "password incorrect");
return result;
}

View File

@ -57,6 +57,7 @@ bool ConnectionManager::setConnectionsFromConfig(const Poco::Util::LayeredConfig
dbConfig << "user=" << config.getString(firstKeyPart + ".db.user", "root") << ";";
dbConfig << "password=" << config.getString(firstKeyPart + ".db.password", "") << ";";
dbConfig << "auto-reconnect=true";
std::clog << "try connect with: " << dbConfig.str() << std::endl;
setConnection(dbConfig.str(), type);

View File

@ -108,7 +108,9 @@ namespace controller {
bool User::isUsernameAlreadyUsed(const std::string& username)
{
auto db = getModel();
return db->loadFromDB({ "username", "group_id" }, username, db->getGroupId(), model::table::MYSQL_CONDITION_AND) > 0;
auto results = db->loadMultipleFromDB<model::table::UserTuple>({ "username", "group_id" }, username, db->getGroupId(), model::table::MYSQL_CONDITION_AND);
return results.size() > 0;
}
int User::load(const unsigned char* pubkey_array)

View File

@ -61,6 +61,12 @@ namespace model {
template<class T1, class T2>
size_t loadFromDB(const std::vector<std::string>& fieldNames, const T1& field1Value, const T2& field2Value, MysqlConditionType conditionType = MYSQL_CONDITION_AND);
template<class Tuple, class T1, class T2>
std::vector<Tuple> loadMultipleFromDB(
const std::vector<std::string>& fieldNames,
const T1& field1Value, const T2& field2Value,
MysqlConditionType conditionType = MYSQL_CONDITION_AND);
template<class Tuple, class T1, class T2, class T3, class T4>
std::vector<Tuple> loadMultipleFromDB(
const std::vector<std::string>& fieldNames,
@ -290,6 +296,43 @@ namespace model {
return resultCount;
}
template<class Tuple, class T1, class T2>
std::vector<Tuple> ModelBase::loadMultipleFromDB(
const std::vector<std::string>& fieldNames,
const T1& field1Value, const T2& field2Value,
MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/)
{
auto cm = ConnectionManager::getInstance();
std::vector<Tuple> results;
if (fieldNames.size() != 2) {
addError(new Error(getTableName(), "error in loadFromDB with 2 different field values, fieldNames count isn't 2"));
return results;
}
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
Poco::Data::Statement select = _loadMultipleFromDB(session, fieldNames, conditionType);
select, Poco::Data::Keywords::into(results),
Poco::Data::Keywords::useRef(field1Value), Poco::Data::Keywords::useRef(field2Value);
size_t resultCount = 0;
try {
resultCount = select.execute();
}
catch (Poco::Exception& ex) {
lock();
addError(new ParamError(getTableName(), "mysql error by selecting with 2 different field types", ex.displayText()));
int count = 0;
for (auto it = fieldNames.begin(); it != fieldNames.end(); it++) {
addError(new ParamError(getTableName(), "field name for select: ", *it));
}
//addError(new ParamError(getTableName(), "field name for select: ", fieldName.data()));
unlock();
}
return results;
}
template<class Tuple, class T1, class T2, class T3, class T4>
std::vector<Tuple> ModelBase::loadMultipleFromDB(
const std::vector<std::string>& fieldNames,

View File

@ -83,11 +83,11 @@ namespace model {
if (mPasswordHashed) {
insert << "INSERT INTO users (email, first_name, last_name, username, description, password, email_hash, language, group_id) VALUES(?,?,?,?,?,?,?,?);",
insert << "INSERT INTO users (email, first_name, last_name, username, description, password, email_hash, language, group_id) VALUES(?,?,?,?,?,?,?,?,?);",
use(mEmail), use(mFirstName), use(mLastName), use(mUsername), use(mDescription), bind(mPasswordHashed), use(mEmailHash), use(mLanguageKey), use(mGroupId);
}
else {
insert << "INSERT INTO users (email, first_name, last_name, username, description, email_hash, language, group_id) VALUES(?,?,?,?,?,?,?);",
insert << "INSERT INTO users (email, first_name, last_name, username, description, email_hash, language, group_id) VALUES(?,?,?,?,?,?,?,?);",
use(mEmail), use(mFirstName), use(mLastName), use(mUsername), use(mDescription), use(mEmailHash), use(mLanguageKey), use(mGroupId);
}

View File

@ -11,7 +11,14 @@ namespace UniLib {
CPUSheduler::CPUSheduler(uint8_t threadCount, const char* name)
: mThreads(new CPUShedulerThread*[threadCount]), mThreadCount(threadCount), mName(name)
{
char nameBuffer[10]; memset(nameBuffer, 0, 10);
char static_nameBuffer[10]; memset(static_nameBuffer, 0, 10);
char* nameBuffer = static_nameBuffer;
if(threadCount > 99) {
int bufferSize = 7 + strlen(std::to_string(threadCount).data())+1;
nameBuffer = (char*)malloc(bufferSize);
memset(nameBuffer, 0, bufferSize);
}
//uint8_t len = std:: min(strlen(name), 7);
uint8_t len = strlen(name);
if(len > 7) len = 7;
@ -24,6 +31,9 @@ namespace UniLib {
sprintf(&nameBuffer[len], "%.2d", i);
mThreads[i] = new CPUShedulerThread(this, nameBuffer);
}
if(threadCount > 99) {
free(nameBuffer);
}
}
CPUSheduler::~CPUSheduler()

View File

@ -0,0 +1,123 @@
#include "gtest/gtest.h"
#include "JSONInterface/JsonCheckUsername.h"
TEST(TestJsonCheckUsername, InvalidGroupAlias)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("group_alias", "robert");
auto result = jsonCall.handle(params);
auto msg = result->get("msg");
ASSERT_FALSE(msg.isEmpty());
ASSERT_TRUE(msg.isString());
ASSERT_EQ(msg.toString(), "unknown group");
delete result;
}
TEST(TestJsonCheckUsername, InvalidGroupId)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("group_id", "4");
auto result = jsonCall.handle(params);
auto msg = result->get("msg");
ASSERT_FALSE(msg.isEmpty());
ASSERT_TRUE(msg.isString());
ASSERT_EQ(msg.toString(), "unknown group");
delete result;
}
TEST(TestJsonCheckUsername, ValidGroupAlias)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("group_alias", "gdd1");
auto result = jsonCall.handle(params);
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "success");
auto group_id = result->get("group_id");
ASSERT_FALSE(group_id.isEmpty());
ASSERT_TRUE(group_id.isInteger());
int group_id_int = 0;
group_id.convert(group_id_int);
ASSERT_EQ(group_id_int, 1);
delete result;
}
TEST(TestJsonCheckUsername, UsernameWithoutGroup)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("username", "maxi");
auto result = jsonCall.handle(params);
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "error");
auto msg = result->get("msg");
ASSERT_FALSE(msg.isEmpty());
ASSERT_TRUE(msg.isString());
ASSERT_EQ(msg.toString(), "no group given");
delete result;
}
TEST(TestJsonCheckUsername, ExistingUsername)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("username", "Erfinder");
params->set("group_id", 1);
auto result = jsonCall.handle(params);
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "warning");
auto msg = result->get("msg");
ASSERT_FALSE(msg.isEmpty());
ASSERT_TRUE(msg.isString());
ASSERT_EQ(msg.toString(), "username already in use");
}
TEST(TestJsonCheckUsername, NewUsername)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("username", "Maxi");
params->set("group_id", 1);
auto result = jsonCall.handle(params);
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "success");
}
TEST(TestJsonCheckUsername, UsernameExistInOtherGroup)
{
JsonCheckUsername jsonCall;
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
params->set("username", "Erfinder");
params->set("group_id", 2);
auto result = jsonCall.handle(params);
auto state = result->get("state");
ASSERT_FALSE(state.isEmpty());
ASSERT_TRUE(state.isString());
ASSERT_EQ(state.toString(), "success");
}

View File

@ -1,45 +0,0 @@
#include "TestHash.h"
#include "../lib/DRHash.h"
#include <string>
TestHash::TestHash()
{
}
TestHash::~TestHash()
{
}
int TestHash::init()
{
return 0;
}
int TestHash::test()
{
std::string testEmails[] = {
"a","b", "c", "d", "aa", "ab",
"@", ".d", "gmx", "@gmx", "@gmx.de",
"***REMOVED***",
"***REMOVED***",
"coin-info5@gradido.net",
"coin-info6@gradido.net",
"coin-info8@gradido.net",
"coin-info9@gradido.net",
"coin-info10@gradido.net",
"coin-info11@gradido.net",
"coin-info12@gradido.net"
};
printf("hashes: \n");
for (int i = 0; i < 20; i++) {
DHASH id = DRMakeStringHash(testEmails[i].data(), testEmails[i].size());
//printf("%s: %lu\n", testEmails[i].data(), id);
//"***REMOVED***" => 1211212
printf("\"%s\" => %lu,\n", testEmails[i].data(), id);
}
return 0;
}

View File

@ -1,19 +0,0 @@
#ifndef __GRADIDO_LOGIN_SERVER_TEST_HASH_
#define __GRADIDO_LOGIN_SERVER_TEST_HASH_
#include "Test.h"
class TestHash : public Test
{
public:
TestHash();
~TestHash();
//! \return 0 if init okay, else return != 0
int init();
//! \return 0 if okay, else return != 0
int test();
const char* getName() { return "TestHash"; };
};
#endif //__GRADIDO_LOGIN_SERVER_TEST_HASH_

View File

@ -3,6 +3,7 @@
#include "Poco/Environment.h"
#include <sodium.h>
#include <math.h>
#include <iostream>
#include "Poco/Logger.h"
#include "Poco/Path.h"
@ -87,27 +88,41 @@ int TestTasks::init()
int TestTasks::test()
{
std::clog << "start with task test" << std::endl;
auto workerCount = Poco::Environment::processorCount() * 4;
auto taskCount = workerCount + workerCount * (randombytes_random() % 4);
printf("[TestTasks::test] taskCount: %d\n", taskCount);
std::clog << "worker count: " << std::to_string(workerCount) << ", task count: " << std::to_string(taskCount) << std::endl;
for (int i = 1; i <= taskCount; i++) {
Poco::AutoPtr<RandomCPUTask> task = new RandomCPUTask(&mTaskScheduler, this, i);
lock();
mTasks.insert(std::pair<int, RandomCPUTask*>(i, task));
unlock();
task->scheduleTask(task);
//std::clog << "start task: " << std::to_string(i) << std::endl;
}
std::clog << "all tasks started" << std::endl;
int maxWaitCylces = 3000;
bool finished = false;
do {
maxWaitCylces--;
Poco::Thread::sleep(5);
lock();
if (mTasks.size() == 0) {
finished = true;
if(mErrors.size() > 0) {
std::clog << std::to_string(mErrors.size()) << " errors" << std::endl;
}
try {
lock();
if (mTasks.size() == 0) {
finished = true;
}
unlock();
} catch(Poco::Exception& ex) {
std::clog << "Poco Exception while waiting on tasks: " << ex.displayText() << std::endl;
} catch(std::exception& ex) {
std::clog << "std::exception while waiting on tasks: " << ex.what() << std::endl;
}
unlock();
} while (!finished && maxWaitCylces > 0);
std::clog << "all tasks now finished" << std::endl;
lock();
bool hasErrors = false;
@ -150,4 +165,5 @@ void TestTasks::releaseTask(int nr)
mErrors.push_back("[TestTasks] task entry not found" + std::to_string(nr));
}
unlock();
}

View File

@ -1,14 +0,0 @@
#include "TestHederaAccount.h"
#include "../../SingletonManager/ConnectionManager.h"
namespace controller {
void TestHederaAccount::SetUp()
{
}
TEST_F(TestHederaAccount, TestPick) {
auto hedera_account = controller::HederaAccount::pick(ServerConfig::HEDERA_TESTNET, false);
EXPECT_FALSE(hedera_account.isNull());
}
}

View File

@ -1,13 +0,0 @@
#include "gtest/gtest.h"
#include "../../controller/HederaAccount.h"
namespace controller {
class TestHederaAccount : public ::testing::Test {
protected:
void SetUp() override;
};
}

View File

@ -1,14 +0,0 @@
#include "TestHederaId.h"
#include "../../SingletonManager/ConnectionManager.h"
namespace controller {
void TestHederaId::SetUp()
{
}
TEST_F(TestHederaId, TestFindTopicId) {
auto hedera_topic_id = controller::HederaId::find(1, ServerConfig::HEDERA_TESTNET);
EXPECT_FALSE(hedera_topic_id.isNull());
}
}

Some files were not shown because too many files have changed in this diff Show More