Compare commits

..

107 Commits

Author SHA1 Message Date
Torsten Grote
2d5f5d4419 WIP: FakeTestData proof-of-concept 2018-09-19 10:51:47 -03:00
Torsten Grote
8393513871 Remove code from TestDataCreator that breaks encapsulation 2018-09-19 10:50:09 -03:00
Torsten Grote
38270fbee8 Throw AssertionError when creating an account while a database key is in memory 2018-09-18 17:53:41 -03:00
Torsten Grote
65c0646812 Refactor tests so that all test data is created in the first test 2018-09-18 17:41:40 -03:00
Torsten Grote
0416583e8c Split up UI and Screenshot tests
Closes #1377
2018-09-18 17:41:40 -03:00
Torsten Grote
91f8c801b8 Create Screenshot of Conversation for Manual 2018-09-18 17:41:40 -03:00
akwizgran
a045d7d306 Merge branch '1384-expiry-time' into 'master'
Fix off-by-one error in expiry calculation

Closes #1384

See merge request briar/briar!923
2018-09-18 17:15:54 +00:00
akwizgran
a29d5efd93 Fix off-by-one error in expiry calculation. 2018-09-18 18:01:44 +01:00
akwizgran
37cd1cdddf Merge branch '541-faster-retransmission-eta' into 'master'
Allow retransmission if it will result in faster delivery

Closes #541

See merge request briar/briar!908
2018-09-18 14:26:22 +00:00
akwizgran
4f495bb4d3 Use now + max latency as ETA, add more tests. 2018-09-18 16:05:25 +02:00
goapunk
1a70200b65 Allow retransmission if faster.
* This commit introduces an estimated time of arrival (eta) to the
message status which helps to decide whether a message should be
retransmitted over a faster transport.
2018-09-18 16:05:25 +02:00
akwizgran
6925dfcbdd Merge branch '1240-message-refactoring' into 'master'
Remove raw representation from Message class

See merge request briar/briar!915
2018-09-18 13:30:26 +00:00
akwizgran
817df9c75a Merge branch '1247-flag-secure-warning' into 'master'
Add warning to FLAG_SECURE about app locking implications

Closes #1247

See merge request briar/briar!922
2018-09-17 16:08:43 +00:00
Torsten Grote
745515457e Add warning to FLAG_SECURE about app locking implications 2018-09-17 12:21:16 -03:00
akwizgran
ba5928218a Reduce code duplication in TestMessageFactory. 2018-09-14 17:50:17 +01:00
akwizgran
9476782ced Bump version numbers for 1.1.1 release. 2018-09-14 13:16:17 +01:00
akwizgran
74445acb55 Merge branch '1379-startup-failure-error' into 'master'
Correct startup database failure error messages

Closes #1379

See merge request briar/briar!920
2018-09-14 12:01:52 +00:00
akwizgran
e32771f964 Merge branch '1359-conversation-progress' into 'master'
Fix progress feel over messages in Conversation view

Closes #1359

See merge request briar/briar!911
2018-09-14 11:59:42 +00:00
akwizgran
d7bf1ee374 Merge branch '1367-db-header-corrupt' into 'master'
Fix duplicate actions triggered by hardware keyboard

Closes #1367

See merge request briar/briar!921
2018-09-14 09:09:41 +00:00
Torsten Grote
10bee05856 Only sign-in once when pressing enter 2018-09-13 18:45:24 -03:00
Torsten Grote
fc626d0921 Only create one private group when pressing enter 2018-09-13 18:45:24 -03:00
Torsten Grote
30f87e626a Only create one forum when pressing enter 2018-09-13 18:45:24 -03:00
Torsten Grote
a0d91da569 Add TODO for not allowing double account creation 2018-09-13 18:19:15 -03:00
Torsten Grote
c90a72617e Do not create two accounts when pressing enter for account creation
Fixes #1367
2018-09-13 18:18:30 -03:00
Torsten Grote
8813bc36af Correct startup database failure error messages 2018-09-13 12:35:39 -03:00
akwizgran
049cf3ad27 Merge branch 'optional-tests' into 'master'
Specify optional tests with an environment variable

See merge request briar/briar!916
2018-09-13 14:36:59 +00:00
Torsten Grote
de8a6b23e5 Merge branch '1189-setup-activity' into 'master'
Launch SetupActivity in same task to prevent relaunching from recent apps

Closes #1189

See merge request briar/briar!919
2018-09-13 14:21:24 +00:00
akwizgran
30193a240b Start SetupActivity in same task, finish other activities. 2018-09-13 13:43:01 +01:00
akwizgran
a52ad8b4cc Bump version numbers for 1.1.0 release. 2018-09-12 17:10:52 +01:00
Torsten Grote
6a1a8b6872 Merge branch '1245-enable-pin-lock' into 'master'
Enable sign-in reminder, PIN lock and dark theme for release builds

See merge request briar/briar!917
2018-09-12 11:15:12 +00:00
Torsten Grote
50ad42a0a2 Update translations, adds Hungarian, sets inclusion threshold to 80% 2018-09-12 07:45:02 -03:00
akwizgran
08005bdf56 Enable PIN lock for release builds. 2018-09-12 11:44:27 +01:00
akwizgran
e32cc3af6d Enable dark theme for release builds. 2018-09-12 11:41:54 +01:00
akwizgran
28a68ff625 Enable sign-in reminder for release builds. 2018-09-12 11:39:54 +01:00
akwizgran
2bef2ac828 Merge branch '1249-sign-in-screenshots' into 'master'
Screenshots for account sign-in improvements and Tor settings

See merge request briar/briar!909
2018-09-06 13:40:03 +00:00
akwizgran
b2febbc6e9 Specify optional tests with an environment variable. 2018-09-06 10:34:04 +01:00
Torsten Grote
e12601dd08 Merge branch 'attach-updated-settings-to-event' into 'master'
Attach updated settings to SettingsUpdatedEvent

See merge request briar/briar!913
2018-09-05 11:22:05 +00:00
akwizgran
3388682dda Use updated settings from event. 2018-09-05 12:04:56 +01:00
akwizgran
74e4a9cbdf Remove raw representation from Message class. 2018-09-05 11:23:36 +01:00
akwizgran
8ad3047f87 Merge branch '1247-pin-lock-fingerprint' into 'master'
Implement fingerprint unlocking with BiometricPromptCompat

See merge request briar/briar!882
2018-09-05 08:39:54 +00:00
akwizgran
0cffaf8646 Merge branch 'move-tor-bridge-tests' into 'master'
Move Tor Bridge tests and rename bramble-j2se to bramble-java

See merge request briar/briar!907
2018-09-05 08:35:33 +00:00
akwizgran
7b116f15df Attach updated settings to SettingsUpdatedEvent. 2018-09-05 09:31:12 +01:00
Torsten Grote
ced0f72fba Fix progress feel over messages in Conversation view
Unlike with many other lists,
we are not clearing the list of private messages when restarting the activity.
We still load the messages from the database and add them to the view.
When there are no new message to add,
the usual insert observers do not trigger
and we do not call list.showData() although we should.
Doing so removes the progress bar as soon as messages have been loaded.
2018-09-04 12:31:16 -03:00
Torsten Grote
24c030f06f Remove button from UnlockActivity 2018-09-04 09:32:24 -03:00
Torsten Grote
a3fa15e90e Blank UnlockActivity when not using fingerprint unlock 2018-09-04 09:04:59 -03:00
Torsten Grote
57841be447 Remove BiometricPromptCompat library and limit feature to API 28 2018-09-04 09:04:58 -03:00
Torsten Grote
c5d374af04 ScreenLock: Implement fingerprint unlocking with BiometricPromptCompat 2018-09-04 09:04:33 -03:00
Torsten Grote
8d592ad2ee Take screenshot of Tor settings 2018-09-03 18:03:57 -03:00
Torsten Grote
055c381cc9 Take a screenshot of the Navigation Drawer with lock action 2018-09-03 16:32:39 -03:00
Torsten Grote
1d259bd51c Screenshots for Sign-in improvements
Screenshots for #1249
2018-09-03 16:32:39 -03:00
Torsten Grote
de63141997 Update translations 2018-09-03 15:02:34 -03:00
Torsten Grote
dee8f68477 Do not run Tor bridge test with every CI run 2018-09-03 13:02:54 -03:00
Torsten Grote
59048f106a Move Tor Bridge tests and rename bramble-j2se to bramble-java 2018-09-03 12:58:20 -03:00
akwizgran
da7cf4af28 Rename bramble-j2se to bramble-java. 2018-09-03 16:28:59 +01:00
akwizgran
0d4cf4db68 Merge branch 'java-tor-plugin' into 'master'
Add a LinuxTorPlugin

See merge request briar/briar!902
2018-09-03 15:23:20 +00:00
Torsten Grote
9efd2d113a Ignore file extension when retrieving resources on Android 2018-09-03 11:58:42 -03:00
Torsten Grote
8e6cd12f07 LinuxTorPlugin: Address review comments 2018-09-03 11:52:10 -03:00
Torsten Grote
3a49ca0d97 Add JavaTorPlugin 2018-09-03 11:52:10 -03:00
akwizgran
c03868e800 Merge branch '1343-vanniktech-emoji' into 'master'
Use vanniktech emoji library

Closes #1343, #1314, #940, #930, #749, and #684

See merge request briar/briar!857
2018-09-03 12:12:01 +00:00
akwizgran
d6c129e919 Hide emoji popup when hiding soft keyboard. 2018-08-28 16:45:04 +01:00
akwizgran
271efdd2bc Hide soft keyboard when reblogging post. 2018-08-28 15:57:55 +01:00
akwizgran
ad4e8d51e9 Hide soft keyboard when sending blog post. 2018-08-28 15:55:16 +01:00
akwizgran
eb19c6e08d Remove unused resources. 2018-08-28 15:55:16 +01:00
akwizgran
83bfeb9075 Initialise EmojiManager for UI tests. 2018-08-28 15:55:16 +01:00
akwizgran
428501cf5f Use vanniktech emoji library. 2018-08-28 15:55:16 +01:00
Torsten Grote
d8b04edcd0 Merge branch '1240-avoid-raw-messages' into 'master'
Avoid raw messages

See merge request briar/briar!906
2018-08-27 14:40:54 +00:00
akwizgran
0bc07cd0c1 Rename message length method. 2018-08-24 16:56:24 +01:00
akwizgran
cb3026959a Remove raw messages from SyncRecordWriter interface. 2018-08-24 16:56:24 +01:00
akwizgran
48933637d8 Remove raw messages from DB interface. 2018-08-24 16:56:24 +01:00
akwizgran
5626f3d761 Remove raw message method from DatabaseComponent interface. 2018-08-24 16:56:23 +01:00
akwizgran
0fce224d88 Add method for getting cooked message from DB. 2018-08-24 16:56:23 +01:00
Torsten Grote
3db35f7061 Merge branch 'network-interfaces-may-be-null' into 'master'
Check whether getNetworkInterfaces() returns null

See merge request briar/briar!903
2018-08-24 15:48:22 +00:00
Torsten Grote
751375035d Merge branch 'message-constructor' into 'master'
Minimise use of message constructor

See merge request briar/briar!905
2018-08-24 14:58:57 +00:00
akwizgran
27a169c6e2 Minimise use of message constructor. 2018-08-24 14:17:25 +01:00
akwizgran
d4a4351786 Merge branch '758-db-exception-for-deleted-messages' into 'master'
Throw an exception if a deleted message is requested from the DB

Closes #758

See merge request briar/briar!904
2018-08-24 09:21:05 +00:00
akwizgran
fbd38dbb94 Throw an exception if a raw message has been deleted. 2018-08-23 14:51:56 +01:00
akwizgran
cd4897e6c9 Check whether getNetworkInterfaces() returns null. 2018-08-23 14:16:18 +01:00
akwizgran
d84e176bb4 Merge branch 'fix_performance_test_db' into 'master'
Fix the database performance tests

See merge request briar/briar!893
2018-08-22 15:46:11 +00:00
Torsten Grote
da8b49bec2 Merge branch 'log-relay-names' into 'master'
Log Tor relay names to detect failing bridges

See merge request briar/briar!901
2018-08-22 14:27:58 +00:00
akwizgran
6c8cc79d87 Log Tor relay names to detect failing bridges. 2018-08-22 14:21:41 +01:00
akwizgran
a5271eee29 Merge branch 'switch-preference-android-4' into 'master'
Use Material style for SwitchPreference on Android 4

See merge request briar/briar!897
2018-08-20 19:40:56 +00:00
akwizgran
4dfc96996d Merge branch '1224-show-explanation-when-contact-exchange-fails' into 'master'
Show an error fragment when contact exchange fails

See merge request briar/briar!890
2018-08-20 19:40:36 +00:00
akwizgran
3139f308a2 Merge branch '1349-empty-state-ui' into 'master'
Implement new empty state icons

Closes #1349

See merge request briar/briar!898
2018-08-20 19:39:56 +00:00
Torsten Grote
cc6daffa61 Merge branch 'update-bridges' into 'master'
Replace two failing bridges

See merge request briar/briar!900
2018-08-20 18:36:07 +00:00
Torsten Grote
f08f441f5f Use Material style for SwitchPreference on Android 4 2018-08-20 15:22:55 -03:00
Torsten Grote
83886c78f1 Empty states: Address review comments 2018-08-20 15:14:53 -03:00
Torsten Grote
5ed0e9efec Implement new empty state icons 2018-08-20 15:14:53 -03:00
akwizgran
169c59349e Merge branch '1269-bridge-setting' into 'master'
Refactor Tor settings and add a setting for forcing the use bridges

Closes #1269

See merge request briar/briar!895
2018-08-20 17:56:56 +00:00
akwizgran
764f60b3fe Replace two failing bridges. 2018-08-20 17:57:36 +01:00
Torsten Grote
e51c437a06 Merge branch 'ci-dev-urandom' into 'master'
Use /dev/urandom for CI

See merge request briar/briar!899
2018-08-20 16:24:49 +00:00
akwizgran
9fbf740ba7 Use /dev/urandom for tests. 2018-08-20 17:08:57 +01:00
akwizgran
db7686ea52 Merge branch '1247-pin-lock-activity-timeout' into 'master'
Screen Lock: Lock after customizable inactivity timeout

See merge request briar/briar!887
2018-08-20 13:52:23 +00:00
akwizgran
7fe21e079f Merge branch '1358-message-bubbles' into 'master'
New Design for Message Bubbles

Closes #1358

See merge request briar/briar!896
2018-08-20 12:11:22 +00:00
Torsten Grote
be72e624a3 ContactExchangeErrorFragment: Address review comments 2018-08-16 13:00:02 -03:00
Torsten Grote
d9e9741112 Replace generic ErrorFragment with specific one
when key agreement protocol doesn't match
2018-08-16 12:34:20 -03:00
Torsten Grote
656ca8d67a Contact failure: Add better icon and remove technical error message 2018-08-16 12:34:20 -03:00
Torsten Grote
d3e44358a4 Move feedback trigger and making link clickable to UiUtils 2018-08-16 12:34:20 -03:00
Torsten Grote
920a1d0431 Show an error fragment when contact exchange fails 2018-08-16 12:34:20 -03:00
Torsten Grote
4b9a9771f8 Tor settings: Address review comments 2018-08-16 12:27:26 -03:00
Torsten Grote
d64252aaf3 Screen Lock Timeout: Address review comments 2018-08-16 12:16:45 -03:00
Torsten Grote
825ed451a3 Screen lock: Add a fallback in case alarm manager didn't run during sleep 2018-08-16 12:14:59 -03:00
Torsten Grote
bffd78d404 Use a dedicated summary for 'never lock Briar' for proper English 2018-08-16 12:14:59 -03:00
Torsten Grote
04ffff0953 Screen Lock: Lock after customizable inactivity timeout 2018-08-16 12:14:59 -03:00
Torsten Grote
21f95ed9af Add a stroke for private message bubbles on Android 4 2018-08-16 12:07:54 -03:00
Torsten Grote
c8b516196c Add new private message bubbles, get rid of 9-patch drawables
This reverts commit f8a8c0d8b8.
2018-08-16 10:22:15 -03:00
goapunk
941a0cccc3 Fix a regression in the performance tests causing the db key to be regenerated everytime. 2018-08-16 12:09:33 +02:00
Torsten Grote
9b17836595 Refactor Tor settings and add a setting for forcing to use bridges 2018-08-15 17:32:43 -03:00
364 changed files with 7398 additions and 5724 deletions

View File

