Renamed gui module to core

This commit is contained in:
Manfred Karrer 2015-03-13 20:15:20 +01:00
parent 3a90fcd022
commit dbf35b2423
688 changed files with 4 additions and 4 deletions

View file

@ -0,0 +1,65 @@
/*
* 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 org.junit.Test;
import org.springframework.core.env.ConfigurableEnvironment;
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.equalTo;
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
}
}

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.bootstrap.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,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,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.network.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,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,314 @@
/*
* 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.trade.protocol.placeoffer;
import io.bitsquare.arbitrator.Arbitrator;
import io.bitsquare.bank.BankAccountType;
import io.bitsquare.btc.BitcoinNetwork;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.UserAgent;
import io.bitsquare.btc.WalletService;
import io.bitsquare.locale.CountryUtil;
import io.bitsquare.locale.LanguageUtil;
import io.bitsquare.network.BootstrapState;
import io.bitsquare.network.Node;
import io.bitsquare.network.tomp2p.BootstrappedPeerBuilder;
import io.bitsquare.network.tomp2p.TomP2PNode;
import io.bitsquare.offer.Direction;
import io.bitsquare.offer.Offer;
import io.bitsquare.offer.OfferBookService;
import io.bitsquare.offer.tomp2p.TomP2POfferBookService;
import io.bitsquare.persistence.Persistence;
import io.bitsquare.trade.TradeMessageService;
import io.bitsquare.trade.tomp2p.TomP2PTradeMessageService;
import io.bitsquare.user.User;
import io.bitsquare.util.DSAKeyUtil;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Threading;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Currency;
import java.util.concurrent.CountDownLatch;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.Observable;
/**
* That test is ignored for automated testing as it needs custom setup.
* <p/>
* It uses RegTest mode of Bitcoin network and localhost TomP2P network.
* <p/>
* 1. Need a first run to get the wallet receiving address.
* 2. Fund that from regtest Bitcoin Core client.
* 3. Create a block on regtest Bitcoin Core (setgenerate true) to get the balance.
* 4. Start BootstrapNodeMain at localhost with program args: --node.name localhost
*/
@Ignore
public class PlaceOfferProtocolTest {
private static final Logger log = LoggerFactory.getLogger(PlaceOfferProtocolTest.class);
private WalletService walletService;
private TradeMessageService tradeMessageService;
private OfferBookService offerBookService;
private final File dir = new File("./temp");
private final static String OFFER_ID = "offerID";
private Address address;
private TomP2PNode tomP2PNode;
private BootstrappedPeerBuilder bootstrappedPeerBuilder;
@Before
public void setup() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
dir.mkdirs();
Persistence persistence = new Persistence(dir, "prefs");
persistence.init();
// messageService
Node bootstrapNode = Node.at("localhost", "127.0.0.1");
User user = new User();
user.applyPersistedUser(null);
bootstrappedPeerBuilder = new BootstrappedPeerBuilder(Node.DEFAULT_PORT, false, bootstrapNode, "<unspecified>");
tomP2PNode = new TomP2PNode(bootstrappedPeerBuilder);
tradeMessageService = new TomP2PTradeMessageService(user, tomP2PNode);
Observable<BootstrapState> messageObservable = tomP2PNode.bootstrap(user.getMessageKeyPair(), tradeMessageService);
messageObservable.publish();
messageObservable.subscribe(
state -> log.trace("state changed: " + state),
error -> {
log.error(error.toString());
},
() -> {
log.trace("message completed");
offerBookService = new TomP2POfferBookService(tomP2PNode);
offerBookService.setExecutor(Threading.SAME_THREAD);
}
);
bootstrappedPeerBuilder.start();
// WalletService
walletService = new WalletService(BitcoinNetwork.REGTEST,
new FeePolicy(BitcoinNetwork.REGTEST),
null,
persistence,
new UserAgent("", ""),
dir,
"Tests"
);
Observable<Object> walletServiceObservable = walletService.initialize(Threading.SAME_THREAD);
walletServiceObservable.subscribe(
next -> {
// log.trace("wallet next");
},
error -> {
log.trace("wallet error");
},
() -> {
log.trace("wallet complete");
});
Observable<?> allTasks = Observable.merge(messageObservable, walletServiceObservable);
allTasks.subscribe(
next -> {
//log.trace("next");
},
error -> log.error(error.toString()),
() -> {
log.trace("wallet completed");
// 1. Use that address for funding the trading wallet
address = walletService.getAddressInfoByTradeID(OFFER_ID).getAddress();
log.info("address for funding wallet = " + address.toString());//muoTvFHJmQwPKYoA8Fr7t87UCSfZM4fciG
log.info("Balance = " + walletService.getBalanceForAddress(address));
countDownLatch.countDown();
});
countDownLatch.await();
}
@After
public void shutDown() throws IOException, InterruptedException {
walletService.shutDown();
bootstrappedPeerBuilder.shutDown();
}
/* @Test
public void validateOfferTest() throws InterruptedException {
try {
Offer offer = getOffer();
getCreateOfferCoordinator(offer).validateOffer();
assertTrue(true);
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void createOfferFeeTxTest() throws InterruptedException {
try {
Offer offer = getOffer();
Transaction transaction = getCreateOfferCoordinator(offer).createOfferFeeTx();
assertNotNull(transaction);
} catch (Exception e) {
log.info("address for funding wallet = " + address.toString());
log.info("Balance = " + walletService.getBalanceForAddress(address));
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void broadcastCreateOfferFeeTxTest() throws InterruptedException {
try {
log.info("Balance pre = " + walletService.getBalanceForAddress(address));
Offer offer = getOffer();
TransactionResultHandler resultHandler = transaction -> assertNotNull(transaction);
FaultHandler faultHandler = (message, throwable) -> {
log.error(message);
throwable.printStackTrace();
fail(throwable.getMessage());
};
PlaceOfferProtocol placeOfferProtocol = getCreateOfferCoordinator(offer);
Transaction transaction = placeOfferProtocol.createOfferFeeTx();
placeOfferProtocol.broadcastCreateOfferFeeTx(transaction, resultHandler, faultHandler);
log.info("Balance post = " + walletService.getBalanceForAddress(address));
} catch (Exception e) {
log.info("address for funding wallet = " + address.toString());
log.info("Balance = " + walletService.getBalanceForAddress(address));
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
public void addOfferTest() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(2);
try {
Offer offer = getOffer();
offerBookService.addListener(new OfferBookService.Listener() {
@Override
public void onOfferAdded(Offer offer1) {
assertEquals("Offer matching", offer.getId(), offer1.getId());
countDownLatch.countDown();
}
@Override
public void onOffersReceived(List<Offer> offers) {
}
@Override
public void onOfferRemoved(Offer offer) {
}
});
TransactionResultHandler resultHandler = transaction -> {
assertNotNull(transaction);
countDownLatch.countDown();
};
FaultHandler faultHandler = (message, throwable) -> {
log.error(message);
throwable.printStackTrace();
fail(throwable.getMessage());
countDownLatch.countDown();
countDownLatch.countDown();
};
PlaceOfferProtocol placeOfferProtocol = getPlaceOfferProtocol(offer, resultHandler, faultHandler);
Transaction transaction = placeOfferProtocol.createOfferFeeTx();
placeOfferProtocol.addOffer(transaction);
countDownLatch.await();
log.info("Finished");
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
countDownLatch.countDown();
countDownLatch.countDown();
}
}
@Test
public void placeOfferTest() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
TransactionResultHandler resultHandler = transaction -> {
assertNotNull(transaction);
countDownLatch.countDown();
};
FaultHandler faultHandler = (message, throwable) -> {
log.error(message);
throwable.printStackTrace();
fail(throwable.getMessage());
countDownLatch.countDown();
countDownLatch.countDown();
};
PlaceOfferProtocol placeOfferProtocol = getPlaceOfferProtocol(getOffer(), resultHandler, faultHandler);
placeOfferProtocol.placeOffer();
countDownLatch.await();
}
private PlaceOfferProtocol getCreateOfferCoordinator(Offer offer) throws InterruptedException {
TransactionResultHandler resultHandler = transaction -> log.debug("result transaction=" + transaction.toString());
FaultHandler faultHandler = (message, throwable) -> {
log.error(message);
throwable.printStackTrace();
log.info("Balance = " + walletService.getBalanceForAddress(walletService.getAddressInfoByTradeID(OFFER_ID).getAddress()));
};
return getPlaceOfferProtocol(offer, resultHandler, faultHandler);
}
private PlaceOfferProtocol getPlaceOfferProtocol(Offer offer, TransactionResultHandler resultHandler, FaultHandler faultHandler) throws
InterruptedException {
return new PlaceOfferProtocol(offer,
walletService,
offerBookService,
resultHandler,
faultHandler);
}*/
private Offer getOffer() {
return new Offer(OFFER_ID,
DSAKeyUtil.generateKeyPair().getPublic(),
Direction.BUY,
100L,
Coin.CENT,
Coin.CENT,
BankAccountType.INTERNATIONAL,
Currency.getInstance("EUR"),
CountryUtil.getDefaultCountry(),
"bankAccountUID",
Arrays.asList(new Arbitrator()),
Coin.CENT,
Arrays.asList(CountryUtil.getDefaultCountry()),
Arrays.asList(LanguageUtil.getDefaultLanguageLocale())
);
}
}

