UpdateFX with maven build (tested only on mac)

This commit is contained in:
Manfred Karrer 2015-02-27 23:47:21 +01:00
parent 491e15c3de
commit 6b4f528f47
706 changed files with 6520 additions and 737 deletions

View file

@ -0,0 +1,79 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.app;
import io.bitsquare.btc.UserAgent;
import org.junit.Test;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.mock.env.MockPropertySource;
import static io.bitsquare.app.BitsquareEnvironment.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.core.env.PropertySource.named;
import static org.springframework.core.env.StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME;
import static org.springframework.core.env.StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME;
public class BitsquareEnvironmentTests {
@Test
public void testPropertySourcePrecedence() {
PropertySource commandlineProps = new MockPropertySource(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME)
.withProperty("key.x", "x.commandline");
PropertySource filesystemProps = new MockPropertySource(BITSQUARE_APP_DIR_PROPERTY_SOURCE_NAME)
.withProperty("key.x", "x.env")
.withProperty("key.y", "y.env");
ConfigurableEnvironment env = new BitsquareEnvironment(commandlineProps) {
@Override
PropertySource<?> appDirProperties() {
return filesystemProps;
}
};
MutablePropertySources propertySources = env.getPropertySources();
assertThat(propertySources.precedenceOf(named(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME)), equalTo(0));
assertThat(propertySources.precedenceOf(named(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)), equalTo(1));
assertThat(propertySources.precedenceOf(named(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)), equalTo(2));
assertThat(propertySources.precedenceOf(named(BITSQUARE_APP_DIR_PROPERTY_SOURCE_NAME)), equalTo(3));
assertThat(propertySources.precedenceOf(named(BITSQUARE_HOME_DIR_PROPERTY_SOURCE_NAME)), equalTo(4));
assertThat(propertySources.precedenceOf(named(BITSQUARE_CLASSPATH_PROPERTY_SOURCE_NAME)), equalTo(5));
assertThat(propertySources.precedenceOf(named(BITSQUARE_DEFAULT_PROPERTY_SOURCE_NAME)), equalTo(6));
assertThat(propertySources.size(), equalTo(7));
assertThat(env.getProperty("key.x"), equalTo("x.commandline")); // commandline value wins due to precedence
assertThat(env.getProperty("key.y"), equalTo("y.env")); // env value wins because it's the only one available
}
@Test
public void bitsquareVersionShouldBeAvailable() {
// we cannot actually test for the value because (a) it requires Gradle's
// processResources task filtering (which does not happen within IDEA) and
// (b) because we do not know the specific version to test for. Instead just
// test that the property has been made available.
Environment env = new BitsquareEnvironment(new MockPropertySource());
assertThat(env.containsProperty(APP_VERSION_KEY), is(true));
assertThat(env.getProperty(UserAgent.VERSION_KEY), equalTo(env.getProperty(APP_VERSION_KEY)));
}
}

View file

@ -0,0 +1,48 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.junit.Test;
import static org.junit.Assert.*;
public class RestrictionsTest {
@Test
public void testIsMinSpendableAmount() {
Coin amount = null;
assertFalse("tx unfunded, pending", Restrictions.isMinSpendableAmount(amount));
amount = Coin.ZERO;
assertFalse("tx unfunded, pending", Restrictions.isMinSpendableAmount(amount));
amount = FeePolicy.TX_FEE;
assertFalse("tx unfunded, pending", Restrictions.isMinSpendableAmount(amount));
amount = Transaction.MIN_NONDUST_OUTPUT;
assertFalse("tx unfunded, pending", Restrictions.isMinSpendableAmount(amount));
amount = FeePolicy.TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT);
assertFalse("tx unfunded, pending", Restrictions.isMinSpendableAmount(amount));
amount = FeePolicy.TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT).add(Coin.valueOf(1));
assertTrue("tx unfunded, pending", Restrictions.isMinSpendableAmount(amount));
}
}

View file

@ -0,0 +1,130 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main.trade.createoffer;
import io.bitsquare.bank.BankAccountType;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.validation.BtcValidator;
import io.bitsquare.gui.util.validation.FiatValidator;
import io.bitsquare.locale.Country;
import io.bitsquare.user.User;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat;
import java.util.Locale;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class CreateOfferViewModelTest {
private CreateOfferDataModel model;
private CreateOfferViewModel presenter;
@Before
public void setup() {
BSFormatter formatter = new BSFormatter(new User());
formatter.setLocale(Locale.US);
formatter.setFiatCurrencyCode("USD");
model = new CreateOfferDataModel(null, null, null, null, null, null, formatter);
presenter = new CreateOfferViewModel(model, new FiatValidator(null), new BtcValidator(), formatter);
}
@Test
public void testAmount() {
presenter.amount.set("0.0001");
model.calculateAmount();
assertEquals("0.0001", presenter.amount.get());
assertEquals(Coin.parseCoin("0.0001"), model.amountAsCoin.get());
presenter.amount.set("0.0009");
model.calculateAmount();
assertEquals("0.0009", presenter.amount.get());
assertEquals(Coin.parseCoin("0.0009"), model.amountAsCoin.get());
presenter.amount.set("0.0029");
model.calculateAmount();
assertEquals("0.0029", presenter.amount.get());
assertEquals(Coin.parseCoin("0.0029"), model.amountAsCoin.get());
}
@Test
public void testBindings() {
presenter.price.set("500");
presenter.volume.set("500");
assertEquals("1.00", presenter.amount.get());
assertEquals(Coin.COIN, model.amountAsCoin.get());
assertEquals(Fiat.valueOf("USD", 500 * 10000), model.priceAsFiat.get());
assertEquals(Fiat.valueOf("USD", 500 * 10000), model.volumeAsFiat.get());
presenter.price.set("300");
presenter.volume.set("1000");
assertEquals("3.3333", presenter.amount.get());
assertEquals(Coin.parseCoin("3.3333"), model.amountAsCoin.get());
assertEquals(Fiat.valueOf("USD", 300 * 10000), model.priceAsFiat.get());
assertEquals(Fiat.valueOf("USD", 9999900), model.volumeAsFiat.get());
presenter.price.set("300");
presenter.amount.set("3.3333");
assertEquals("999.99", presenter.volume.get());
assertEquals(Coin.parseCoin("3.3333"), model.amountAsCoin.get());
assertEquals(Fiat.valueOf("USD", 300 * 10000), model.priceAsFiat.get());
assertEquals(Fiat.valueOf("USD", 9999900), model.volumeAsFiat.get());
presenter.price.set("300");
presenter.amount.set("3.33333333");
assertEquals("999.99", presenter.volume.get());
assertEquals(Coin.parseCoin("3.3333"), model.amountAsCoin.get());
assertEquals(Fiat.valueOf("USD", 300 * 10000), model.priceAsFiat.get());
assertEquals(Fiat.valueOf("USD", 9999900), model.volumeAsFiat.get());
model.bankAccountType.set(BankAccountType.SEPA.toString());
assertEquals("Sepa", presenter.bankAccountType.get());
model.bankAccountType.set(BankAccountType.WIRE.toString());
assertEquals("Wire", presenter.bankAccountType.get());
model.bankAccountCurrency.set("USD");
assertEquals("USD", presenter.bankAccountCurrency.get());
model.bankAccountCurrency.set("USD");
assertEquals("USD", presenter.bankAccountCurrency.get());
model.bankAccountCounty.set("Spain");
assertEquals("Spain", presenter.bankAccountCounty.get());
model.bankAccountCounty.set("Italy");
assertEquals("Italy", presenter.bankAccountCounty.get());
model.acceptedCountries.add(new Country(null, "Italy", null));
assertEquals("Italy", presenter.acceptedCountries.get());
model.acceptedCountries.add(new Country(null, "Spain", null));
assertEquals("Italy, Spain", presenter.acceptedCountries.get());
}
}

View file