@@ -11,8 +11,8 @@ test:
- .gradle/caches
script:
- ./gradlew --no-daemon animalSnifferMain animalSnifferTest
- ./gradlew --no-daemon test
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom animalSnifferMain animalSnifferTest
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom test
after_script:
# these file change every time but should not be cached

View File

@@ -22,8 +22,8 @@
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-api" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-core" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-android" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-j2se" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-java" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in briar-core" run_configuration_type="AndroidJUnit" />
</method>
</configuration>
</component>
</component>

View File

@@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-j2se" type="AndroidJUnit" factoryName="Android JUnit">
<configuration default="false" name="All tests in bramble-java" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-j2se" />
<module name="bramble-java" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" />
@@ -10,7 +10,7 @@
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea -Djava.library.path=libs" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-j2se" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-java" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">

View File

@@ -9,8 +9,8 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 26
versionCode 10013
versionName "1.0.13"
versionCode 10101
versionName "1.1.1"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -41,12 +41,6 @@ dependencies {
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
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'
}
project.afterEvaluate {

View File

@@ -1,20 +0,0 @@
package org.briarproject.bramble.test;
import android.app.Application;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import static android.support.test.InstrumentationRegistry.getTargetContext;
@Module
class ApplicationModule {
@Provides
@Singleton
Application provideApplication() {
return (Application) getTargetContext().getApplicationContext();
}
}

View File

@@ -22,9 +22,11 @@ class AndroidResourceProvider implements ResourceProvider {
}
@Override
public InputStream getResourceInputStream(String name) {
public InputStream getResourceInputStream(String name, String extension) {
Resources res = appContext.getResources();
int resId = res.getIdentifier(name, "raw", appContext.getPackageName());
// extension is ignored on Android, resources are retrieved without it
int resId =
res.getIdentifier(name, "raw", appContext.getPackageName());
return res.openRawResource(resId);
}
}

View File

@@ -1,9 +1,6 @@
dependencyVerification {
verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.android.support.test:monitor:1.0.2:monitor-1.0.2.aar:38ef4fa98a32dc55550ff49bb36a583e178b3a9b830fcb8dcc27bfc4254bc2bc',
'com.android.support.test:runner:1.0.2:runner-1.0.2.aar:f04b9ae342975ba1cb3e4a06e13426e3e6b8a73faa45acba604493d83c9a4f00',
'com.android.support:support-annotations:27.1.1:support-annotations-27.1.1.jar:3365960206c3d2b09e845f555e7f88f8effc8d2f00b369e66c4be384029299cf',
'com.android.tools.analytics-library:protos:26.1.3:protos-26.1.3.jar:818c9f256f141d9dafec03a1aa2b94d240b2c140acfd7ee31a8b3e6c2b9479e3',
'com.android.tools.analytics-library:shared:26.1.3:shared-26.1.3.jar:7110706c7ada96c8b6f5ca80c478291bc7899d46277de2c48527e045442401a3',
'com.android.tools.analytics-library:tracker:26.1.3:tracker-26.1.3.jar:4155424bf2ce4872da83332579a1707252bc66cbd77c5144fdc4483d0f2e1418',

View File

@@ -16,7 +16,6 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
@Immutable
@@ -49,14 +48,13 @@ public abstract class BdfMessageValidator implements MessageValidator {
throw new InvalidMessageException(
"Timestamp is too far in the future");
}
byte[] raw = m.getRaw();
if (raw.length <= MESSAGE_HEADER_LENGTH) {
byte[] body = m.getBody();
if (body.length == 0) {
throw new InvalidMessageException("Message is too short");
}
try {
BdfList body = clientHelper.toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
BdfMessageContext result = validateMessage(m, g, body);
BdfList bodyList = clientHelper.toList(body);
BdfMessageContext result = validateMessage(m, g, bodyList);
Metadata meta = metadataEncoder.encode(result.getDictionary());
return new MessageContext(meta, result.getDependencies());
} catch (FormatException e) {

View File

@@ -16,8 +16,6 @@ import org.briarproject.bramble.api.sync.MessageId;
import java.security.GeneralSecurityException;
import java.util.Map;
import javax.annotation.Nullable;
@NotNullByDefault
public interface ClientHelper {
@@ -32,16 +30,12 @@ public interface ClientHelper {
Message createMessageForStoringMetadata(GroupId g);
@Nullable
Message getMessage(MessageId m) throws DbException;
@Nullable
Message getMessage(Transaction txn, MessageId m) throws DbException;
@Nullable
BdfList getMessageAsList(MessageId m) throws DbException, FormatException;
@Nullable
BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException,
FormatException;

View File

@@ -151,13 +151,13 @@ public interface DatabaseComponent {
throws DbException;
/**
* Returns a batch of raw messages for the given contact, with a total
* length less than or equal to the given length, for transmission over a
* Returns a batch of messages for the given contact, with a total length
* less than or equal to the given length, for transmission over a
* transport with the given maximum latency. Returns null if there are no
* sendable messages that fit in the given length.
*/
@Nullable
Collection<byte[]> generateBatch(Transaction txn, ContactId c,
Collection<Message> generateBatch(Transaction txn, ContactId c,
int maxLength, int maxLatency) throws DbException;
/**
@@ -178,14 +178,14 @@ public interface DatabaseComponent {
throws DbException;
/**
* Returns a batch of raw messages for the given contact, with a total
* length less than or equal to the given length, for transmission over a
* Returns a batch of messages for the given contact, with a total length
* less than or equal to the given length, for transmission over a
* transport with the given maximum latency. Only messages that have been
* requested by the contact are returned. Returns null if there are no
* sendable messages that fit in the given length.
*/
@Nullable
Collection<byte[]> generateRequestedBatch(Transaction txn, ContactId c,
Collection<Message> generateRequestedBatch(Transaction txn, ContactId c,
int maxLength, int maxLatency) throws DbException;
/**
@@ -263,6 +263,15 @@ public interface DatabaseComponent {
*/
Collection<LocalAuthor> getLocalAuthors(Transaction txn) throws DbException;
/**
* Returns the message with the given ID.
* <p/>
* Read-only.
*
* @throws MessageDeletedException if the message has been deleted
*/
Message getMessage(Transaction txn, MessageId m) throws DbException;
/**
* Returns the IDs of all delivered messages in the given group.
* <p/>
@@ -297,15 +306,6 @@ public interface DatabaseComponent {
Collection<MessageId> getMessagesToShare(Transaction txn)
throws DbException;
/**
* Returns the message with the given ID, in serialised form, or null if
* the message has been deleted.
* <p/>
* Read-only.
*/
@Nullable
byte[] getRawMessage(Transaction txn, MessageId m) throws DbException;
/**
* Returns the metadata for all delivered messages in the given group.
* <p/>

View File

@@ -0,0 +1,9 @@
package org.briarproject.bramble.api.db;
/**
* Thrown when a message that has been deleted is requested from the database.
* This exception may occur due to concurrent updates and does not indicate a
* database error.
*/
public class MessageDeletedException extends DbException {
}

View File

@@ -12,12 +12,13 @@ public interface TorConstants {
int CONNECT_TO_PROXY_TIMEOUT = 5000; // Milliseconds
int EXTRA_SOCKET_TIMEOUT = 30000; // Milliseconds
String PREF_TOR_NETWORK = "network";
String PREF_TOR_NETWORK = "network2";
String PREF_TOR_PORT = "port";
String PREF_TOR_DISABLE_BLOCKED = "disableWhenBlocked";
String PREF_TOR_MOBILE = "useMobileData";
int PREF_TOR_NETWORK_NEVER = 0;
int PREF_TOR_NETWORK_WIFI = 1;
int PREF_TOR_NETWORK_ALWAYS = 2;
int PREF_TOR_NETWORK_AUTOMATIC = 0;
int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1;
int PREF_TOR_NETWORK_WITH_BRIDGES = 2;
int PREF_TOR_NETWORK_NEVER = 3;
}

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.api.settings;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
@@ -11,6 +12,11 @@ public interface SettingsManager {
*/
Settings getSettings(String namespace) throws DbException;
/**
* Returns all settings in the given namespace.
*/
Settings getSettings(Transaction txn, String namespace) throws DbException;
/**
* Merges the given settings with any existing settings in the given
* namespace.

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble.api.settings.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.settings.Settings;
import javax.annotation.concurrent.Immutable;
@@ -13,12 +14,18 @@ import javax.annotation.concurrent.Immutable;
public class SettingsUpdatedEvent extends Event {
private final String namespace;
private final Settings settings;
public SettingsUpdatedEvent(String namespace) {
public SettingsUpdatedEvent(String namespace, Settings settings) {
this.namespace = namespace;
this.settings = settings;
}
public String getNamespace() {
return namespace;
}
public Settings getSettings() {
return settings;
}
}

View File

@@ -1,6 +1,6 @@
package org.briarproject.bramble.api.sync;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
public class Message {
@@ -13,17 +13,15 @@ public class Message {
private final MessageId id;
private final GroupId groupId;
private final long timestamp;
private final byte[] raw;
private final byte[] body;
public Message(MessageId id, GroupId groupId, long timestamp, byte[] raw) {
if (raw.length <= MESSAGE_HEADER_LENGTH)
throw new IllegalArgumentException();
if (raw.length > MAX_MESSAGE_LENGTH)
public Message(MessageId id, GroupId groupId, long timestamp, byte[] body) {
if (body.length > MAX_MESSAGE_BODY_LENGTH)
throw new IllegalArgumentException();
this.id = id;
this.groupId = groupId;
this.timestamp = timestamp;
this.raw = raw;
this.body = body;
}
/**
@@ -50,15 +48,15 @@ public class Message {
/**
* Returns the length of the raw message in bytes.
*/
public int getLength() {
return raw.length;
public int getRawLength() {
return MESSAGE_HEADER_LENGTH + body.length;
}
/**
* Returns the raw message.
* Returns the message body.
*/
public byte[] getRaw() {
return raw;
public byte[] getBody() {
return body;
}
@Override

View File

@@ -9,5 +9,5 @@ public interface MessageFactory {
Message createMessage(byte[] raw);
Message createMessage(MessageId m, byte[] raw);
byte[] getRawMessage(Message m);
}

View File

@@ -9,7 +9,7 @@ public interface SyncRecordWriter {
void writeAck(Ack a) throws IOException;
void writeMessage(byte[] raw) throws IOException;
void writeMessage(Message m) throws IOException;
void writeOffer(Offer o) throws IOException;

View File

@@ -7,5 +7,5 @@ import java.io.InputStream;
@NotNullByDefault
public interface ResourceProvider {
InputStream getResourceInputStream(String name);
InputStream getResourceInputStream(String name, String extension);
}

View File

@@ -0,0 +1,23 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.api.system.Clock;
public class ArrayClock implements Clock {
private final long[] times;
private int index = 0;
public ArrayClock(long... times) {
this.times = times;
}
@Override
public long currentTimeMillis() {
return times[index++];
}
@Override
public void sleep(long milliseconds) throws InterruptedException {
Thread.sleep(milliseconds);
}
}

View File

@@ -24,6 +24,7 @@ import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import static java.util.Arrays.asList;
import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
@@ -32,7 +33,6 @@ import static org.briarproject.bramble.api.properties.TransportPropertyConstants
import static org.briarproject.bramble.api.sync.ClientId.MAX_CLIENT_ID_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
public class TestUtils {
@@ -40,6 +40,7 @@ public class TestUtils {
private static final AtomicInteger nextTestDir =
new AtomicInteger((int) (Math.random() * 1000 * 1000));
private static final Random random = new Random();
private static final long timestamp = System.currentTimeMillis();
public static File getTestDirectory() {
int name = nextTestDir.getAndIncrement();
@@ -101,9 +102,8 @@ public class TestUtils {
String name = getRandomString(nameLength);
byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
byte[] privateKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
long created = System.currentTimeMillis();
return new LocalAuthor(id, FORMAT_VERSION, name, publicKey, privateKey,
created);
timestamp);
}
public static Author getAuthor() {
@@ -131,14 +131,13 @@ public class TestUtils {
public static Message getMessage(GroupId groupId) {
int bodyLength = 1 + random.nextInt(MAX_MESSAGE_BODY_LENGTH);
return getMessage(groupId, MESSAGE_HEADER_LENGTH + bodyLength);
return getMessage(groupId, bodyLength);
}
public static Message getMessage(GroupId groupId, int rawLength) {
public static Message getMessage(GroupId groupId, int bodyLength) {
MessageId id = new MessageId(getRandomId());
byte[] raw = getRandomBytes(rawLength);
long timestamp = System.currentTimeMillis();
return new Message(id, groupId, timestamp, raw);
byte[] body = getRandomBytes(bodyLength);
return new Message(id, groupId, timestamp, body);
}
public static double getMedian(Collection<? extends Number> samples) {
@@ -174,4 +173,10 @@ public class TestUtils {
Collection<? extends Number> samples) {
return Math.sqrt(getVariance(samples));
}
public static boolean isOptionalTestEnabled(Class testClass) {
String optionalTests = System.getenv("OPTIONAL_TESTS");
return optionalTests != null &&
asList(optionalTests.split(",")).contains(testClass.getName());
}
}

View File

@@ -33,7 +33,7 @@ dependencies {
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
}
// needed to make test output available to bramble-j2se
// needed to make test output available to bramble-java
configurations {
testOutput.extendsFrom(testCompile)
}

View File

@@ -159,6 +159,8 @@ class AccountManagerImpl implements AccountManager {
@Override
public boolean createAccount(String name, String password) {
synchronized (stateChangeLock) {
if (hasDatabaseKey())
throw new AssertionError("Already have a database key");
LocalAuthor localAuthor = identityManager.createLocalAuthor(name);
identityManager.registerLocalAuthor(localAuthor);
SecretKey key = crypto.generateSecretKey();
@@ -181,6 +183,7 @@ class AccountManagerImpl implements AccountManager {
LOG.info("Deleting account");
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
databaseKey = null;
}
}

View File

@@ -41,7 +41,6 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_N
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
@@ -127,9 +126,7 @@ class ClientHelperImpl implements ClientHelper {
@Override
public Message getMessage(Transaction txn, MessageId m) throws DbException {
byte[] raw = db.getRawMessage(txn, m);
if (raw == null) return null;
return messageFactory.createMessage(m, raw);
return db.getMessage(txn, m);
}
@Override
@@ -149,10 +146,7 @@ class ClientHelperImpl implements ClientHelper {
@Override
public BdfList getMessageAsList(Transaction txn, MessageId m)
throws DbException, FormatException {
byte[] raw = db.getRawMessage(txn, m);
if (raw == null) return null;
return toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
return toList(db.getMessage(txn, m).getBody());
}
@Override
@@ -364,9 +358,7 @@ class ClientHelperImpl implements ClientHelper {
@Override
public BdfList toList(Message m) throws FormatException {
byte[] raw = m.getRaw();
return toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
return toList(m.getBody());
}
@Override

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DataTooNewException;
import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Author;
@@ -297,6 +298,15 @@ interface Database<T> {
*/
Collection<LocalAuthor> getLocalAuthors(T txn) throws DbException;
/**
* Returns the message with the given ID.
* <p/>
* Read-only.
*
* @throws MessageDeletedException if the message has been deleted
*/
Message getMessage(T txn, MessageId m) throws DbException;
/**
* Returns the IDs and states of all dependencies of the given message.
* For missing dependencies and dependencies in other groups, the state
@@ -411,7 +421,7 @@ interface Database<T> {
* Read-only.
*/
Collection<MessageId> getMessagesToOffer(T txn, ContactId c,
int maxMessages) throws DbException;
int maxMessages, int maxLatency) throws DbException;
/**
* Returns the IDs of some messages that are eligible to be requested from
@@ -428,8 +438,8 @@ interface Database<T> {
* <p/>
* Read-only.
*/
Collection<MessageId> getMessagesToSend(T txn, ContactId c, int maxLength)
throws DbException;
Collection<MessageId> getMessagesToSend(T txn, ContactId c, int maxLength,
int maxLatency) throws DbException;
/**
* Returns the IDs of any messages that need to be validated.
@@ -464,15 +474,6 @@ interface Database<T> {
*/
long getNextSendTime(T txn, ContactId c) throws DbException;
/**
* Returns the message with the given ID, in serialised form, or null if
* the message has been deleted.
* <p/>
* Read-only.
*/
@Nullable
byte[] getRawMessage(T txn, MessageId m) throws DbException;
/**
* Returns the IDs of some messages that are eligible to be sent to the
* given contact and have been requested by the contact, up to the given
@@ -481,7 +482,7 @@ interface Database<T> {
* Read-only.
*/
Collection<MessageId> getRequestedMessagesToSend(T txn, ContactId c,
int maxLength) throws DbException;
int maxLength, int maxLatency) throws DbException;
/**
* Returns all settings in the given namespace.
@@ -646,11 +647,11 @@ interface Database<T> {
throws DbException;
/**
* Updates the transmission count and expiry time of the given message
* with respect to the given contact, using the latency of the transport
* over which it was sent.
* Updates the transmission count, expiry time and estimated time of arrival
* of the given message with respect to the given contact, using the latency
* of the transport over which it was sent.
*/
void updateExpiryTime(T txn, ContactId c, MessageId m, int maxLatency)
void updateExpiryTimeAndEta(T txn, ContactId c, MessageId m, int maxLatency)
throws DbException;
/**

View File

@@ -307,17 +307,18 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Nullable
@Override
public Collection<byte[]> generateBatch(Transaction transaction,
public Collection<Message> generateBatch(Transaction transaction,
ContactId c, int maxLength, int maxLatency) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
Collection<MessageId> ids = db.getMessagesToSend(txn, c, maxLength);
List<byte[]> messages = new ArrayList<>(ids.size());
Collection<MessageId> ids =
db.getMessagesToSend(txn, c, maxLength, maxLatency);
List<Message> messages = new ArrayList<>(ids.size());
for (MessageId m : ids) {
messages.add(db.getRawMessage(txn, m));
db.updateExpiryTime(txn, c, m, maxLatency);
messages.add(db.getMessage(txn, m));
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
}
if (ids.isEmpty()) return null;
db.lowerRequestedFlag(txn, c, ids);
@@ -333,9 +334,11 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
Collection<MessageId> ids = db.getMessagesToOffer(txn, c, maxMessages);
Collection<MessageId> ids =
db.getMessagesToOffer(txn, c, maxMessages, maxLatency);
if (ids.isEmpty()) return null;
for (MessageId m : ids) db.updateExpiryTime(txn, c, m, maxLatency);
for (MessageId m : ids)
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
return new Offer(ids);
}
@@ -356,18 +359,18 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Nullable
@Override
public Collection<byte[]> generateRequestedBatch(Transaction transaction,
public Collection<Message> generateRequestedBatch(Transaction transaction,
ContactId c, int maxLength, int maxLatency) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
Collection<MessageId> ids = db.getRequestedMessagesToSend(txn, c,
maxLength);
List<byte[]> messages = new ArrayList<>(ids.size());
Collection<MessageId> ids =
db.getRequestedMessagesToSend(txn, c, maxLength, maxLatency);
List<Message> messages = new ArrayList<>(ids.size());
for (MessageId m : ids) {
messages.add(db.getRawMessage(txn, m));
db.updateExpiryTime(txn, c, m, maxLatency);
messages.add(db.getMessage(txn, m));
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
}
if (ids.isEmpty()) return null;
db.lowerRequestedFlag(txn, c, ids);
@@ -457,6 +460,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.getLocalAuthors(txn);
}
@Override
public Message getMessage(Transaction transaction, MessageId m)
throws DbException {
T txn = unbox(transaction);
if (!db.containsMessage(txn, m))
throw new NoSuchMessageException();
return db.getMessage(txn, m);
}
@Override
public Collection<MessageId> getMessageIds(Transaction transaction,
GroupId g) throws DbException {
@@ -487,16 +499,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.getMessagesToShare(txn);
}
@Nullable
@Override
public byte[] getRawMessage(Transaction transaction, MessageId m)
throws DbException {
T txn = unbox(transaction);
if (!db.containsMessage(txn, m))
throw new NoSuchMessageException();
return db.getRawMessage(txn, m);
}
@Override
public Map<MessageId, Metadata> getMessageMetadata(Transaction transaction,
GroupId g) throws DbException {
@@ -656,7 +658,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
merged.putAll(s);
if (!merged.equals(old)) {
db.mergeSettings(txn, s, namespace);
transaction.attach(new SettingsUpdatedEvent(namespace));
transaction.attach(new SettingsUpdatedEvent(namespace, merged));
}
}
@@ -856,7 +858,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
if (!db.containsMessage(txn, m))
throw new NoSuchMessageException();
if (db.getMessageState(txn, m) != DELIVERED)
throw new IllegalArgumentException("Shared undelivered message");
throw new IllegalArgumentException(
"Shared undelivered message");
db.setMessageShared(txn, m);
transaction.attach(new MessageSharedEvent(m));
}
@@ -882,7 +885,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
throw new NoSuchMessageException();
State dependentState = db.getMessageState(txn, dependent.getId());
for (MessageId dependency : dependencies) {
db.addMessageDependency(txn, dependent, dependency, dependentState);
db.addMessageDependency(txn, dependent, dependency,
dependentState);
}
}
@@ -914,7 +918,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
T txn = unbox(transaction);
for (KeySet ks : keys) {
TransportId t = ks.getTransportKeys().getTransportId();
if (db.containsTransport(txn, t)) db.updateTransportKeys(txn, ks);
if (db.containsTransport(txn, t))
db.updateTransportKeys(txn, ks);
}
}
}

View File

@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import java.sql.Connection;
@@ -18,8 +19,9 @@ public class DatabaseModule {
@Provides
@Singleton
Database<Connection> provideDatabase(DatabaseConfig config, Clock clock) {
return new H2Database(config, clock);
Database<Connection> provideDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) {
return new H2Database(config, messageFactory, clock);
}
@Provides

View File

@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils;
@@ -36,9 +37,10 @@ class H2Database extends JdbcDatabase {
private volatile SecretKey key = null;
@Inject
H2Database(DatabaseConfig config, Clock clock) {
H2Database(DatabaseConfig config, MessageFactory messageFactory,
Clock clock) {
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
clock);
messageFactory, clock);
this.config = config;
File dir = config.getDatabaseDirectory();
String path = new File(dir, "db").getAbsolutePath();

View File

@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils;
@@ -37,9 +38,10 @@ class HyperSqlDatabase extends JdbcDatabase {
private volatile SecretKey key = null;
@Inject
HyperSqlDatabase(DatabaseConfig config, Clock clock) {
HyperSqlDatabase(DatabaseConfig config, MessageFactory messageFactory,
Clock clock) {
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
clock);
messageFactory, clock);
this.config = config;
File dir = config.getDatabaseDirectory();
String path = new File(dir, "db").getAbsolutePath();

View File

@@ -7,6 +7,7 @@ import org.briarproject.bramble.api.db.DataTooNewException;
import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DbClosedException;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Author;
@@ -20,6 +21,7 @@ import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.Group.Visibility;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.ValidationManager.State;
@@ -36,6 +38,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -53,13 +56,13 @@ import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.sql.Types.INTEGER;
import static java.util.Collections.singletonList;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
@@ -76,7 +79,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
abstract class JdbcDatabase implements Database<Connection> {
// Package access for testing
static final int CODE_SCHEMA_VERSION = 39;
static final int CODE_SCHEMA_VERSION = 40;
// Rotation period offsets for incoming transport keys
private static final int OFFSET_PREV = -1;
@@ -216,6 +219,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " requested BOOLEAN NOT NULL,"
+ " expiry BIGINT NOT NULL,"
+ " txCount INT NOT NULL,"
+ " eta BIGINT NOT NULL,"
+ " PRIMARY KEY (messageId, contactId),"
+ " FOREIGN KEY (messageId)"
+ " REFERENCES messages (messageId)"
@@ -304,6 +308,7 @@ abstract class JdbcDatabase implements Database<Connection> {
// Different database libraries use different names for certain types
private final String hashType, secretType, binaryType;
private final String counterType, stringType;
private final MessageFactory messageFactory;
private final Clock clock;
// Locking: connectionsLock
@@ -319,12 +324,14 @@ abstract class JdbcDatabase implements Database<Connection> {
private final Condition connectionsChanged = connectionsLock.newCondition();
JdbcDatabase(String hashType, String secretType, String binaryType,
String counterType, String stringType, Clock clock) {
String counterType, String stringType,
MessageFactory messageFactory, Clock clock) {
this.hashType = hashType;
this.secretType = secretType;
this.binaryType = binaryType;
this.counterType = counterType;
this.stringType = stringType;
this.messageFactory = messageFactory;
this.clock = clock;
}
@@ -391,7 +398,7 @@ abstract class JdbcDatabase implements Database<Connection> {
// Package access for testing
List<Migration<Connection>> getMigrations() {
return singletonList(new Migration38_39());
return Arrays.asList(new Migration38_39(), new Migration39_40());
}
private void storeSchemaVersion(Connection txn, int version)
@@ -726,7 +733,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.setLong(3, m.getTimestamp());
ps.setInt(4, state.getValue());
ps.setBoolean(5, messageShared);
byte[] raw = m.getRaw();
byte[] raw = messageFactory.getRawMessage(m);
ps.setInt(6, raw.length);
ps.setBytes(7, raw);
int affected = ps.executeUpdate();
@@ -740,7 +747,7 @@ abstract class JdbcDatabase implements Database<Connection> {
boolean offered = removeOfferedMessage(txn, c, m.getId());
boolean seen = offered || (sender != null && c.equals(sender));
addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(),
m.getLength(), state, e.getValue(), messageShared,
raw.length, state, e.getValue(), messageShared,
false, seen);
}
// Update denormalised column in messageDependencies if dependency
@@ -799,8 +806,9 @@ abstract class JdbcDatabase implements Database<Connection> {
try {
String sql = "INSERT INTO statuses (messageId, contactId, groupId,"
+ " timestamp, length, state, groupShared, messageShared,"
+ " deleted, ack, seen, requested, expiry, txCount)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, 0, 0)";
+ " deleted, ack, seen, requested, expiry, txCount, eta)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, 0, 0,"
+ " 0)";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
ps.setInt(2, c.getInt());
@@ -1482,6 +1490,35 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public Message getMessage(Connection txn, MessageId m) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT groupId, timestamp, raw FROM messages"
+ " WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
GroupId g = new GroupId(rs.getBytes(1));
long timestamp = rs.getLong(2);
byte[] raw = rs.getBytes(3);
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
if (raw == null) throw new MessageDeletedException();
if (raw.length < MESSAGE_HEADER_LENGTH) throw new AssertionError();
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
return new Message(m, g, timestamp, body);
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
@Override
public Collection<MessageId> getMessageIds(Connection txn, GroupId g)
throws DbException {
@@ -1834,8 +1871,9 @@ abstract class JdbcDatabase implements Database<Connection> {
@Override
public Collection<MessageId> getMessagesToOffer(Connection txn,
ContactId c, int maxMessages) throws DbException {
ContactId c, int maxMessages, int maxLatency) throws DbException {
long now = clock.currentTimeMillis();
long eta = now + maxLatency;
PreparedStatement ps = null;
ResultSet rs = null;
try {
@@ -1844,13 +1882,14 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " AND groupShared = TRUE AND messageShared = TRUE"
+ " AND deleted = FALSE"
+ " AND seen = FALSE AND requested = FALSE"
+ " AND expiry < ?"
+ " AND (expiry <= ? OR eta > ?)"
+ " ORDER BY timestamp LIMIT ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setInt(2, DELIVERED.getValue());
ps.setLong(3, now);
ps.setInt(4, maxMessages);
ps.setLong(4, eta);
ps.setInt(5, maxMessages);
rs = ps.executeQuery();
List<MessageId> ids = new ArrayList<>();
while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
@@ -1891,8 +1930,9 @@ abstract class JdbcDatabase implements Database<Connection> {
@Override
public Collection<MessageId> getMessagesToSend(Connection txn, ContactId c,
int maxLength) throws DbException {
int maxLength, int maxLatency) throws DbException {
long now = clock.currentTimeMillis();
long eta = now + maxLatency;
PreparedStatement ps = null;
ResultSet rs = null;
try {
@@ -1901,12 +1941,13 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " AND groupShared = TRUE AND messageShared = TRUE"
+ " AND deleted = FALSE"
+ " AND seen = FALSE"
+ " AND expiry < ?"
+ " AND (expiry <= ? OR eta > ?)"
+ " ORDER BY timestamp";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setInt(2, DELIVERED.getValue());
ps.setLong(3, now);
ps.setLong(4, eta);
rs = ps.executeQuery();
List<MessageId> ids = new ArrayList<>();
int total = 0;
@@ -2018,34 +2059,11 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
@Nullable
public byte[] getRawMessage(Connection txn, MessageId m)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT raw FROM messages WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
byte[] raw = rs.getBytes(1);
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
return raw;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
@Override
public Collection<MessageId> getRequestedMessagesToSend(Connection txn,
ContactId c, int maxLength) throws DbException {
ContactId c, int maxLength, int maxLatency) throws DbException {
long now = clock.currentTimeMillis();
long eta = now + maxLatency;
PreparedStatement ps = null;
ResultSet rs = null;
try {
@@ -2054,12 +2072,13 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " AND groupShared = TRUE AND messageShared = TRUE"
+ " AND deleted = FALSE"
+ " AND seen = FALSE AND requested = TRUE"
+ " AND expiry < ?"
+ " AND (expiry <= ? OR eta > ?)"
+ " ORDER BY timestamp";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setInt(2, DELIVERED.getValue());
ps.setLong(3, now);
ps.setLong(4, eta);
rs = ps.executeQuery();
List<MessageId> ids = new ArrayList<>();
int total = 0;
@@ -2870,7 +2889,7 @@ abstract class JdbcDatabase implements Database<Connection> {
}
@Override
public void updateExpiryTime(Connection txn, ContactId c, MessageId m,
public void updateExpiryTimeAndEta(Connection txn, ContactId c, MessageId m,
int maxLatency) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
@@ -2886,13 +2905,16 @@ abstract class JdbcDatabase implements Database<Connection> {
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
sql = "UPDATE statuses SET expiry = ?, txCount = txCount + 1"
sql = "UPDATE statuses"
+ " SET expiry = ?, txCount = txCount + 1, eta = ?"
+ " WHERE messageId = ? AND contactId = ?";
ps = txn.prepareStatement(sql);
long now = clock.currentTimeMillis();
long eta = now + maxLatency;
ps.setLong(1, calculateExpiry(now, maxLatency, txCount));
ps.setBytes(2, m.getBytes());
ps.setInt(3, c.getInt());
ps.setLong(2, eta);
ps.setBytes(3, m.getBytes());
ps.setInt(4, c.getInt());
int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException();
ps.close();

View File

@@ -0,0 +1,54 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DbException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
class Migration39_40 implements Migration<Connection> {
private static final Logger LOG =
Logger.getLogger(Migration39_40.class.getName());
@Override
public int getStartVersion() {
return 39;
}
@Override
public int getEndVersion() {
return 40;
}
@Override
public void migrate(Connection txn) throws DbException {
Statement s = null;
try {
s = txn.createStatement();
s.execute("ALTER TABLE statuses"
+ " ADD eta BIGINT");
s.execute("UPDATE statuses SET eta = 0");
s.execute("ALTER TABLE statuses"
+ " ALTER COLUMN eta"
+ " SET NOT NULL");
} catch (SQLException e) {
tryToClose(s);
throw new DbException(e);
}
}
private void tryToClose(@Nullable Statement s) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
}

View File

@@ -102,6 +102,7 @@ class KeyAgreementTaskImpl extends Thread implements KeyAgreementTask,
KeyAgreementTransport transport =
connector.connect(remotePayload, alice);
if (transport == null) {
LOG.warning("Key agreement failed. Transport was null.");
// Notify caller that the connection failed
eventBus.broadcast(new KeyAgreementFailedEvent());
return;

View File

@@ -21,6 +21,7 @@ import org.briarproject.bramble.api.plugin.event.BluetoothEnabledEvent;
import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent;
import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
import org.briarproject.bramble.util.StringUtils;
@@ -146,16 +147,15 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
}
updateProperties();
running = true;
loadSettings();
loadSettings(callback.getSettings());
if (shouldAllowContactConnections()) {
if (isAdapterEnabled()) bind();
else enableAdapter();
}
}
private void loadSettings() {
contactConnections =
callback.getSettings().getBoolean(PREF_BT_ENABLE, false);
private void loadSettings(Settings settings) {
contactConnections = settings.getBoolean(PREF_BT_ENABLE, false);
}
private boolean shouldAllowContactConnections() {
@@ -387,7 +387,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
} else if (e instanceof SettingsUpdatedEvent) {
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(ID.getString()))
ioExecutor.execute(this::onSettingsUpdated);
ioExecutor.execute(() -> onSettingsUpdated(s.getSettings()));
} else if (e instanceof KeyAgreementListeningEvent) {
ioExecutor.execute(connectionLimiter::keyAgreementStarted);
} else if (e instanceof KeyAgreementStoppedListeningEvent) {
@@ -395,9 +395,9 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
}
}
private void onSettingsUpdated() {
private void onSettingsUpdated(Settings settings) {
boolean wasAllowed = shouldAllowContactConnections();
loadSettings();
loadSettings(settings);
boolean isAllowed = shouldAllowContactConnections();
if (wasAllowed && !isAllowed) {
LOG.info("Contact connections disabled");

View File

@@ -24,7 +24,7 @@ import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -35,6 +35,9 @@ import java.util.regex.Pattern;
import javax.annotation.Nullable;
import static java.net.NetworkInterface.getNetworkInterfaces;
import static java.util.Collections.emptyList;
import static java.util.Collections.list;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@@ -303,16 +306,16 @@ abstract class TcpPlugin implements DuplexPlugin {
}
Collection<InetAddress> getLocalIpAddresses() {
List<NetworkInterface> ifaces;
try {
ifaces = Collections.list(NetworkInterface.getNetworkInterfaces());
Enumeration<NetworkInterface> ifaces = getNetworkInterfaces();
if (ifaces == null) return emptyList();
List<InetAddress> addrs = new ArrayList<>();
for (NetworkInterface iface : list(ifaces))
addrs.addAll(list(iface.getInetAddresses()));
return addrs;
} catch (SocketException e) {
logException(LOG, WARNING, e);
return Collections.emptyList();
return emptyList();
}
List<InetAddress> addrs = new ArrayList<>();
for (NetworkInterface iface : ifaces)
addrs.addAll(Collections.list(iface.getInetAddresses()));
return addrs;
}
}

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.system.ResourceProvider;
import java.io.InputStream;
import java.util.ArrayList;
@@ -24,14 +23,11 @@ class CircumventionProviderImpl implements CircumventionProvider {
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
new HashSet<>(asList(BRIDGES));
private final ResourceProvider resourceProvider;
@Nullable
private volatile List<String> bridges = null;
@Inject
CircumventionProviderImpl(ResourceProvider resourceProvider) {
this.resourceProvider = resourceProvider;
CircumventionProviderImpl() {
}
@Override
@@ -50,8 +46,8 @@ class CircumventionProviderImpl implements CircumventionProvider {
List<String> bridges = this.bridges;
if (bridges != null) return new ArrayList<>(bridges);
InputStream is =
resourceProvider.getResourceInputStream(BRIDGE_FILE_NAME);
InputStream is = getClass().getClassLoader()
.getResourceAsStream(BRIDGE_FILE_NAME);
Scanner scanner = new Scanner(is);
bridges = new ArrayList<>();

View File

@@ -64,11 +64,11 @@ import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.ID;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_DISABLE_BLOCKED;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_MOBILE;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_ALWAYS;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_AUTOMATIC;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_NEVER;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WIFI;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WITH_BRIDGES;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION;
import static org.briarproject.bramble.util.LogUtils.logException;
@@ -108,6 +108,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private volatile ServerSocket socket = null;
private volatile Socket controlSocket = null;
private volatile TorControlConnection controlConnection = null;
private volatile Settings settings = null;
protected volatile boolean running = false;
@@ -166,10 +167,20 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override
public void start() throws PluginException {
if (used.getAndSet(true)) throw new IllegalStateException();
if (!torDirectory.exists()) {
if (!torDirectory.mkdirs()) {
LOG.warning("Could not create Tor directory.");
throw new PluginException();
}
}
// Load the settings
settings = callback.getSettings();
// Install or update the assets if necessary
if (!assetsAreUpToDate()) installAssets();
if (cookieFile.exists() && !cookieFile.delete())
LOG.warning("Old auth cookie not deleted");
// Migrate old settings before having a chance to stop
migrateSettings();
// Start a new Tor process
LOG.info("Starting Tor");
String torPath = torFile.getAbsolutePath();
@@ -286,22 +297,23 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private InputStream getTorInputStream() throws IOException {
if (LOG.isLoggable(INFO))
LOG.info("Installing Tor binary for " + architecture);
InputStream in =
resourceProvider.getResourceInputStream("tor_" + architecture);
InputStream in = resourceProvider
.getResourceInputStream("tor_" + architecture, ".zip");
ZipInputStream zin = new ZipInputStream(in);
if (zin.getNextEntry() == null) throw new IOException();
return zin;
}
private InputStream getGeoIpInputStream() throws IOException {
InputStream in = resourceProvider.getResourceInputStream("geoip");
InputStream in = resourceProvider.getResourceInputStream("geoip",
".zip");
ZipInputStream zin = new ZipInputStream(in);
if (zin.getNextEntry() == null) throw new IOException();
return zin;
}
private InputStream getConfigInputStream() {
return resourceProvider.getResourceInputStream("torrc");
return getClass().getClassLoader().getResourceAsStream("torrc");
}
private void tryToClose(@Nullable Closeable c) {
@@ -348,7 +360,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private void bind() {
ioExecutor.execute(() -> {
// If there's already a port number stored in config, reuse it
String portString = callback.getSettings().get(PREF_TOR_PORT);
String portString = settings.get(PREF_TOR_PORT);
int port;
if (StringUtils.isNullOrEmpty(portString)) port = 0;
else port = Integer.parseInt(portString);
@@ -393,7 +405,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private void publishHiddenService(String port) {
if (!running) return;
LOG.info("Creating hidden service");
String privKey = callback.getSettings().get(HS_PRIVKEY);
String privKey = settings.get(HS_PRIVKEY);
Map<Integer, String> portLines =
Collections.singletonMap(80, "127.0.0.1:" + port);
Map<String, String> response;
@@ -576,7 +588,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override
public void orConnStatus(String status, String orName) {
if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
if (LOG.isLoggable(INFO))
LOG.info("OR connection " + status + " " + orName);
if (status.equals("CLOSED") || status.equals("FAILED")) {
// Check whether we've lost connectivity
updateConnectionStatus(networkManager.getNetworkStatus());
@@ -613,6 +626,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(ID.getString())) {
LOG.info("Tor settings updated");
settings = s.getSettings();
updateConnectionStatus(networkManager.getNetworkStatus());
}
} else if (e instanceof NetworkStatusEvent) {
@@ -628,10 +642,11 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
String country = locationUtils.getCurrentCountry();
boolean blocked =
circumventionProvider.isTorProbablyBlocked(country);
Settings s = callback.getSettings();
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
boolean disableWhenBlocked =
s.getBoolean(PREF_TOR_DISABLE_BLOCKED, true);
int network = settings.getInt(PREF_TOR_NETWORK,
PREF_TOR_NETWORK_AUTOMATIC);
boolean useMobile = settings.getBoolean(PREF_TOR_MOBILE, true);
boolean bridgesWork = circumventionProvider.doBridgesWork(country);
boolean automatic = network == PREF_TOR_NETWORK_AUTOMATIC;
if (LOG.isLoggable(INFO)) {
LOG.info("Online: " + online + ", wifi: " + wifi);
@@ -643,25 +658,20 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (!online) {
LOG.info("Disabling network, device is offline");
enableNetwork(false);
} else if (network == PREF_TOR_NETWORK_NEVER
|| (network == PREF_TOR_NETWORK_WIFI && !wifi)) {
LOG.info("Disabling network due to data setting");
} else if (network == PREF_TOR_NETWORK_NEVER ||
(!useMobile && !wifi)) {
LOG.info("Disabling network due to setting");
enableNetwork(false);
} else if (blocked) {
if (circumventionProvider.doBridgesWork(country)) {
LOG.info("Enabling network, using bridges");
enableBridges(true);
enableNetwork(true);
} else if (disableWhenBlocked) {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
} else {
LOG.info("Enabling network but country is blocked");
enableBridges(false);
enableNetwork(true);
}
} else if (automatic && blocked && !bridgesWork) {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
} else if (network == PREF_TOR_NETWORK_WITH_BRIDGES ||
(automatic && bridgesWork)) {
LOG.info("Enabling network, using bridges");
enableBridges(true);
enableNetwork(true);
} else {
LOG.info("Enabling network");
LOG.info("Enabling network, not using bridges");
enableBridges(false);
enableNetwork(true);
}
@@ -671,6 +681,21 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
});
}
// TODO remove when sufficient time has passed. Added 2018-08-15
private void migrateSettings() {
Settings sOld = callback.getSettings();
int oldNetwork = sOld.getInt("network", -1);
if (oldNetwork == -1) return;
Settings s = new Settings();
if (oldNetwork == 0) {
s.putInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_NEVER);
} else if (oldNetwork == 1) {
s.putBoolean(PREF_TOR_MOBILE, false);
}
s.putInt("network", -1);
callback.mergeSettings(s);
}
private static class ConnectionStatus {
// All of the following are locking: this

View File

@@ -164,7 +164,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) {
BdfList message = clientHelper.getMessageAsList(txn,
e.getValue().messageId);
if (message == null) throw new DbException();
local.put(e.getKey(), parseProperties(message));
}
return local;
@@ -187,7 +186,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
// Retrieve and parse the latest local properties
BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId);
if (message == null) throw new DbException();
p = parseProperties(message);
}
db.commitTransaction(txn);
@@ -227,7 +225,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
// Retrieve and parse the latest remote properties
BdfList message =
clientHelper.getMessageAsList(txn, latest.messageId);
if (message == null) throw new DbException();
return parseProperties(message);
} catch (FormatException e) {
throw new DbException(e);
@@ -265,7 +262,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
} else {
BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId);
if (message == null) throw new DbException();
TransportProperties old = parseProperties(message);
merged = new TransportProperties(old);
merged.putAll(p);

View File

@@ -34,6 +34,12 @@ class SettingsManagerImpl implements SettingsManager {
return s;
}
@Override
public Settings getSettings(Transaction txn, String namespace)
throws DbException {
return db.getSettings(txn, namespace);
}
@Override
public void mergeSettings(Settings s, String namespace) throws DbException {
Transaction txn = db.startTransaction(false);

View File

@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.SyncRecordWriter;
@@ -274,7 +275,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
if (!generateBatchQueued.getAndSet(false))
throw new AssertionError();
try {
Collection<byte[]> b;
Collection<Message> b;
Transaction txn = db.startTransaction(false);
try {
b = db.generateRequestedBatch(txn, contactId,
@@ -296,9 +297,9 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
private class WriteBatch implements ThrowingRunnable<IOException> {
private final Collection<byte[]> batch;
private final Collection<Message> batch;
private WriteBatch(Collection<byte[]> batch) {
private WriteBatch(Collection<Message> batch) {
this.batch = batch;
}
@@ -306,7 +307,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
@Override
public void run() throws IOException {
if (interrupted) return;
for (byte[] raw : batch) recordWriter.writeMessage(raw);
for (Message m : batch) recordWriter.writeMessage(m);
LOG.info("Sent batch");
generateBatch();
}

View File

@@ -39,11 +39,7 @@ class MessageFactoryImpl implements MessageFactory {
if (body.length > MAX_MESSAGE_BODY_LENGTH)
throw new IllegalArgumentException();
MessageId id = getMessageId(g, timestamp, body);
byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length];
System.arraycopy(g.getBytes(), 0, raw, 0, UniqueId.LENGTH);
ByteUtils.writeUint64(timestamp, raw, UniqueId.LENGTH);
System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length);
return new Message(id, g, timestamp, raw);
return new Message(id, g, timestamp, body);
}
private MessageId getMessageId(GroupId g, long timestamp, byte[] body) {
@@ -69,18 +65,16 @@ class MessageFactoryImpl implements MessageFactory {
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
MessageId id = getMessageId(g, timestamp, body);
return new Message(id, g, timestamp, raw);
return new Message(id, g, timestamp, body);
}
@Override
public Message createMessage(MessageId m, byte[] raw) {
if (raw.length < MESSAGE_HEADER_LENGTH)
throw new IllegalArgumentException();
if (raw.length > MAX_MESSAGE_LENGTH)
throw new IllegalArgumentException();
byte[] groupId = new byte[UniqueId.LENGTH];
System.arraycopy(raw, 0, groupId, 0, UniqueId.LENGTH);
long timestamp = ByteUtils.readUint64(raw, UniqueId.LENGTH);
return new Message(m, new GroupId(groupId), timestamp, raw);
public byte[] getRawMessage(Message m) {
byte[] body = m.getBody();
byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length];
System.arraycopy(m.getGroupId().getBytes(), 0, raw, 0, UniqueId.LENGTH);
ByteUtils.writeUint64(m.getTimestamp(), raw, UniqueId.LENGTH);
System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length);
return raw;
}
}

View File

@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.SyncRecordWriter;
import org.briarproject.bramble.api.sync.SyncSession;
import org.briarproject.bramble.api.transport.StreamWriter;
@@ -171,7 +172,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
public void run() {
if (interrupted) return;
try {
Collection<byte[]> b;
Collection<Message> b;
Transaction txn = db.startTransaction(false);
try {
b = db.generateBatch(txn, contactId,
@@ -193,9 +194,9 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
private class WriteBatch implements ThrowingRunnable<IOException> {
private final Collection<byte[]> batch;
private final Collection<Message> batch;
private WriteBatch(Collection<byte[]> batch) {
private WriteBatch(Collection<Message> batch) {
this.batch = batch;
}
@@ -203,7 +204,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
@Override
public void run() throws IOException {
if (interrupted) return;
for (byte[] raw : batch) recordWriter.writeMessage(raw);
for (Message m : batch) recordWriter.writeMessage(m);
LOG.info("Sent batch");
dbExecutor.execute(new GenerateBatch());
}

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.record.RecordWriter;
import org.briarproject.bramble.api.record.RecordWriterFactory;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.SyncRecordWriter;
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
@@ -13,16 +14,19 @@ import javax.inject.Inject;
@NotNullByDefault
class SyncRecordWriterFactoryImpl implements SyncRecordWriterFactory {
private final MessageFactory messageFactory;
private final RecordWriterFactory recordWriterFactory;
@Inject
SyncRecordWriterFactoryImpl(RecordWriterFactory recordWriterFactory) {
SyncRecordWriterFactoryImpl(MessageFactory messageFactory,
RecordWriterFactory recordWriterFactory) {
this.messageFactory = messageFactory;
this.recordWriterFactory = recordWriterFactory;
}
@Override
public SyncRecordWriter createRecordWriter(OutputStream out) {
RecordWriter writer = recordWriterFactory.createRecordWriter(out);
return new SyncRecordWriterImpl(writer);
return new SyncRecordWriterImpl(messageFactory, writer);
}
}

View File

@@ -4,6 +4,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.record.Record;
import org.briarproject.bramble.api.record.RecordWriter;
import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request;
@@ -24,10 +26,12 @@ import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
@NotNullByDefault
class SyncRecordWriterImpl implements SyncRecordWriter {
private final MessageFactory messageFactory;
private final RecordWriter writer;
private final ByteArrayOutputStream payload = new ByteArrayOutputStream();
SyncRecordWriterImpl(RecordWriter writer) {
SyncRecordWriterImpl(MessageFactory messageFactory, RecordWriter writer) {
this.messageFactory = messageFactory;
this.writer = writer;
}
@@ -44,7 +48,8 @@ class SyncRecordWriterImpl implements SyncRecordWriter {
}
@Override
public void writeMessage(byte[] raw) throws IOException {
public void writeMessage(Message m) throws IOException {
byte[] raw = messageFactory.getRawMessage(m);
writer.writeRecord(new Record(PROTOCOL_VERSION, MESSAGE, raw));
}

View File

@@ -16,7 +16,6 @@ import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.ValidationManager;
import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
@@ -52,7 +51,6 @@ class ValidationManagerImpl implements ValidationManager, Service,
private final DatabaseComponent db;
private final Executor dbExecutor, validationExecutor;
private final MessageFactory messageFactory;
private final Map<ClientMajorVersion, MessageValidator> validators;
private final Map<ClientMajorVersion, IncomingMessageHook> hooks;
private final AtomicBoolean used = new AtomicBoolean(false);
@@ -60,12 +58,10 @@ class ValidationManagerImpl implements ValidationManager, Service,
@Inject
ValidationManagerImpl(DatabaseComponent db,
@DatabaseExecutor Executor dbExecutor,
@ValidationExecutor Executor validationExecutor,
MessageFactory messageFactory) {
@ValidationExecutor Executor validationExecutor) {
this.db = db;
this.dbExecutor = dbExecutor;
this.validationExecutor = validationExecutor;
this.messageFactory = messageFactory;
validators = new ConcurrentHashMap<>();
hooks = new ConcurrentHashMap<>();
}
@@ -128,9 +124,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
Transaction txn = db.startTransaction(true);
try {
MessageId id = unvalidated.poll();
byte[] raw = db.getRawMessage(txn, id);
if (raw == null) throw new DbException();
m = messageFactory.createMessage(id, raw);
m = db.getMessage(txn, id);
g = db.getGroup(txn, m.getGroupId());
db.commitTransaction(txn);
} finally {
@@ -197,9 +191,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
invalidateMessage(txn, id);
invalidate = getDependentsToInvalidate(txn, id);
} else if (allDelivered) {
byte[] raw = db.getRawMessage(txn, id);
if (raw == null) throw new DbException();
Message m = messageFactory.createMessage(id, raw);
Message m = db.getMessage(txn, id);
Group g = db.getGroup(txn, m.getGroupId());
ClientId c = g.getClientId();
int majorVersion = g.getMajorVersion();

View File

@@ -7,13 +7,15 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Collections;
import java.util.List;
import java.util.Enumeration;
import java.util.Map.Entry;
import java.util.Properties;
import javax.annotation.concurrent.Immutable;
import static java.net.NetworkInterface.getNetworkInterfaces;
import static java.util.Collections.list;
@Immutable
@NotNullByDefault
abstract class AbstractSecureRandomProvider implements SecureRandomProvider {
@@ -23,13 +25,14 @@ abstract class AbstractSecureRandomProvider implements SecureRandomProvider {
out.writeLong(System.currentTimeMillis());
out.writeLong(System.nanoTime());
out.writeLong(Runtime.getRuntime().freeMemory());
List<NetworkInterface> ifaces =
Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface i : ifaces) {
List<InetAddress> addrs = Collections.list(i.getInetAddresses());
for (InetAddress a : addrs) out.write(a.getAddress());
byte[] hardware = i.getHardwareAddress();
if (hardware != null) out.write(hardware);
Enumeration<NetworkInterface> ifaces = getNetworkInterfaces();
if (ifaces != null) {
for (NetworkInterface i : list(ifaces)) {
for (InetAddress a : list(i.getInetAddresses()))
out.write(a.getAddress());
byte[] hardware = i.getHardwareAddress();
if (hardware != null) out.write(hardware);
}
}
for (Entry<String, String> e : System.getenv().entrySet()) {
out.writeUTF(e.getKey());

View File

@@ -139,7 +139,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
}
@Override
public void stopService() throws ServiceException {
public void stopService() {
}
@Override
@@ -274,9 +274,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
private List<ClientVersion> loadClientVersions(Transaction txn,
MessageId m) throws DbException {
try {
BdfList body = clientHelper.getMessageAsList(txn, m);
if (body == null) throw new DbException();
return parseClientVersions(body);
return parseClientVersions(clientHelper.getMessageAsList(txn, m));
} catch (FormatException e) {
throw new DbException(e);
}
@@ -359,9 +357,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
private Update loadUpdate(Transaction txn, MessageId m) throws DbException {
try {
BdfList body = clientHelper.getMessageAsList(txn, m);
if (body == null) throw new DbException();
return parseUpdate(body);
return parseUpdate(clientHelper.getMessageAsList(txn, m));
} catch (FormatException e) {
throw new DbException(e);
}

View File

@@ -3,6 +3,6 @@ Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D
Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC
Bridge 195.91.239.8:9001 BA83F62551545655BBEBBFF353A45438D73FD45A
Bridge 185.165.184.217:6429 64CC94BEC51254E4409AD059192833854CCB95F0
Bridge 45.55.1.74:8443 6F18FEFBB0CAECD5ABA755312FCCB34FC11A7AB8
Bridge 95.85.40.163:9001 40057BE9CF76B6C5BDBE713753468BE0A990DE9C
Bridge 97.107.131.168:65341 DCDA8A5F1E2C50A6756A58462E5CF4B6B2DFDE26
Bridge 85.229.131.78:444 50E433CCC5FEC11CC34CB4D92033561E065EA106

View File

@@ -16,8 +16,8 @@ import org.jmock.Expectations;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Test;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
@@ -28,8 +28,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
new BdfMessageValidator(clientHelper, metadataEncoder, clock) {
@Override
protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body)
throws InvalidMessageException, FormatException {
BdfList body) {
throw new AssertionError();
}
};
@@ -57,8 +56,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis();
will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE));
oneOf(clientHelper).toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
oneOf(clientHelper).toList(message.getBody());
will(returnValue(body));
oneOf(metadataEncoder).encode(dictionary);
will(returnValue(meta));
@@ -69,7 +67,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
metadataEncoder, clock) {
@Override
protected BdfMessageContext validateMessage(Message m, Group g,
BdfList b) throws InvalidMessageException, FormatException {
BdfList b) {
assertSame(message, m);
assertSame(group, g);
assertSame(body, b);
@@ -83,17 +81,11 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
@Test(expected = InvalidMessageException.class)
public void testRejectsTooShortMessage() throws Exception {
byte[] invalidRaw = new byte[MESSAGE_HEADER_LENGTH];
// Use a mock message so the length of the raw message can be invalid
Message invalidMessage = context.mock(Message.class);
Message invalidMessage = getMessage(groupId, 0);
context.checking(new Expectations() {{
oneOf(invalidMessage).getTimestamp();
will(returnValue(timestamp));
oneOf(clock).currentTimeMillis();
will(returnValue(timestamp));
oneOf(invalidMessage).getRaw();
will(returnValue(invalidRaw));
}});
failIfSubclassIsCalled.validateMessage(invalidMessage, group);
@@ -101,15 +93,12 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
@Test
public void testAcceptsMinLengthMessage() throws Exception {
byte[] shortRaw = new byte[MESSAGE_HEADER_LENGTH + 1];
Message shortMessage =
new Message(messageId, groupId, timestamp, shortRaw);
Message shortMessage = getMessage(groupId, 1);
context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis();
will(returnValue(timestamp));
oneOf(clientHelper).toList(shortRaw, MESSAGE_HEADER_LENGTH,
shortRaw.length - MESSAGE_HEADER_LENGTH);
oneOf(clientHelper).toList(shortMessage.getBody());
will(returnValue(body));
oneOf(metadataEncoder).encode(dictionary);
will(returnValue(meta));
@@ -120,7 +109,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
metadataEncoder, clock) {
@Override
protected BdfMessageContext validateMessage(Message m, Group g,
BdfList b) throws InvalidMessageException, FormatException {
BdfList b) {
assertSame(shortMessage, m);
assertSame(group, g);
assertSame(body, b);
@@ -137,8 +126,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis();
will(returnValue(timestamp));
oneOf(clientHelper).toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
oneOf(clientHelper).toList(message.getBody());
will(throwException(new FormatException()));
}});
@@ -150,8 +138,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis();
will(returnValue(timestamp));
oneOf(clientHelper).toList(raw, MESSAGE_HEADER_LENGTH,
raw.length - MESSAGE_HEADER_LENGTH);
oneOf(clientHelper).toList(message.getBody());
will(returnValue(body));
}});
@@ -160,7 +147,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
metadataEncoder, clock) {
@Override
protected BdfMessageContext validateMessage(Message m, Group g,
BdfList b) throws InvalidMessageException, FormatException {
BdfList b) throws FormatException {
throw new FormatException();
}
};

View File

@@ -39,6 +39,7 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_N
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
@@ -67,11 +68,9 @@ public class ClientHelperImplTest extends BrambleTestCase {
private final GroupId groupId = new GroupId(getRandomId());
private final BdfDictionary dictionary = new BdfDictionary();
private final long timestamp = 42L;
private final byte[] rawMessage = getRandomBytes(42);
private final MessageId messageId = new MessageId(getRandomId());
private final Message message =
new Message(messageId, groupId, timestamp, rawMessage);
private final Message message = getMessage(groupId);
private final MessageId messageId = message.getId();
private final long timestamp = message.getTimestamp();
private final Metadata metadata = new Metadata();
private final BdfList list = BdfList.of("Sign this!", getRandomBytes(42));
private final String label = StringUtils.getRandomString(5);
@@ -120,8 +119,8 @@ public class ClientHelperImplTest extends BrambleTestCase {
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getRawMessage(txn, messageId);
will(returnValue(rawMessage));
oneOf(db).getMessage(txn, messageId);
will(returnValue(message));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
@@ -267,7 +266,7 @@ public class ClientHelperImplTest extends BrambleTestCase {
public void testToList() throws Exception {
expectToList(true);
assertEquals(list, clientHelper.toList(rawMessage));
assertEquals(list, clientHelper.toList(getRandomBytes(123)));
context.assertIsSatisfied();
}
@@ -276,7 +275,7 @@ public class ClientHelperImplTest extends BrambleTestCase {
expectToList(false); // no EOF after list
try {
clientHelper.toList(rawMessage);
clientHelper.toList(getRandomBytes(123));
fail();
} catch (FormatException e) {
// expected

View File

@@ -11,6 +11,8 @@ import java.util.HashSet;
import java.util.Set;
import static junit.framework.TestCase.assertTrue;
import org.briarproject.bramble.test.ArrayClock;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.junit.Assert.assertEquals;
@@ -74,24 +76,4 @@ public class ScryptKdfTest extends BrambleTestCase {
PasswordBasedKdf kdf = new ScryptKdf(clock);
assertEquals(256, kdf.chooseCostParameter());
}
private static class ArrayClock implements Clock {
private final long[] times;
private int index = 0;
private ArrayClock(long... times) {
this.times = times;
}
@Override
public long currentTimeMillis() {
return times[index++];
}
@Override
public void sleep(long milliseconds) throws InterruptedException {
Thread.sleep(milliseconds);
}
}
}

View File

@@ -64,6 +64,7 @@ import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
@@ -72,6 +73,7 @@ import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getClientId;
import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTransportId;
@@ -97,10 +99,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
private final Group group;
private final Author author;
private final LocalAuthor localAuthor;
private final Message message, message1;
private final MessageId messageId, messageId1;
private final int size;
private final byte[] raw;
private final Message message;
private final Metadata metadata;
private final TransportId transportId;
private final int maxLatency;
@@ -115,12 +115,10 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
groupId = group.getId();
author = getAuthor();
localAuthor = getLocalAuthor();
messageId = new MessageId(getRandomId());
messageId1 = new MessageId(getRandomId());
long timestamp = System.currentTimeMillis();
size = 1234;
raw = new byte[size];
message = new Message(messageId, groupId, timestamp, raw);
message = getMessage(groupId);
message1 = getMessage(groupId);
messageId = message.getId();
messageId1 = message1.getId();
metadata = new Metadata();
metadata.put("foo", new byte[] {'b', 'a', 'r'});
transportId = getTransportId();
@@ -646,7 +644,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
transaction = db.startTransaction(false);
try {
db.getRawMessage(transaction, messageId);
db.getMessage(transaction, messageId);
fail();
} catch (NoSuchMessageException expected) {
// Expected
@@ -865,23 +863,23 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
@Test
public void testGenerateBatch() throws Exception {
byte[] raw1 = new byte[size];
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
Collection<byte[]> messages = Arrays.asList(raw, raw1);
Collection<Message> messages = Arrays.asList(message, message1);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).getMessagesToSend(txn, contactId, size * 2);
oneOf(database).getMessagesToSend(txn, contactId,
MAX_MESSAGE_LENGTH * 2, maxLatency);
will(returnValue(ids));
oneOf(database).getRawMessage(txn, messageId);
will(returnValue(raw));
oneOf(database).updateExpiryTime(txn, contactId, messageId,
oneOf(database).getMessage(txn, messageId);
will(returnValue(message));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
maxLatency);
oneOf(database).getRawMessage(txn, messageId1);
will(returnValue(raw1));
oneOf(database).updateExpiryTime(txn, contactId, messageId1,
oneOf(database).getMessage(txn, messageId1);
will(returnValue(message1));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
maxLatency);
oneOf(database).lowerRequestedFlag(txn, contactId, ids);
oneOf(database).commitTransaction(txn);
@@ -893,7 +891,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
Transaction transaction = db.startTransaction(false);
try {
assertEquals(messages, db.generateBatch(transaction, contactId,
size * 2, maxLatency));
MAX_MESSAGE_LENGTH * 2, maxLatency));
db.commitTransaction(transaction);
} finally {
db.endTransaction(transaction);
@@ -909,11 +907,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).getMessagesToOffer(txn, contactId, 123);
oneOf(database).getMessagesToOffer(txn, contactId, 123, maxLatency);
will(returnValue(ids));
oneOf(database).updateExpiryTime(txn, contactId, messageId,
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
maxLatency);
oneOf(database).updateExpiryTime(txn, contactId, messageId1,
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
maxLatency);
oneOf(database).commitTransaction(txn);
}});
@@ -961,24 +959,23 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
@Test
public void testGenerateRequestedBatch() throws Exception {
byte[] raw1 = new byte[size];
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
Collection<byte[]> messages = Arrays.asList(raw, raw1);
Collection<Message> messages = Arrays.asList(message, message1);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).getRequestedMessagesToSend(txn, contactId,
size * 2);
MAX_MESSAGE_LENGTH * 2, maxLatency);
will(returnValue(ids));
oneOf(database).getRawMessage(txn, messageId);
will(returnValue(raw));
oneOf(database).updateExpiryTime(txn, contactId, messageId,
oneOf(database).getMessage(txn, messageId);
will(returnValue(message));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
maxLatency);
oneOf(database).getRawMessage(txn, messageId1);
will(returnValue(raw1));
oneOf(database).updateExpiryTime(txn, contactId, messageId1,
oneOf(database).getMessage(txn, messageId1);
will(returnValue(message1));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
maxLatency);
oneOf(database).lowerRequestedFlag(txn, contactId, ids);
oneOf(database).commitTransaction(txn);
@@ -990,7 +987,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
Transaction transaction = db.startTransaction(false);
try {
assertEquals(messages, db.generateRequestedBatch(transaction,
contactId, size * 2, maxLatency));
contactId, MAX_MESSAGE_LENGTH * 2, maxLatency));
db.commitTransaction(transaction);
} finally {
db.endTransaction(transaction);

View File

@@ -7,10 +7,12 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.TestDatabaseConfig;
import org.briarproject.bramble.test.TestMessageFactory;
import org.briarproject.bramble.test.TestUtils;
import org.jmock.Expectations;
import org.junit.After;
@@ -45,6 +47,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
protected final DatabaseConfig config =
new TestDatabaseConfig(testDir, 1024 * 1024);
protected final MessageFactory messageFactory = new TestMessageFactory();
protected final SecretKey key = getSecretKey();
protected final Clock clock = new SystemClock();

View File

@@ -1,10 +1,13 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.TestDatabaseConfig;
import org.briarproject.bramble.test.TestMessageFactory;
import org.briarproject.bramble.test.UTest;
import java.io.IOException;
@@ -26,9 +29,11 @@ public abstract class DatabasePerformanceComparisonTest
* How many blocks of each condition to compare.
*/
private static final int COMPARISON_BLOCKS = 10;
private SecretKey databaseKey = getSecretKey();
abstract Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, Clock clock);
DatabaseConfig databaseConfig, MessageFactory messageFactory,
Clock clock);
@Override
protected void benchmark(String name,
@@ -71,8 +76,9 @@ public abstract class DatabasePerformanceComparisonTest
private Database<Connection> openDatabase(boolean conditionA)
throws DbException {
Database<Connection> db = createDatabase(conditionA,
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
db.open(getSecretKey(), null);
new TestDatabaseConfig(testDir, MAX_SIZE),
new TestMessageFactory(), new SystemClock());
db.open(databaseKey, null);
return db;
}

View File

@@ -96,6 +96,9 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
*/
private static final int STEADY_STATE_BLOCKS = 5;
// All our transports use a maximum latency of 30 seconds
private static final int MAX_LATENCY = 30 * 1000;
protected final File testDir = getTestDirectory();
private final File resultsFile = new File(getTestName() + ".tsv");
protected final Random random = new Random();
@@ -448,7 +451,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.getMessagesToOffer(txn, pickRandom(contacts).getId(),
MAX_MESSAGE_IDS);
MAX_MESSAGE_IDS, MAX_LATENCY);
db.commitTransaction(txn);
});
}
@@ -470,7 +473,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.getMessagesToSend(txn, pickRandom(contacts).getId(),
MAX_MESSAGE_IDS);
MAX_MESSAGE_IDS, MAX_LATENCY);
db.commitTransaction(txn);
});
}
@@ -506,11 +509,11 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
}
@Test
public void testGetRawMessage() throws Exception {
String name = "getRawMessage(T, MessageId)";
public void testGetMessage() throws Exception {
String name = "getMessage(T, MessageId)";
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.getRawMessage(txn, pickRandom(messages).getId());
db.getMessage(txn, pickRandom(messages).getId());
db.commitTransaction(txn);
});
}
@@ -521,7 +524,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.getRequestedMessagesToSend(txn, pickRandom(contacts).getId(),
MAX_MESSAGE_IDS);
MAX_MESSAGE_IDS, MAX_LATENCY);
db.commitTransaction(txn);
});
}

View File

@@ -1,10 +1,13 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.TestDatabaseConfig;
import org.briarproject.bramble.test.TestMessageFactory;
import org.briarproject.bramble.util.IoUtils;
import java.io.File;
@@ -20,8 +23,10 @@ import static org.briarproject.bramble.test.TestUtils.getSecretKey;
public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
private SecretKey databaseKey = getSecretKey();
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
Clock clock);
MessageFactory messageFactory, Clock clock);
@Nullable
protected abstract File getTraceFile();
@@ -43,8 +48,9 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
private Database<Connection> openDatabase() throws DbException {
Database<Connection> db = createDatabase(
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
db.open(getSecretKey(), null);
new TestDatabaseConfig(testDir, MAX_SIZE),
new TestMessageFactory(), new SystemClock());
db.open(databaseKey, null);
return db;
}

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore;
@@ -13,7 +14,8 @@ public class H2DatabasePerformanceTest extends SingleDatabasePerformanceTest {
}
@Override
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) {
return new H2Database(config, clock);
protected JdbcDatabase createDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) {
return new H2Database(config, messageFactory, clock);
}
}

View File

@@ -1,16 +1,14 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
public class H2DatabaseTest extends JdbcDatabaseTest {
public H2DatabaseTest() throws Exception {
super();
}
@Override
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) {
return new H2Database(config, clock);
protected JdbcDatabase createDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) {
return new H2Database(config, messageFactory, clock);
}
}

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore;
@@ -14,8 +15,8 @@ public class H2DatabaseTraceTest extends DatabaseTraceTest {
@Override
Database<Connection> createDatabase(DatabaseConfig databaseConfig,
Clock clock) {
return new H2Database(databaseConfig, clock) {
MessageFactory messageFactory, Clock clock) {
return new H2Database(databaseConfig, messageFactory, clock) {
@Override
@Nonnull
String getUrl() {

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore;
@@ -12,9 +13,11 @@ public class H2HyperSqlDatabasePerformanceComparisonTest
@Override
Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, Clock clock) {
if (conditionA) return new H2Database(databaseConfig, clock);
else return new HyperSqlDatabase(databaseConfig, clock);
DatabaseConfig databaseConfig, MessageFactory messageFactory,
Clock clock) {
if (conditionA)
return new H2Database(databaseConfig, messageFactory, clock);
else return new HyperSqlDatabase(databaseConfig, messageFactory, clock);
}
@Override

View File

@@ -11,7 +11,7 @@ public class H2MigrationTest extends DatabaseMigrationTest {
@Override
Database<Connection> createDatabase(
List<Migration<Connection>> migrations) {
return new H2Database(config, clock) {
return new H2Database(config, messageFactory, clock) {
@Override
List<Migration<Connection>> getMigrations() {
return migrations;

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore;
@@ -17,8 +18,9 @@ public class H2SelfDatabasePerformanceComparisonTest
@Override
Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, Clock clock) {
return new H2Database(databaseConfig, clock);
DatabaseConfig databaseConfig, MessageFactory messageFactory,
Clock clock) {
return new H2Database(databaseConfig, messageFactory, clock);
}
@Override

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore;
@@ -19,11 +20,12 @@ public class H2SleepDatabasePerformanceComparisonTest
@Override
Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, Clock clock) {
DatabaseConfig databaseConfig, MessageFactory messageFactory,
Clock clock) {
if (conditionA) {
return new H2Database(databaseConfig, clock);
return new H2Database(databaseConfig, messageFactory, clock);
} else {
return new H2Database(databaseConfig, clock) {
return new H2Database(databaseConfig, messageFactory, clock) {
@Override
@NotNullByDefault
public void commitTransaction(Connection txn)

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore;
@@ -14,7 +15,8 @@ public class HyperSqlDatabasePerformanceTest
}
@Override
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) {
return new HyperSqlDatabase(config, clock);
protected JdbcDatabase createDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) {
return new HyperSqlDatabase(config, messageFactory, clock);
}
}

View File

@@ -1,16 +1,14 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
public class HyperSqlDatabaseTest extends JdbcDatabaseTest {
public HyperSqlDatabaseTest() throws Exception {
super();
}
@Override
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) {
return new HyperSqlDatabase(config, clock);
protected JdbcDatabase createDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) {
return new HyperSqlDatabase(config, messageFactory ,clock);
}
}

View File

@@ -9,9 +9,9 @@ import java.util.List;
public class HyperSqlMigrationTest extends DatabaseMigrationTest {
@Override
Database<Connection> createDatabase(List<Migration<Connection>> migrations)
throws Exception {
return new HyperSqlDatabase(config, clock) {
Database<Connection> createDatabase(
List<Migration<Connection>> migrations) {
return new HyperSqlDatabase(config, messageFactory, clock) {
@Override
List<Migration<Connection>> getMigrations() {
return migrations;

View File

@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.LocalAuthor;
@@ -14,6 +15,7 @@ import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.ValidationManager.State;
@@ -24,8 +26,10 @@ import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.OutgoingKeys;
import org.briarproject.bramble.api.transport.TransportKeys;
import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.ArrayClock;
import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.TestDatabaseConfig;
import org.briarproject.bramble.test.TestMessageFactory;
import org.briarproject.bramble.test.TestUtils;
import org.junit.After;
import org.junit.Before;
@@ -52,16 +56,17 @@ import static org.briarproject.bramble.api.db.Metadata.REMOVE;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getClientId;
import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
@@ -79,6 +84,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
private static final int ONE_MEGABYTE = 1024 * 1024;
private static final int MAX_SIZE = 5 * ONE_MEGABYTE;
// All our transports use a maximum latency of 30 seconds
private static final int MAX_LATENCY = 30 * 1000;
private final SecretKey key = getSecretKey();
private final File testDir = getTestDirectory();
@@ -88,11 +96,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
private final Group group;
private final Author author;
private final LocalAuthor localAuthor;
private final MessageId messageId;
private final long timestamp;
private final int size;
private final byte[] raw;
private final Message message;
private final MessageId messageId;
private final TransportId transportId;
private final ContactId contactId;
private final KeySetId keySetId, keySetId1;
@@ -105,11 +110,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
groupId = group.getId();
author = getAuthor();
localAuthor = getLocalAuthor();
messageId = new MessageId(getRandomId());
timestamp = System.currentTimeMillis();
size = 1234;
raw = getRandomBytes(size);
message = new Message(messageId, groupId, timestamp, raw);
message = getMessage(groupId);
messageId = message.getId();
transportId = getTransportId();
contactId = new ContactId(1);
keySetId = new KeySetId(1);
@@ -117,7 +119,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
}
protected abstract JdbcDatabase createDatabase(DatabaseConfig config,
Clock clock);
MessageFactory messageFactory, Clock clock);
@Before
public void setUp() {
@@ -149,8 +151,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertTrue(db.containsContact(txn, contactId));
assertTrue(db.containsGroup(txn, groupId));
assertTrue(db.containsMessage(txn, messageId));
byte[] raw1 = db.getRawMessage(txn, messageId);
assertArrayEquals(raw, raw1);
assertArrayEquals(message.getBody(),
db.getMessage(txn, messageId).getBody());
// Delete the records
db.removeMessage(txn, messageId);
@@ -202,16 +204,16 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
// The contact has not seen the message, so it should be sendable
Collection<MessageId> ids =
db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
// Changing the status to seen = true should make the message unsendable
db.raiseSeenFlag(txn, contactId, messageId);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertTrue(ids.isEmpty());
db.commitTransaction(txn);
@@ -233,30 +235,30 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
// The message has not been validated, so it should not be sendable
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
ONE_MEGABYTE);
ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertTrue(ids.isEmpty());
// Marking the message delivered should make it sendable
db.setMessageState(txn, messageId, DELIVERED);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
// Marking the message invalid should make it unsendable
db.setMessageState(txn, messageId, INVALID);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertTrue(ids.isEmpty());
// Marking the message pending should make it unsendable
db.setMessageState(txn, messageId, PENDING);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertTrue(ids.isEmpty());
db.commitTransaction(txn);
@@ -277,37 +279,37 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
// The group is invisible, so the message should not be sendable
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
ONE_MEGABYTE);
ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertTrue(ids.isEmpty());
// Making the group visible should not make the message sendable
db.addGroupVisibility(txn, contactId, groupId, false);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertTrue(ids.isEmpty());
// Sharing the group should make the message sendable
db.setGroupVisibility(txn, contactId, groupId, true);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
// Unsharing the group should make the message unsendable
db.setGroupVisibility(txn, contactId, groupId, false);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertTrue(ids.isEmpty());
// Making the group invisible should make the message unsendable
db.removeGroupVisibility(txn, contactId, groupId);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertTrue(ids.isEmpty());
db.commitTransaction(txn);
@@ -329,16 +331,16 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
// The message is not shared, so it should not be sendable
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
ONE_MEGABYTE);
ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertTrue(ids.isEmpty());
// Sharing the message should make it sendable
db.setMessageShared(txn, messageId);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
db.commitTransaction(txn);
@@ -359,12 +361,13 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
db.addMessage(txn, message, DELIVERED, true, null);
// The message is sendable, but too large to send
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
size - 1);
Collection<MessageId> ids =
db.getMessagesToSend(txn, contactId, message.getRawLength() - 1,
MAX_LATENCY);
assertTrue(ids.isEmpty());
// The message is just the right size to send
ids = db.getMessagesToSend(txn, contactId, size);
ids = db.getMessagesToSend(txn, contactId, message.getRawLength(),
MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
db.commitTransaction(txn);
@@ -384,8 +387,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
db.addGroupVisibility(txn, contactId, groupId, false);
// Add some messages to ack
MessageId messageId1 = new MessageId(getRandomId());
Message message1 = new Message(messageId1, groupId, timestamp, raw);
Message message1 = getMessage(groupId);
MessageId messageId1 = message1.getId();
db.addMessage(txn, message, DELIVERED, true, contactId);
db.addMessage(txn, message1, DELIVERED, true, contactId);
@@ -427,19 +430,19 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
// Retrieve the message from the database and mark it as sent
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
ONE_MEGABYTE);
ONE_MEGABYTE, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
db.updateExpiryTime(txn, contactId, messageId, Integer.MAX_VALUE);
db.updateExpiryTimeAndEta(txn, contactId, messageId, MAX_LATENCY);
// The message should no longer be sendable
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
// Pretend that the message was acked
db.raiseSeenFlag(txn, contactId, messageId);
// The message still should not be sendable
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
db.commitTransaction(txn);
@@ -448,9 +451,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testGetFreeSpace() throws Exception {
byte[] largeBody = new byte[MAX_MESSAGE_LENGTH];
for (int i = 0; i < largeBody.length; i++) largeBody[i] = (byte) i;
Message message = new Message(messageId, groupId, timestamp, largeBody);
Message message = getMessage(groupId, MAX_MESSAGE_BODY_LENGTH);
Database<Connection> db = open(false);
// Sanity check: there should be enough space on disk for this test
@@ -1104,8 +1105,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testMetadataQueries() throws Exception {
MessageId messageId1 = new MessageId(getRandomId());
Message message1 = new Message(messageId1, groupId, timestamp, raw);
Message message1 = getMessage(groupId);
MessageId messageId1 = message1.getId();
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
@@ -1208,8 +1209,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testMetadataQueriesOnlyForDeliveredMessages() throws Exception {
MessageId messageId1 = new MessageId(getRandomId());
Message message1 = new Message(messageId1, groupId, timestamp, raw);
Message message1 = getMessage(groupId);
MessageId messageId1 = message1.getId();
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
@@ -1279,14 +1280,14 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testMessageDependencies() throws Exception {
MessageId messageId1 = new MessageId(getRandomId());
MessageId messageId2 = new MessageId(getRandomId());
MessageId messageId3 = new MessageId(getRandomId());
MessageId messageId4 = new MessageId(getRandomId());
Message message1 = new Message(messageId1, groupId, timestamp, raw);
Message message2 = new Message(messageId2, groupId, timestamp, raw);
Message message3 = new Message(messageId3, groupId, timestamp, raw);
Message message4 = new Message(messageId4, groupId, timestamp, raw);
Message message1 = getMessage(groupId);
Message message2 = getMessage(groupId);
Message message3 = getMessage(groupId);
Message message4 = getMessage(groupId);
MessageId messageId1 = message1.getId();
MessageId messageId2 = message2.getId();
MessageId messageId3 = message3.getId();
MessageId messageId4 = message4.getId();
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
@@ -1384,16 +1385,16 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
db.addGroup(txn, group1);
// Add a message to the second group
MessageId messageId1 = new MessageId(getRandomId());
Message message1 = new Message(messageId1, groupId1, timestamp, raw);
Message message1 = getMessage(groupId1);
MessageId messageId1 = message1.getId();
db.addMessage(txn, message1, DELIVERED, true, contactId);
// Create an ID for a missing message
MessageId messageId2 = new MessageId(getRandomId());
// Add another message to the first group
MessageId messageId3 = new MessageId(getRandomId());
Message message3 = new Message(messageId3, groupId, timestamp, raw);
Message message3 = getMessage(groupId);
MessageId messageId3 = message3.getId();
db.addMessage(txn, message3, DELIVERED, true, contactId);
// Add dependencies between the messages
@@ -1427,36 +1428,32 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testGetPendingMessagesForDelivery() throws Exception {
MessageId mId1 = new MessageId(getRandomId());
MessageId mId2 = new MessageId(getRandomId());
MessageId mId3 = new MessageId(getRandomId());
MessageId mId4 = new MessageId(getRandomId());
Message m1 = new Message(mId1, groupId, timestamp, raw);
Message m2 = new Message(mId2, groupId, timestamp, raw);
Message m3 = new Message(mId3, groupId, timestamp, raw);
Message m4 = new Message(mId4, groupId, timestamp, raw);
Message message1 = getMessage(groupId);
Message message2 = getMessage(groupId);
Message message3 = getMessage(groupId);
Message message4 = getMessage(groupId);
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a group and some messages with different states
db.addGroup(txn, group);
db.addMessage(txn, m1, UNKNOWN, true, contactId);
db.addMessage(txn, m2, INVALID, true, contactId);
db.addMessage(txn, m3, PENDING, true, contactId);
db.addMessage(txn, m4, DELIVERED, true, contactId);
db.addMessage(txn, message1, UNKNOWN, true, contactId);
db.addMessage(txn, message2, INVALID, true, contactId);
db.addMessage(txn, message3, PENDING, true, contactId);
db.addMessage(txn, message4, DELIVERED, true, contactId);
Collection<MessageId> result;
// Retrieve messages to be validated
result = db.getMessagesToValidate(txn);
assertEquals(1, result.size());
assertTrue(result.contains(mId1));
assertTrue(result.contains(message1.getId()));
// Retrieve pending messages
result = db.getPendingMessages(txn);
assertEquals(1, result.size());
assertTrue(result.contains(mId3));
assertTrue(result.contains(message3.getId()));
db.commitTransaction(txn);
db.close();
@@ -1464,35 +1461,31 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testGetMessagesToShare() throws Exception {
MessageId mId1 = new MessageId(getRandomId());
MessageId mId2 = new MessageId(getRandomId());
MessageId mId3 = new MessageId(getRandomId());
MessageId mId4 = new MessageId(getRandomId());
Message m1 = new Message(mId1, groupId, timestamp, raw);
Message m2 = new Message(mId2, groupId, timestamp, raw);
Message m3 = new Message(mId3, groupId, timestamp, raw);
Message m4 = new Message(mId4, groupId, timestamp, raw);
Message message1 = getMessage(groupId);
Message message2 = getMessage(groupId);
Message message3 = getMessage(groupId);
Message message4 = getMessage(groupId);
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a group and some messages
db.addGroup(txn, group);
db.addMessage(txn, m1, DELIVERED, true, contactId);
db.addMessage(txn, m2, DELIVERED, false, contactId);
db.addMessage(txn, m3, DELIVERED, false, contactId);
db.addMessage(txn, m4, DELIVERED, true, contactId);
db.addMessage(txn, message1, DELIVERED, true, contactId);
db.addMessage(txn, message2, DELIVERED, false, contactId);
db.addMessage(txn, message3, DELIVERED, false, contactId);
db.addMessage(txn, message4, DELIVERED, true, contactId);
// Introduce dependencies between the messages
db.addMessageDependency(txn, m1, mId2, DELIVERED);
db.addMessageDependency(txn, m3, mId1, DELIVERED);
db.addMessageDependency(txn, m4, mId3, DELIVERED);
db.addMessageDependency(txn, message1, message2.getId(), DELIVERED);
db.addMessageDependency(txn, message3, message1.getId(), DELIVERED);
db.addMessageDependency(txn, message4, message3.getId(), DELIVERED);
// Retrieve messages to be shared
Collection<MessageId> result = db.getMessagesToShare(txn);
assertEquals(2, result.size());
assertTrue(result.contains(mId2));
assertTrue(result.contains(mId3));
assertTrue(result.contains(message2.getId()));
assertTrue(result.contains(message3.getId()));
db.commitTransaction(txn);
db.close();
@@ -1530,7 +1523,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertFalse(status.isSeen());
// Pretend the message was sent to the contact
db.updateExpiryTime(txn, contactId, messageId, Integer.MAX_VALUE);
db.updateExpiryTimeAndEta(txn, contactId, messageId, Integer.MAX_VALUE);
// The message should be sent but not seen
status = db.getMessageStatus(txn, contactId, messageId);
@@ -1649,13 +1642,17 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
// The message should be sendable
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
ONE_MEGABYTE);
ONE_MEGABYTE, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
// The raw message should not be null
assertNotNull(db.getRawMessage(txn, messageId));
// The message should be available
Message m = db.getMessage(txn, messageId);
assertEquals(messageId, m.getId());
assertEquals(groupId, m.getGroupId());
assertEquals(message.getTimestamp(), m.getTimestamp());
assertArrayEquals(message.getBody(), m.getBody());
// Delete the message
db.deleteMessage(txn, messageId);
@@ -1664,13 +1661,18 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertTrue(db.containsVisibleMessage(txn, contactId, messageId));
// The message should not be sendable
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
ids = db.getMessagesToOffer(txn, contactId, 100);
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
assertTrue(ids.isEmpty());
// The raw message should be null
assertNull(db.getRawMessage(txn, messageId));
// Requesting the message should throw an exception
try {
db.getMessage(txn, messageId);
fail();
} catch (MessageDeletedException expected) {
// Expected
}
db.commitTransaction(txn);
db.close();
@@ -1733,7 +1735,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testGetNextSendTime() throws Exception {
long now = System.currentTimeMillis();
Database<Connection> db = open(false, new StoppedClock(now));
Database<Connection> db = open(false, new TestMessageFactory(),
new StoppedClock(now));
Connection txn = db.startTransaction();
// Add a contact, a group and a message
@@ -1764,12 +1767,12 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
// Update the message's expiry time as though we sent it - now the
// message should be sendable after one round-trip
db.updateExpiryTime(txn, contactId, messageId, 1000);
db.updateExpiryTimeAndEta(txn, contactId, messageId, 1000);
assertEquals(now + 2000, db.getNextSendTime(txn, contactId));
// Update the message's expiry time again - now it should be sendable
// after two round-trips
db.updateExpiryTime(txn, contactId, messageId, 1000);
db.updateExpiryTimeAndEta(txn, contactId, messageId, 1000);
assertEquals(now + 4000, db.getNextSendTime(txn, contactId));
// Delete the message - there should be no messages to send
@@ -1802,7 +1805,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
try {
// Ask for a nonexistent message - an exception should be thrown
db.getRawMessage(txn, messageId);
db.getMessage(txn, messageId);
fail();
} catch (DbException expected) {
// It should be possible to abort the transaction without error
@@ -1812,14 +1815,112 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
db.close();
}
private Database<Connection> open(boolean resume) throws Exception {
return open(resume, new SystemClock());
@Test
public void testMessageRetransmission() throws Exception {
long now = System.currentTimeMillis();
long steps[] = {now, now, now + MAX_LATENCY * 2 - 1,
now + MAX_LATENCY * 2};
Database<Connection> db =
open(false, new TestMessageFactory(), new ArrayClock(steps));
Connection txn = db.startTransaction();
// Add a contact, a shared group and a shared message
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
true, true));
db.addGroup(txn, group);
db.addGroupVisibility(txn, contactId, groupId, true);
db.addMessage(txn, message, DELIVERED, true, null);
// Time: now
// Retrieve the message from the database
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
ONE_MEGABYTE, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
// Time: now
// Mark the message as sent
db.updateExpiryTimeAndEta(txn, contactId, messageId, MAX_LATENCY);
// The message should expire after 2 * MAX_LATENCY
assertEquals(now + MAX_LATENCY * 2, db.getNextSendTime(txn, contactId));
// Time: now + MAX_LATENCY * 2 - 1
// The message should not yet be sendable
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
// Time: now + MAX_LATENCY * 2
// The message should have expired and should now be sendable
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
db.commitTransaction(txn);
db.close();
}
private Database<Connection> open(boolean resume, Clock clock)
throws Exception {
Database<Connection> db = createDatabase(
new TestDatabaseConfig(testDir, MAX_SIZE), clock);
@Test
public void testFasterMessageRetransmission() throws Exception {
long now = System.currentTimeMillis();
long steps[] = {now, now, now, now, now + 1};
Database<Connection> db =
open(false, new TestMessageFactory(), new ArrayClock(steps));
Connection txn = db.startTransaction();
// Add a contact, a shared group and a shared message
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
true, true));
db.addGroup(txn, group);
db.addGroupVisibility(txn, contactId, groupId, true);
db.addMessage(txn, message, DELIVERED, true, null);
// Time: now
// Retrieve the message from the database
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
ONE_MEGABYTE, MAX_LATENCY);
assertEquals(singletonList(messageId), ids);
// Time: now
// Mark the message as sent
db.updateExpiryTimeAndEta(txn, contactId, messageId, MAX_LATENCY);
// The message should expire after 2 * MAX_LATENCY
assertEquals(now + MAX_LATENCY * 2, db.getNextSendTime(txn, contactId));
// Time: now
// The message should not be sendable via the same transport
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
assertTrue(ids.isEmpty());
// Time: now
// The message should be sendable via a transport with a faster ETA
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE,
MAX_LATENCY - 1);
assertEquals(singletonList(messageId), ids);
// Time: now + 1
// The message should no longer be sendable via the faster transport,
// as the ETA is now equal
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE,
MAX_LATENCY - 1);
assertTrue(ids.isEmpty());
db.commitTransaction(txn);
db.close();
}
private Database<Connection> open(boolean resume) throws Exception {
return open(resume, new TestMessageFactory(), new SystemClock());
}
private Database<Connection> open(boolean resume,
MessageFactory messageFactory, Clock clock) throws Exception {
Database<Connection> db =
createDatabase(new TestDatabaseConfig(testDir, MAX_SIZE),
messageFactory, clock);
if (!resume) TestUtils.deleteTestDirectory(testDir);
db.open(key, null);
return db;
@@ -1848,7 +1949,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@After
public void tearDown() {
TestUtils.deleteTestDirectory(testDir);
deleteTestDirectory(testDir);
}
private static class StoppedClock implements Clock {

View File

@@ -1,10 +1,13 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.TestDatabaseConfig;
import org.briarproject.bramble.test.TestMessageFactory;
import java.io.IOException;
import java.sql.Connection;
@@ -20,7 +23,9 @@ public abstract class SingleDatabasePerformanceTest
extends DatabasePerformanceTest {
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
Clock clock);
MessageFactory messageFactory, Clock clock);
private SecretKey databaseKey = getSecretKey();
@Override
protected void benchmark(String name,
@@ -40,8 +45,9 @@ public abstract class SingleDatabasePerformanceTest
private Database<Connection> openDatabase() throws DbException {
Database<Connection> db = createDatabase(
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
db.open(getSecretKey(), null);
new TestDatabaseConfig(testDir, MAX_SIZE),
new TestMessageFactory(), new SystemClock());
db.open(databaseKey, null);
return db;
}

View File

@@ -34,11 +34,10 @@ import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_ID;
import static org.briarproject.bramble.api.properties.TransportPropertyManager.MAJOR_VERSION;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -187,8 +186,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
throws Exception {
Transaction txn = new Transaction(null, false);
GroupId contactGroupId = new GroupId(getRandomId());
long timestamp = 123456789;
Message message = getMessage(contactGroupId, timestamp);
Message message = getMessage(contactGroupId);
Metadata meta = new Metadata();
BdfDictionary metaDictionary = BdfDictionary.of(
new BdfEntry("transportId", "foo"),
@@ -229,8 +227,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
throws Exception {
Transaction txn = new Transaction(null, false);
GroupId contactGroupId = new GroupId(getRandomId());
long timestamp = 123456789;
Message message = getMessage(contactGroupId, timestamp);
Message message = getMessage(contactGroupId);
Metadata meta = new Metadata();
// Version 4 is being delivered
BdfDictionary metaDictionary = BdfDictionary.of(
@@ -267,8 +264,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
public void testDeletesObsoleteUpdateWhenDelivered() throws Exception {
Transaction txn = new Transaction(null, false);
GroupId contactGroupId = new GroupId(getRandomId());
long timestamp = 123456789;
Message message = getMessage(contactGroupId, timestamp);
Message message = getMessage(contactGroupId);
Metadata meta = new Metadata();
// Version 3 is being delivered
BdfDictionary metaDictionary = BdfDictionary.of(
@@ -619,12 +615,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
true, active);
}
private Message getMessage(GroupId g, long timestamp) {
MessageId messageId = new MessageId(getRandomId());
byte[] raw = getRandomBytes(MAX_MESSAGE_BODY_LENGTH);
return new Message(messageId, g, timestamp, raw);
}
private void expectGetLocalProperties(Transaction txn) throws Exception {
Map<MessageId, BdfDictionary> messageMetadata = new LinkedHashMap<>();
// The latest update for transport "foo" should be returned
@@ -664,9 +654,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
private void expectStoreMessage(Transaction txn, GroupId g,
String transportId, BdfDictionary properties, long version,
boolean local, boolean shared) throws Exception {
long timestamp = 123456789;
BdfList body = BdfList.of(transportId, version, properties);
Message message = getMessage(g, timestamp);
Message message = getMessage(g);
long timestamp = message.getTimestamp();
BdfDictionary meta = BdfDictionary.of(
new BdfEntry("transportId", transportId),
new BdfEntry("version", version),

View File

@@ -5,6 +5,8 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.SyncRecordWriter;
import org.briarproject.bramble.api.transport.StreamWriter;
@@ -13,11 +15,11 @@ import org.briarproject.bramble.test.ImmediateExecutor;
import org.jmock.Expectations;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.Executor;
import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
@@ -32,7 +34,8 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
private final Executor dbExecutor = new ImmediateExecutor();
private final ContactId contactId = new ContactId(234);
private final MessageId messageId = new MessageId(getRandomId());
private final Message message = getMessage(new GroupId(getRandomId()));
private final MessageId messageId = message.getId();
@Test
public void testNothingToSend() throws Exception {
@@ -71,8 +74,7 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
@Test
public void testSomethingToSend() throws Exception {
Ack ack = new Ack(Collections.singletonList(messageId));
byte[] raw = new byte[1234];
Ack ack = new Ack(singletonList(messageId));
SimplexOutgoingSession session = new SimplexOutgoingSession(db,
dbExecutor, eventBus, contactId, MAX_LATENCY, streamWriter,
recordWriter);
@@ -97,10 +99,10 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
will(returnValue(msgTxn));
oneOf(db).generateBatch(with(msgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY));
will(returnValue(Arrays.asList(raw)));
will(returnValue(singletonList(message)));
oneOf(db).commitTransaction(msgTxn);
oneOf(db).endTransaction(msgTxn);
oneOf(recordWriter).writeMessage(raw);
oneOf(recordWriter).writeMessage(message);
// No more acks
oneOf(db).startTransaction(false);
will(returnValue(noAckTxn));

View File

@@ -108,8 +108,8 @@ public class SyncIntegrationTest extends BrambleTestCase {
streamWriter.getOutputStream());
recordWriter.writeAck(new Ack(messageIds));
recordWriter.writeMessage(message.getRaw());
recordWriter.writeMessage(message1.getRaw());
recordWriter.writeMessage(message);
recordWriter.writeMessage(message1);
recordWriter.writeOffer(new Offer(messageIds));
recordWriter.writeRequest(new Request(messageIds));
@@ -169,7 +169,7 @@ public class SyncIntegrationTest extends BrambleTestCase {
assertArrayEquals(m1.getGroupId().getBytes(),
m2.getGroupId().getBytes());
assertEquals(m1.getTimestamp(), m2.getTimestamp());
assertEquals(m1.getLength(), m2.getLength());
assertArrayEquals(m1.getRaw(), m2.getRaw());
assertEquals(m1.getRawLength(), m2.getRawLength());
assertArrayEquals(m1.getBody(), m2.getBody());
}
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.sync;
import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.Metadata;
@@ -13,7 +12,6 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.ValidationManager.IncomingMessageHook;
import org.briarproject.bramble.api.sync.ValidationManager.MessageValidator;
@@ -21,30 +19,31 @@ import org.briarproject.bramble.api.sync.ValidationManager.State;
import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.ImmediateExecutor;
import org.briarproject.bramble.util.ByteUtils;
import org.jmock.Expectations;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
import static org.briarproject.bramble.test.TestUtils.getClientId;
import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
public class ValidationManagerImplTest extends BrambleMockTestCase {
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
private final MessageFactory messageFactory =
context.mock(MessageFactory.class);
private final MessageValidator validator =
context.mock(MessageValidator.class);
private final IncomingMessageHook hook =
@@ -54,38 +53,26 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
private final Executor validationExecutor = new ImmediateExecutor();
private final ClientId clientId = getClientId();
private final int majorVersion = 123;
private final MessageId messageId = new MessageId(getRandomId());
private final MessageId messageId1 = new MessageId(getRandomId());
private final MessageId messageId2 = new MessageId(getRandomId());
private final Group group = getGroup(clientId, majorVersion);
private final GroupId groupId = group.getId();
private final long timestamp = System.currentTimeMillis();
private final byte[] raw = new byte[123];
private final Message message = new Message(messageId, groupId, timestamp,
raw);
private final Message message1 = new Message(messageId1, groupId, timestamp,
raw);
private final Message message2 = new Message(messageId2, groupId, timestamp,
raw);
private final Message message = getMessage(groupId);
private final Message message1 = getMessage(groupId);
private final Message message2 = getMessage(groupId);
private final MessageId messageId = message.getId();
private final MessageId messageId1 = message1.getId();
private final MessageId messageId2 = message2.getId();
private final Metadata metadata = new Metadata();
private final MessageContext validResult = new MessageContext(metadata);
private final ContactId contactId = new ContactId(234);
private final MessageContext validResultWithDependencies =
new MessageContext(metadata, Collections.singletonList(messageId1));
new MessageContext(metadata, singletonList(messageId1));
private ValidationManagerImpl vm;
public ValidationManagerImplTest() {
// Encode the messages
System.arraycopy(groupId.getBytes(), 0, raw, 0, UniqueId.LENGTH);
ByteUtils.writeUint64(timestamp, raw, UniqueId.LENGTH);
}
@Before
public void setUp() {
vm = new ValidationManagerImpl(db, dbExecutor, validationExecutor,
messageFactory);
vm = new ValidationManagerImpl(db, dbExecutor, validationExecutor);
vm.registerMessageValidator(clientId, majorVersion, validator);
vm.registerIncomingMessageHook(clientId, majorVersion, hook);
}
@@ -101,21 +88,21 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessagesToValidate(txn);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// deliverOutstandingMessages()
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getPendingMessages(txn1);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// shareOutstandingMessages()
oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).getMessagesToShare(txn2);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}});
@@ -145,9 +132,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Load the first raw message and group
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getRawMessage(txn1, messageId);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId, raw);
oneOf(db).getMessage(txn1, messageId);
will(returnValue(message));
oneOf(db).getGroup(txn1, groupId);
will(returnValue(group));
@@ -166,15 +151,13 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn2, messageId, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn2, messageId);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Load the second raw message and group
oneOf(db).startTransaction(true);
will(returnValue(txn3));
oneOf(db).getRawMessage(txn3, messageId1);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId1, raw);
oneOf(db).getMessage(txn3, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn3, groupId);
will(returnValue(group));
@@ -193,21 +176,21 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn4, messageId1);
// Recursively invalidate any dependents
oneOf(db).getMessageDependents(txn4, messageId1);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Get pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn5));
oneOf(db).getPendingMessages(txn5);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
// Get messages to share
oneOf(db).startTransaction(true);
will(returnValue(txn6));
oneOf(db).getMessagesToShare(txn6);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn6);
oneOf(db).endTransaction(txn6);
}});
@@ -228,14 +211,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessagesToValidate(txn);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Get pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getPendingMessages(txn1);
will(returnValue(Collections.singletonList(messageId)));
will(returnValue(singletonList(messageId)));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Check whether the message is ready to deliver
@@ -244,11 +227,9 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageState(txn2, messageId);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn2, messageId);
will(returnValue(Collections.singletonMap(messageId1, DELIVERED)));
will(returnValue(singletonMap(messageId1, DELIVERED)));
// Get the message and its metadata to deliver
oneOf(db).getRawMessage(txn2, messageId);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId, raw);
oneOf(db).getMessage(txn2, messageId);
will(returnValue(message));
oneOf(db).getGroup(txn2, groupId);
will(returnValue(group));
@@ -260,7 +241,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn2, messageId, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn2, messageId);
will(returnValue(Collections.singletonMap(messageId2, PENDING)));
will(returnValue(singletonMap(messageId2, PENDING)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Check whether the dependent is ready to deliver
@@ -269,11 +250,9 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageState(txn3, messageId2);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn3, messageId2);
will(returnValue(Collections.singletonMap(messageId1, DELIVERED)));
will(returnValue(singletonMap(messageId1, DELIVERED)));
// Get the dependent and its metadata to deliver
oneOf(db).getRawMessage(txn3, messageId2);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId2, raw);
oneOf(db).getMessage(txn3, messageId2);
will(returnValue(message2));
oneOf(db).getGroup(txn3, groupId);
will(returnValue(group));
@@ -285,7 +264,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn3, messageId2, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn3, messageId2);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
@@ -293,7 +272,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).startTransaction(true);
will(returnValue(txn4));
oneOf(db).getMessagesToShare(txn4);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
}});
@@ -314,14 +293,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getMessagesToValidate(txn);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// No pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getPendingMessages(txn1);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
@@ -329,7 +308,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).getMessagesToShare(txn2);
will(returnValue(Collections.singletonList(messageId)));
will(returnValue(singletonList(messageId)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Share message and get dependencies
@@ -337,7 +316,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
will(returnValue(txn3));
oneOf(db).setMessageShared(txn3, messageId);
oneOf(db).getMessageDependencies(txn3, messageId);
will(returnValue(Collections.singletonMap(messageId2, DELIVERED)));
will(returnValue(singletonMap(messageId2, DELIVERED)));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Share dependency
@@ -345,7 +324,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
will(returnValue(txn4));
oneOf(db).setMessageShared(txn4, messageId2);
oneOf(db).getMessageDependencies(txn4, messageId2);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
}});
@@ -376,7 +355,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies());
oneOf(db).getMessageDependencies(txn1, messageId);
will(returnValue(Collections.singletonMap(messageId1, DELIVERED)));
will(returnValue(singletonMap(messageId1, DELIVERED)));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
// Deliver the message
oneOf(hook).incomingMessage(txn1, message, metadata);
@@ -384,7 +363,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn1, messageId, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
// Share message
oneOf(db).setMessageShared(txn1, messageId);
oneOf(db).commitTransaction(txn1);
@@ -394,7 +373,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
will(returnValue(txn2));
oneOf(db).setMessageShared(txn2, messageId1);
oneOf(db).getMessageDependencies(txn2, messageId1);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}});
@@ -423,16 +402,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Load the first raw message - *gasp* it's gone!
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getRawMessage(txn1, messageId);
oneOf(db).getMessage(txn1, messageId);
will(throwException(new NoSuchMessageException()));
never(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Load the second raw message and group
oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).getRawMessage(txn2, messageId1);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId1, raw);
oneOf(db).getMessage(txn2, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId);
will(returnValue(group));
@@ -451,21 +428,21 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn3, messageId1);
// Recursively invalidate dependents
oneOf(db).getMessageDependents(txn3, messageId1);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Get pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn4));
oneOf(db).getPendingMessages(txn4);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Get messages to share
oneOf(db).startTransaction(true);
will(returnValue(txn5));
oneOf(db).getMessagesToShare(txn5);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
}});
@@ -494,9 +471,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Load the first raw message
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).getRawMessage(txn1, messageId);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId, raw);
oneOf(db).getMessage(txn1, messageId);
will(returnValue(message));
// Load the group - *gasp* it's gone!
oneOf(db).getGroup(txn1, groupId);
@@ -506,9 +481,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Load the second raw message and group
oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).getRawMessage(txn2, messageId1);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId1, raw);
oneOf(db).getMessage(txn2, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId);
will(returnValue(group));
@@ -527,21 +500,21 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn3, messageId1);
// Recursively invalidate dependents
oneOf(db).getMessageDependents(txn3, messageId1);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Get pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn4));
oneOf(db).getPendingMessages(txn4);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Get messages to share
oneOf(db).startTransaction(true);
will(returnValue(txn5));
oneOf(db).getMessagesToShare(txn5);
will(returnValue(Collections.emptyList()));
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
}});
@@ -575,7 +548,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn1, messageId, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
}});
@@ -584,7 +557,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
}
@Test
public void testLocalMessagesAreNotValidatedWhenAdded() throws Exception {
public void testLocalMessagesAreNotValidatedWhenAdded() {
vm.eventOccurred(new MessageAddedEvent(message, null));
}
@@ -611,7 +584,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies());
oneOf(db).getMessageDependencies(txn1, messageId);
will(returnValue(Collections.singletonMap(messageId1, UNKNOWN)));
will(returnValue(singletonMap(messageId1, UNKNOWN)));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
oneOf(db).setMessageState(txn1, messageId, PENDING);
oneOf(db).commitTransaction(txn1);
@@ -644,7 +617,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies());
oneOf(db).getMessageDependencies(txn1, messageId);
will(returnValue(Collections.singletonMap(messageId1, DELIVERED)));
will(returnValue(singletonMap(messageId1, DELIVERED)));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
// Deliver the message
oneOf(hook).incomingMessage(txn1, message, metadata);
@@ -652,7 +625,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn1, messageId, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
}});
@@ -685,7 +658,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
validResultWithDependencies.getDependencies());
// Check for invalid dependencies
oneOf(db).getMessageDependencies(txn1, messageId);
will(returnValue(Collections.singletonMap(messageId1, INVALID)));
will(returnValue(singletonMap(messageId1, INVALID)));
// Invalidate message
oneOf(db).getMessageState(txn1, messageId);
will(returnValue(UNKNOWN));
@@ -694,7 +667,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn1, messageId);
// Recursively invalidate dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(Collections.singletonMap(messageId2, UNKNOWN)));
will(returnValue(singletonMap(messageId2, UNKNOWN)));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Invalidate dependent in a new transaction
@@ -706,7 +679,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessage(txn2, messageId2);
oneOf(db).deleteMessageMetadata(txn2, messageId2);
oneOf(db).getMessageDependents(txn2, messageId2);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}});
@@ -763,7 +736,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn2, messageId1);
// Message 1 has one dependent: 3
oneOf(db).getMessageDependents(txn2, messageId1);
will(returnValue(Collections.singletonMap(messageId3, PENDING)));
will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Invalidate message 2
@@ -776,7 +749,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn3, messageId2);
// Message 2 has one dependent: 3 (same dependent as 1)
oneOf(db).getMessageDependents(txn3, messageId2);
will(returnValue(Collections.singletonMap(messageId3, PENDING)));
will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Invalidate message 3 (via 1)
@@ -789,7 +762,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn4, messageId3);
// Message 3 has one dependent: 4
oneOf(db).getMessageDependents(txn4, messageId3);
will(returnValue(Collections.singletonMap(messageId4, PENDING)));
will(returnValue(singletonMap(messageId4, PENDING)));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Invalidate message 3 (again, via 2)
@@ -809,7 +782,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn6, messageId4);
// Message 4 has no dependents
oneOf(db).getMessageDependents(txn6, messageId4);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn6);
oneOf(db).endTransaction(txn6);
}});
@@ -819,12 +792,10 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
@Test
public void testPendingDependentsGetDelivered() throws Exception {
MessageId messageId3 = new MessageId(getRandomId());
MessageId messageId4 = new MessageId(getRandomId());
Message message3 = new Message(messageId3, groupId, timestamp,
raw);
Message message4 = new Message(messageId4, groupId, timestamp,
raw);
Message message3 = getMessage(groupId);
Message message4 = getMessage(groupId);
MessageId messageId3 = message3.getId();
MessageId messageId4 = message4.getId();
Map<MessageId, State> twoDependents = new LinkedHashMap<>();
twoDependents.put(messageId1, PENDING);
twoDependents.put(messageId2, PENDING);
@@ -869,11 +840,9 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageState(txn2, messageId1);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn2, messageId1);
will(returnValue(Collections.singletonMap(messageId, DELIVERED)));
will(returnValue(singletonMap(messageId, DELIVERED)));
// Get message 1 and its metadata
oneOf(db).getRawMessage(txn2, messageId1);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId1, raw);
oneOf(db).getMessage(txn2, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId);
will(returnValue(group));
@@ -885,7 +854,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn2, messageId1, DELIVERED);
// Message 1 has one pending dependent: 3
oneOf(db).getMessageDependents(txn2, messageId1);
will(returnValue(Collections.singletonMap(messageId3, PENDING)));
will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Check whether message 2 is ready to be delivered
@@ -894,11 +863,9 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageState(txn3, messageId2);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn3, messageId2);
will(returnValue(Collections.singletonMap(messageId, DELIVERED)));
will(returnValue(singletonMap(messageId, DELIVERED)));
// Get message 2 and its metadata
oneOf(db).getRawMessage(txn3, messageId2);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId2, raw);
oneOf(db).getMessage(txn3, messageId2);
will(returnValue(message2));
oneOf(db).getGroup(txn3, groupId);
will(returnValue(group));
@@ -910,7 +877,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn3, messageId2, DELIVERED);
// Message 2 has one pending dependent: 3 (same dependent as 1)
oneOf(db).getMessageDependents(txn3, messageId2);
will(returnValue(Collections.singletonMap(messageId3, PENDING)));
will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Check whether message 3 is ready to be delivered (via 1)
@@ -921,9 +888,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn4, messageId3);
will(returnValue(twoDependencies));
// Get message 3 and its metadata
oneOf(db).getRawMessage(txn4, messageId3);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId3, raw);
oneOf(db).getMessage(txn4, messageId3);
will(returnValue(message3));
oneOf(db).getGroup(txn4, groupId);
will(returnValue(group));
@@ -934,7 +899,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn4, messageId3, DELIVERED);
// Message 3 has one pending dependent: 4
oneOf(db).getMessageDependents(txn4, messageId3);
will(returnValue(Collections.singletonMap(messageId4, PENDING)));
will(returnValue(singletonMap(messageId4, PENDING)));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Check whether message 3 is ready to be delivered (again, via 2)
@@ -950,11 +915,9 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageState(txn6, messageId4);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn6, messageId4);
will(returnValue(Collections.singletonMap(messageId3, DELIVERED)));
will(returnValue(singletonMap(messageId3, DELIVERED)));
// Get message 4 and its metadata
oneOf(db).getRawMessage(txn6, messageId4);
will(returnValue(raw));
oneOf(messageFactory).createMessage(messageId4, raw);
oneOf(db).getMessage(txn6, messageId4);
will(returnValue(message4));
oneOf(db).getGroup(txn6, groupId);
will(returnValue(group));
@@ -966,7 +929,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn6, messageId4, DELIVERED);
// Message 4 has no pending dependents
oneOf(db).getMessageDependents(txn6, messageId4);
will(returnValue(Collections.emptyMap()));
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn6);
oneOf(db).endTransaction(txn6);
}});
@@ -1004,7 +967,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).setMessageState(txn1, messageId, DELIVERED);
// Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(Collections.singletonMap(messageId1, PENDING)));
will(returnValue(singletonMap(messageId1, PENDING)));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Check whether the pending dependent is ready to be delivered

