mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-14 11:15:51 +00:00
Move TestUtils and TestWithWallet into the core package so they can be used by third party code in their unit tests.
This commit is contained in:
parent
baeaa64201
commit
90942041e7
@ -18,6 +18,7 @@ package com.google.bitcoin.core;
|
|||||||
|
|
||||||
import com.google.bitcoin.script.Script;
|
import com.google.bitcoin.script.Script;
|
||||||
import com.google.bitcoin.script.ScriptBuilder;
|
import com.google.bitcoin.script.ScriptBuilder;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -974,7 +975,8 @@ public class Block extends Message {
|
|||||||
/**
|
/**
|
||||||
* Returns a solved block that builds on top of this one. This exists for unit tests.
|
* Returns a solved block that builds on top of this one. This exists for unit tests.
|
||||||
*/
|
*/
|
||||||
Block createNextBlock(Address to, long time) {
|
@VisibleForTesting
|
||||||
|
public Block createNextBlock(Address to, long time) {
|
||||||
return createNextBlock(to, null, time, EMPTY_BYTES, Utils.toNanoCoins(50, 0));
|
return createNextBlock(to, null, time, EMPTY_BYTES, Utils.toNanoCoins(50, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,6 +505,11 @@ public abstract class Message implements Serializable {
|
|||||||
return cursor < bytes.length;
|
return cursor < bytes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Network parameters this message was created with. */
|
||||||
|
public NetworkParameters getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
public static class LazyParseException extends RuntimeException {
|
public static class LazyParseException extends RuntimeException {
|
||||||
private static final long serialVersionUID = 6971943053112975594L;
|
private static final long serialVersionUID = 6971943053112975594L;
|
||||||
|
|
||||||
|
@ -739,7 +739,7 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi
|
|||||||
* risky it is. If this method returns true then {@link Wallet#receivePending(Transaction, java.util.List)}
|
* risky it is. If this method returns true then {@link Wallet#receivePending(Transaction, java.util.List)}
|
||||||
* will soon be called with the transactions dependencies as well.
|
* will soon be called with the transactions dependencies as well.
|
||||||
*/
|
*/
|
||||||
boolean isPendingTransactionRelevant(Transaction tx) throws ScriptException {
|
public boolean isPendingTransactionRelevant(Transaction tx) throws ScriptException {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
// Ignore it if we already know about this transaction. Receiving a pending transaction never moves it
|
// Ignore it if we already know about this transaction. Receiving a pending transaction never moves it
|
||||||
|
@ -14,8 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.google.bitcoin.core;
|
package com.google.bitcoin.utils;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.*;
|
||||||
import com.google.bitcoin.store.BlockStore;
|
import com.google.bitcoin.store.BlockStore;
|
||||||
import com.google.bitcoin.store.BlockStoreException;
|
import com.google.bitcoin.store.BlockStoreException;
|
||||||
|
|
||||||
@ -146,15 +147,15 @@ public class TestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class BlockPair {
|
public static class BlockPair {
|
||||||
StoredBlock storedBlock;
|
public StoredBlock storedBlock;
|
||||||
Block block;
|
public Block block;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emulates receiving a valid block that builds on top of the chain.
|
// Emulates receiving a valid block that builds on top of the chain.
|
||||||
public static BlockPair createFakeBlock(BlockStore blockStore, long timeSeconds, Transaction... transactions) {
|
public static BlockPair createFakeBlock(BlockStore blockStore, long timeSeconds, Transaction... transactions) {
|
||||||
try {
|
try {
|
||||||
Block chainHead = blockStore.getChainHead().getHeader();
|
Block chainHead = blockStore.getChainHead().getHeader();
|
||||||
Address to = new ECKey().toAddress(chainHead.params);
|
Address to = new ECKey().toAddress(chainHead.getParams());
|
||||||
Block b = chainHead.createNextBlock(to, timeSeconds);
|
Block b = chainHead.createNextBlock(to, timeSeconds);
|
||||||
// Coinbase tx was already added.
|
// Coinbase tx was already added.
|
||||||
for (Transaction tx : transactions) {
|
for (Transaction tx : transactions) {
|
||||||
@ -186,7 +187,7 @@ public class TestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Block makeSolvedTestBlock(Block prev, Transaction... transactions) throws BlockStoreException {
|
public static Block makeSolvedTestBlock(Block prev, Transaction... transactions) throws BlockStoreException {
|
||||||
Address to = new ECKey().toAddress(prev.params);
|
Address to = new ECKey().toAddress(prev.getParams());
|
||||||
Block b = prev.createNextBlock(to);
|
Block b = prev.createNextBlock(to);
|
||||||
// Coinbase tx already exists.
|
// Coinbase tx already exists.
|
||||||
for (Transaction tx : transactions) {
|
for (Transaction tx : transactions) {
|
@ -14,22 +14,27 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.google.bitcoin.core;
|
package com.google.bitcoin.utils;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.*;
|
||||||
import com.google.bitcoin.params.UnitTestParams;
|
import com.google.bitcoin.params.UnitTestParams;
|
||||||
import com.google.bitcoin.store.BlockStore;
|
import com.google.bitcoin.store.BlockStore;
|
||||||
import com.google.bitcoin.store.MemoryBlockStore;
|
import com.google.bitcoin.store.MemoryBlockStore;
|
||||||
import com.google.bitcoin.utils.BriefLogFormatter;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import static com.google.bitcoin.core.TestUtils.createFakeBlock;
|
import static com.google.bitcoin.utils.TestUtils.createFakeBlock;
|
||||||
import static com.google.bitcoin.core.TestUtils.createFakeTx;
|
import static com.google.bitcoin.utils.TestUtils.createFakeTx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility class that you can derive from in your unit tests. TestWithWallet sets up a wallet with a key,
|
||||||
|
* an in memory block store and a block chain object. It also provides helper methods for filling the wallet
|
||||||
|
* with money in whatever ways you wish. Note that for simplicity with amounts, this class sets the default
|
||||||
|
* fee per kilobyte to zero in setUp and back to normal in tearDown. If you are wanting to test your behaviour
|
||||||
|
* with fees (a good idea!) make sure you set the {@link Wallet.SendRequest#DEFAULT_FEE_PER_KB} value to
|
||||||
|
* {@link Transaction#REFERENCE_DEFAULT_MIN_TX_FEE} before doing so.
|
||||||
|
*/
|
||||||
public class TestWithWallet {
|
public class TestWithWallet {
|
||||||
protected static final NetworkParameters params = UnitTestParams.get();
|
protected static final NetworkParameters params = UnitTestParams.get();
|
||||||
protected ECKey myKey;
|
protected ECKey myKey;
|
||||||
@ -38,7 +43,6 @@ public class TestWithWallet {
|
|||||||
protected BlockChain chain;
|
protected BlockChain chain;
|
||||||
protected BlockStore blockStore;
|
protected BlockStore blockStore;
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
BriefLogFormatter.init();
|
BriefLogFormatter.init();
|
||||||
Wallet.SendRequest.DEFAULT_FEE_PER_KB = BigInteger.ZERO;
|
Wallet.SendRequest.DEFAULT_FEE_PER_KB = BigInteger.ZERO;
|
||||||
@ -50,13 +54,12 @@ public class TestWithWallet {
|
|||||||
chain = new BlockChain(params, wallet, blockStore);
|
chain = new BlockChain(params, wallet, blockStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
Wallet.SendRequest.DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
|
Wallet.SendRequest.DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Transaction sendMoneyToWallet(Wallet wallet, Transaction tx, AbstractBlockChain.NewBlockType type)
|
protected Transaction sendMoneyToWallet(Wallet wallet, Transaction tx, AbstractBlockChain.NewBlockType type)
|
||||||
throws IOException, ProtocolException, VerificationException {
|
throws IOException, VerificationException {
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
// Pending/broadcast tx.
|
// Pending/broadcast tx.
|
||||||
if (wallet.isPendingTransactionRelevant(tx))
|
if (wallet.isPendingTransactionRelevant(tx))
|
@ -23,6 +23,7 @@ import com.google.bitcoin.params.UnitTestParams;
|
|||||||
import com.google.bitcoin.store.BlockStore;
|
import com.google.bitcoin.store.BlockStore;
|
||||||
import com.google.bitcoin.store.MemoryBlockStore;
|
import com.google.bitcoin.store.MemoryBlockStore;
|
||||||
import com.google.bitcoin.utils.BriefLogFormatter;
|
import com.google.bitcoin.utils.BriefLogFormatter;
|
||||||
|
import com.google.bitcoin.utils.TestUtils;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -32,8 +33,8 @@ import java.math.BigInteger;
|
|||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import static com.google.bitcoin.core.TestUtils.createFakeBlock;
|
import static com.google.bitcoin.utils.TestUtils.createFakeBlock;
|
||||||
import static com.google.bitcoin.core.TestUtils.createFakeTx;
|
import static com.google.bitcoin.utils.TestUtils.createFakeTx;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
// Handling of chain splits/reorgs are in ChainSplitTests.
|
// Handling of chain splits/reorgs are in ChainSplitTests.
|
||||||
|
@ -28,8 +28,8 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static com.google.bitcoin.core.TestUtils.createFakeBlock;
|
import static com.google.bitcoin.utils.TestUtils.createFakeBlock;
|
||||||
import static com.google.bitcoin.core.TestUtils.createFakeTx;
|
import static com.google.bitcoin.utils.TestUtils.createFakeTx;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class LazyParseByteCacheTest {
|
public class LazyParseByteCacheTest {
|
||||||
|
@ -18,6 +18,7 @@ package com.google.bitcoin.core;
|
|||||||
|
|
||||||
import com.google.bitcoin.params.UnitTestParams;
|
import com.google.bitcoin.params.UnitTestParams;
|
||||||
import com.google.bitcoin.utils.BriefLogFormatter;
|
import com.google.bitcoin.utils.BriefLogFormatter;
|
||||||
|
import com.google.bitcoin.utils.TestUtils;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import com.google.bitcoin.discovery.PeerDiscovery;
|
|||||||
import com.google.bitcoin.discovery.PeerDiscoveryException;
|
import com.google.bitcoin.discovery.PeerDiscoveryException;
|
||||||
import com.google.bitcoin.params.UnitTestParams;
|
import com.google.bitcoin.params.UnitTestParams;
|
||||||
import com.google.bitcoin.store.MemoryBlockStore;
|
import com.google.bitcoin.store.MemoryBlockStore;
|
||||||
|
import com.google.bitcoin.utils.TestUtils;
|
||||||
import com.google.bitcoin.utils.Threading;
|
import com.google.bitcoin.utils.Threading;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -18,6 +18,7 @@ package com.google.bitcoin.core;
|
|||||||
|
|
||||||
import com.google.bitcoin.core.Peer.PeerHandler;
|
import com.google.bitcoin.core.Peer.PeerHandler;
|
||||||
import com.google.bitcoin.params.TestNet3Params;
|
import com.google.bitcoin.params.TestNet3Params;
|
||||||
|
import com.google.bitcoin.utils.TestUtils;
|
||||||
import com.google.bitcoin.utils.Threading;
|
import com.google.bitcoin.utils.Threading;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
@ -43,7 +44,7 @@ import java.util.List;
|
|||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
import static com.google.bitcoin.core.TestUtils.*;
|
import static com.google.bitcoin.utils.TestUtils.*;
|
||||||
import static org.easymock.EasyMock.*;
|
import static org.easymock.EasyMock.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
@ -25,6 +25,8 @@ import com.google.bitcoin.crypto.KeyCrypterScrypt;
|
|||||||
import com.google.bitcoin.crypto.TransactionSignature;
|
import com.google.bitcoin.crypto.TransactionSignature;
|
||||||
import com.google.bitcoin.store.WalletProtobufSerializer;
|
import com.google.bitcoin.store.WalletProtobufSerializer;
|
||||||
import com.google.bitcoin.utils.MockTransactionBroadcaster;
|
import com.google.bitcoin.utils.MockTransactionBroadcaster;
|
||||||
|
import com.google.bitcoin.utils.TestUtils;
|
||||||
|
import com.google.bitcoin.utils.TestWithWallet;
|
||||||
import com.google.bitcoin.utils.Threading;
|
import com.google.bitcoin.utils.Threading;
|
||||||
import com.google.bitcoin.wallet.KeyTimeCoinSelector;
|
import com.google.bitcoin.wallet.KeyTimeCoinSelector;
|
||||||
import com.google.bitcoin.wallet.WalletFiles;
|
import com.google.bitcoin.wallet.WalletFiles;
|
||||||
@ -34,6 +36,7 @@ import com.google.protobuf.ByteString;
|
|||||||
import org.bitcoinj.wallet.Protos;
|
import org.bitcoinj.wallet.Protos;
|
||||||
import org.bitcoinj.wallet.Protos.ScryptParameters;
|
import org.bitcoinj.wallet.Protos.ScryptParameters;
|
||||||
import org.bitcoinj.wallet.Protos.Wallet.EncryptionType;
|
import org.bitcoinj.wallet.Protos.Wallet.EncryptionType;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -49,7 +52,7 @@ import java.util.concurrent.CountDownLatch;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import static com.google.bitcoin.core.TestUtils.*;
|
import static com.google.bitcoin.utils.TestUtils.*;
|
||||||
import static com.google.bitcoin.core.Utils.*;
|
import static com.google.bitcoin.core.Utils.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
@ -94,6 +97,12 @@ public class WalletTest extends TestWithWallet {
|
|||||||
myEncryptedAddress2 = myEncryptedKey2.toAddress(params);
|
myEncryptedAddress2 = myEncryptedKey2.toAddress(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
@Override
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
super.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void basicSpending() throws Exception {
|
public void basicSpending() throws Exception {
|
||||||
basicSpendingCommon(wallet, myAddress, false);
|
basicSpendingCommon(wallet, myAddress, false);
|
||||||
|
@ -18,6 +18,7 @@ package com.google.bitcoin.protocols.channels;
|
|||||||
|
|
||||||
import com.google.bitcoin.core.*;
|
import com.google.bitcoin.core.*;
|
||||||
import com.google.bitcoin.store.WalletProtobufSerializer;
|
import com.google.bitcoin.store.WalletProtobufSerializer;
|
||||||
|
import com.google.bitcoin.utils.TestWithWallet;
|
||||||
import com.google.bitcoin.utils.Threading;
|
import com.google.bitcoin.utils.Threading;
|
||||||
import com.google.bitcoin.wallet.WalletFiles;
|
import com.google.bitcoin.wallet.WalletFiles;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
@ -93,6 +94,12 @@ public class ChannelConnectionTest extends TestWithWallet {
|
|||||||
Threading.warnOnLockCycles();
|
Threading.warnOnLockCycles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
@Override
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
super.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void checkFail() {
|
public void checkFail() {
|
||||||
assertFalse(fail.get());
|
assertFalse(fail.get());
|
||||||
|
@ -19,9 +19,11 @@ package com.google.bitcoin.protocols.channels;
|
|||||||
import com.google.bitcoin.core.*;
|
import com.google.bitcoin.core.*;
|
||||||
import com.google.bitcoin.script.Script;
|
import com.google.bitcoin.script.Script;
|
||||||
import com.google.bitcoin.script.ScriptBuilder;
|
import com.google.bitcoin.script.ScriptBuilder;
|
||||||
|
import com.google.bitcoin.utils.TestWithWallet;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.common.util.concurrent.SettableFuture;
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -32,8 +34,8 @@ import java.util.concurrent.BlockingQueue;
|
|||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
import static com.google.bitcoin.core.TestUtils.createFakeTx;
|
import static com.google.bitcoin.utils.TestUtils.createFakeTx;
|
||||||
import static com.google.bitcoin.core.TestUtils.makeSolvedTestBlock;
|
import static com.google.bitcoin.utils.TestUtils.makeSolvedTestBlock;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class PaymentChannelStateTest extends TestWithWallet {
|
public class PaymentChannelStateTest extends TestWithWallet {
|
||||||
@ -84,6 +86,12 @@ public class PaymentChannelStateTest extends TestWithWallet {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
@Override
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
super.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void stateErrors() throws Exception {
|
public void stateErrors() throws Exception {
|
||||||
PaymentChannelClientState channelState = new PaymentChannelClientState(wallet, myKey, serverKey,
|
PaymentChannelClientState channelState = new PaymentChannelClientState(wallet, myKey, serverKey,
|
||||||
|
@ -6,6 +6,7 @@ import com.google.bitcoin.core.TransactionConfidence.ConfidenceType;
|
|||||||
import com.google.bitcoin.params.MainNetParams;
|
import com.google.bitcoin.params.MainNetParams;
|
||||||
import com.google.bitcoin.params.UnitTestParams;
|
import com.google.bitcoin.params.UnitTestParams;
|
||||||
import com.google.bitcoin.utils.BriefLogFormatter;
|
import com.google.bitcoin.utils.BriefLogFormatter;
|
||||||
|
import com.google.bitcoin.utils.TestUtils;
|
||||||
import com.google.bitcoin.utils.Threading;
|
import com.google.bitcoin.utils.Threading;
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
import org.bitcoinj.wallet.Protos;
|
import org.bitcoinj.wallet.Protos;
|
||||||
@ -20,7 +21,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static com.google.bitcoin.core.TestUtils.createFakeTx;
|
import static com.google.bitcoin.utils.TestUtils.createFakeTx;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class WalletProtobufSerializerTest {
|
public class WalletProtobufSerializerTest {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user