@ -0,0 +1,189 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.util;
import io.bitsquare.user.User;
import org.bitcoinj.core.Coin;
import java.util.Locale;
import org.junit.Test;
import static org.junit.Assert.*;
public class BSFormatterTest {
@Test
public void testParseToBtc() {
BSFormatter formatter = new BSFormatter(new User());
formatter.useMilliBitFormat(false);
assertEquals(Coin.ZERO, formatter.parseToCoin("0"));
assertEquals(Coin.COIN, formatter.parseToCoin("1"));
assertEquals(Coin.SATOSHI, formatter.parseToCoin("0,00000001"));
assertEquals(Coin.parseCoin("-1"), formatter.parseToCoin("-1"));
assertEquals(Coin.parseCoin("1.1"), formatter.parseToCoin("1,1"));
assertEquals(Coin.parseCoin("1.1"), formatter.parseToCoin("1.1"));
assertEquals(Coin.parseCoin("0"), formatter.parseToCoin("1.123,45"));
assertEquals(Coin.parseCoin("0"), formatter.parseToCoin("1,123.45"));
assertEquals(Coin.parseCoin("1.1234"), formatter.parseToCoinWith4Decimals("1,12342"));
assertEquals(Coin.parseCoin("1.1235"), formatter.parseToCoinWith4Decimals("1,12345"));
assertEquals(Coin.parseCoin("1.1230"), formatter.parseToCoinWith4Decimals("1,123"));
// change to mBTC
formatter.useMilliBitFormat(true);
assertEquals(Coin.parseCoin("1"), formatter.parseToCoin("1000"));
assertEquals(Coin.parseCoin("0.123"), formatter.parseToCoin("123"));
assertEquals(Coin.parseCoin("0.1234"), formatter.parseToCoin("123.4"));
assertEquals(Coin.parseCoin("0.12345"), formatter.parseToCoin("123.45"));
assertEquals(Coin.parseCoin("0.123456"), formatter.parseToCoin("123.456"));
assertEquals(Coin.parseCoin("0"), formatter.parseToCoin("123,456.7"));
assertEquals(Coin.parseCoin("0.001123"), formatter.parseToCoinWith4Decimals("1.123"));
assertEquals(Coin.parseCoin("0.0011234"), formatter.parseToCoinWith4Decimals("1.1234"));
assertEquals(Coin.parseCoin("0.0011234"), formatter.parseToCoinWith4Decimals("1.12342"));
assertEquals(Coin.parseCoin("0.0011235"), formatter.parseToCoinWith4Decimals("1.12345"));
}
@Test
public void testFormatCoin() {
BSFormatter formatter = new BSFormatter(new User());
formatter.useMilliBitFormat(false);
assertEquals("1.00", formatter.formatCoin(Coin.COIN));
assertEquals("1.0120", formatter.formatCoin(Coin.parseCoin("1.012")));
assertEquals("1012.30", formatter.formatCoin(Coin.parseCoin("1012.3")));
assertEquals("1.0120", formatter.formatCoin(Coin.parseCoin("1.01200")));
assertEquals("1.000123", formatter.formatCoin(Coin.parseCoin("1.0001234")));
assertEquals("0.10", formatter.formatCoin(Coin.parseCoin("0.1")));
assertEquals("0.01", formatter.formatCoin(Coin.parseCoin("0.01")));
assertEquals("0.0010", formatter.formatCoin(Coin.parseCoin("0.001")));
assertEquals("0.0001", formatter.formatCoin(Coin.parseCoin("0.0001")));
assertEquals("0.000010", formatter.formatCoin(Coin.parseCoin("0.00001")));
assertEquals("0.000001", formatter.formatCoin(Coin.parseCoin("0.000001")));
assertEquals("0.00", formatter.formatCoin(Coin.parseCoin("0.0000001")));
assertEquals("1.2345", formatter.formatCoin(Coin.parseCoin("1.2345")));
assertEquals("1.002346", formatter.formatCoin(Coin.parseCoin("1.0023456")));
assertEquals("1.002346", formatter.formatCoin(Coin.parseCoin("1.00234567")));
assertEquals("1.002345", formatter.formatCoin(Coin.parseCoin("1.0023448")));
assertEquals("1.00", formatter.formatCoin(Coin.COIN));
assertEquals("1012.30", formatter.formatCoin(Coin.parseCoin("1012.3")));
// change to mBTC
formatter.useMilliBitFormat(true);
assertEquals("1000.00", formatter.formatCoin(Coin.COIN));
assertEquals("1.00", formatter.formatCoin(Coin.MILLICOIN));
assertEquals("0.0010", formatter.formatCoin(Coin.MICROCOIN));
}
@Test
public void testFormatCoinWithCode() {
BSFormatter formatter = new BSFormatter(new User());
formatter.useMilliBitFormat(false);
assertEquals("1.00 BTC", formatter.formatCoinWithCode(Coin.COIN));
assertEquals("1.01 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1.01")));
assertEquals("1.0120 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1.012")));
assertEquals("1012.30 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1012.3")));
assertEquals("1.0120 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1.01200")));
assertEquals("1.012340 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1.01234")));
assertEquals("1.012345 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1.012345")));
assertEquals("1.012345 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1.0123454")));
assertEquals("1.012346 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1.0123455")));
assertEquals("0.10 BTC", formatter.formatCoinWithCode(Coin.parseCoin("0.1")));
assertEquals("0.01 BTC", formatter.formatCoinWithCode(Coin.parseCoin("0.01")));
assertEquals("0.0010 BTC", formatter.formatCoinWithCode(Coin.parseCoin("0.001")));
assertEquals("0.0001 BTC", formatter.formatCoinWithCode(Coin.parseCoin("0.0001")));
assertEquals("1.2345 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1.2345")));
assertEquals("1.002346 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1.0023456")));
assertEquals("1.002346 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1.00234567")));
assertEquals("1.002345 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1.0023448")));
assertEquals("1.00 BTC", formatter.formatCoinWithCode(Coin.COIN));
assertEquals("1012.30 BTC", formatter.formatCoinWithCode(Coin.parseCoin("1012.3")));
// change to mBTC
formatter.useMilliBitFormat(true);
assertEquals("1000.00 mBTC", formatter.formatCoinWithCode(Coin.COIN));
assertEquals("1.00 mBTC", formatter.formatCoinWithCode(Coin.MILLICOIN));
assertEquals("0.0010 mBTC", formatter.formatCoinWithCode(Coin.MICROCOIN));
}
@Test
public void testParseToBtcWith4Decimals() {
BSFormatter formatter = new BSFormatter(new User());
formatter.useMilliBitFormat(false);
assertEquals(Coin.parseCoin("0"), formatter.parseToCoinWith4Decimals("0"));
assertEquals(Coin.parseCoin("0"), formatter.parseToCoinWith4Decimals(null));
assertEquals(Coin.parseCoin("0"), formatter.parseToCoinWith4Decimals("s"));
assertEquals(Coin.parseCoin("0.0012"), formatter.parseToCoinWith4Decimals("0,00123"));
assertEquals(Coin.parseCoin("0.0013"), formatter.parseToCoinWith4Decimals("0,00125"));
}
@Test
public void testHasBtcValidDecimals() {
BSFormatter formatter = new BSFormatter(new User());
formatter.useMilliBitFormat(false);
formatter.setLocale(Locale.GERMAN);
assertTrue(formatter.hasBtcValidDecimals(null));
assertTrue(formatter.hasBtcValidDecimals("0"));
assertTrue(formatter.hasBtcValidDecimals("0,0001"));
assertTrue(formatter.hasBtcValidDecimals("0.0001"));
assertTrue(formatter.hasBtcValidDecimals("0.0009"));
assertTrue(formatter.hasBtcValidDecimals("20000000.0001"));
assertFalse(formatter.hasBtcValidDecimals("20000000.000123"));
assertFalse(formatter.hasBtcValidDecimals("0.00012"));
assertFalse(formatter.hasBtcValidDecimals("0.0001222312312312313"));
}
@Test
public void testParseToFiatWith2Decimals() {
BSFormatter formatter = new BSFormatter(new User());
formatter.useMilliBitFormat(false);
formatter.setLocale(Locale.GERMAN);
assertEquals("0", formatter.parseToFiatWith2Decimals("0").toPlainString());
assertEquals("0", formatter.parseToFiatWith2Decimals(null).toPlainString());
assertEquals("0", formatter.parseToFiatWith2Decimals("s").toPlainString());
assertEquals("0.12", formatter.parseToFiatWith2Decimals("0.123").toPlainString());
assertEquals("0.13", formatter.parseToFiatWith2Decimals("0.125").toPlainString());
assertEquals("0.13", formatter.parseToFiatWith2Decimals("0,125").toPlainString());
}
@Test
public void testHasFiatValidDecimals() {
BSFormatter formatter = new BSFormatter(new User());
formatter.useMilliBitFormat(false);
formatter.setLocale(Locale.GERMAN);
assertTrue(formatter.hasFiatValidDecimals(null));
assertTrue(formatter.hasFiatValidDecimals("0"));
assertTrue(formatter.hasFiatValidDecimals("0,01"));
assertTrue(formatter.hasFiatValidDecimals("0.01"));
assertTrue(formatter.hasFiatValidDecimals("0.09"));
assertTrue(formatter.hasFiatValidDecimals("20000000.01"));
assertFalse(formatter.hasFiatValidDecimals("20000000.0123"));
assertFalse(formatter.hasFiatValidDecimals("0.012"));
assertFalse(formatter.hasFiatValidDecimals("0.01222312312312313"));
}
}

