Add Android integration tests that checks if included bridges work

This also changes the way bridges are used.
Instead of using the torrc config file,
bridges are now activated via Tor's control port.
This commit is contained in:
Torsten Grote
2018-06-26 15:47:19 -03:00
parent eac1f9ed74
commit 7e05a49bda
11 changed files with 253 additions and 10 deletions

View File

@@ -11,6 +11,8 @@ android {
versionCode 10011
versionName "1.0.11"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
compileOptions {
@@ -31,6 +33,12 @@ dependencies {
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0'
androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput')
androidTestImplementation project(path: ':bramble-core', configuration: 'testOutput')
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestAnnotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
}
dependencyVerification {

View File

@@ -0,0 +1,23 @@
package org.briarproject.bramble;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.plugin.tor.BridgeTest;
import org.briarproject.bramble.system.SystemModule;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = {
BrambleAndroidModule.class,
PluginModule.class, // needed for BackoffFactory
EventModule.class,
SystemModule.class,
})
public interface IntegrationTestComponent {
void inject(BridgeTest init);
}

View File

@@ -0,0 +1,102 @@
package org.briarproject.bramble.plugin.tor;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.briarproject.bramble.DaggerIntegrationTestComponent;
import org.briarproject.bramble.IntegrationTestComponent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.net.SocketFactory;
import static java.util.Collections.singletonList;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.bramble.plugin.tor.BridgeProviderImpl.BRIDGES;
import static org.briarproject.bramble.plugin.tor.TorNetworkMetadata.doBridgesWork;
import static org.briarproject.bramble.plugin.tor.TorNetworkMetadata.isTorProbablyBlocked;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@RunWith(AndroidJUnit4.class)
public class BridgeTest extends BrambleTestCase {
private final static String BRIDGE_COUNTRY = "VE";
private final static long TIMEOUT = SECONDS.toMillis(23);
private final static Logger LOG =
Logger.getLogger(BridgeTest.class.getSimpleName());
@Inject
EventBus eventBus;
@Inject
BackoffFactory backoffFactory;
@Inject
Clock clock;
private final TorPluginFactory factory;
private TorPlugin plugin;
private int currentBridge = 0;
public BridgeTest() {
IntegrationTestComponent component =
DaggerIntegrationTestComponent.builder().build();
component.inject(this);
Executor ioExecutor = Executors.newCachedThreadPool();
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
Context appContext = InstrumentationRegistry.getTargetContext();
LocationUtils locationUtils = () -> BRIDGE_COUNTRY;
SocketFactory torSocketFactory = SocketFactory.getDefault();
BridgeProvider bridgeProvider =
() -> singletonList(BRIDGES[currentBridge]);
factory = new TorPluginFactory(ioExecutor, scheduler, appContext,
locationUtils, eventBus, torSocketFactory,
backoffFactory, bridgeProvider, clock);
}
@Test
public void testBridges() throws Exception {
assertTrue(isTorProbablyBlocked(BRIDGE_COUNTRY));
assertTrue(doBridgesWork(BRIDGE_COUNTRY));
assertTrue(BRIDGES.length > 0);
for (int i = 0; i < BRIDGES.length; i++) {
plugin = (TorPlugin) factory.createPlugin(new TorPluginCallBack());
testBridge(i);
}
}
private void testBridge(int bridge) throws Exception {
currentBridge = bridge;
LOG.warning("Testing " + BRIDGES[currentBridge]);
try {
plugin.start();
long start = clock.currentTimeMillis();
while (clock.currentTimeMillis() - start < TIMEOUT) {
if (plugin.isRunning()) return;
clock.sleep(500);
}
if (!plugin.isRunning()) {
fail("Could not connect to Tor within timeout.");
}
} finally {
plugin.stop();
}
}
}

View File

@@ -0,0 +1,54 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
@NotNullByDefault
public class TorPluginCallBack implements DuplexPluginCallback {
@Override
public void incomingConnectionCreated(DuplexTransportConnection d) {
}
@Override
public void outgoingConnectionCreated(ContactId c,
DuplexTransportConnection d) {
}
@Override
public Settings getSettings() {
return new Settings();
}
@Override
public TransportProperties getLocalProperties() {
return new TransportProperties();
}
@Override
public void mergeSettings(Settings s) {
}
@Override
public void mergeLocalProperties(TransportProperties p) {
}
@Override
public void transportEnabled() {
}
@Override
public void transportDisabled() {
}
}

View File

@@ -1,11 +1,23 @@
package org.briarproject.bramble;
import org.briarproject.bramble.plugin.tor.BridgeProvider;
import org.briarproject.bramble.plugin.tor.BridgeProviderImpl;
import org.briarproject.bramble.system.AndroidSystemModule;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module(includes = {
AndroidSystemModule.class
})
public class BrambleAndroidModule {
@Provides
@Singleton
BridgeProvider provideBridgeProvider() {
return new BridgeProviderImpl();
}
}

View File

@@ -0,0 +1,9 @@
package org.briarproject.bramble.plugin.tor;
import java.util.List;
public interface BridgeProvider {
List<String> getBridges();
}

View File

@@ -0,0 +1,20 @@
package org.briarproject.bramble.plugin.tor;
import java.util.Arrays;
import java.util.List;
public class BridgeProviderImpl implements BridgeProvider {
final static String[] BRIDGES = {
"Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42",
// "Bridge 128.105.214.161:8081 1E326AAFB3FCB515015250D8FCCC8E37F91A153B",
"Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98",
"Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D",
};
@Override
public List<String> getBridges() {
return Arrays.asList(BRIDGES);
}
}

View File

@@ -50,7 +50,9 @@ import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -120,6 +122,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private final Backoff backoff;
private final DuplexPluginCallback callback;
private final String architecture;
private final BridgeProvider bridgeProvider;
private final int maxLatency, maxIdleTime, socketTimeout;
private final ConnectionStatus connectionStatus;
private final File torDirectory, torFile, geoIpFile, configFile;
@@ -139,7 +142,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
Context appContext, LocationUtils locationUtils,
SocketFactory torSocketFactory, Clock clock, Backoff backoff,
DuplexPluginCallback callback, String architecture,
int maxLatency, int maxIdleTime) {
BridgeProvider bridgeProvider, int maxLatency, int maxIdleTime) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.appContext = appContext;
@@ -149,6 +152,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
this.backoff = backoff;
this.callback = callback;
this.architecture = architecture;
this.bridgeProvider = bridgeProvider;
this.maxLatency = maxLatency;
this.maxIdleTime = maxIdleTime;
if (maxIdleTime > Integer.MAX_VALUE / 2)
@@ -499,6 +503,17 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
}
private void enableBridges(boolean enable) throws IOException {
if (enable) {
Collection<String> conf = new ArrayList<>();
conf.add("UseBridges 1");
conf.addAll(bridgeProvider.getBridges());
controlConnection.setConf(conf);
} else {
controlConnection.setConf("UseBridges", "0");
}
}
@Override
public void stop() {
running = false;
@@ -681,7 +696,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} else if (blocked) {
if (doBridgesWork(country)) {
LOG.info("Enabling network, using bridges");
controlConnection.setConf("UseBridges", "1");
enableBridges(true);
enableNetwork(true);
} else {
LOG.info("Disabling network, country is blocked");
@@ -693,6 +708,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
enableNetwork(false);
} else {
LOG.info("Enabling network");
enableBridges(false);
enableNetwork(true);
}
} catch (IOException e) {

View File

@@ -43,12 +43,14 @@ public class TorPluginFactory implements DuplexPluginFactory {
private final EventBus eventBus;
private final SocketFactory torSocketFactory;
private final BackoffFactory backoffFactory;
private final BridgeProvider bridgeProvider;
private final Clock clock;
public TorPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler, Context appContext,
LocationUtils locationUtils, EventBus eventBus,
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
BridgeProvider bridgeProvider,
Clock clock) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
@@ -57,6 +59,7 @@ public class TorPluginFactory implements DuplexPluginFactory {
this.eventBus = eventBus;
this.torSocketFactory = torSocketFactory;
this.backoffFactory = backoffFactory;
this.bridgeProvider = bridgeProvider;
this.clock = clock;
}
@@ -95,7 +98,7 @@ public class TorPluginFactory implements DuplexPluginFactory {
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
locationUtils, torSocketFactory, clock, backoff, callback,
architecture, MAX_LATENCY, MAX_IDLE_TIME);
architecture, bridgeProvider, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -4,8 +4,3 @@ DisableNetwork 1
RunAsDaemon 1
SafeSocks 1
SocksPort 59050
UseBridges 0
Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42
Bridge 128.105.214.161:8081 1E326AAFB3FCB515015250D8FCCC8E37F91A153B
Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D

View File

@@ -25,6 +25,7 @@ import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.Scheduler;
import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory;
import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
import org.briarproject.bramble.plugin.tor.BridgeProvider;
import org.briarproject.bramble.plugin.tor.TorPluginFactory;
import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.StringUtils;
@@ -99,14 +100,14 @@ public class AppModule {
AndroidExecutor androidExecutor, SecureRandom random,
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
Application app, LocationUtils locationUtils, EventBus eventBus,
Clock clock) {
BridgeProvider bridgeProvider, Clock clock) {
Context appContext = app.getApplicationContext();
DuplexPluginFactory bluetooth =
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
appContext, random, eventBus, backoffFactory);
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, scheduler,
appContext, locationUtils, eventBus, torSocketFactory,
backoffFactory, clock);
backoffFactory, bridgeProvider, clock);
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
scheduler, backoffFactory, appContext);
Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan);