Skip to content

Commit

Permalink
Merge branch 'develop' into devshares
Browse files Browse the repository at this point in the history
  • Loading branch information
vikramrajkumar committed Feb 25, 2015
2 parents 3411e22 + beb1cb2 commit cfd5a28
Show file tree
Hide file tree
Showing 25 changed files with 912 additions and 172 deletions.
187 changes: 181 additions & 6 deletions docs/btstest/btstest.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ Here is the code that achieves all of that:
rpc_client.wait_for_rpc()
run_testdir(my_path)

btstest file format
-------------------
Simple btstest usage
--------------------

The main purpose of `.btstest` files is to act as a list of commands and command output.
Taking inspiration from `regression_tests`, a session interacting with the BitShares client is a valid test!
Expand All @@ -88,21 +88,194 @@ Here is an example of a `.btstest` file with no output:
>>> blockchain_get_account myaccount
>>> wallet_account_register myaccount myaccount
>>> blockchain_get_account myaccount
>>> blockchain_get_info
>>> debug_advance_time 1 block
>>> debug_wait_for_block_by_number 1 rlast
>>> blockchain_get_info
>>> blockchain_get_account myaccount
>>> debug_advance_time 1 block
>>> debug_wait_for_block_by_number 1 rlast
>>> blockchain_get_account myaccount
>>> quit

This test is present in the `tests/btstests/tutorial/register_account_0` directory with a suitable `testenv`. The test can easily be run by compiling the `develop` branch and running the following command:

tests/btstest.py tests/btstests/tutorial/register_account_0

The presence of `>>>` characters in a line flags that line as a command. The rest of the line is passed through to the `execute_command_line` RPC, unless it is a *metacommand*, which
is a command that begins with `!`. Metacommands are handled directly by the `btstest` framework. In this case, the `!client` command addreses subsequent commands to the client named `alice` (which was specified in the testenv),
and the `!expect disable` command disables the *expectation functionality* (checking of command output). Disabling expectation is useful to run a test as a *batch script*, only executing the commands and not complaining about failure to match output. Which is often useful for developing new tests or upgrading badly broken tests.

Expectation
-----------

Like `regression_tests`, the `btstest` framework has the capability to test that command output matches a given string. Placing the previous test's output into a file and deleting `!expect disable` gives this output:

>>> !showmatch enable
>>> !client alice
>>> debug_start_simulated_time "20140620T144030.000000"
OK
>>> wallet_create default password
OK
>>> wallet_set_automatic_backups false
false
>>> debug_deterministic_private_keys 0 101 init true
[
"5JZAeEjgszF9kXVpFsAK9wsVer2L3z9WwY63DT7p9kLNZUFYyRQ",
"5KegApb8VGr1CAtUJH4a41KGqX1ZMK2ik64YCjRD3LR95k7LJAS",
...
"5KZw3WpATeW1JdthN6jpdEAwJsgdupgF2CRovbjw4rCE9xvCZp7"
]
>>> wallet_delegate_set_block_production ALL true
OK
>>> wallet_set_transaction_scanning true
true
>>> debug_wait_for_block_by_number 1
OK
>>> wallet_account_create myaccount
"XTS8RCamk6kQtmQeaew1U42qaR67dFnSpQodEZUjWeQGQQhsm53PZ"
...
>>> blockchain_get_account myaccount
Name: myaccount
Registered: 2014-06-20T14:40:30
Last Updated: 36 weeks ago
Owner Key: XTS8RCamk6kQtmQeaew1U42qaR67dFnSpQodEZUjWeQGQQhsm53PZ
Active Key History:
- XTS5VjXgz22FTUrPtv7Y2jp1HnWEcEQm2ksQLenRncBf59wSh6fmq, last used 36 weeks ago
Not a delegate.
>>> quit

Again, this file is present in `tests/btstests/tutorial/register_account_1` directory. When you run this test, you will see the following output:

>>> !client alice
>>> debug_start_simulated_time "20140620T144030.000000"
OK
>>> wallet_create default password
OK
>>> wallet_set_automatic_backups false
false
>>> debug_deterministic_private_keys 0 101 init true
[
"5JZAeEjgszF9kXVpFsAK9wsVer2L3z9WwY63DT7p9kLNZUFYyRQ",
...
"5KZw3WpATeW1JdthN6jpdEAwJsgdupgF2CRovbjw4rCE9xvCZp7"
]
>>> wallet_delegate_set_block_production ALL true
OK
>>> wallet_set_transaction_scanning true
true
>>> debug_wait_for_block_by_number 1
OK
>>> wallet_account_create myaccount
!{ "XTS8RCamk6kQtmQeaew1U42qaR67dFnSpQodEZUjWeQGQQhsm53PZ" }!~{ "XTS7wmhc95NpJuRQE8aGDUzzZhd7W34JQbgCbNdHrtPV1nnGxEq9V" }~
...
>>> blockchain_get_account myaccount
Name: myaccount
Registered: 2014-06-20T14:40:30
Last Updated: 36 weeks ago
Owner Key: !{ XTS8RCamk6kQtmQeaew1U42qaR67dFnSpQodEZUjWeQGQQhsm53PZ }!~{ XTS7wmhc95NpJuRQE8aGDUzzZhd7W34JQbgCbNdHrtPV1nnGxEq9V }~
Active Key History:
- !{ XTS5VjXgz22FTUrPtv7Y2jp1HnWEcEQm2ksQLenRncBf59wSh6fmq, }!~{ XTS5kjEMtBUEzpoe2aZf4C8XGSZrTTc4Ch9Y1jdkp3XgnnA1qy2cE, }~ last used 36 weeks ago
Not a delegate.
>>> quit

The mismatches are clearly marked with `!{ }!` delimiters, and the text that was actually output is `~{ }~` delimiters.
It is clear that the mismatch is due to randomly generated keys which change from run to run. In the next section, you will learn how to use regular expressions to deal with this properly and flexibly.

TODO: Eventually mismatches will trigger a final error message and OS exit code, but this is not implemented yet.

TODO: The `!showmatch` command will eventually allow to toggle between the above form and just straight-up output, but this is not implemented yet.

Expecting regular expressions
-----------------------------

The `${ }$` delimiters cause anything between to be interpreted as Python code. The code runs in an environment which defines a few functions. The one which will be presented in this section is called `expect_regex`.

Here is an example:

>>> !showmatch enable
>>> !client alice
>>> debug_start_simulated_time "20140620T144030.000000"
OK
>>> wallet_create default password
OK
>>> wallet_set_automatic_backups false
false
>>> debug_deterministic_private_keys 0 101 init true
[ ${ expect_regex(r'(?:\s*"[a-zA-Z0-9]+"[,]?){101}') }$ ]
>>> wallet_delegate_set_block_production ALL true
OK
>>> wallet_set_transaction_scanning true
true
>>> debug_wait_for_block_by_number 1
OK
>>> wallet_account_create myaccount
"XTS ${ expect_regex(r'[a-zA-Z0-9]+') }$ "
>>> wallet_account_balance myaccount
No balances found.
>>> debug_deterministic_private_keys 0 1 alice true myaccount false true
[
"${ expect_regex(r'[a-zA-Z0-9]+') }$"
]
>>> wallet_account_balance myaccount
ACCOUNT BALANCE
============================================================
myaccount 100,000.00000 XTS
>>> blockchain_get_account myaccount
No account found.
>>> wallet_account_register myaccount myaccount
TIMESTAMP BLOCK FROM TO AMOUNT MEMO FEE ID
======================================================================================================================================================================
2014-06-20T14:40:30 PENDING myaccount myaccount 0.00000 XTS register myaccount 0.50000 XTS ${ regex(r'[0-9a-f]{8}') }$
>>> blockchain_get_account myaccount
No account found.
>>> debug_advance_time 1 block
OK
>>> debug_wait_for_block_by_number 1 rlast
OK
>>> blockchain_get_account myaccount
No account found.
>>> debug_advance_time 1 block
OK
>>> debug_wait_for_block_by_number 1 rlast
OK
>>> blockchain_get_account myaccount
Name: myaccount
Registered: 2014-06-20T14:40:30
Last Updated: ${ expect_regex(r'[^\n]*') }$
Owner Key: ${ expect_regex(r'[a-zA-Z0-9]+') }$
Active Key History:
- XTS ${ expect_regex(r'[a-zA-Z0-9]+') }$, last used ${ expect_regex(r'[^\n]*') }$
Not a delegate.
>>> quit

However, the problem with copy-pasted output is that some output may change between testing and production, and some other output will change from run to run.
This test exists in `tests/btstests/tutorial/register_account_2`.

Here's a quick primer on what you need to know about Python's syntax and regular expression library in order to use `expect_regex`.
The regular expression passed to `expect_regex` is a Python string literal.
The `r` prefix denotes a *raw string literal* which is a Python language feature to disable the usual C-style handling of escape sequences for a particular string.
Using `r` allows regular expressions like the first one can contain sequences like `\s` which are passed through to the regular expression engine.
The actual syntax of the regular expressions themselves is detailed in `https://docs.python.org/3/library/re.html`.

This test also shows the `btstest` matching is rather "loose" about spare whitespace in your tests.
You can basically write whitespace anywhere in your test and it will be ignored.
This allows you to write readable tests by adding extra whitespace as needed.

You can see the regular expression match here:

>>> blockchain_get_account myaccount
Name: myaccount
Registered: 2014-06-20T14:40:30
Last Updated: ${ expect_regex(r'[^\n]*') }$~{36 weeks ago}~
Owner Key: ${ expect_regex(r'[a-zA-Z0-9]+') }$~{XTS7A6gUbHCiye1JNv2HWNBxmjZxsUkPUXPCEeYLGcQk855umGi31}~
Active Key History:
- XTS ${ expect_regex(r'[a-zA-Z0-9]+') }$~{63EXgREEvRAFyzWw3apqTimmQwf3HvQALiMUYZzXXQwcza8Uf8}~, last used ${ expect_regex(r'[^\n]*') }$~{36 weeks ago}~
Not a delegate.

TODO: Regex flags will be passed in, but this is not currently implemented. Will likely require killing the compiled RE cache.

Improvements to btstest
-----------------------

- Document how to do comments in `.btstest` file
- Better whitespace handling
- Custom comment syntax
- When expected input doesn't match, display line number in `btstest` file
- Command line option to toggle echo on/off
Expand All @@ -120,6 +293,8 @@ Test API
- `register_client` will register a new `TestClient` object
- `_btstest` directly exposes the `btstest.py` module content. The API should evolve to a point where using this is unnecessary

TODO: Document new features after refactoring