View file

@ -0,0 +1,55 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.util.validation;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.NetworkParameters;
import org.junit.Test;
import static org.junit.Assert.*;
public class BtcValidatorTest {
@Test
public void testIsValid() {
BtcValidator validator = new BtcValidator();
assertTrue(validator.validate("1").isValid);
assertTrue(validator.validate("1,1").isValid);
assertTrue(validator.validate("1.1").isValid);
assertTrue(validator.validate(",1").isValid);
assertTrue(validator.validate(".1").isValid);
assertTrue(validator.validate("0.12345678").isValid);
assertTrue(validator.validate(Coin.SATOSHI.toPlainString()).isValid);
assertTrue(validator.validate(NetworkParameters.MAX_MONEY.toPlainString()).isValid);
assertFalse(validator.validate(null).isValid);
assertFalse(validator.validate("").isValid);
assertFalse(validator.validate("0").isValid);
assertFalse(validator.validate("0.0").isValid);
assertFalse(validator.validate("0,1,1").isValid);
assertFalse(validator.validate("0.1.1").isValid);
assertFalse(validator.validate("1,000.1").isValid);
assertFalse(validator.validate("1.000,1").isValid);
assertFalse(validator.validate("0.123456789").isValid);
assertFalse(validator.validate("-1").isValid);
assertFalse(validator.validate(String.valueOf(NetworkParameters.MAX_MONEY.longValue() + Coin.SATOSHI
.longValue())).isValid);
}
}

View file

@ -0,0 +1,62 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.util.validation;
import org.junit.Test;
import static org.junit.Assert.*;
public class FiatValidatorTest {
@Test
public void testValidate() {
FiatValidator validator = new FiatValidator(null);
NumberValidator.ValidationResult validationResult;
assertTrue(validator.validate("1").isValid);
assertTrue(validator.validate("1,1").isValid);
assertTrue(validator.validate("1.1").isValid);
assertTrue(validator.validate(",1").isValid);
assertTrue(validator.validate(".1").isValid);
assertTrue(validator.validate("0.01").isValid);
assertTrue(validator.validate("1000000.00").isValid);
assertTrue(validator.validate(String.valueOf(FiatValidator.MIN_FIAT_VALUE)).isValid);
assertTrue(validator.validate(String.valueOf(FiatValidator.MAX_FIAT_VALUE)).isValid);
assertFalse(validator.validate(null).isValid);
assertFalse(validator.validate("").isValid);
assertFalse(validator.validate("a").isValid);
assertFalse(validator.validate("2a").isValid);
assertFalse(validator.validate("a2").isValid);
assertFalse(validator.validate("0").isValid);
assertFalse(validator.validate("-1").isValid);
assertFalse(validator.validate("0.0").isValid);
assertFalse(validator.validate("0,1,1").isValid);
assertFalse(validator.validate("0.1.1").isValid);
assertFalse(validator.validate("1,000.1").isValid);
assertFalse(validator.validate("1.000,1").isValid);
assertFalse(validator.validate("0.009").isValid);
assertFalse(validator.validate("1000000.01").isValid);
assertFalse(validator.validate(String.valueOf(FiatValidator.MIN_FIAT_VALUE - 0.0000001)).isValid);
assertFalse(validator.validate(String.valueOf(FiatValidator.MAX_FIAT_VALUE + 0.0000001)).isValid);
assertFalse(validator.validate(String.valueOf(Double.MIN_VALUE)).isValid);
assertFalse(validator.validate(String.valueOf(Double.MAX_VALUE)).isValid);
}
}

View file