View file

@ -0,0 +1,136 @@
/*
* 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.trade.protocol.placeoffer;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TaskRunner {
private static final Logger log = LoggerFactory.getLogger(TaskRunner.class);
private Queue<Class> tasks;
private SharedModel sharedModel = new SharedModel();
private FaultHandler faultHandler;
private ResultHandler taskCompleted;
private final boolean[] failed = {false};
@Test
public void test() {
// Task1.run();
//Task2.run();
tasks = new LinkedBlockingQueue<>();
tasks.add(Task1.class);
tasks.add(Task2.class);
faultHandler = (throwable) -> {
log.debug(throwable.getMessage());
failed[0] = true;
};
taskCompleted = () -> {
next();
};
next();
/* ResultHandler handleResult = () -> {
Class task = tasks.poll();
try {
if (!failed[0])
((Task) task.newInstance()).run(sharedModel, taskCompleted, faultHandler);
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
};*/
/* tasks.stream().forEach((e) -> {
try {
((Task) e.newInstance()).run(sharedModel, faultHandler);
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
});*/
}
private void next() {
Class task = tasks.poll();
if (task != null) {
try {
if (!failed[0])
((Task) task.newInstance()).run(sharedModel, taskCompleted, faultHandler);
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
}
}
}
interface ResultHandler {
void handleResult();
}
interface FaultHandler {
void handleFault(Throwable throwable);
}
class SharedModel {
public int data = 42;
}
class Task {
protected void run(SharedModel sharedModel, ResultHandler resultHandler, FaultHandler faultHandler) {
}
}
class Task1 extends Task {
private static final Logger log = LoggerFactory.getLogger(Task1.class);
@Override
public void run(SharedModel sharedModel, ResultHandler resultHandler, FaultHandler faultHandler) {
log.debug("run " + Task1.class);
log.debug("data " + sharedModel.data);
// faultHandler.handleFault(new Exception("test"));
sharedModel.data++;
resultHandler.handleResult();
}
}
class Task2 extends Task {
private static final Logger log = LoggerFactory.getLogger(Task2.class);
@Override
public void run(SharedModel sharedModel, ResultHandler resultHandler, FaultHandler faultHandler) {
log.debug("run " + Task2.class);
log.debug("data " + sharedModel.data);
resultHandler.handleResult();
}
}

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));
}
}