Goals of btstest framework
--------------------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace bts { namespace light_wallet {
struct light_wallet_data
{
fc::time_point_sec last_balance_sync_time;
uint32_t last_transaction_sync_block;
uint32_t last_transaction_sync_block = 0;
unordered_map<string,pair<price,fc::time_point>> price_cache;
unordered_map<string,account_data> accounts;
};
Expand Down
5 changes: 2 additions & 3 deletions libraries/rpc/rpc_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,8 @@ namespace bts { namespace rpc {
}

// ilog( "\n\n\n username: ${user} password ${password}", ("path",r.path)("user",username)("password", password));
if( _config.rpc_user != "nouser" &&
(_config.rpc_user != username ||
_config.rpc_password != password ) )
if( _config.rpc_user != username ||
_config.rpc_password != password )
{
//fc_ilog( fc::logger::get("rpc"), "Unauthorized ${path}, username: ${user}", ("path",r.path)("user",username));
// WARNING: logging RPC calls can capture passwords and private keys
Expand Down
5 changes: 4 additions & 1 deletion programs/light_wallet/LightWallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,10 @@ void LightWallet::connectToServer(QString host, quint16 port, QString serverKey,
Q_EMIT connectedChanged(isConnected());
Q_EMIT allAssetsChanged();
} catch (fc::exception e) {
m_connectionError = convert(e.get_log().begin()->get_message()).replace("\n", " ");
if( e.get_log().size() )
m_connectionError = convert(e.get_log().begin()->get_message()).replace("\n", " ");
else
m_connectionError = tr("Unknown error");
Q_EMIT errorConnecting(m_connectionError);
}
END_THREAD
Expand Down
2 changes: 1 addition & 1 deletion programs/light_wallet/QtWrappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ TransactionSummary::TransactionSummary(QString id, fc::time_point_sec timestamp,
});
}

QString TransactionSummary::timestamp() const
QString TransactionSummary::timeString() const
{
using bts::blockchain::now;

Expand Down
8 changes: 5 additions & 3 deletions programs/light_wallet/QtWrappers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ class TransactionSummary : public QObject
{
Q_OBJECT
Q_PROPERTY(QString id MEMBER m_id NOTIFY stub)
Q_PROPERTY(QString timestamp READ timestamp NOTIFY timestampChanged)
Q_PROPERTY(QString timeString READ timeString NOTIFY timestampChanged)
Q_PROPERTY(QDateTime timestamp READ timestamp NOTIFY timestampChanged)
Q_PROPERTY(QString feeAmount MEMBER m_feeAmount NOTIFY stub)
Q_PROPERTY(QString feeSymbol MEMBER m_feeSymbol NOTIFY stub)
Q_PROPERTY(QQmlListProperty<LedgerEntry> ledger READ ledger CONSTANT)
Expand All @@ -49,10 +50,11 @@ class TransactionSummary : public QObject

public:
// TransactionSummary takes ownership of the LedgerEntries in ledger
TransactionSummary(QString id, fc::time_point_sec timestamp, QList<LedgerEntry*>&& ledger, QObject* parent = nullptr);
TransactionSummary(QString id, fc::time_point_sec timeString, QList<LedgerEntry*>&& ledger, QObject* parent = nullptr);
~TransactionSummary(){}

QString timestamp() const;
QString timeString() const;
QDateTime timestamp() const { return convert(m_timestamp); }

QQmlListProperty<LedgerEntry> ledger()
{
Expand Down
2 changes: 1 addition & 1 deletion programs/light_wallet/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ int main(int argc, char *argv[])
app.setApplicationName(QStringLiteral("BitShares %1 Light Wallet").arg(BTS_BLOCKCHAIN_SYMBOL));
app.setOrganizationName(BTS_BLOCKCHAIN_NAME);
app.setOrganizationDomain("bitshares.org");
app.setApplicationVersion("1.0 Beta");
app.setApplicationVersion("1.0 Beta 2");

//Fire up the NTP system
bts::blockchain::now();
Expand Down
10 changes: 9 additions & 1 deletion programs/light_wallet/qml/Transaction.qml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Rectangle {
Item { Layout.preferredWidth: visuals.margins }
Label {
id: timestampLabel
text: trx.timestamp
text: timestampHoverBox.containsMouse? trx.timestamp.toLocaleString() : trx.timeString
font.pixelSize: units.dp(12)

Behavior on text {
Expand All @@ -83,6 +83,13 @@ Rectangle {
}
}
}
MouseArea {
id: timestampHoverBox
anchors.fill: parent
anchors.margins: units.dp(-10)
hoverEnabled: true
acceptedButtons: Qt.NoButton
}
}
Item { Layout.fillWidth: true }
Label {
Expand All @@ -99,6 +106,7 @@ Rectangle {
Ink {
id: transactionInk

hoverEnabled: false
anchors.fill: parent
onClicked: {
//Iterate ledger entries looking for one which contains the mouse
Expand Down
2 changes: 1 addition & 1 deletion programs/web_wallet
12 changes: 6 additions & 6 deletions tests/acceptance_tests/features/advanced_uia.feature
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ Feature: Advanced User Issued Asset Functionality
And I wait for one block


Scenario: authority can still issue shares because hasn't set "restricted" flag.
Scenario: authority can still issue shares because hasn't set "supply_unlimit" flag.
When I'm Alice
And I issue 100 ALICE to account: customer
And I wait for one block
Then I should see the following assets:
| Symbol | Name | Current Share Supply | Maximum Share Supply | Precision |
| ALICE | alice_iou | 100000 | 1000000000 | 1000 |

Scenario: Customer can send his asset to anyone and anybody can trade in the ALICE market.
Scenario: Alice can make the asset restricted and whitelist only customer, meaning Bob can't receive or trade in ALICE markets
Scenario: Alice can unfreeze the market.
Scenario: Alice can spend Bob's funds.
Scenario: Alice can unfreeze funds and bob can spend them again.
Scenario: Alice can restrict issuer's ability to freeze funds again.
When I'm Alice
And I authorize customer for ALICE asset
And I traf
Scenario: Alice can spend customer's funds.
Scenario: Alice can freeze the market

Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
default_permissions = ["retractable","market_halt","balance_halt", "supply_unlimit"]
default_permissions = ["restricted", "retractable","market_halt","balance_halt", "supply_unlimit"]
default_state = ["retractable"]
Given(/^I give default auth permissions for (\w+) to (\d+) of (\[.*\])$/) do |asset, m, addrs|
addr_name_list = JSON.parse(addrs.gsub(/(\w+)/, '"\1"'))
addr_list = []
for name in addr_name_list
addr_list << @addresses[name]
end
@current_actor.node.exec 'wallet_asset_update', asset, nil, nil, nil, nil, nil, 0, default_state, default_permissions, "", m, addr_list
@current_actor.node.exec('wallet_asset_update', asset, nil, nil, nil, nil, nil, 0, default_state, default_permissions, "", m, addr_list)
end

Then(/^I set asset permissions for (\w+) to: (\[.*?\])$/) do |symbol, perm_list|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
Given(/^exec: (\w+)$/) do |cmd|
@current_actor.node.exec cmd
end
Given(/^exec: (\w+) (\w+)$/) do |cmd, arg1|
@current_actor.node.exec cmd, arg1
end
Given(/^(\w+) <- exec: (\w+) (\w+)$/) do |var, cmd, arg1|
@env[var] = @current_actor.node.exec cmd, arg1
end
Given(/^exec: (\w+) (\w+) (\w+)$/) do |cmd, arg1, arg2|
@current_actor.node.exec cmd, arg1, arg2
end
Given(/^exec: (\w+) (\w+) (\w+) (\w+)$/) do |cmd, arg1, arg2, arg3|
@current_actor.node.exec cmd, arg1, arg2, arg3
Given(/^exec: (\w+)$/) do |argstr|
args = argstr.split(";")
@current_actor.node.exec(*args)
end


Given(/^I'm (\w+)$/) do |name|
@current_actor = get_actor(name)
@env ||= {}
Expand Down
Loading

0 comments on commit cfd5a28

Please sign in to comment.