@ -0,0 +1,758 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.msg;
import io.bitsquare.network.BootstrapNodes;
import io.bitsquare.network.ConnectionType;
import io.bitsquare.network.Node;
import io.bitsquare.util.Repeat;
import io.bitsquare.util.RepeatRule;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import net.tomp2p.connection.Bindings;
import net.tomp2p.connection.StandardProtocolFamily;
import net.tomp2p.dht.FutureGet;
import net.tomp2p.dht.FuturePut;
import net.tomp2p.dht.FutureRemove;
import net.tomp2p.dht.PeerBuilderDHT;
import net.tomp2p.dht.PeerDHT;
import net.tomp2p.futures.BaseFuture;
import net.tomp2p.futures.BaseFutureListener;
import net.tomp2p.futures.FutureBootstrap;
import net.tomp2p.futures.FutureDirect;
import net.tomp2p.futures.FutureDiscover;
import net.tomp2p.futures.FuturePeerConnection;
import net.tomp2p.nat.FutureNAT;
import net.tomp2p.nat.FutureRelayNAT;
import net.tomp2p.nat.PeerBuilderNAT;
import net.tomp2p.nat.PeerNAT;
import net.tomp2p.p2p.Peer;
import net.tomp2p.p2p.PeerBuilder;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.peers.PeerMap;
import net.tomp2p.peers.PeerMapConfiguration;
import net.tomp2p.relay.tcp.TCPRelayClientConfig;
import net.tomp2p.storage.Data;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.junit.Assert.*;
/**
* Test bootstrapping, DHT operations like put/get/add/remove and sendDirect in both LAN and WAN environment
* Test scenarios in direct connection, auto port forwarding or relay mode.
* <p>
* To start a bootstrap node code use the {@link io.bitsquare.app.cli.BootstrapNode} class.
* <p>
* To configure your test environment edit the static fields for id, IP and port.
* In the configure method and the connectionType you can define your test scenario.
*/
@Ignore
public class TomP2PTests {
private static final Logger log = LoggerFactory.getLogger(TomP2PTests.class);
// If you want to test in one specific connection mode define it directly, otherwise use UNKNOWN
private static final ConnectionType FORCED_CONNECTION_TYPE = ConnectionType.RELAY;
// Typically you run the bootstrap node in localhost to test direct connection.
// If you have a setup where you are not behind a router you can also use a WAN bootstrap node.
private static final Node BOOTSTRAP_NODE = (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT) ?
BootstrapNodes.LOCALHOST : Node.at("digitalocean1.dev.bitsquare.io", "188.226.179.109", 7367);
private static final PeerAddress BOOTSTRAP_NODE_ADDRESS;
static {
try {
BOOTSTRAP_NODE_ADDRESS = new PeerAddress(
Number160.createHash(BOOTSTRAP_NODE.getName()),
BOOTSTRAP_NODE.getIp(), BOOTSTRAP_NODE.getPort(), BOOTSTRAP_NODE.getPort());
} catch (UnknownHostException ex) {
throw new RuntimeException(BOOTSTRAP_NODE.toString(), ex);
}
}
// Use to stress tests by repeating them
private static final int STRESS_TEST_COUNT = 1;
private Peer peer;
private PeerDHT peer1DHT;
private PeerDHT peer2DHT;
private int client1Port;
private int client2Port;
private ConnectionType resolvedConnectionType;
public @Rule RepeatRule repeatRule = new RepeatRule();
@Before
public void setUp() {
client1Port = 7367;
client2Port = 7368;
}
@After
public void tearDown() {
if (peer1DHT != null)
peer1DHT.shutdown().awaitUninterruptibly().awaitListenersUninterruptibly();
if (peer2DHT != null)
peer2DHT.shutdown().awaitUninterruptibly().awaitListenersUninterruptibly();
if (peer != null)
peer.shutdown().awaitUninterruptibly().awaitListenersUninterruptibly();
}
@Test
@Repeat(STRESS_TEST_COUNT)
public void bootstrapInUnknownMode() throws Exception {
if (FORCED_CONNECTION_TYPE == ConnectionType.UNKNOWN) {
peer = bootstrapInUnknownMode(client1Port);
assertNotNull(peer);
}
}
@Test
@Repeat(STRESS_TEST_COUNT)
public void testBootstrapDirectConnection() throws Exception {
if (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT) {
peer = bootstrapDirectConnection(client1Port);
assertNotNull(peer);
}
}
@Test
@Repeat(STRESS_TEST_COUNT)
public void testBootstrapWithPortForwarding() throws Exception {
if (FORCED_CONNECTION_TYPE == ConnectionType.AUTO_PORT_FORWARDING ||
FORCED_CONNECTION_TYPE == ConnectionType.MANUAL_PORT_FORWARDING) {
peer = bootstrapWithPortForwarding(client2Port);
assertNotNull(peer);
}
}
@Test
@Repeat(STRESS_TEST_COUNT)
public void testBootstrapInRelayMode() throws Exception {
if (FORCED_CONNECTION_TYPE == ConnectionType.RELAY) {
peer = bootstrapInRelayMode(client1Port);
assertNotNull(peer);
}
}
@Test
@Repeat(STRESS_TEST_COUNT)
public void testPut() throws Exception {
peer1DHT = getDHTPeer(client1Port);
FuturePut futurePut = peer1DHT.put(Number160.createHash("key")).data(new Data("hallo")).start();
futurePut.awaitUninterruptibly();
assertTrue(futurePut.isSuccess());
}
@Test
@Repeat(STRESS_TEST_COUNT)
public void testPutGet() throws Exception {
peer1DHT = getDHTPeer(client1Port);
FuturePut futurePut = peer1DHT.put(Number160.createHash("key")).data(new Data("hallo")).start();
futurePut.awaitUninterruptibly();
assertTrue(futurePut.isSuccess());
peer2DHT = getDHTPeer(client2Port);
FutureGet futureGet = peer2DHT.get(Number160.createHash("key")).start();
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
assertEquals("hallo", futureGet.data().object());
}
@Test
@Repeat(STRESS_TEST_COUNT)
public void testAdd() throws Exception {
peer1DHT = getDHTPeer(client1Port);
FuturePut futurePut1 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo1")).start();
futurePut1.awaitUninterruptibly();
assertTrue(futurePut1.isSuccess());
}
@Test
@Repeat(STRESS_TEST_COUNT)
public void testAddGet() throws Exception {
peer1DHT = getDHTPeer(client1Port);
FuturePut futurePut1 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo1"))
.start();
futurePut1.awaitUninterruptibly();
assertTrue(futurePut1.isSuccess());
FuturePut futurePut2 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo2"))
.start();
futurePut2.awaitUninterruptibly();
assertTrue(futurePut2.isSuccess());
peer2DHT = getDHTPeer(client2Port);
FutureGet futureGet = peer2DHT.get(Number160.createHash("locationKey")).all().start();
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
assertTrue(futureGet.dataMap().values().contains(new Data("hallo1")));
assertTrue(futureGet.dataMap().values().contains(new Data("hallo2")));
assertTrue(futureGet.dataMap().values().size() == 2);
}
@Test
@Repeat(STRESS_TEST_COUNT)
public void testAddGetWithReconnect() throws Exception {
peer1DHT = getDHTPeer(client1Port);
FuturePut futurePut1 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo1")).start();
futurePut1.awaitUninterruptibly();
assertTrue(futurePut1.isSuccess());
FuturePut futurePut2 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo2")).start();
futurePut2.awaitUninterruptibly();
assertTrue(futurePut2.isSuccess());
peer2DHT = getDHTPeer(client2Port);
FutureGet futureGet = peer2DHT.get(Number160.createHash("locationKey")).all().start();
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
assertTrue(futureGet.dataMap().values().contains(new Data("hallo1")));
assertTrue(futureGet.dataMap().values().contains(new Data("hallo2")));
assertTrue(futureGet.dataMap().values().size() == 2);
// shut down peer2
BaseFuture future = peer2DHT.shutdown();
future.awaitUninterruptibly();
future.awaitListenersUninterruptibly();
// start up peer2
peer2DHT = getDHTPeer(client2Port);
futureGet = peer2DHT.get(Number160.createHash("locationKey")).all().start();
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
assertTrue(futureGet.dataMap().values().contains(new Data("hallo1")));
assertTrue(futureGet.dataMap().values().contains(new Data("hallo2")));
assertTrue(futureGet.dataMap().values().size() == 2);
futureGet = peer1DHT.get(Number160.createHash("locationKey")).all().start();
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
assertTrue(futureGet.dataMap().values().contains(new Data("hallo1")));
assertTrue(futureGet.dataMap().values().contains(new Data("hallo2")));
assertTrue(futureGet.dataMap().values().size() == 2);
// shut down both
future = peer2DHT.shutdown();
future.awaitUninterruptibly();
future.awaitListenersUninterruptibly();
future = peer1DHT.shutdown();
future.awaitUninterruptibly();
future.awaitListenersUninterruptibly();
// start up both
peer1DHT = getDHTPeer(client1Port);
futureGet = peer1DHT.get(Number160.createHash("locationKey")).all().start();
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
assertTrue(futureGet.dataMap().values().contains(new Data("hallo1")));
assertTrue(futureGet.dataMap().values().contains(new Data("hallo2")));
assertTrue(futureGet.dataMap().values().size() == 2);
peer2DHT = getDHTPeer(client2Port);
futureGet = peer2DHT.get(Number160.createHash("locationKey")).all().start();
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
assertTrue(futureGet.dataMap().values().contains(new Data("hallo1")));
assertTrue(futureGet.dataMap().values().contains(new Data("hallo2")));
assertTrue(futureGet.dataMap().values().size() == 2);
}
@Test
@Repeat(STRESS_TEST_COUNT)
public void testParallelStartupWithPutGet() throws IOException, ClassNotFoundException, InterruptedException {
PeerMapConfiguration pmc1 = new PeerMapConfiguration(Number160.createHash("peer1")).peerNoVerification();
PeerMap pm1 = new PeerMap(pmc1);
PeerDHT peer1 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash("peer1")).ports(3006).peerMap(pm1).start()).start();
PeerMapConfiguration pmc2 = new PeerMapConfiguration(Number160.createHash("peer2")).peerNoVerification();
PeerMap pm2 = new PeerMap(pmc2);
PeerDHT peer2 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash("peer2")).ports(3007).peerMap(pm2).start()).start();
/* PeerAddress masterPeerAddress = new PeerAddress(Number160.createHash(BOOTSTRAP_NODE_ID),
BOOTSTRAP_NODE_IP, BOOTSTRAP_NODE_PORT,
BOOTSTRAP_NODE_PORT);
PeerDHT peer1 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash("peer1")).ports(3006).start()).start();
PeerDHT peer2 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash("peer2")).ports(3007).start()).start();
*/
PeerAddress masterPeerAddress = new PeerAddress(Number160.createHash(BootstrapNodes.LOCALHOST.getName()),
BootstrapNodes.LOCALHOST.getIp(), BootstrapNodes.LOCALHOST.getPort(),
BootstrapNodes.LOCALHOST.getPort());
// start both at the same time
BaseFuture fb1 = peer1.peer().bootstrap().peerAddress(masterPeerAddress).start();
BaseFuture fb2 = peer2.peer().bootstrap().peerAddress(masterPeerAddress).start();
final AtomicBoolean peer1Done = new AtomicBoolean();
final AtomicBoolean peer2Done = new AtomicBoolean();
fb1.addListener(new BaseFutureListener<BaseFuture>() {
@Override
public void operationComplete(BaseFuture future) throws Exception {
peer1Done.set(true);
}
@Override
public void exceptionCaught(Throwable t) throws Exception {
log.error(t.toString());
}
});
fb2.addListener(new BaseFutureListener<BaseFuture>() {
@Override
public void operationComplete(BaseFuture future) throws Exception {
peer2Done.set(true);
}
@Override
public void exceptionCaught(Throwable t) throws Exception {
log.error(t.toString());
}
});
while (!peer1Done.get() && !peer2Done.get())
Thread.sleep(100);
// both are started up
Assert.assertTrue(fb1.isSuccess());
Assert.assertTrue(fb2.isSuccess());
// peer1 put data
FuturePut fp = peer1.put(Number160.ONE).object("test").start().awaitUninterruptibly();
Assert.assertTrue(fp.isSuccess());
// both get data
FutureGet fg1 = peer1.get(Number160.ONE).start().awaitUninterruptibly();
Assert.assertTrue(fg1.isSuccess());
Assert.assertEquals("test", fg1.data().object());
FutureGet fg2 = peer2.get(Number160.ONE).start().awaitUninterruptibly();
Assert.assertTrue(fg2.isSuccess());
Assert.assertEquals("test", fg2.data().object());
// shutdown both
peer1.shutdown().awaitUninterruptibly().awaitListenersUninterruptibly();
peer2.shutdown().awaitUninterruptibly().awaitListenersUninterruptibly();
// start both again at the same time
peer1 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash("peer1")).ports(3005).start()).start();
peer2 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash("peer2")).ports(3006).start()).start();
fb1 = peer1.peer().bootstrap().peerAddress(masterPeerAddress).start();
fb2 = peer2.peer().bootstrap().peerAddress(masterPeerAddress).start();
peer1Done.set(false);
peer2Done.set(false);
final PeerDHT _peer1 = peer1;
fb1.addListener(new BaseFutureListener<BaseFuture>() {
@Override
public void operationComplete(BaseFuture future) throws Exception {
peer1Done.set(true);
// when peer1 is ready it gets the data
FutureGet fg = _peer1.get(Number160.ONE).start();
fg.addListener(new BaseFutureListener<BaseFuture>() {
@Override
public void operationComplete(BaseFuture future) throws Exception {
Assert.assertTrue(fg.isSuccess());
Assert.assertEquals("test", fg.data().object());
}
@Override
public void exceptionCaught(Throwable t) throws Exception {
}
});
}
@Override
public void exceptionCaught(Throwable t) throws Exception {
}
});
final PeerDHT _peer2 = peer2;
fb2.addListener(new BaseFutureListener<BaseFuture>() {
@Override
public void operationComplete(BaseFuture future) throws Exception {
peer2Done.set(true);
// when peer2 is ready it gets the data
FutureGet fg = _peer2.get(Number160.ONE).start();
fg.addListener(new BaseFutureListener<BaseFuture>() {
@Override
public void operationComplete(BaseFuture future) throws Exception {
Assert.assertTrue(fg.isSuccess());
Assert.assertEquals("test", fg.data().object());
}
@Override
public void exceptionCaught(Throwable t) throws Exception {
}
});
}
@Override
public void exceptionCaught(Throwable t) throws Exception {
}
});
while (!peer1Done.get() && !peer2Done.get())
Thread.sleep(100);
// both are started up
Assert.assertTrue(fb1.isSuccess());
Assert.assertTrue(fb2.isSuccess());
// get data again for both
fg1 = peer1.get(Number160.ONE).start().awaitUninterruptibly();
Assert.assertTrue(fg1.isSuccess());
Assert.assertEquals("test", fg1.data().object());
fg2 = peer2.get(Number160.ONE).start().awaitUninterruptibly();
Assert.assertTrue(fg2.isSuccess());
Assert.assertEquals("test", fg2.data().object());
peer1.shutdown().awaitUninterruptibly().awaitListenersUninterruptibly();
peer2.shutdown().awaitUninterruptibly().awaitListenersUninterruptibly();
}
@Test
@Repeat(STRESS_TEST_COUNT)
public void testAddRemove() throws Exception {
peer1DHT = getDHTPeer(client1Port);
FuturePut futurePut1 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo1")).start();
futurePut1.awaitUninterruptibly();
futurePut1.awaitListenersUninterruptibly();
assertTrue(futurePut1.isSuccess());
FuturePut futurePut2 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo2")).start();
futurePut2.awaitUninterruptibly();
futurePut2.awaitListenersUninterruptibly();
assertTrue(futurePut2.isSuccess());
peer2DHT = getDHTPeer(client2Port);
Number160 contentKey = new Data("hallo1").hash();
FutureRemove futureRemove = peer2DHT.remove(Number160.createHash("locationKey")).contentKey(contentKey).start();
futureRemove.awaitUninterruptibly();
futureRemove.awaitListenersUninterruptibly();
// We don't test futureRemove.isSuccess() as this API does not fit well to that operation,
// it might change in future to something like foundAndRemoved and notFound
// See discussion at: https://github.com/tomp2p/TomP2P/issues/57#issuecomment-62069840
assertTrue(futureRemove.isSuccess());
FutureGet futureGet = peer2DHT.get(Number160.createHash("locationKey")).all().start();
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
if (!futureGet.dataMap().values().contains(new Data("hallo2"))) {
log.error("raw data has the value, the evaluated not!");
}
assertTrue(futureGet.dataMap().values().contains(new Data("hallo2")));
assertTrue(futureGet.dataMap().values().size() == 1);
}
// The sendDirect operation fails in port forwarding mode because most routers does not support NAT reflections.
// So if both clients are behind NAT they cannot send direct message to each other.
// Seems that in relay mode that is also not working
// That will probably be fixed in a future version of TomP2P
@Test
@Repeat(STRESS_TEST_COUNT)
public void testSendDirectBetweenLocalPeers() throws Exception {
if (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT || resolvedConnectionType == ConnectionType.DIRECT) {
peer1DHT = getDHTPeer(client1Port);
peer2DHT = getDHTPeer(client2Port);
final CountDownLatch countDownLatch = new CountDownLatch(1);
final StringBuilder result = new StringBuilder();
peer2DHT.peer().objectDataReply((sender, request) -> {
countDownLatch.countDown();
result.append(String.valueOf(request));
return "pong";
});
FuturePeerConnection futurePeerConnection = peer1DHT.peer().createPeerConnection(peer2DHT.peer()
.peerAddress(), 500);
FutureDirect futureDirect = peer1DHT.peer().sendDirect(futurePeerConnection).object("hallo").start();
futureDirect.awaitUninterruptibly();
countDownLatch.await(3, TimeUnit.SECONDS);
if (countDownLatch.getCount() > 0)
Assert.fail("The test method did not complete successfully!");
assertEquals("hallo", result.toString());
assertTrue(futureDirect.isSuccess());
log.debug(futureDirect.object().toString());
assertEquals("pong", futureDirect.object());
}
}
// This test should always succeed as we use the bootstrap node as receiver.
// A node can send a message to another peer which is not in the same LAN.
@Test
@Repeat(STRESS_TEST_COUNT)
public void testSendDirectToSeedNode() throws Exception {
peer1DHT = getDHTPeer(client1Port);
FuturePeerConnection futurePeerConnection =
peer1DHT.peer().createPeerConnection(BOOTSTRAP_NODE_ADDRESS, 500);
FutureDirect futureDirect = peer1DHT.peer().sendDirect(futurePeerConnection).object("hallo").start();
futureDirect.awaitUninterruptibly();
assertTrue(futureDirect.isSuccess());
// server node does not reply
// assertEquals("pong", futureDirect.object());
}
private Peer bootstrapDirectConnection(int clientPort) {
Peer peer = null;
try {
/* Number160 peerId = Number160.createHash(UUID.randomUUID().toString());
PeerMapConfiguration pmc = new PeerMapConfiguration(peerId).peerNoVerification();
PeerMap pm = new PeerMap(pmc);
ChannelClientConfiguration cc = PeerBuilder.createDefaultChannelClientConfiguration();
cc.maxPermitsTCP(100);
cc.maxPermitsUDP(100);
peer = new PeerBuilder(peerId).bindings(getBindings()).channelClientConfiguration(cc).peerMap(pm)
.ports(clientPort).start();*/
Number160 peerId = Number160.createHash(UUID.randomUUID().toString());
peer = new PeerBuilder(peerId).bindings(getBindings())
.ports(clientPort).start();
FutureDiscover futureDiscover = peer.discover().peerAddress(BOOTSTRAP_NODE_ADDRESS).start();
futureDiscover.awaitUninterruptibly();
if (futureDiscover.isSuccess()) {
log.info("Discover with direct connection successful. Address = " + futureDiscover.peerAddress());
FutureBootstrap futureBootstrap = peer.bootstrap().peerAddress(BOOTSTRAP_NODE_ADDRESS).start();
futureBootstrap.awaitUninterruptibly();
if (futureBootstrap.isSuccess()) {
return peer;
}
else {
log.warn("Bootstrap failed. Reason = " + futureBootstrap.failedReason());
peer.shutdown().awaitUninterruptibly();
return null;
}
}
else {
log.warn("Discover with direct connection failed. Reason = " + futureDiscover.failedReason());
peer.shutdown().awaitUninterruptibly();
return null;
}
} catch (IOException e) {
log.warn("Discover with direct connection failed. Exception = " + e.getMessage());
if (peer != null)
peer.shutdown().awaitUninterruptibly();
e.printStackTrace();
return null;
}
}
private Peer bootstrapWithPortForwarding(int clientPort) {
Number160 peerId = Number160.createHash(UUID.randomUUID().toString());
Peer peer = null;
try {
if (FORCED_CONNECTION_TYPE == ConnectionType.MANUAL_PORT_FORWARDING ||
resolvedConnectionType == ConnectionType.MANUAL_PORT_FORWARDING) {
peer = new PeerBuilder(peerId).bindings(getBindings())
.behindFirewall()
.tcpPortForwarding(clientPort)
.udpPortForwarding(clientPort)
.ports(clientPort)
.start();
}
else {
peer = new PeerBuilder(peerId).bindings(getBindings())
.behindFirewall()
.ports(clientPort)
.start();
}
PeerNAT peerNAT = new PeerBuilderNAT(peer).start();
FutureDiscover futureDiscover = peer.discover().peerAddress(BOOTSTRAP_NODE_ADDRESS).start();
FutureNAT futureNAT = peerNAT.startSetupPortforwarding(futureDiscover);
futureNAT.awaitUninterruptibly();
if (futureNAT.isSuccess()) {
log.info("Automatic port forwarding is setup. Now we do a futureDiscover again. Address = " +
futureNAT.peerAddress());
futureDiscover = peer.discover().peerAddress(BOOTSTRAP_NODE_ADDRESS).start();
futureDiscover.awaitUninterruptibly();
if (futureDiscover.isSuccess()) {
log.info("Discover with automatic port forwarding was successful. Address = " + futureDiscover
.peerAddress());
FutureBootstrap futureBootstrap = peer.bootstrap().peerAddress(BOOTSTRAP_NODE_ADDRESS).start();
futureBootstrap.awaitUninterruptibly();
if (futureBootstrap.isSuccess()) {
return peer;
}
else {
log.warn("Bootstrap failed. Reason = " + futureBootstrap.failedReason());
peer.shutdown().awaitUninterruptibly();
return null;
}
}
else {
log.warn("Discover with automatic port forwarding failed. Reason = " + futureDiscover
.failedReason());
peer.shutdown().awaitUninterruptibly();
return null;
}
}
else {
log.warn("StartSetupPortforwarding failed. Reason = " + futureNAT
.failedReason());
peer.shutdown().awaitUninterruptibly();
return null;
}
} catch (IOException e) {
log.warn("Discover with automatic port forwarding failed. Exception = " + e.getMessage());
if (peer != null)
peer.shutdown().awaitUninterruptibly();
e.printStackTrace();
return null;
}
}
private Peer bootstrapInRelayMode(int clientPort) {
Number160 peerId = Number160.createHash(UUID.randomUUID().toString());
Peer peer = null;
try {
peer = new PeerBuilder(peerId).bindings(getBindings()).behindFirewall()
.ports(clientPort).start();
PeerNAT peerNAT = new PeerBuilderNAT(peer).start();
FutureDiscover futureDiscover = peer.discover().peerAddress(BOOTSTRAP_NODE_ADDRESS).start();
FutureNAT futureNAT = peerNAT.startSetupPortforwarding(futureDiscover);
FutureRelayNAT futureRelayNAT = peerNAT.startRelay(new TCPRelayClientConfig(), futureDiscover, futureNAT);
futureRelayNAT.awaitUninterruptibly();
if (futureRelayNAT.isSuccess()) {
log.info("Bootstrap using relay was successful. Address = " + peer.peerAddress());
FutureBootstrap futureBootstrap = peer.bootstrap().peerAddress(BOOTSTRAP_NODE_ADDRESS).start();
futureBootstrap.awaitUninterruptibly();
if (futureBootstrap.isSuccess()) {
return peer;
}
else {
log.warn("Bootstrap failed. Reason = " + futureBootstrap.failedReason());
peer.shutdown().awaitUninterruptibly();
return null;
}
}
else {
log.error("Bootstrap using relay failed " + futureRelayNAT.failedReason());
futureRelayNAT.shutdown();
peer.shutdown().awaitUninterruptibly();
return null;
}
} catch (IOException e) {
log.error("Bootstrap using relay failed. Exception " + e.getMessage());
if (peer != null)
peer.shutdown().awaitUninterruptibly();
e.printStackTrace();
return null;
}
}
private Peer bootstrapInUnknownMode(int clientPort) {
resolvedConnectionType = ConnectionType.DIRECT;
Peer peer = bootstrapDirectConnection(clientPort);
if (peer != null)
return peer;
resolvedConnectionType = ConnectionType.MANUAL_PORT_FORWARDING;
peer = bootstrapWithPortForwarding(clientPort);
if (peer != null)
return peer;
resolvedConnectionType = ConnectionType.AUTO_PORT_FORWARDING;
peer = bootstrapWithPortForwarding(clientPort);
if (peer != null)
return peer;
resolvedConnectionType = ConnectionType.RELAY;
peer = bootstrapInRelayMode(clientPort);
if (peer != null)
return peer;
else
log.error("Bootstrapping in all modes failed. Is bootstrap node " + BOOTSTRAP_NODE + "running?");
resolvedConnectionType = null;
return peer;
}
private PeerDHT getDHTPeer(int clientPort) {
Peer peer;
if (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT) {
peer = bootstrapDirectConnection(clientPort);
}
else if (FORCED_CONNECTION_TYPE == ConnectionType.AUTO_PORT_FORWARDING) {
peer = bootstrapWithPortForwarding(clientPort);
}
else if (FORCED_CONNECTION_TYPE == ConnectionType.RELAY) {
peer = bootstrapInRelayMode(clientPort);
}
else {
peer = bootstrapInUnknownMode(clientPort);
}
if (peer == null)
Assert.fail("Bootstrapping failed." +
" forcedConnectionType= " + FORCED_CONNECTION_TYPE +
" resolvedConnectionType= " + resolvedConnectionType + "." +
" Is bootstrap node " + BOOTSTRAP_NODE + "running?");
return new PeerBuilderDHT(peer).start();
}
private Bindings getBindings() {
Bindings bindings = new Bindings();
bindings.addProtocol(StandardProtocolFamily.INET);
return bindings;
}
}

