Michelson: Add a test suite
This commit is contained in:
parent
110e0206e7
commit
a663e43f18
@ -14,6 +14,7 @@ build:
|
|||||||
run:
|
run:
|
||||||
${MAKE} ${addprefix run-,${DIR}}
|
${MAKE} ${addprefix run-,${DIR}}
|
||||||
${MAKE} run-basic.sh
|
${MAKE} run-basic.sh
|
||||||
|
${MAKE} run-contracts.sh
|
||||||
clean:
|
clean:
|
||||||
${MAKE} -C lib clean
|
${MAKE} -C lib clean
|
||||||
${MAKE} ${addprefix clean-,${DIR}}
|
${MAKE} ${addprefix clean-,${DIR}}
|
||||||
@ -27,3 +28,6 @@ ${addprefix clean-,${DIR}}: clean-%:
|
|||||||
|
|
||||||
run-basic.sh:
|
run-basic.sh:
|
||||||
./test-basic.sh
|
./test-basic.sh
|
||||||
|
|
||||||
|
run-contracts.sh:
|
||||||
|
./test-contracts.sh
|
||||||
|
5
test/contracts/and.tz
Normal file
5
test/contracts/and.tz
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
parameter (pair bool bool);
|
||||||
|
return bool;
|
||||||
|
storage unit;
|
||||||
|
code {DUP; CADR; CAR; SWAP; CADR; CDR; AND;
|
||||||
|
UNIT; SWAP; PAIR};
|
4
test/contracts/balance.tz
Normal file
4
test/contracts/balance.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter unit;
|
||||||
|
storage unit;
|
||||||
|
return tez;
|
||||||
|
code {DROP; UNIT; BALANCE; PAIR};
|
7
test/contracts/build_list.tz
Normal file
7
test/contracts/build_list.tz
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
parameter uint64;
|
||||||
|
return (list uint64);
|
||||||
|
storage unit;
|
||||||
|
code {CADR; NIL uint64; SWAP; DUP; PUSH uint64 0; CMPNEQ;
|
||||||
|
LOOP {DUP; DIP {SWAP}; CONS; SWAP; PUSH uint64 1; SWAP; SUB;
|
||||||
|
DUP; PUSH uint64 0; CMPNEQ};
|
||||||
|
CONS; UNIT; SWAP; PAIR};
|
5
test/contracts/check_signature.tz
Normal file
5
test/contracts/check_signature.tz
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
parameter key;
|
||||||
|
storage (pair signature string);
|
||||||
|
return bool;
|
||||||
|
code {DUP; DUP; DIP{CDR; DUP; CAR; DIP{CDR; H}; PAIR};
|
||||||
|
CADR; CHECK_SIGNATURE; DIP{CDR}; PAIR};
|
10
test/contracts/compare.tz
Normal file
10
test/contracts/compare.tz
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
parameter (pair tez tez);
|
||||||
|
return (list bool);
|
||||||
|
storage unit;
|
||||||
|
code {CADR; DUP; DUP; DUP; DUP; DIIIIIP {NIL bool};
|
||||||
|
DIIIIP {DUP; CAR; DIP {CDR}; COMPARE; LE; CONS};
|
||||||
|
DIIIP {DUP; CAR; DIP {CDR}; COMPARE; GE; CONS};
|
||||||
|
DIIP{DUP; CAR; DIP {CDR}; COMPARE; LT; CONS};
|
||||||
|
DIP {DUP; CAR; DIP {CDR}; COMPARE; GT; CONS}
|
||||||
|
DUP; CAR; DIP {CDR}; COMPARE; EQ; CONS;
|
||||||
|
UNIT; SWAP; PAIR};
|
4
test/contracts/concat_hello.tz
Normal file
4
test/contracts/concat_hello.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter (list string);
|
||||||
|
return (list string);
|
||||||
|
storage unit;
|
||||||
|
code {CADR; LAMBDA string string {PUSH string "Hello "; CONCAT}; MAP; UNIT; SWAP; PAIR};
|
5
test/contracts/concat_list.tz
Normal file
5
test/contracts/concat_list.tz
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
parameter (list string);
|
||||||
|
return string;
|
||||||
|
storage unit;
|
||||||
|
code {CADR; PUSH string ""; SWAP; LAMBDA (pair string string) string {DUP; CAR; SWAP; CDR; SWAP; CONCAT}; REDUCE;
|
||||||
|
UNIT; SWAP; PAIR};
|
8
test/contracts/contains_all.tz
Normal file
8
test/contracts/contains_all.tz
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
parameter (pair (list string) (list string));
|
||||||
|
storage unit;
|
||||||
|
return bool;
|
||||||
|
code {CADR; DUP; CAR; DIP{CDR}; EMPTY_SET string; SWAP;
|
||||||
|
LAMBDA (pair string (set string)) (set string) {DUP; CAR; DIP{CDR}; PUSH bool True; SWAP; UPDATE};
|
||||||
|
REDUCE; PUSH bool True; SWAP; PAIR; SWAP;
|
||||||
|
LAMBDA (pair string (pair (set string) bool)) (pair (set string) bool) {DUP; DUP; CAR; DIP{CDAR; DIP{CDDR}; DUP}; MEM; DIP{SWAP}; AND; SWAP; PAIR};
|
||||||
|
REDUCE; CDR; UNIT; SWAP; PAIR};
|
5
test/contracts/create_account.tz
Normal file
5
test/contracts/create_account.tz
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
parameter key;
|
||||||
|
return unit;
|
||||||
|
storage (contract unit unit);
|
||||||
|
code {CADR; DIP{PUSH tez "100.00"; PUSH bool False; NONE key}; CREATE_ACCOUNT;
|
||||||
|
UNIT; PAIR};
|
7
test/contracts/create_contract.tz
Normal file
7
test/contracts/create_contract.tz
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
parameter key;
|
||||||
|
storage string;
|
||||||
|
return unit;
|
||||||
|
code {CADR; DIP{UNIT; LAMBDA (pair (pair tez string) unit) (pair string unit) {CADR; UNIT; SWAP; PAIR};
|
||||||
|
PUSH tez "100.00"; PUSH bool False; PUSH bool False; NONE key};
|
||||||
|
CREATE_CONTRACT; DIP{PUSH string ""}; PUSH tez "0.00"; PUSH string "abcdefg"; TRANSFER_TOKENS;
|
||||||
|
DIP{DROP}; UNIT; PAIR};
|
4
test/contracts/empty_map.tz
Normal file
4
test/contracts/empty_map.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
storage unit;
|
||||||
|
return (map string string);
|
||||||
|
parameter unit;
|
||||||
|
code {DROP; EMPTY_MAP string string; PUSH string "world"; SOME; PUSH string "hello"; UPDATE; UNIT; SWAP; PAIR};
|
4
test/contracts/exec_concat.tz
Normal file
4
test/contracts/exec_concat.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter string;
|
||||||
|
return string;
|
||||||
|
storage unit;
|
||||||
|
code {CADR; LAMBDA string string {PUSH string "_abc"; SWAP; CONCAT}; SWAP; EXEC; UNIT; SWAP; PAIR};
|
4
test/contracts/get_map_value.tz
Normal file
4
test/contracts/get_map_value.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter string;
|
||||||
|
storage (map string string);
|
||||||
|
return (option string);
|
||||||
|
code {DUP; CADR; DIP{CDR; DUP}; GET; PAIR};
|
4
test/contracts/hash_string.tz
Normal file
4
test/contracts/hash_string.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter string;
|
||||||
|
return string;
|
||||||
|
storage unit;
|
||||||
|
code {CADR; H; UNIT; SWAP; PAIR};
|
4
test/contracts/if.tz
Normal file
4
test/contracts/if.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter bool;
|
||||||
|
storage unit;
|
||||||
|
return bool;
|
||||||
|
code {CADR; IF {PUSH bool True} {PUSH bool False}; UNIT; SWAP; PAIR};
|
10
test/contracts/max_in_list.tz
Normal file
10
test/contracts/max_in_list.tz
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
parameter (list int32);
|
||||||
|
storage unit;
|
||||||
|
return (option int32);
|
||||||
|
code {CADR; DIP{NONE int32};
|
||||||
|
LAMBDA
|
||||||
|
(pair int32 (option int32))
|
||||||
|
(option int32)
|
||||||
|
{DUP; DUP; CAR; SWAP; CDR;
|
||||||
|
IF_NONE {DIP{DROP}; SOME} {CMPGT; IF {CDR} {CAR; SOME}}};
|
||||||
|
REDUCE; UNIT; SWAP; PAIR};
|
4
test/contracts/not.tz
Normal file
4
test/contracts/not.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter bool;
|
||||||
|
return bool;
|
||||||
|
storage unit;
|
||||||
|
code {CADR; NOT; UNIT; SWAP; PAIR};
|
5
test/contracts/or.tz
Normal file
5
test/contracts/or.tz
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
parameter (pair bool bool);
|
||||||
|
return bool;
|
||||||
|
storage unit;
|
||||||
|
code {CADR; DUP; CAR; SWAP; CDR; OR;
|
||||||
|
UNIT; SWAP; PAIR};
|
4
test/contracts/ret_int.tz
Normal file
4
test/contracts/ret_int.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter unit;
|
||||||
|
code {CADR; PUSH uint32 300; PAIR};
|
||||||
|
return uint32;
|
||||||
|
storage unit;
|
7
test/contracts/reverse.tz
Normal file
7
test/contracts/reverse.tz
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
parameter (list string);
|
||||||
|
storage unit;
|
||||||
|
return (list string);
|
||||||
|
code {CADR; DIP {NIL string}; SWAP; PUSH bool True;
|
||||||
|
# INV: BOOL : ORIG_LIST : REV_LIST : []
|
||||||
|
LOOP {IF_CONS {DIP {SWAP}; CONS; SWAP; PUSH bool True} {NIL string; PUSH bool False}};
|
||||||
|
DROP; UNIT; SWAP; PAIR};
|
4
test/contracts/set_member.tz
Normal file
4
test/contracts/set_member.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter string;
|
||||||
|
storage (set string);
|
||||||
|
return bool;
|
||||||
|
code {DUP; CADR; DIP{CDR}; MEM; DIP{EMPTY_SET string}; PAIR};
|
4
test/contracts/steps_to_quota.tz
Normal file
4
test/contracts/steps_to_quota.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter unit;
|
||||||
|
return uint32;
|
||||||
|
storage unit;
|
||||||
|
code {DROP; UNIT; STEPS_TO_QUOTA; PAIR};
|
4
test/contracts/store_input.tz
Normal file
4
test/contracts/store_input.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter string;
|
||||||
|
return unit;
|
||||||
|
storage string;
|
||||||
|
code {CADR; UNIT; PAIR};
|
4
test/contracts/store_now.tz
Normal file
4
test/contracts/store_now.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter unit;
|
||||||
|
storage timestamp;
|
||||||
|
return unit;
|
||||||
|
code {DROP; NOW; UNIT; PAIR};
|
4
test/contracts/str_id.tz
Normal file
4
test/contracts/str_id.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter string;
|
||||||
|
return string;
|
||||||
|
storage unit;
|
||||||
|
code {CADR; UNIT; SWAP; PAIR};
|
4
test/contracts/swap_left_right.tz
Normal file
4
test/contracts/swap_left_right.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter (or bool string);
|
||||||
|
return (or string bool);
|
||||||
|
storage unit;
|
||||||
|
code {CADR; IF_LEFT {RIGHT string} {LEFT bool}; UNIT; SWAP; PAIR};
|
6
test/contracts/tez_add_sub.tz
Normal file
6
test/contracts/tez_add_sub.tz
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
parameter (pair tez tez);
|
||||||
|
storage unit;
|
||||||
|
return (pair tez tez);
|
||||||
|
code {CADR; DUP; DUP; CAR; DIP{CDR}; ADD;
|
||||||
|
DIP{DUP; CAR; DIP{CDR}; SUB};
|
||||||
|
PAIR; UNIT; SWAP; PAIR};
|
4
test/contracts/transfer_amount.tz
Normal file
4
test/contracts/transfer_amount.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter unit;
|
||||||
|
storage tez;
|
||||||
|
return unit;
|
||||||
|
code {DROP; AMOUNT; UNIT; PAIR};
|
4
test/contracts/transfer_to.tz
Normal file
4
test/contracts/transfer_to.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter (contract unit unit);
|
||||||
|
return unit;
|
||||||
|
storage unit;
|
||||||
|
code {CADR; DIP{UNIT}; PUSH tez "100.00"; UNIT; TRANSFER_TOKENS; PAIR};
|
16
test/contracts/weather_insurance.tz
Normal file
16
test/contracts/weather_insurance.tz
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# (pair signed_weather_data actual_level)
|
||||||
|
parameter (pair signature uint16);
|
||||||
|
# (pair (under_key over_key) (pair weather_service_key (pair rain_level days_in_future)))
|
||||||
|
storage (pair (pair (contract unit unit) (contract unit unit)) (pair uint16 key));
|
||||||
|
return unit;
|
||||||
|
code {DUP; DUP;
|
||||||
|
CADR; DUP; DIP{CDR; H}; CAR; PAIR;
|
||||||
|
SWAP; CDDDR; CHECK_SIGNATURE; # Check if the data has been correctly signed
|
||||||
|
IF {NOP} {FAIL} # If signature is not correct, end the execution
|
||||||
|
DUP; DUP; DUP; DIIIP{CDR}; # Place storage type on bottom of stack
|
||||||
|
DIIP{CDAR}; # Place contracts below numbers
|
||||||
|
DIP{CADDR}; # Get actual rain
|
||||||
|
CDDAR; # Get rain threshold
|
||||||
|
CMPLT; IF {CAR} {CDR}; # Select contract to receive tokens
|
||||||
|
BALANCE; UNIT; TRANSFER_TOKENS; # Setup and execute transfer
|
||||||
|
PAIR}; # Save storage
|
4
test/contracts/xor.tz
Normal file
4
test/contracts/xor.tz
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
parameter (pair bool bool);
|
||||||
|
return bool;
|
||||||
|
storage unit;
|
||||||
|
code {CADR; DUP; CAR; DIP{CDR}; XOR; UNIT; SWAP; PAIR};
|
@ -1,104 +1,45 @@
|
|||||||
#! /bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
DIR=$(dirname "$0")
|
source test-utils.sh
|
||||||
cd "${DIR}"
|
|
||||||
|
|
||||||
DATA_DIR="$(mktemp -d -t tezos_node.XXXXXXXXXX)"
|
${TZCLIENT} list known identities
|
||||||
CLIENT_DIR="$(mktemp -d -t tezos_client.XXXXXXXXXX)"
|
|
||||||
|
|
||||||
cleanup() {
|
${TZCLIENT} transfer 1000 from bootstrap1 to ${KEY1}
|
||||||
[ -z "${NODE_PID}" ] || kill -9 ${NODE_PID} || true
|
${TZCLIENT} transfer 2000 from bootstrap1 to ${KEY2}
|
||||||
echo
|
|
||||||
echo "Node's log:"
|
|
||||||
echo
|
|
||||||
cat $DATA_DIR/LOG
|
|
||||||
rm -fr ${DATA_DIR} ${CLIENT_DIR}
|
|
||||||
}
|
|
||||||
trap cleanup EXIT QUIT INT
|
|
||||||
|
|
||||||
NODE=../tezos-node
|
${TZCLIENT} get balance for ${KEY1} | assert "1,000.00 ꜩ"
|
||||||
CLIENT="../tezos-client -base-dir ${CLIENT_DIR}"
|
${TZCLIENT} get balance for ${KEY2} | assert "2,000.00 ꜩ"
|
||||||
|
|
||||||
CUSTOM_PARAM="--sandbox ./sandbox.json"
|
${TZCLIENT} transfer 1000 from ${KEY2} to ${KEY1}
|
||||||
${NODE} run --data-dir "${DATA_DIR}" ${CUSTOM_PARAM} --rpc-addr "[::]:8732" > "$DATA_DIR"/LOG 2>&1 &
|
|
||||||
NODE_PID="$!"
|
|
||||||
|
|
||||||
echo "Created node, pid: ${NODE_PID}, log: $DATA_DIR/LOG"
|
${TZCLIENT} get balance for ${KEY1} | assert "2,000.00 ꜩ"
|
||||||
|
${TZCLIENT} get balance for ${KEY2} | assert "999.95 ꜩ"
|
||||||
sleep 3
|
|
||||||
|
|
||||||
${CLIENT} -block genesis list versions
|
|
||||||
|
|
||||||
${CLIENT} -block genesis \
|
|
||||||
activate \
|
|
||||||
protocol ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK \
|
|
||||||
with fitness 1 \
|
|
||||||
and key edskRhxswacLW6jF6ULavDdzwqnKJVS4UcDTNiCyiH6H8ZNnn2pmNviL7pRNz9kRxxaWQFzEQEcZExGHKbwmuaAcoMegj5T99z
|
|
||||||
|
|
||||||
${CLIENT} add identity bootstrap1 tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx
|
|
||||||
${CLIENT} add public key bootstrap1 edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav
|
|
||||||
${CLIENT} add secret key bootstrap1 edskRuR1azSfboG86YPTyxrQgosh5zChf5bVDmptqLTb5EuXAm9rsnDYfTKhq7rDQujdn5WWzwUMeV3agaZ6J2vPQT58jJAJPi
|
|
||||||
${CLIENT} add identity bootstrap2 tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN
|
|
||||||
${CLIENT} add identity bootstrap3 tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU
|
|
||||||
${CLIENT} add identity bootstrap4 tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv
|
|
||||||
${CLIENT} add identity bootstrap5 tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv
|
|
||||||
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
KEY1=foo
|
|
||||||
KEY2=bar
|
|
||||||
|
|
||||||
${CLIENT} gen keys ${KEY1}
|
|
||||||
${CLIENT} gen keys ${KEY2}
|
|
||||||
|
|
||||||
${CLIENT} list known identities
|
|
||||||
|
|
||||||
${CLIENT} transfer 1000 from bootstrap1 to ${KEY1}
|
|
||||||
${CLIENT} transfer 2000 from bootstrap1 to ${KEY2}
|
|
||||||
|
|
||||||
assert() {
|
|
||||||
local expected="$1"
|
|
||||||
local result="$(cat)"
|
|
||||||
if [ "${result}" != "${expected}" ]; then
|
|
||||||
echo "Unexpected result: \"${result}\""
|
|
||||||
echo "Expected: \"${expected}\""
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
${CLIENT} get balance for ${KEY1} | assert "1,000.00 ꜩ"
|
|
||||||
${CLIENT} get balance for ${KEY2} | assert "2,000.00 ꜩ"
|
|
||||||
|
|
||||||
${CLIENT} transfer 1000 from ${KEY2} to ${KEY1}
|
|
||||||
|
|
||||||
${CLIENT} get balance for ${KEY1} | assert "2,000.00 ꜩ"
|
|
||||||
${CLIENT} get balance for ${KEY2} | assert "999.95 ꜩ"
|
|
||||||
|
|
||||||
# Should fail
|
# Should fail
|
||||||
# ${CLIENT} transfer 999.95 from ${KEY2} to ${KEY1}
|
# ${TZCLIENT} transfer 999.95 from ${KEY2} to ${KEY1}
|
||||||
|
|
||||||
${CLIENT} mine for bootstrap1
|
${TZCLIENT} mine for bootstrap1
|
||||||
|
|
||||||
${CLIENT} remember program noop file:scripts/noop.tez
|
${TZCLIENT} remember program noop file:contracts/noop.tz
|
||||||
${CLIENT} typecheck program noop
|
${TZCLIENT} typecheck program noop
|
||||||
${CLIENT} originate contract noop \
|
${TZCLIENT} originate contract noop \
|
||||||
for ${KEY1} transferring 1000 from bootstrap1 \
|
for ${KEY1} transferring 1000 from bootstrap1 \
|
||||||
running noop
|
running noop
|
||||||
${CLIENT} transfer 10 from bootstrap1 to noop -arg "Unit"
|
${TZCLIENT} transfer 10 from bootstrap1 to noop -arg "Unit"
|
||||||
|
|
||||||
${CLIENT} originate contract hardlimit \
|
${TZCLIENT} originate contract hardlimit \
|
||||||
for ${KEY1} transferring 1000 from bootstrap1 \
|
for ${KEY1} transferring 1000 from bootstrap1 \
|
||||||
running file:scripts/hardlimit.tez -init "3"
|
running file:contracts/hardlimit.tz -init "3"
|
||||||
${CLIENT} transfer 10 from bootstrap1 to hardlimit -arg "Unit"
|
${TZCLIENT} transfer 10 from bootstrap1 to hardlimit -arg "Unit"
|
||||||
${CLIENT} transfer 10 from bootstrap1 to hardlimit -arg "Unit"
|
${TZCLIENT} transfer 10 from bootstrap1 to hardlimit -arg "Unit"
|
||||||
# ${CLIENT} transfer 10 from bootstrap1 to hardlimit -arg "unit" # should fail
|
# ${TZCLIENT} transfer 10 from bootstrap1 to hardlimit -arg "unit" # should fail
|
||||||
|
|
||||||
${CLIENT} originate free account free_account for ${KEY1}
|
${TZCLIENT} originate free account free_account for ${KEY1}
|
||||||
${CLIENT} get delegate for free_account
|
${TZCLIENT} get delegate for free_account
|
||||||
${CLIENT} set delegate for free_account to ${KEY2}
|
${TZCLIENT} set delegate for free_account to ${KEY2}
|
||||||
${CLIENT} get delegate for free_account
|
${TZCLIENT} get delegate for free_account
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo End of test
|
echo End of test
|
||||||
|
194
test/test-contracts.sh
Executable file
194
test/test-contracts.sh
Executable file
@ -0,0 +1,194 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
source test-utils.sh
|
||||||
|
|
||||||
|
CONTRACT_PATH=contracts
|
||||||
|
|
||||||
|
# FORMAT: assert_output contract_file storage input expected_result
|
||||||
|
|
||||||
|
assert_output $CONTRACT_PATH/ret_int.tz Unit Unit 300
|
||||||
|
assert_output $CONTRACT_PATH/str_id.tz Unit '"Hello"' '"Hello"'
|
||||||
|
assert_output $CONTRACT_PATH/str_id.tz Unit '"abcd"' '"abcd"'
|
||||||
|
|
||||||
|
# Logical not
|
||||||
|
assert_output $CONTRACT_PATH/not.tz Unit True False
|
||||||
|
assert_output $CONTRACT_PATH/not.tz Unit False True
|
||||||
|
|
||||||
|
# Logical and
|
||||||
|
assert_output $CONTRACT_PATH/and.tz Unit "(Pair False False)" False
|
||||||
|
assert_output $CONTRACT_PATH/and.tz Unit "(Pair False True)" False
|
||||||
|
assert_output $CONTRACT_PATH/and.tz Unit "(Pair True False)" False
|
||||||
|
assert_output $CONTRACT_PATH/and.tz Unit "(Pair True True)" True
|
||||||
|
|
||||||
|
# Logical or
|
||||||
|
assert_output $CONTRACT_PATH/or.tz Unit "(Pair False False)" False
|
||||||
|
assert_output $CONTRACT_PATH/or.tz Unit "(Pair False True)" True
|
||||||
|
assert_output $CONTRACT_PATH/or.tz Unit "(Pair True False)" True
|
||||||
|
assert_output $CONTRACT_PATH/or.tz Unit "(Pair True True)" True
|
||||||
|
|
||||||
|
# XOR
|
||||||
|
assert_output $CONTRACT_PATH/xor.tz Unit "(Pair False False)" False
|
||||||
|
assert_output $CONTRACT_PATH/xor.tz Unit "(Pair False True)" True
|
||||||
|
assert_output $CONTRACT_PATH/xor.tz Unit "(Pair True False)" True
|
||||||
|
assert_output $CONTRACT_PATH/xor.tz Unit "(Pair True True)" False
|
||||||
|
|
||||||
|
|
||||||
|
# Build list
|
||||||
|
assert_output $CONTRACT_PATH/build_list.tz Unit 0 "(List 0)"
|
||||||
|
assert_output $CONTRACT_PATH/build_list.tz Unit 3 "(List 0 1 2 3)"
|
||||||
|
assert_output $CONTRACT_PATH/build_list.tz Unit 10 \
|
||||||
|
"(List 0 1 2 3 4 5 6 7 8 9 10)"
|
||||||
|
|
||||||
|
# Concatenate all strings of a list into one string
|
||||||
|
assert_output $CONTRACT_PATH/concat_list.tz Unit '(List "a" "b" "c")' '"abc"'
|
||||||
|
assert_output $CONTRACT_PATH/concat_list.tz Unit '(List )' '""'
|
||||||
|
assert_output $CONTRACT_PATH/concat_list.tz \
|
||||||
|
Unit '(List "Hello" " " "World" "!")' '"Hello World!"'
|
||||||
|
|
||||||
|
# Find maximum int32 in list -- returns None if not found
|
||||||
|
assert_output $CONTRACT_PATH/max_in_list.tz Unit '(List)' 'None'
|
||||||
|
assert_output $CONTRACT_PATH/max_in_list.tz Unit '(List 1)' '(Some 1)'
|
||||||
|
assert_output $CONTRACT_PATH/max_in_list.tz Unit '(List -1)' '(Some -1)'
|
||||||
|
assert_output $CONTRACT_PATH/max_in_list.tz Unit \
|
||||||
|
'(List 10 -1 -20 100 0)' '(Some 100)'
|
||||||
|
assert_output $CONTRACT_PATH/max_in_list.tz Unit \
|
||||||
|
'(List 10 -1 -20 100 0)' '(Some 100)'
|
||||||
|
assert_output $CONTRACT_PATH/max_in_list.tz Unit \
|
||||||
|
'(List -10 -1 -20 -100)' '(Some -1)'
|
||||||
|
|
||||||
|
# Set member -- set is in storage
|
||||||
|
assert_output $CONTRACT_PATH/set_member.tz '(Set)' '"Hi"' 'False'
|
||||||
|
assert_output $CONTRACT_PATH/set_member.tz '(Set "Hi")' '"Hi"' 'True'
|
||||||
|
assert_output $CONTRACT_PATH/set_member.tz '(Set "Hello" "World")' '""' 'False'
|
||||||
|
|
||||||
|
# Contains all elements -- does the second list contain all of the same elements
|
||||||
|
# as the first one? I'm ignoring element multiplicity
|
||||||
|
assert_output $CONTRACT_PATH/contains_all.tz \
|
||||||
|
Unit '(Pair (List) (List))' 'True'
|
||||||
|
assert_output $CONTRACT_PATH/contains_all.tz \
|
||||||
|
Unit '(Pair (List "a") (List "B"))' 'False'
|
||||||
|
assert_output $CONTRACT_PATH/contains_all.tz \
|
||||||
|
Unit '(Pair (List "A") (List "B"))' 'False'
|
||||||
|
assert_output $CONTRACT_PATH/contains_all.tz \
|
||||||
|
Unit '(Pair (List "B") (List "B"))' 'True'
|
||||||
|
assert_output $CONTRACT_PATH/contains_all.tz Unit \
|
||||||
|
'(Pair (List "B" "C" "asdf") (List "B" "B" "asdf" "C"))' 'True'
|
||||||
|
assert_output $CONTRACT_PATH/contains_all.tz Unit \
|
||||||
|
'(Pair (List "B" "B" "asdf" "C") (List "B" "C" "asdf"))' 'True'
|
||||||
|
|
||||||
|
# Concatenate the string in storage with all strings in the given list
|
||||||
|
assert_output $CONTRACT_PATH/concat_hello.tz Unit \
|
||||||
|
'(List "World!")' '(List "Hello World!")'
|
||||||
|
assert_output $CONTRACT_PATH/concat_hello.tz Unit \
|
||||||
|
'(List)' 'List'
|
||||||
|
assert_output $CONTRACT_PATH/concat_hello.tz Unit \
|
||||||
|
'(List "test1" "test2")' '(List "Hello test1" "Hello test2")'
|
||||||
|
|
||||||
|
# Create an empty map and add a string to it
|
||||||
|
assert_output $CONTRACT_PATH/empty_map.tz Unit Unit \
|
||||||
|
'(Map (Item "hello" "world"))'
|
||||||
|
|
||||||
|
# Get the value stored at the given key in the map
|
||||||
|
assert_output $CONTRACT_PATH/get_map_value.tz '(Map (Item "hello" "hi"))' \
|
||||||
|
'"hello"' '(Some "hi")'
|
||||||
|
assert_output $CONTRACT_PATH/get_map_value.tz '(Map (Item "hello" "hi"))' \
|
||||||
|
'""' 'None'
|
||||||
|
assert_output $CONTRACT_PATH/get_map_value.tz \
|
||||||
|
'(Map (Item "1" "one") (Item "2" "two"))' \
|
||||||
|
'"1"' '(Some "one")'
|
||||||
|
|
||||||
|
# Return True if True branch of if was taken and False otherwise
|
||||||
|
assert_output $CONTRACT_PATH/if.tz Unit True True
|
||||||
|
assert_output $CONTRACT_PATH/if.tz Unit False False
|
||||||
|
|
||||||
|
# Generate a pair of or types
|
||||||
|
assert_output $CONTRACT_PATH/swap_left_right.tz Unit '(Left True)' '(Right True)'
|
||||||
|
assert_output $CONTRACT_PATH/swap_left_right.tz Unit '(Right "a")' '(Left "a")'
|
||||||
|
|
||||||
|
# Reverse a list
|
||||||
|
assert_output $CONTRACT_PATH/reverse.tz Unit '(List )' 'List'
|
||||||
|
assert_output $CONTRACT_PATH/reverse.tz Unit '(List "c" "b" "a")' '(List "a" "b" "c")'
|
||||||
|
|
||||||
|
# Exec concat contract
|
||||||
|
assert_output $CONTRACT_PATH/exec_concat.tz Unit '""' '"_abc"'
|
||||||
|
assert_output $CONTRACT_PATH/exec_concat.tz Unit '"test"' '"test_abc"'
|
||||||
|
|
||||||
|
# Get current steps to quota
|
||||||
|
assert_output $CONTRACT_PATH/steps_to_quota.tz Unit Unit 16382
|
||||||
|
|
||||||
|
# Get the current balance of the contract
|
||||||
|
assert_output $CONTRACT_PATH/balance.tz Unit Unit '"4,000,000.00"'
|
||||||
|
|
||||||
|
# Test comparisons on tez (List EQ GT LT GE LE)
|
||||||
|
assert_output $CONTRACT_PATH/compare.tz Unit '(Pair "1.00" "2.00")' '(List False False True False True)'
|
||||||
|
assert_output $CONTRACT_PATH/compare.tz Unit '(Pair "2.00" "1.00")' '(List False True False True False)'
|
||||||
|
assert_output $CONTRACT_PATH/compare.tz Unit '(Pair "2.37" "2.37")' '(List True False False True True)'
|
||||||
|
|
||||||
|
# Test addition and subtraction on tez
|
||||||
|
assert_output $CONTRACT_PATH/tez_add_sub.tz Unit '(Pair "2.00" "1.00")' '(Pair "3.00" "1.00")'
|
||||||
|
assert_output $CONTRACT_PATH/tez_add_sub.tz Unit '(Pair "2.31" "1.01")' '(Pair "3.32" "1.30")'
|
||||||
|
|
||||||
|
# Hash input string
|
||||||
|
# Test assumed to be correct -- hash is based on encoding of AST
|
||||||
|
assert_output $CONTRACT_PATH/hash_string.tz Unit '"abcdefg"' '"exprv3MnhXvjthGzZ7jDtXRRFremZyey9rsGtL7JRkeaQX1fThN7WF"'
|
||||||
|
assert_output $CONTRACT_PATH/hash_string.tz Unit '"12345"' '"expru81QVHsW2qaWLNHnMHSxDNhqtat17ajadri6mKUvXyc2EWHZC3"'
|
||||||
|
|
||||||
|
# Did the given key sign the string?
|
||||||
|
assert_output $CONTRACT_PATH/check_signature.tz \
|
||||||
|
'(Pair "26981d372a7b3866621bf79713d249197fe6d518ef702fa65738e1715bde9da54df04fefbcc84287ecaa9f74ad9296462731aa24bbcece63c6bf73a8f5752309" "hello")' \
|
||||||
|
'"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"' True
|
||||||
|
|
||||||
|
assert_output $CONTRACT_PATH/check_signature.tz \
|
||||||
|
'(Pair "26981d372a7b3866621bf79713d249197fe6d518ef702fa65738e1715bde9da54df04fefbcc84287ecaa9f74ad9296462731aa24bbcece63c6bf73a8f5752309" "abcd")' \
|
||||||
|
'"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"' False
|
||||||
|
|
||||||
|
|
||||||
|
${TZCLIENT} transfer 1000 from bootstrap1 to ${KEY1}
|
||||||
|
${TZCLIENT} transfer 2000 from bootstrap1 to ${KEY2}
|
||||||
|
|
||||||
|
assert_balance ${KEY1} "1,000.00 ꜩ"
|
||||||
|
assert_balance ${KEY2} "2,000.00 ꜩ"
|
||||||
|
|
||||||
|
# Create a contract and transfer 100 ꜩ to it
|
||||||
|
init_with_transfer $CONTRACT_PATH/store_input.tz ${KEY1} '""' 100 bootstrap1
|
||||||
|
${TZCLIENT} transfer 100 from bootstrap1 to store_input -arg '"abcdefg"'
|
||||||
|
assert_balance store_input "200.00 ꜩ"
|
||||||
|
assert_storage_contains store_input '"abcdefg"'
|
||||||
|
${TZCLIENT} transfer 100 from bootstrap1 to store_input -arg '"xyz"'
|
||||||
|
assert_storage_contains store_input '"xyz"'
|
||||||
|
|
||||||
|
init_with_transfer $CONTRACT_PATH/transfer_amount.tz ${KEY1} '"0"' "100" bootstrap1
|
||||||
|
${TZCLIENT} transfer 500 from bootstrap1 to transfer_amount -arg Unit
|
||||||
|
assert_storage_contains transfer_amount 500
|
||||||
|
|
||||||
|
# This tests the `NOW` instruction.
|
||||||
|
# This test may fail if timings are marginal, though I have not yet seen this happen
|
||||||
|
init_with_transfer $CONTRACT_PATH/store_now.tz ${KEY1} '"2017-07-13T09:19:01Z"' "100" bootstrap1
|
||||||
|
${TZCLIENT} transfer 500 from bootstrap1 to store_now -arg Unit
|
||||||
|
assert_storage_contains store_now "$(${TZCLIENT} get timestamp)"
|
||||||
|
|
||||||
|
# Tests TRANSFER_TO
|
||||||
|
${TZCLIENT} originate account "test_transfer_account1" for ${KEY1} transferring 100 from bootstrap1
|
||||||
|
${TZCLIENT} originate account "test_transfer_account2" for ${KEY1} transferring 20 from bootstrap1
|
||||||
|
init_with_transfer $CONTRACT_PATH/transfer_to.tz ${KEY2} Unit 1000 bootstrap1
|
||||||
|
assert_balance test_transfer_account1 "100.00 ꜩ"
|
||||||
|
${TZCLIENT} transfer 100 from bootstrap1 to transfer_to \
|
||||||
|
-arg "\"$(get_contract_addr test_transfer_account1)\""
|
||||||
|
assert_balance test_transfer_account1 "200.00 ꜩ" # Why isn't this 200 ꜩ? Mining fee?
|
||||||
|
${TZCLIENT} transfer 100 from bootstrap1 to transfer_to \
|
||||||
|
-arg "\"$(get_contract_addr test_transfer_account2)\""
|
||||||
|
assert_balance test_transfer_account2 "120.00 ꜩ" # Why isn't this 120 ꜩ? Mining fee?
|
||||||
|
|
||||||
|
# Tests create_account
|
||||||
|
init_with_transfer $CONTRACT_PATH/create_account.tz ${KEY2} \
|
||||||
|
"\"$(get_contract_addr test_transfer_account1)\"" 1000 bootstrap1
|
||||||
|
${TZCLIENT} transfer 100 from bootstrap1 to create_account \
|
||||||
|
-arg '"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"' | assert_in_output "New contract"
|
||||||
|
|
||||||
|
# Creates a contract, transfers data to it and stores the data
|
||||||
|
init_with_transfer $CONTRACT_PATH/create_contract.tz ${KEY2} \
|
||||||
|
"\"$(get_contract_addr test_transfer_account1)\"" 1000 bootstrap1
|
||||||
|
${TZCLIENT} transfer 0.00 from bootstrap1 to create_contract -arg '"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"'
|
||||||
|
assert_storage_contains create_contract '"abcdefg"'
|
153
test/test-utils.sh
Executable file
153
test/test-utils.sh
Executable file
@ -0,0 +1,153 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Run this as a command in scripts to test if a contract produces the correct output
|
||||||
|
# Write `source test-michelson.sh`
|
||||||
|
|
||||||
|
DATA_DIR="$(mktemp -d -t tezos_node.XXXXXXXXXX)"
|
||||||
|
CLIENT_DIR="$(mktemp -d -t tezos_client.XXXXXXXXXX)"
|
||||||
|
|
||||||
|
TZCLIENT="../tezos-client -base-dir ${CLIENT_DIR}"
|
||||||
|
TZNODE=../tezos-node
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
[ -z "${TZNODE_PID}" ] || kill -9 ${TZNODE_PID} || true
|
||||||
|
printf "\nNode's log:\n" > /dev/stderr
|
||||||
|
cat $DATA_DIR/LOG > /dev/stderr
|
||||||
|
rm -fr ${DATA_DIR} ${CLIENT_DIR}
|
||||||
|
}
|
||||||
|
trap cleanup EXIT QUIT INT SIGINT SIGKILL
|
||||||
|
|
||||||
|
CUSTOM_PARAM="--sandbox sandbox.json"
|
||||||
|
${TZNODE} run --data-dir "${DATA_DIR}" ${CUSTOM_PARAM} --rpc-addr "[::]:8732" > "$DATA_DIR"/LOG 2>&1 &
|
||||||
|
TZNODE_PID="$!"
|
||||||
|
|
||||||
|
echo "Created node, pid: ${TZNODE_PID}, log: $DATA_DIR/LOG" > /dev/stderr
|
||||||
|
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
${TZCLIENT} -block genesis \
|
||||||
|
activate \
|
||||||
|
protocol ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK \
|
||||||
|
with fitness 1 \
|
||||||
|
and key edskRhxswacLW6jF6ULavDdzwqnKJVS4UcDTNiCyiH6H8ZNnn2pmNviL7pRNz9kRxxaWQFzEQEcZExGHKbwmuaAcoMegj5T99z
|
||||||
|
|
||||||
|
|
||||||
|
run_contract_file () {
|
||||||
|
local contract=$1;
|
||||||
|
local storage=$2;
|
||||||
|
local input=$3;
|
||||||
|
${TZCLIENT} run program "$contract" on storage "$storage" and input "$input";
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_output () {
|
||||||
|
local contract=$1;
|
||||||
|
local input=$2;
|
||||||
|
local storage=$3;
|
||||||
|
local expected=$4;
|
||||||
|
local output=$(run_contract_file "$contract" "$input" "$storage" | sed '1,/output/d' |
|
||||||
|
sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' ||
|
||||||
|
{ printf '\nTest failed with error at line %s\n' "$(caller)" > /dev/stderr;
|
||||||
|
exit 1; });
|
||||||
|
if [ "$expected" != "$output" ]; then
|
||||||
|
echo "Test at" `caller` failed > /dev/stderr;
|
||||||
|
printf "Expected %s but got %s" "$expected" "$output" > /dev/stderr;
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_balance () {
|
||||||
|
local KEY="$1"
|
||||||
|
local EXPECTED_BALANCE="$2"
|
||||||
|
local RESULT=$(${TZCLIENT} get balance for ${KEY})
|
||||||
|
if [ "${RESULT}" != "${EXPECTED_BALANCE}" ]; then
|
||||||
|
printf "Balance assertion failed for ${KEY} on line '%s'. Expected %s but got %s.\n" \
|
||||||
|
"$(caller)" "${EXPECTED_BALANCE}" "${RESULT}"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
contract_name_of_file () {
|
||||||
|
basename ${FILE} ".tz"
|
||||||
|
}
|
||||||
|
|
||||||
|
init_contract_from_file () {
|
||||||
|
local FILE="$1"
|
||||||
|
local NAME=$(contract_name_of_file ${FILE})
|
||||||
|
${TZCLIENT} remember program "${NAME}" "file:${FILE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
init_with_transfer () {
|
||||||
|
local FILE="$1"
|
||||||
|
local NAME=$(contract_name_of_file ${FILE})
|
||||||
|
local KEY="$2"
|
||||||
|
local INITIAL_STORAGE="$3"
|
||||||
|
local TRANSFER_AMT="$4"
|
||||||
|
local TRANSFER_SRC=${5-bootstrap1}
|
||||||
|
${TZCLIENT} originate contract ${NAME} \
|
||||||
|
for ${KEY} transferring "${TRANSFER_AMT}" \
|
||||||
|
from ${TRANSFER_SRC} running "${FILE}" -init "${INITIAL_STORAGE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Takes a grep regexp and fails with an error message if command does not include
|
||||||
|
# the regexp
|
||||||
|
assert_in_output () {
|
||||||
|
local MATCHING="$1"
|
||||||
|
local INPUT=${2-/dev/stdin}
|
||||||
|
if ! grep -q "${MATCHING}" ${INPUT}; then
|
||||||
|
printf "Failure on line %s. Expected to find %s in output." \
|
||||||
|
"$(caller)" "${MATCHING}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_contract_addr () {
|
||||||
|
local CONTRACT_NAME="$1"
|
||||||
|
${TZCLIENT} show known contract "${CONTRACT_NAME}"
|
||||||
|
}
|
||||||
|
|
||||||
|
contract_storage () {
|
||||||
|
local CONTRACT_NAME="$1" # Can be either an alias or hash
|
||||||
|
${TZCLIENT} get storage for ${CONTRACT_NAME}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_storage_contains () {
|
||||||
|
local CONTRACT_NAME="$1"
|
||||||
|
local EXPECTED_STORAGE="$2"
|
||||||
|
contract_storage ${CONTRACT_NAME} | assert_in_output ${EXPECTED_STORAGE}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert() {
|
||||||
|
local expected="$1"
|
||||||
|
local result="$(cat)"
|
||||||
|
if [ "${result}" != "${expected}" ]; then
|
||||||
|
echo "Unexpected result: \"${result}\""
|
||||||
|
echo "Expected: \"${expected}\""
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOTSTRAP1_IDENTITY=tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx
|
||||||
|
BOOTSTRAP1_PUBLIC=edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav
|
||||||
|
BOOTSTRAP1_SECRET=edskRuR1azSfboG86YPTyxrQgosh5zChf5bVDmptqLTb5EuXAm9rsnDYfTKhq7rDQujdn5WWzwUMeV3agaZ6J2vPQT58jJAJPi
|
||||||
|
BOOTSTRAP2_IDENTITY=tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN
|
||||||
|
BOOTSTRAP3_IDENTITY=tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU
|
||||||
|
BOOTSTRAP4_IDENTITY=tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv
|
||||||
|
BOOTSTRAP5_IDENTITY=tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv
|
||||||
|
|
||||||
|
KEY1=foo
|
||||||
|
KEY2=bar
|
||||||
|
|
||||||
|
${TZCLIENT} add identity bootstrap1 ${BOOTSTRAP1_IDENTITY}
|
||||||
|
${TZCLIENT} add public key bootstrap1 ${BOOTSTRAP1_PUBLIC}
|
||||||
|
${TZCLIENT} add secret key bootstrap1 ${BOOTSTRAP1_SECRET}
|
||||||
|
${TZCLIENT} add identity bootstrap2 ${BOOTSTRAP2_IDENTITY}
|
||||||
|
${TZCLIENT} add identity bootstrap3 ${BOOTSTRAP3_IDENTITY}
|
||||||
|
${TZCLIENT} add identity bootstrap4 ${BOOTSTRAP4_IDENTITY}
|
||||||
|
${TZCLIENT} add identity bootstrap5 ${BOOTSTRAP5_IDENTITY}
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
${TZCLIENT} gen keys ${KEY1}
|
||||||
|
${TZCLIENT} gen keys ${KEY2}
|
||||||
|
|
||||||
|
# For ease of use outside of the script
|
||||||
|
alias client="${TZCLIENT}"
|
Loading…
Reference in New Issue
Block a user