View file

@ -0,0 +1,20 @@
<!--
~ 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/>.
-->
<?import javafx.scene.layout.*?>
<AnchorPane xmlns:fx="http://javafx.com/fxml">
</AnchorPane>

View file

@ -0,0 +1,21 @@
<!--
~ 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/>.
-->
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="root" fx:controller="io.bitsquare.viewfx.view.fxml.FxmlViewLoaderTests$MissingFxmlViewAnnotation"
xmlns:fx="http://javafx.com/fxml">
</AnchorPane>

View file

@ -0,0 +1,21 @@
<!--
~ 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/>.
-->
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="root" fx:controller="io.bitsquare.viewfx.view.fxml.FxmlViewLoaderTests$WellFormed"
xmlns:fx="http://javafx.com/fxml">
</AnchorPane>

View file

@ -0,0 +1,131 @@
/*
* 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.viewfx.view.fxml;
import io.bitsquare.viewfx.ViewfxException;
import io.bitsquare.viewfx.view.FxmlView;
import io.bitsquare.viewfx.view.View;
import java.util.ResourceBundle;
import io.bitsquare.viewfx.view.ViewFactory;
import io.bitsquare.viewfx.view.ViewLoader;
import io.bitsquare.viewfx.view.AbstractView;
import javafx.fxml.LoadException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
public class FxmlViewLoaderTests {
private ViewLoader viewLoader;
private ViewFactory viewFactory;
@Rule
public ExpectedException thrown = ExpectedException.none();
@Before
public void setUp() {
viewFactory = mock(ViewFactory.class);
ResourceBundle resourceBundle = mock(ResourceBundle.class);
viewLoader = new FxmlViewLoader(viewFactory, resourceBundle);
}
@FxmlView
static class WellFormed extends AbstractView {
}
@Test
public void wellFormedFxmlFileShouldSucceed() {
given(viewFactory.call(WellFormed.class)).willReturn(new WellFormed());
View view = viewLoader.load(WellFormed.class);
assertThat(view, instanceOf(WellFormed.class));
}
@FxmlView
static class MissingFxController extends AbstractView {
}
@Test
public void fxmlFileMissingFxControllerAttributeShouldThrow() {
thrown.expect(ViewfxException.class);
thrown.expectMessage("Does it declare an fx:controller attribute?");
viewLoader.load(MissingFxController.class);
}
static class MissingFxmlViewAnnotation extends AbstractView {
}
@Test
public void fxmlViewAnnotationShouldBeOptional() {
given(viewFactory.call(MissingFxmlViewAnnotation.class)).willReturn(new MissingFxmlViewAnnotation());
View view = viewLoader.load(MissingFxmlViewAnnotation.class);
assertThat(view, instanceOf(MissingFxmlViewAnnotation.class));
}
@FxmlView
static class Malformed extends AbstractView {
}
@Test
public void malformedFxmlFileShouldThrow() {
thrown.expect(ViewfxException.class);
thrown.expectMessage("Failed to load view from FXML file");
thrown.expectCause(instanceOf(LoadException.class));
viewLoader.load(Malformed.class);
}
@FxmlView
static class MissingFxmlFile extends AbstractView {
}
@Test
public void missingFxmlFileShouldThrow() {
thrown.expect(ViewfxException.class);
thrown.expectMessage("Does it exist?");
viewLoader.load(MissingFxmlFile.class);
}
@FxmlView(location = "unconventionally/located.fxml")
static class CustomLocation extends AbstractView {
}
@Test
public void customFxmlFileLocationShouldOverrideDefaultConvention() {
thrown.expect(ViewfxException.class);
thrown.expectMessage("Failed to load view class");
thrown.expectMessage("CustomLocation");
thrown.expectMessage("[unconventionally/located.fxml] could not be loaded");
viewLoader.load(CustomLocation.class);
}
}

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.viewfx.view.support;
import io.bitsquare.viewfx.view.AbstractView;
import io.bitsquare.viewfx.view.CachingViewLoader;
import io.bitsquare.viewfx.view.ViewLoader;
import org.junit.Test;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.*;
public class CachingViewLoaderTests {
@Test
public void test() {
ViewLoader delegateViewLoader = mock(ViewLoader.class);
ViewLoader cachingViewLoader = new CachingViewLoader(delegateViewLoader);
cachingViewLoader.load(TestView1.class);
cachingViewLoader.load(TestView1.class);
cachingViewLoader.load(TestView2.class);
then(delegateViewLoader).should(times(1)).load(TestView1.class);
then(delegateViewLoader).should(times(1)).load(TestView2.class);
then(delegateViewLoader).should(times(0)).load(TestView3.class);
}
static class TestView1 extends AbstractView {
}
static class TestView2 extends AbstractView {
}
static class TestView3 extends AbstractView {
}
}

View file

@ -0,0 +1,368 @@
/*
* Copyright 2012 Thomas Bocek
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package net.tomp2p.dht;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.NavigableSet;
import java.util.Random;
import java.util.TreeSet;
import net.tomp2p.connection.Bindings;
import net.tomp2p.futures.FutureBootstrap;
import net.tomp2p.futures.FutureDiscover;
import net.tomp2p.message.Message;
import net.tomp2p.message.Message.Type;
import net.tomp2p.p2p.AutomaticFuture;
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.peers.PeerSocketAddress;
public class UtilsDHT2 {
/**
* Used to make the testcases predictable. Used as an input for {@link Random}.
*/
public static final long THE_ANSWER = 42L;
/**
* Having two peers in a network, the seed needs to be different, otherwise we create a peer with the same id twice.
*/
public static final long THE_ANSWER2 = 43L;
public static Message createDummyMessage() throws UnknownHostException {
return createDummyMessage(false, false);
}
public static Message createDummyMessage(boolean firewallUDP, boolean firewallTCP)
throws UnknownHostException {
return createDummyMessage(new Number160("0x4321"), "127.0.0.1", 8001, 8002, new Number160("0x1234"),
"127.0.0.1", 8003, 8004, (byte) 0, Type.REQUEST_1, firewallUDP, firewallTCP);
}
public static PeerAddress createAddress(Number160 id) throws UnknownHostException {
return createAddress(id, "127.0.0.1", 8005, 8006, false, false);
}
public static PeerAddress createAddress() throws UnknownHostException {
return createAddress(new Number160("0x5678"), "127.0.0.1", 8005, 8006, false, false);
}
public static PeerAddress createAddress(int id) throws UnknownHostException {
return createAddress(new Number160(id), "127.0.0.1", 8005, 8006, false, false);
}
public static PeerAddress createAddress(String id) throws UnknownHostException {
return createAddress(new Number160(id), "127.0.0.1", 8005, 8006, false, false);
}
public static PeerAddress createAddress(Number160 idSender, String inetSender, int tcpPortSender,
int udpPortSender, boolean firewallUDP, boolean firewallTCP) throws UnknownHostException {
InetAddress inetSend = InetAddress.getByName(inetSender);
PeerSocketAddress peerSocketAddress = new PeerSocketAddress(inetSend, tcpPortSender, udpPortSender);
PeerAddress n1 = new PeerAddress(idSender, peerSocketAddress, firewallTCP, firewallUDP, false, false, false,
PeerAddress.EMPTY_PEER_SOCKET_ADDRESSES);
return n1;
}
public static Message createDummyMessage(Number160 idSender, String inetSender, int tcpPortSendor,
int udpPortSender, Number160 idRecipien, String inetRecipient, int tcpPortRecipient,
int udpPortRecipient, byte command, Type type, boolean firewallUDP, boolean firewallTCP)
throws UnknownHostException {
Message message = new Message();
PeerAddress n1 = createAddress(idSender, inetSender, tcpPortSendor, udpPortSender, firewallUDP,
firewallTCP);
message.sender(n1);
//
PeerAddress n2 = createAddress(idRecipien, inetRecipient, tcpPortRecipient, udpPortRecipient,
firewallUDP, firewallTCP);
message.recipient(n2);
message.type(type);
message.command(command);
return message;
}
public static PeerDHT[] createNodes(int nrOfPeers, Random rnd, int port) throws Exception {
return createNodes(nrOfPeers, rnd, port, null);
}
public static PeerDHT[] createNodes(int nrOfPeers, Random rnd, int port, AutomaticFuture automaticFuture)
throws Exception {
return createNodes(nrOfPeers, rnd, port, automaticFuture, false);
}
/**
* Creates peers for testing. The first peer (peer[0]) will be used as the master. This means that shutting down
* peer[0] will shut down all other peers
*
* @param nrOfPeers
* The number of peers to create including the master
* @param rnd
* The random object to create random peer IDs
* @param port
* The port where the master peer will listen to
* @return All the peers, with the master peer at position 0 -> peer[0]
* @throws Exception
* If the creation of nodes fail.
*/
public static PeerDHT[] createNodes(int nrOfPeers, Random rnd, int port, AutomaticFuture automaticFuture,
boolean maintenance) throws Exception {
if (nrOfPeers < 1) {
throw new IllegalArgumentException("Cannot create less than 1 peer");
}
Bindings bindings = new Bindings();
PeerDHT[] peers = new PeerDHT[nrOfPeers];
final Peer master;
if (automaticFuture != null) {
Number160 peerId = new Number160(rnd);
PeerMap peerMap = new PeerMap(new PeerMapConfiguration(peerId));
master = new PeerBuilder(peerId)
.ports(port).enableMaintenance(maintenance)
.bindings(bindings).peerMap(peerMap).start().addAutomaticFuture(automaticFuture);
peers[0] = new PeerBuilderDHT(master).start();
}
else {
Number160 peerId = new Number160(rnd);
PeerMap peerMap = new PeerMap(new PeerMapConfiguration(peerId));
master = new PeerBuilder(peerId).enableMaintenance(maintenance).bindings(bindings)
.peerMap(peerMap).ports(port).start();
peers[0] = new PeerBuilderDHT(master).start();
}
for (int i = 1; i < nrOfPeers; i++) {
if (automaticFuture != null) {
Number160 peerId = new Number160(rnd);
PeerMap peerMap = new PeerMap(new PeerMapConfiguration(peerId));
Peer peer = new PeerBuilder(peerId)
.masterPeer(master)
.enableMaintenance(maintenance).enableMaintenance(maintenance).peerMap(peerMap).bindings(bindings).start().addAutomaticFuture
(automaticFuture);
peers[i] = new PeerBuilderDHT(peer).start();
}
else {
Number160 peerId = new Number160(rnd);
PeerMap peerMap = new PeerMap(new PeerMapConfiguration(peerId).peerNoVerification());
Peer peer = new PeerBuilder(peerId).enableMaintenance(maintenance)
.bindings(bindings).peerMap(peerMap).masterPeer(master)
.start();
peers[i] = new PeerBuilderDHT(peer).start();
}
}
System.err.println("peers created.");
return peers;
}
public static Peer[] createRealNodes(int nrOfPeers, Random rnd, int startPort,
AutomaticFuture automaticFuture) throws Exception {
if (nrOfPeers < 1) {
throw new IllegalArgumentException("Cannot create less than 1 peer");
}
Peer[] peers = new Peer[nrOfPeers];
for (int i = 0; i < nrOfPeers; i++) {
peers[i] = new PeerBuilder(new Number160(rnd))
.ports(startPort + i).start().addAutomaticFuture(automaticFuture);
}
System.err.println("real peers created.");
return peers;
}
public static Peer[] createNonMaintenanceNodes(int nrOfPeers, Random rnd, int port) throws IOException {
if (nrOfPeers < 1) {
throw new IllegalArgumentException("Cannot create less than 1 peer");
}
Peer[] peers = new Peer[nrOfPeers];
peers[0] = new PeerBuilder(new Number160(rnd)).enableMaintenance(false).ports(port).start();
for (int i = 1; i < nrOfPeers; i++) {
peers[i] = new PeerBuilder(new Number160(rnd)).enableMaintenance(false).masterPeer(peers[0])
.start();
}
System.err.println("non-maintenance peers created.");
return peers;
}
/**
* Perfect routing, where each neighbor has contacted each other. This means that for small number of peers, every
* peer knows every other peer.
*
* @param peers
* The peers taking part in the p2p network.
*/
public static void perfectRouting(PeerDHT... peers) {
for (int i = 0; i < peers.length; i++) {
for (int j = 0; j < peers.length; j++)
peers[i].peer().peerBean().peerMap().peerFound(peers[j].peer().peerAddress(), null, null, null);
}
System.err.println("perfect routing done.");
}
public static void perfectRoutingIndirect(PeerDHT... peers) {
for (int i = 0; i < peers.length; i++) {
for (int j = 0; j < peers.length; j++)
peers[i].peerBean().peerMap().peerFound(peers[j].peerAddress(), peers[j].peerAddress(), null, null);
}
System.err.println("perfect routing done.");
}
public static void main(String[] args) throws IOException {
createTempDirectory();
}
private static final int TEMP_DIR_ATTEMPTS = 10000;
public static File createTempDirectory() throws IOException {
File baseDir = new File(System.getProperty("java.io.tmpdir"));
String baseName = System.currentTimeMillis() + "-";
for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
File tempDir = new File(baseDir, baseName + counter);
if (tempDir.mkdir()) {
return tempDir;
}
}
throw new IllegalStateException("Failed to create directory within " + TEMP_DIR_ATTEMPTS
+ " attempts (tried " + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ')');
}
public static Peer[] createAndAttachNodes(int nr, int port, Random rnd) throws Exception {
Peer[] peers = new Peer[nr];
for (int i = 0; i < nr; i++) {
if (i == 0) {
peers[0] = new PeerBuilder(new Number160(rnd)).ports(port).start();
}
else {
peers[i] = new PeerBuilder(new Number160(rnd)).masterPeer(peers[0]).start();
}
}
return peers;
}
public static void bootstrap(Peer[] peers) {
List<FutureBootstrap> futures1 = new ArrayList<FutureBootstrap>();
List<FutureDiscover> futures2 = new ArrayList<FutureDiscover>();
for (int i = 1; i < peers.length; i++) {
FutureDiscover tmp = peers[i].discover().peerAddress(peers[0].peerAddress()).start();
futures2.add(tmp);
}
for (FutureDiscover future : futures2) {
future.awaitUninterruptibly();
}
for (int i = 1; i < peers.length; i++) {
FutureBootstrap tmp = peers[i].bootstrap().peerAddress(peers[0].peerAddress()).start();
futures1.add(tmp);
}
for (int i = 1; i < peers.length; i++) {
FutureBootstrap tmp = peers[0].bootstrap().peerAddress(peers[i].peerAddress()).start();
futures1.add(tmp);
}
for (FutureBootstrap future : futures1)
future.awaitUninterruptibly();
}
public static void routing(Number160 key, Peer[] peers, int start) {
System.out.println("routing: searching for key " + key);
NavigableSet<PeerAddress> pa1 = new TreeSet<PeerAddress>(PeerMap.createXORAddressComparator(key));
NavigableSet<PeerAddress> queried = new TreeSet<PeerAddress>(PeerMap.createXORAddressComparator(key));
Number160 result = Number160.ZERO;
Number160 resultPeer = new Number160("0xd75d1a3d57841fbc9e2a3d175d6a35dc2e15b9f");
int round = 0;
while (!resultPeer.equals(result)) {
System.out.println("round " + round);
round++;
pa1.addAll(peers[start].peerBean().peerMap().all());
queried.add(peers[start].peerAddress());
System.out.println("closest so far: " + queried.first());
PeerAddress next = pa1.pollFirst();
while (queried.contains(next)) {
next = pa1.pollFirst();
}
result = next.peerId();
start = findNr(next.peerId().toString(), peers);
}
}
public static void findInMap(PeerAddress key, Peer[] peers) {
for (int i = 0; i < peers.length; i++) {
if (peers[i].peerBean().peerMap().contains(key)) {
System.out.println("Peer " + i + " with the id " + peers[i].peerID() + " knows the peer "
+ key);
}
}
}
public static int findNr(String string, Peer[] peers) {
for (int i = 0; i < peers.length; i++) {
if (peers[i].peerID().equals(new Number160(string))) {
System.out.println("we found the number " + i + " for peer with id " + string);
return i;
}
}
return -1;
}
public static Peer find(String string, Peer[] peers) {
for (int i = 0; i < peers.length; i++) {
if (peers[i].peerID().equals(new Number160(string))) {
System.out.println("!!we found the number " + i + " for peer with id " + string);
return peers[i];
}
}
return null;
}
public static void exec(String cmd) throws Exception {
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
}
public static PeerAddress createAddressIP(String inet) throws UnknownHostException {
return createAddress(Number160.createHash(inet), inet, 8005, 8006, false, false);
}
public static PeerAddress[] createDummyAddress(int size, int portTCP, int portUDP) throws UnknownHostException {
PeerAddress[] pa = new PeerAddress[size];
for (int i = 0; i < size; i++) {
pa[i] = createAddress(i + 1, portTCP, portUDP);
}
return pa;
}
public static PeerAddress createAddress(int iid, int portTCP, int portUDP) throws UnknownHostException {
Number160 id = new Number160(iid);
InetAddress address = InetAddress.getByName("127.0.0.1");
return new PeerAddress(id, address, portTCP, portUDP);
}
}