View file

@ -0,0 +1,421 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.msg.tomp2p;
import java.io.IOException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.Random;
import net.tomp2p.connection.Ports;
import net.tomp2p.dht.FutureGet;
import net.tomp2p.dht.FuturePut;
import net.tomp2p.dht.FutureRemove;
import net.tomp2p.dht.PeerBuilderDHT;
import net.tomp2p.dht.PeerDHT;
import net.tomp2p.dht.UtilsDHT2;
import net.tomp2p.futures.FutureDirect;
import net.tomp2p.p2p.PeerBuilder;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.rpc.ObjectDataReply;
import net.tomp2p.storage.Data;
import net.tomp2p.utils.Utils;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
// TODO Reactivate tests when TomP2PNode is using original code again. we deactivated the security features atm.
// cause IOException: Not listening to anything. Maybe your binding information is wrong.
// investigate what has broken it, probably from update to latest head
@Ignore
public class TomP2PNodeTest {
final private static Random rnd = new Random(42L);
@Test
public void testSendData() throws Exception {
PeerDHT[] peers = UtilsDHT2.createNodes(3, rnd, new Ports().tcpPort());
PeerDHT master = peers[0];
PeerDHT client = peers[1];
PeerDHT otherPeer = peers[2];
UtilsDHT2.perfectRouting(peers);
for (final PeerDHT peer : peers) {
peer.peer().objectDataReply(new ObjectDataReply() {
@Override
public Object reply(PeerAddress sender, Object request) throws Exception {
return true;
}
});
}
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(1024);
KeyPair keyPairClient = keyGen.genKeyPair();
KeyPair keyPairOtherPeer = keyGen.genKeyPair();
TomP2PNode node;
Number160 locationKey;
Object object;
FutureDirect futureDirect;
node = new TomP2PNode(keyPairClient, client);
object = "clients data";
futureDirect = node.sendData(otherPeer.peerAddress(), object);
futureDirect.awaitUninterruptibly();
assertTrue(futureDirect.isSuccess());
// we return true from objectDataReply
assertTrue((Boolean) futureDirect.object());
master.shutdown();
}
@Test
public void testProtectedPutGet() throws Exception {
PeerDHT[] peers = UtilsDHT2.createNodes(3, rnd, new Ports().tcpPort());
PeerDHT master = peers[0];
PeerDHT client = peers[1];
PeerDHT otherPeer = peers[2];
UtilsDHT2.perfectRouting(peers);
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(1024);
KeyPair keyPairClient = keyGen.genKeyPair();
KeyPair keyPairOtherPeer = keyGen.genKeyPair();
TomP2PNode node;
Number160 locationKey;
Data data;
FuturePut futurePut;
FutureGet futureGet;
// otherPeer tries to squat clients location store
// he can do it but as he has not the domain key of the client he cannot do any harm
// he only can store und that path: locationKey.otherPeerDomainKey.data
node = new TomP2PNode(keyPairOtherPeer, otherPeer);
locationKey = Number160.createHash("clients location");
data = new Data("otherPeer data");
futurePut = node.putDomainProtectedData(locationKey, data);
futurePut.awaitUninterruptibly();
assertTrue(futurePut.isSuccess());
futureGet = node.getDomainProtectedData(locationKey, keyPairOtherPeer.getPublic());
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
assertEquals("otherPeer data", futureGet.data().object());
// client store his data und his domainkey, no problem with previous occupied
// he only can store und that path: locationKey.clientDomainKey.data
node = new TomP2PNode(keyPairClient, client);
locationKey = Number160.createHash("clients location");
data = new Data("client data");
futurePut = node.putDomainProtectedData(locationKey, data);
futurePut.awaitUninterruptibly();
assertTrue(futurePut.isSuccess());
futureGet = node.getDomainProtectedData(locationKey, keyPairClient.getPublic());
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
assertEquals("client data", futureGet.data().object());
// also other peers can read that data if they know the public key of the client
node = new TomP2PNode(keyPairOtherPeer, otherPeer);
futureGet = node.getDomainProtectedData(locationKey, keyPairClient.getPublic());
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
assertEquals("client data", futureGet.data().object());
// other peer try to use pub key of other peer as domain key hash.
// must fail as he don't have the full key pair (private key of client missing)
locationKey = Number160.createHash("clients location");
data = new Data("otherPeer data hack");
data.protectEntry(keyPairOtherPeer);
// he use the pub key from the client
final Number160 keyHash = Utils.makeSHAHash(keyPairClient.getPublic().getEncoded());
futurePut = otherPeer.put(locationKey).data(data).keyPair(keyPairOtherPeer).domainKey(keyHash)
.protectDomain().start();
futurePut.awaitUninterruptibly();
assertFalse(futurePut.isSuccess());
// he can read his prev. stored data
node = new TomP2PNode(keyPairOtherPeer, otherPeer);
futureGet = node.getDomainProtectedData(locationKey, keyPairOtherPeer.getPublic());
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
assertEquals("otherPeer data", futureGet.data().object());
// he can read clients data
futureGet = node.getDomainProtectedData(locationKey, keyPairClient.getPublic());
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
assertEquals("client data", futureGet.data().object());
master.shutdown();
}
@Test
public void testChangeEntryProtectionKey() throws Exception {
KeyPairGenerator gen = KeyPairGenerator.getInstance("DSA");
KeyPair keyPair1 = gen.generateKeyPair();
KeyPair keyPair2 = gen.generateKeyPair();
PeerDHT p1 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash(1)).ports(4838)
.keyPair(keyPair1).start()).start();
PeerDHT p2 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash(2)).ports(4839)
.keyPair(keyPair2).start()).start();
p2.peer().bootstrap().peerAddress(p1.peerAddress()).start().awaitUninterruptibly();
p1.peer().bootstrap().peerAddress(p2.peerAddress()).start().awaitUninterruptibly();
Data data = new Data("test").protectEntry(keyPair1);
FuturePut fp1 = p1.put(Number160.createHash("key1")).sign().data(data).start().awaitUninterruptibly();
Assert.assertTrue(fp1.isSuccess());
FuturePut fp2 = p2.put(Number160.createHash("key1")).data(data).start().awaitUninterruptibly();
Assert.assertTrue(!fp2.isSuccess());
Data data2 = new Data().protectEntry(keyPair2);
data2.publicKey(keyPair2.getPublic());
FuturePut fp3 =
p1.put(Number160.createHash("key1")).sign().putMeta().data(data2).start().awaitUninterruptibly();
Assert.assertTrue(fp3.isSuccess());
FuturePut fp4 = p2.put(Number160.createHash("key1")).sign().data(data).start().awaitUninterruptibly();
Assert.assertTrue(fp4.isSuccess());
p1.shutdown().awaitUninterruptibly();
p2.shutdown().awaitUninterruptibly();
}
@Test
public void testAddToListGetList() throws Exception {
PeerDHT[] peers = UtilsDHT2.createNodes(3, rnd, new Ports().tcpPort());
PeerDHT master = peers[0];
PeerDHT client = peers[1];
PeerDHT otherPeer = peers[2];
UtilsDHT2.perfectRouting(peers);
TomP2PNode node;
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(1024);
KeyPair keyPairClient = keyGen.genKeyPair();
KeyPair keyPairOtherPeer = keyGen.genKeyPair();
Number160 locationKey;
Data data;
FuturePut futurePut;
FutureGet futureGet;
// client add a value
KeyPairGenerator gen = KeyPairGenerator.getInstance("DSA");
KeyPair keyPair1 = gen.generateKeyPair();
keyPairClient = keyPair1;
node = new TomP2PNode(keyPairClient, client);
locationKey = Number160.createHash("add to list clients location");
data = new Data("add to list client data1");
Data data_1 = data;
futurePut = node.addProtectedData(locationKey, data);
futurePut.awaitUninterruptibly();
assertTrue(futurePut.isSuccess());
data = new Data("add to list client data2");
Data data_2 = data;
futurePut = node.addProtectedData(locationKey, data);
futurePut.awaitUninterruptibly();
assertTrue(futurePut.isSuccess());
futureGet = node.getDataMap(locationKey);
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
boolean foundData1 = futureGet.dataMap().values().stream().anyMatch(data1 -> {
try {
return data1.object().equals("add to list client data1");
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return false;
});
boolean foundData2 = futureGet.dataMap().values().stream().anyMatch(data1 -> {
try {
return data1.object().equals("add to list client data2");
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return false;
});
assertTrue(foundData1);
assertTrue(foundData2);
assertEquals(2, futureGet.dataMap().values().size());
// other peer tried to overwrite that entry
// but will not succeed, instead he will add a new entry.
// TODO investigate why it is not possible to overwrite the entry with that method
// The protection entry with the key does not make any difference as also the client himself cannot overwrite
// any entry
// http://tomp2p.net/doc/P2P-with-TomP2P-1.pdf
// "add(location_key, value) is translated to put(location_key, hash(value), value)"
// fake content key with content key from previous clients entry
Number160 contentKey = Number160.createHash("add to list client data1");
data = new Data("add to list other peer data HACK!");
data.protectEntry(keyPairOtherPeer); // also with client key it does not work...
futurePut = otherPeer.put(locationKey).data(contentKey, data).keyPair(keyPairOtherPeer).start();
futurePut.awaitUninterruptibly();
assertTrue(futurePut.isSuccess());
node = new TomP2PNode(keyPairOtherPeer, otherPeer);
futureGet = node.getDataMap(locationKey);
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
foundData1 = futureGet.dataMap().values().stream().anyMatch(data1 -> {
try {
return data1.object().equals("add to list client data1");
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return false;
});
foundData2 = futureGet.dataMap().values().stream().anyMatch(data1 -> {
try {
return data1.object().equals("add to list client data2");
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return false;
});
boolean foundData3 = futureGet.dataMap().values().stream().anyMatch(data1 -> {
try {
return data1.object().equals("add to list other peer data HACK!");
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return false;
});
assertTrue(foundData1);
assertTrue(foundData2);
assertTrue(foundData3);
assertEquals(3, futureGet.dataMap().values().size());
// client removes his entry -> OK
node = new TomP2PNode(keyPairClient, client);
FutureRemove futureRemove = node.removeFromDataMap(locationKey, data_1);
futureRemove.awaitUninterruptibly();
// We don't test futureRemove.isSuccess() as this API does not fit well to that operation,
// it might change in future to something like foundAndRemoved and notFound
// See discussion at: https://github.com/tomp2p/TomP2P/issues/57#issuecomment-62069840
futureGet = node.getDataMap(locationKey);
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
foundData1 = futureGet.dataMap().values().stream().anyMatch(data1 -> {
try {
return data1.object().equals("add to list client data1");
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return false;
});
foundData2 = futureGet.dataMap().values().stream().anyMatch(data1 -> {
try {
return data1.object().equals("add to list client data2");
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return false;
});
foundData3 = futureGet.dataMap().values().stream().anyMatch(data1 -> {
try {
return data1.object().equals("add to list other peer data HACK!");
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return false;
});
assertFalse(foundData1);
assertTrue(foundData2);
assertTrue(foundData3);
assertEquals(2, futureGet.dataMap().values().size());
// otherPeer tries to removes client entry -> FAIL
node = new TomP2PNode(keyPairOtherPeer, otherPeer);
futureRemove = node.removeFromDataMap(locationKey, data_2);
futureRemove.awaitUninterruptibly();
assertFalse(futureRemove.isSuccess());
futureGet = node.getDataMap(locationKey);
futureGet.awaitUninterruptibly();
assertTrue(futureGet.isSuccess());
foundData1 = futureGet.dataMap().values().stream().anyMatch(data1 -> {
try {
return data1.object().equals("add to list client data1");
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return false;
});
foundData2 = futureGet.dataMap().values().stream().anyMatch(data1 -> {
try {
return data1.object().equals("add to list client data2");
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return false;
});
foundData3 = futureGet.dataMap().values().stream().anyMatch(data1 -> {
try {
return data1.object().equals("add to list other peer data HACK!");
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return false;
});
assertFalse(foundData1);
assertTrue(foundData2);
assertTrue(foundData3);
assertEquals(2, futureGet.dataMap().values().size());
master.shutdown();
}
}

View file

@ -0,0 +1,61 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.network;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
public class NodeTests {
@Test
public void testEqualsAndHashCode() {
Node node1a = Node.at("bitsquare1.example.com", "203.0.113.1");
Node node1b = Node.at("bitsquare1.example.com", "203.0.113.1");
assertThat(node1a, equalTo(node1a));
assertThat(node1a, equalTo(node1b));
assertThat(node1b, equalTo(node1a));
assertThat(node1a, not((Object) equalTo(null)));
assertThat(node1a, not((Object) equalTo("not a node")));
assertThat(node1a, not(equalTo(Node.at("bitsquare2.example.com", node1a.getIp()))));
assertThat(node1a, not(equalTo(Node.at(node1a.getName(), "203.0.113.2"))));
assertThat(node1a, not(equalTo(Node.at(node1a.getName(), node1a.getIp(), Node.DEFAULT_PORT + 1))));
Node node2 = Node.at("bitsquare2.example.com", "203.0.113.2");
assertThat(node1a.hashCode(), equalTo(node1b.hashCode()));
assertThat(node1a.hashCode(), not(equalTo(node2.hashCode())));
assertThat(node1a.getPort(), equalTo(Node.DEFAULT_PORT));
Node node3a = Node.at("bitsquare3.example.com", "203.0.113.3", 1234);
Node node3b = Node.at("bitsquare3.example.com", "203.0.113.3", "1234");
assertThat(node3a, equalTo(node3b));
}
@Test
public void testToString() {
Node node = Node.at("bitsquare1.example.com", "203.0.113.1", 5001);
assertThat(node.toString(), equalTo("Node{name=bitsquare1.example.com, ip=203.0.113.1, port=5001}"));
}
}

View file

@ -0,0 +1,32 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.network.tomp2p;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.*;
public class TomP2PPeerTest {
@Test
public void testToString() {
TomP2PPeer peer = new TomP2PPeer(null);
assertThat(peer.toString(), equalTo("TomP2PPeer{peerAddress=null}"));
}
}

View file

@ -0,0 +1,37 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Method-level annotation to be used in connection with {@link RepeatRule} to cause a
* given {@link org.junit.Test} method to be repeated a specified number of times.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Repeat {
/**
* Specifies the number of times to repeat the annotated {@link org.junit.Test}.
*/
int value();
}

View file

@ -0,0 +1,57 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.util;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
/**
* @see {@link Repeat}
*/
public class RepeatRule implements TestRule {
private static class RepeatStatement extends Statement {
private final int times;
private final Statement statement;
private RepeatStatement(int times, Statement statement) {
this.times = times;
this.statement = statement;
}
@Override
public void evaluate() throws Throwable {
for (int i = 0; i < times; i++) {
statement.evaluate();
}
}
}
@Override
public Statement apply(Statement statement, Description description) {
Statement result = statement;
Repeat repeat = description.getAnnotation(Repeat.class);
if (repeat != null) {
int times = repeat.value();
result = new RepeatStatement(times, statement);
}
return result;
}
}

View file

@ -0,0 +1,68 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.util;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.*;
public class RepeatRuleTests {
private static final int EXPECTED_COUNT = 10;
private static int ACTUAL_BEFORE_COUNT;
private static int ACTUAL_TEST_COUNT;
private static int ACTUAL_AFTER_COUNT;
public @Rule RepeatRule repeatRule = new RepeatRule();
@BeforeClass
public static void beforeTests() {
ACTUAL_BEFORE_COUNT = 0;
ACTUAL_TEST_COUNT = 0;
ACTUAL_AFTER_COUNT = 0;
}
@Before
public void setUp() {
ACTUAL_BEFORE_COUNT++;
}
@Test
@Repeat(EXPECTED_COUNT)
public void shouldBeRepeated() {
ACTUAL_TEST_COUNT++;
}
@After
public void tearDown() {
ACTUAL_AFTER_COUNT++;
}
@AfterClass
public static void afterTests() {
assertThat(ACTUAL_BEFORE_COUNT, equalTo(EXPECTED_COUNT));
assertThat(ACTUAL_TEST_COUNT, equalTo(EXPECTED_COUNT));
assertThat(ACTUAL_AFTER_COUNT, equalTo(EXPECTED_COUNT));
}
}