View File

@@ -0,0 +1,30 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
@NotNullByDefault
public class TestMessageFactory implements MessageFactory {
@Override
public Message createMessage(GroupId g, long timestamp, byte[] body) {
throw new UnsupportedOperationException();
}
@Override
public Message createMessage(byte[] raw) {
throw new UnsupportedOperationException();
}
@Override
public byte[] getRawMessage(Message m) {
byte[] body = m.getBody();
byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length];
System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length);
return raw;
}
}

View File

@@ -30,7 +30,6 @@ public abstract class ValidatorTestCase extends BrambleMockTestCase {
protected final Message message = getMessage(groupId);
protected final MessageId messageId = message.getId();
protected final long timestamp = message.getTimestamp();
protected final byte[] raw = message.getRaw();
protected final Author author = getAuthor();
protected final BdfList authorList = BdfList.of(
author.getFormatVersion(),

View File

@@ -1,3 +0,0 @@
bin
build
.settings

4
bramble-java/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
bin
build
.settings
src/main/resources/*.zip

View File

@@ -7,11 +7,16 @@ apply plugin: 'idea'
apply plugin: 'witness'
apply from: 'witness.gradle'
configurations {
tor
}
dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
implementation fileTree(dir: 'libs', include: '*.jar')
implementation 'net.java.dev.jna:jna:4.4.0'
implementation 'net.java.dev.jna:jna-platform:4.4.0'
tor 'org.briarproject:tor:0.2.9.16@zip'
apt 'com.google.dagger:dagger-compiler:2.0.2'
@@ -23,6 +28,15 @@ dependencies {
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
testApt 'com.google.dagger:dagger-compiler:2.0.2'
}
project.afterEvaluate {
copy {
from configurations.tor.collect { zipTree(it) }
into 'src/main/resources'
}
}
tasks.withType(Test) {

View File

@@ -0,0 +1,16 @@
package org.briarproject.bramble;
import org.briarproject.bramble.network.JavaNetworkModule;
import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.system.JavaSystemModule;
import dagger.Module;
@Module(includes = {
JavaNetworkModule.class,
JavaSystemModule.class,
CircumventionModule.class
})
public class BrambleJavaModule {
}

View File

@@ -0,0 +1,71 @@
package org.briarproject.bramble.network;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.network.NetworkStatus;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.logging.Logger;
import javax.inject.Inject;
import static java.net.NetworkInterface.getNetworkInterfaces;
import static java.util.Collections.list;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class JavaNetworkManager implements NetworkManager, Service {
private static final Logger LOG =
Logger.getLogger(JavaNetworkManager.class.getName());
private final EventBus eventBus;
@Inject
JavaNetworkManager(EventBus eventBus) {
this.eventBus = eventBus;
}
@Override
public void startService() {
eventBus.broadcast(new NetworkStatusEvent(getNetworkStatus()));
}
@Override
public void stopService() {
}
@Override
public NetworkStatus getNetworkStatus() {
boolean connected = false;
try {
Enumeration<NetworkInterface> interfaces = getNetworkInterfaces();
if (interfaces != null) {
for (NetworkInterface i : list(interfaces)) {
if (i.isLoopback()) continue;
if (i.isUp() && i.getInetAddresses().hasMoreElements()) {
if (LOG.isLoggable(INFO)) {
LOG.info("Interface " + i.getDisplayName() +
" is up with at least one address.");
}
connected = true;
break;
}
}
}
} catch (SocketException e) {
logException(LOG, WARNING, e);
}
return new NetworkStatus(connected, false);
}
}

View File

@@ -0,0 +1,21 @@
package org.briarproject.bramble.network;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.network.NetworkManager;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class JavaNetworkModule {
@Provides
@Singleton
NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,
JavaNetworkManager networkManager) {
lifecycleManager.registerService(networkManager);
return networkManager;
}
}

Some files were not shown because too many files have changed in this diff Show More