├── lib
└── ios
│ └── Cartfile
├── test
├── www
│ ├── jxcore
│ │ ├── .gitignore
│ │ ├── lib
│ │ │ ├── utils
│ │ │ │ ├── Promise.js
│ │ │ │ ├── process.js
│ │ │ │ └── asserts.js
│ │ │ ├── parsePlatformArg.js
│ │ │ ├── sinonTest.js
│ │ │ ├── testLogger.js
│ │ │ ├── thaliTape.js
│ │ │ ├── MockMobile.js
│ │ │ ├── testLoader.js
│ │ │ └── CoordinatedTape.js
│ │ ├── bv_tests
│ │ │ ├── disabled
│ │ │ │ ├── pkcs12folderbad
│ │ │ │ │ └── pkcs12.pfx
│ │ │ │ ├── CITestClass.js
│ │ │ │ ├── TestThaliMobileNative
│ │ │ │ │ ├── QuitSignal.js
│ │ │ │ │ └── Message.js
│ │ │ │ ├── IdentityExchange
│ │ │ │ │ ├── identityExchangeTestUtils.js
│ │ │ │ │ ├── testIdentityExchangeUtils.js
│ │ │ │ │ ├── testConnectionTable.js
│ │ │ │ │ └── testLiveIdentityExchange.js
│ │ │ │ ├── mockmobile.js
│ │ │ │ ├── testMultiplex.js
│ │ │ │ ├── testThaliManagerStopCoordinated.js
│ │ │ │ └── testThaliCryptoManager.js
│ │ │ ├── testUsn.js
│ │ │ ├── testNativeMethod.js
│ │ │ └── testPouchDBGenerator.js
│ │ ├── cleanme.sh
│ │ ├── meta_tests
│ │ │ ├── disabled
│ │ │ │ ├── testPerfTestFramework.js
│ │ │ │ └── testPerfTestFrameworkClient.js
│ │ │ ├── testTestUtils.js
│ │ │ ├── testInstall.js
│ │ │ ├── testCanBeSkipped.js
│ │ │ ├── testPouchDBAgent.js
│ │ │ ├── testResultsProcessor.js
│ │ │ ├── testSync.js
│ │ │ └── testTestSendData.js
│ │ ├── public
│ │ │ └── index.css
│ │ ├── views
│ │ │ └── ejs
│ │ │ │ └── index.ejs
│ │ ├── config.js
│ │ ├── perf_tests
│ │ │ ├── disabled
│ │ │ │ └── testNewFindPeers.js
│ │ │ ├── ReConnectTCPServer.js
│ │ │ ├── SendDataTCPServer.js
│ │ │ └── BluetoothConnectionLimits.js
│ │ ├── package.json
│ │ ├── readme.md
│ │ ├── UnitTest_app.js
│ │ ├── PerfTest_app.js
│ │ ├── CITestMode.js
│ │ └── runTests.js
│ ├── index.html
│ └── js
│ │ └── thali_main.js
└── TestServer
│ ├── utils
│ ├── Promise.js
│ ├── process.js
│ ├── ThaliLogger.js
│ └── asserts.js
│ ├── config
│ ├── Socket.js
│ ├── TestDevice.js
│ └── UnitTest.js
│ ├── package.json
│ ├── generateServerAddress.js
│ ├── TestPerfTestConfig.js
│ ├── PerfTestConfig.js
│ ├── TestPerfTestConfig2.js
│ ├── index.js
│ ├── IPAddressToFile.js
│ └── HttpServer.js
├── thali
├── install
│ ├── utils
│ │ ├── Promise.js
│ │ ├── process.js
│ │ └── child_process.js
│ ├── SSDPReplacer
│ │ ├── plugin.xml
│ │ ├── package.json
│ │ └── process.js
│ ├── postPublishThaliCordovaPlugin.js
│ ├── package.json
│ ├── prePublishThaliCordovaPlugin.js
│ ├── include.sh
│ │ └── build-dep.sh
│ ├── setUpDesktop.sh
│ ├── cordova-hooks
│ │ └── ios
│ │ │ ├── before_plugin_install.js
│ │ │ └── after_plugin_install.js
│ └── ios
│ │ ├── build-ci-no-tests.xcconfig
│ │ └── build-ci.xcconfig
├── conf.json
├── NextGeneration
│ ├── utils
│ │ ├── leveldownMobileAdapter.js
│ │ ├── platform.js
│ │ ├── usn.js
│ │ ├── common.js
│ │ └── pouchDBCheckpointsPlugin.js
│ ├── security
│ │ └── hkdf.js
│ ├── identityExchange
│ │ └── connectionTable.js
│ ├── thaliConfig.js
│ ├── notification
│ │ └── thaliPskMapCache.js
│ └── makeIntoCloseAllServer.js
├── validations.js
├── installCordovaPlugin.js
├── ThaliLogger.js
├── package.json
├── thalicryptomanager.js
└── thaliemitter.js
├── src
├── android
│ ├── test
│ │ ├── io
│ │ │ └── jxcore
│ │ │ │ └── node
│ │ │ │ ├── JXcoreThaliCallbackMock.java
│ │ │ │ ├── InputStreamMock.java
│ │ │ │ ├── OutputStreamMock.java
│ │ │ │ ├── CITestClass.java
│ │ │ │ ├── SocketThreadBaseMock.java
│ │ │ │ ├── ListenerMock.java
│ │ │ │ ├── IncomingSocketThreadMock.java
│ │ │ │ └── OutgoingSocketThreadMock.java
│ │ ├── com
│ │ │ └── test
│ │ │ │ └── thalitest
│ │ │ │ └── ThaliTestSuite.java
│ │ └── build-extras.gradle
│ ├── java
│ │ ├── build-extras.gradle
│ │ └── io
│ │ │ └── jxcore
│ │ │ └── node
│ │ │ ├── ConnectionData.java
│ │ │ ├── WifiLocker.java
│ │ │ ├── SurroundingStateObserver.java
│ │ │ ├── JXcoreThaliCallback.java
│ │ │ └── ListenerOrIncomingConnection.java
│ ├── JXcore.gradle
│ └── project.properties
└── ios
│ └── Testing
│ ├── TestRunnerProtocol.swift
│ └── AppContext+TestRuner.swift
├── mobile_test.json
├── appveyor.yml
├── .editorconfig
├── .github
└── ISSUE_TEMPLATE.md
├── LICENSE
├── .gitignore
├── www
└── android
│ └── thaliPermissions.js
└── .eslintrc.js
/lib/ios/Cartfile:
--------------------------------------------------------------------------------
1 | github "thaliproject/thali-ios" "master"
2 |
--------------------------------------------------------------------------------
/test/www/jxcore/.gitignore:
--------------------------------------------------------------------------------
1 | /customPouchDir/
2 | /customPouchServerDir/
3 |
--------------------------------------------------------------------------------
/thali/install/utils/Promise.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Promise = require('bluebird');
4 |
5 | module.exports = Promise;
6 |
--------------------------------------------------------------------------------
/test/TestServer/utils/Promise.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Promise = require('bluebird');
4 |
5 | module.exports = Promise;
6 |
--------------------------------------------------------------------------------
/test/www/jxcore/lib/utils/Promise.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Promise = require('bluebird');
4 |
5 | module.exports = Promise;
6 |
--------------------------------------------------------------------------------
/test/TestServer/config/Socket.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | retryCount: 120,
5 | retryTimeout: 1 * 1000
6 | };
7 |
--------------------------------------------------------------------------------
/src/android/test/io/jxcore/node/JXcoreThaliCallbackMock.java:
--------------------------------------------------------------------------------
1 | package io.jxcore.node;
2 |
3 | public class JXcoreThaliCallbackMock extends JXcoreThaliCallback{
4 | }
5 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/disabled/pkcs12folderbad/pkcs12.pfx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thaliproject/Thali_CordovaPlugin/HEAD/test/www/jxcore/bv_tests/disabled/pkcs12folderbad/pkcs12.pfx
--------------------------------------------------------------------------------
/test/TestServer/config/TestDevice.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | setupTimeout: 1 * 60 * 1000,
5 | testTimeout: 3 * 60 * 1000,
6 | teardownTimeout: 1 * 60 * 1000
7 | };
8 |
--------------------------------------------------------------------------------
/thali/conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["plugins/markdown"],
3 | "opts": { "recurse": true },
4 | "source": {
5 | "exclude": [ "node_modules", "install"],
6 | "includePattern": ".+\\.js?$"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/android/java/build-extras.gradle:
--------------------------------------------------------------------------------
1 | ext.postBuildExtras = {
2 | android {
3 | compileOptions {
4 | sourceCompatibility JavaVersion.VERSION_1_6
5 | targetCompatibility JavaVersion.VERSION_1_6
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/android/test/com/test/thalitest/ThaliTestSuite.java:
--------------------------------------------------------------------------------
1 | package com.test.thalitest;
2 |
3 | import org.junit.runner.RunWith;
4 | import org.junit.runners.Suite;
5 |
6 | @RunWith(Suite.class)
7 | @Suite.SuiteClasses({
8 | })
9 |
10 | public class ThaliTestSuite {
11 | }
12 |
--------------------------------------------------------------------------------
/thali/install/SSDPReplacer/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SSDP replacer hook
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/android/JXcore.gradle:
--------------------------------------------------------------------------------
1 | repositories {
2 | mavenLocal()
3 | maven {
4 | url "https://bintray.com/artifact/download/thali/Thali"
5 | }
6 | }
7 |
8 | dependencies {
9 | compile(group: 'org.thaliproject.p2p.btconnectorlib', name: 'btconnectorlib2', version: btconnectorlib2Version, ext: 'aar')
10 | }
11 |
--------------------------------------------------------------------------------
/test/www/jxcore/cleanme.sh:
--------------------------------------------------------------------------------
1 | find ./node_modules -name \*.o -exec rm {} \;
2 | find ./node_modules -name \*.a -exec rm {} \;
3 | find ./node_modules -name \*.c -exec rm {} \;
4 | find ./node_modules -name \*.cc -exec rm {} \;
5 | find ./node_modules -name \*.d -exec rm {} \;
6 | find ./node_modules -name \*.gif -exec rm {} \;
7 | find ./node_modules -name \*.html -exec rm {} \;
8 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/disabled/CITestClass.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var tape = require('../lib/thaliTape');
4 | var test = tape({
5 |
6 | setup: function (t) {
7 | t.end();
8 | },
9 | teardown: function (t) {
10 | t.end();
11 | }
12 | });
13 |
14 | test('The test that always pass', function (t) {
15 | t.ok(true);
16 | t.end();
17 | });
18 |
--------------------------------------------------------------------------------
/src/ios/Testing/TestRunnerProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestRunnerProtocol.swift
3 | // Thali
4 | //
5 | // Copyright (C) Microsoft. All rights reserved.
6 | // Licensed under the MIT license.
7 | // See LICENSE.txt file in the project root for full license information.
8 | //
9 |
10 | @objc
11 | protocol TestRunnerProtocol {
12 |
13 | func runNativeTests() -> String
14 | }
15 |
--------------------------------------------------------------------------------
/mobile_test.json:
--------------------------------------------------------------------------------
1 | {
2 | "build": "./build.sh",
3 | "binary_path": {
4 | "ios": "ThaliTest.app",
5 | "android": "android-release-unsigned.apk"
6 | },
7 | "target": "all",
8 | "priority": "normal",
9 | "csname": {
10 | "android": "com.thaliproject.thalitest",
11 | "ios": "com.thaliproject.thalitest"
12 | },
13 | "timeout": 1400,
14 | "serverScript": "test/TestServer/"
15 | }
16 |
--------------------------------------------------------------------------------
/test/TestServer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "thali-test-server",
3 | "version": "0.0.1",
4 | "description": "Thali Test Server App - to be run under CI",
5 | "dependencies": {
6 | "express": "4.13.3",
7 | "fs-extra-promise": "0.2.0",
8 | "bluebird": "3.4.6",
9 | "socket.io": "1.4.8",
10 | "winston": "2.2.0",
11 | "object-assign": "4.1.0",
12 | "node-uuid": "1.4.7"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/TestServer/generateServerAddress.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var iPAddressToFile = require('./IPAddressToFile');
4 |
5 | /**
6 | * A quick little command line utility to allow us to generate the server config
7 | * before creating a Cordova test project.
8 | */
9 |
10 | iPAddressToFile(process.argv[2]).then(function () {
11 | process.exit(0);
12 | }).catch(function (err) {
13 | console.log(err);
14 | process.exit(1);
15 | });
16 |
--------------------------------------------------------------------------------
/thali/install/SSDPReplacer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SSDPReplacer",
3 | "version": "0.0.1",
4 | "description": "Used to replace hardcoded SSDP values",
5 | "main": "hook.js",
6 | "dependencies": {
7 | "bluebird": "3.4.6",
8 | "end-with": "1.0.2",
9 | "findit": "2.0.0",
10 | "randomstring": "1.1.5",
11 | "node-uuid": "1.4.7",
12 | "fs-extra-promise": "0.2.0"
13 | },
14 | "author": "Microsoft",
15 | "license": "MIT"
16 | }
17 |
--------------------------------------------------------------------------------
/src/android/test/io/jxcore/node/InputStreamMock.java:
--------------------------------------------------------------------------------
1 | package io.jxcore.node;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 |
6 | public class InputStreamMock extends InputStream {
7 | public boolean isClosed = false;
8 |
9 | @Override
10 | public int read() throws IOException {
11 | return 0;
12 | }
13 |
14 | @Override
15 | public void close() throws IOException {
16 | isClosed = true;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/android/test/io/jxcore/node/OutputStreamMock.java:
--------------------------------------------------------------------------------
1 | package io.jxcore.node;
2 |
3 | import java.io.IOException;
4 | import java.io.OutputStream;
5 |
6 | public class OutputStreamMock extends OutputStream {
7 | public boolean isClosed = false;
8 |
9 | @Override
10 | public void write(int oneByte) throws IOException {
11 |
12 | }
13 |
14 | @Override
15 | public void close() throws IOException {
16 | isClosed = true;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | os: Visual Studio 2015
2 | clone_folder: C:\Thali_CordovaPlugin
3 | install:
4 | - npm install -g cordova@6.1.0
5 | - appveyor DownloadFile http://jxcore.azureedge.net/jxcore/0312/release/jx_win64v8.zip
6 | - jar xf jx_win64v8.zip
7 | - SET PATH=%PATH%;C:\Thali_CordovaPlugin\jx_win64v8
8 | - SET NVM_NODEJS_ORG_MIRROR=https://jxcore.azureedge.net
9 | - SET JX_NPM_JXB=jxb311
10 | build_script:
11 | - '"C:\Program Files\Git\bin\sh.exe" --login -c "./build.sh"'
12 | test: off
13 |
--------------------------------------------------------------------------------
/src/android/test/io/jxcore/node/CITestClass.java:
--------------------------------------------------------------------------------
1 | package io.jxcore.node;
2 |
3 | import org.junit.Test;
4 | import static org.hamcrest.CoreMatchers.is;
5 | import static org.hamcrest.MatcherAssert.assertThat;
6 | import static org.hamcrest.core.IsNull.notNullValue;
7 |
8 | public class CITestClass {
9 | @Test
10 | public void test() throws Exception {
11 | String str = "TestingString";
12 | assertThat("String is not null", str, is(notNullValue()));
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/TestServer/TestPerfTestConfig.js:
--------------------------------------------------------------------------------
1 | var config = {
2 |
3 | userConfig : {
4 | "ios" : {
5 | "startTimeout": 3000,
6 | },
7 | "android" : {
8 | "startTimeout": 3000
9 | }
10 | },
11 |
12 | testConfig : [
13 | {
14 | "name": "testSendData.js",
15 | "serverTimeout": 15000,
16 | "timeout": 1000000,
17 | "rounds": 1,
18 | "dataTimeout": 10000,
19 | "dataAmount": 100000,
20 | "conReTryTimeout": 5000,
21 | "conReTryCount": 5
22 | }
23 | ]
24 | };
25 |
26 | module.exports = config;
27 |
--------------------------------------------------------------------------------
/src/android/test/io/jxcore/node/SocketThreadBaseMock.java:
--------------------------------------------------------------------------------
1 | package io.jxcore.node;
2 |
3 | import android.bluetooth.BluetoothSocket;
4 |
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.io.OutputStream;
8 |
9 | public class SocketThreadBaseMock extends SocketThreadBase {
10 | public SocketThreadBaseMock(BluetoothSocket bluetoothSocket, Listener listener,
11 | InputStream inputStream, OutputStream outputStream)
12 | throws IOException {
13 | super(bluetoothSocket, listener, inputStream, outputStream);
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/test/www/jxcore/lib/parsePlatformArg.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function () {
4 | var platform = require('thali/NextGeneration/utils/platform');
5 | var argv = require('minimist')(process.argv.slice(2));
6 | if (!argv.platform) {
7 | return null;
8 | }
9 | switch (argv.platform) {
10 | case platform.names.IOS:
11 | case platform.names.ANDROID: {
12 | return argv.platform;
13 | }
14 | default: {
15 | throw new Error('Unrecognized platform: ' + argv.platform + '. ' +
16 | 'Available platforms: ' + JSON.stringify(platform.names));
17 | }
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/thali/install/utils/process.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | process
5 | .on('SIGINT', function () {
6 | console.error('got \'SIGINT\', terminating');
7 | process.exit(130); // Ctrl-C std exit code
8 | })
9 | .on('uncaughtException', function (error) {
10 | console.error(
11 | 'uncaught exception, error: \'%s\', stack: \'%s\'',
12 | error.toString(), error.stack
13 | );
14 | process.exit(1);
15 | })
16 | .on('unhandledRejection', function (error, p) {
17 | console.error(
18 | 'uncaught promise rejection, error: \'%s\', stack: \'%s\'',
19 | error.toString(), error.stack
20 | );
21 | process.exit(2);
22 | });
23 |
--------------------------------------------------------------------------------
/src/android/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-21
15 |
--------------------------------------------------------------------------------
/thali/install/SSDPReplacer/process.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | process
5 | .on('SIGINT', function () {
6 | console.error('got \'SIGINT\', terminating');
7 | process.exit(130); // Ctrl-C std exit code
8 | })
9 | .on('uncaughtException', function (error) {
10 | console.error(
11 | 'uncaught exception, error: \'%s\', stack: \'%s\'',
12 | error.toString(), error.stack
13 | );
14 | process.exit(1);
15 | })
16 | .on('unhandledRejection', function (error, p) {
17 | console.error(
18 | 'uncaught promise rejection, error: \'%s\', stack: \'%s\'',
19 | error.toString(), error.stack
20 | );
21 | process.exit(2);
22 | });
23 |
--------------------------------------------------------------------------------
/thali/NextGeneration/utils/leveldownMobileAdapter.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var CoreLeveldownAdapter = require('pouchdb-adapter-leveldb-core');
4 |
5 | function LeveldownMobileAdapter(opts, callback) {
6 | if (!opts.db) {
7 | return callback(new Error('leveldown is not defined'));
8 | }
9 |
10 | CoreLeveldownAdapter.call(this, opts, callback);
11 | }
12 |
13 | // overrides for normal LevelDB behavior on Node
14 | LeveldownMobileAdapter.valid = function () {
15 | return true;
16 | };
17 | LeveldownMobileAdapter.use_prefix = false;
18 |
19 | module.exports = function (PouchDB) {
20 | PouchDB.adapter('leveldb-mobile', LeveldownMobileAdapter, true);
21 | };
22 |
--------------------------------------------------------------------------------
/thali/install/postPublishThaliCordovaPlugin.js:
--------------------------------------------------------------------------------
1 | // Copyright (C) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE.txt file in the project root
3 | // for full license information.
4 | //
5 |
6 | 'use strict';
7 |
8 | var fs = require('fs');
9 | var path = require('path');
10 |
11 | // We don't want to checkin the readme.md in the local directory
12 | // since it is just a copy of the one in the parent directory
13 | // so we clean it up after publishing so we don't accidentally
14 | // check it in.
15 |
16 | var readMeFileName = 'readme.md';
17 | var localReadMe = path.join(__dirname, '..', readMeFileName);
18 | fs.unlinkSync(localReadMe);
19 | process.exit(0);
20 |
--------------------------------------------------------------------------------
/test/TestServer/utils/process.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var logger = require('./ThaliLogger')('TestServerProcess');
4 |
5 |
6 | process
7 | .on('SIGINT', function () {
8 | logger.error('got \'SIGINT\', terminating');
9 | process.exit(130); // Ctrl-C std exit code
10 | })
11 | .on('uncaughtException', function (error) {
12 | logger.error(
13 | 'uncaught exception, error: \'%s\', stack: \'%s\'',
14 | error.toString(), error.stack
15 | );
16 | process.exit(1);
17 | })
18 | .on('unhandledRejection', function (error, p) {
19 | logger.error(
20 | 'uncaught promise rejection, error: \'%s\', stack: \'%s\'',
21 | error.toString(), error.stack
22 | );
23 | process.exit(2);
24 | });
25 |
--------------------------------------------------------------------------------
/test/TestServer/config/UnitTest.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Default amount of devices required to run tests.
4 |
5 | module.exports = {
6 | devices: {
7 | // This is a list of required platforms.
8 | // All required platform should have minDevices entry.
9 | // So all required platforms should be listed in desired platform list.
10 | ios: -1,
11 | android: -1,
12 | desktop: -1
13 | },
14 | minDevices: {
15 | // This is a list of desired platforms.
16 | ios: 3,
17 | android: 3,
18 | desktop: 3
19 | },
20 | // if 'devices[platform]' is -1 we wont limit the amount of devices.
21 | // We will wait some amount of time before tests.
22 | waiting_for_devices_timeout: 5 * 1000
23 | };
24 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 | end_of_line = lf
10 | charset = utf-8
11 | trim_trailing_whitespace = true
12 | insert_final_newline = true
13 | indent_style = space
14 | indent_size = 2
15 |
16 | [*.java]
17 | indent_style = space
18 | indent_size = 4
19 |
20 | [*.js]
21 | indent_style = space
22 | indent_size = 2
23 |
24 | [*.hbs]
25 | indent_style = space
26 | indent_size = 2
27 |
28 | [*.css]
29 | indent_style = space
30 | indent_size = 2
31 |
32 | [*.html]
33 | indent_style = space
34 | indent_size = 2
35 |
36 | [*.{diff,md}]
37 | trim_trailing_whitespace = false
38 |
--------------------------------------------------------------------------------
/test/www/jxcore/lib/utils/process.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var logger = require('thali/ThaliLogger')('TestsProcess');
4 |
5 |
6 | process
7 | .on('SIGINT', function () {
8 | logger.error('got \'SIGINT\', terminating');
9 | process.exit(130); // Ctrl-C std exit code
10 | })
11 | .on('uncaughtException', function (error) {
12 | logger.error(
13 | 'uncaught exception, error: \'%s\', stack: \'%s\'',
14 | error.toString(), error.stack
15 | );
16 | logger.error('****TEST_LOGGER:[PROCESS_ON_EXIT_FAILED]****');
17 | process.exit(1);
18 | })
19 | .on('unhandledRejection', function (error) {
20 | logger.error(
21 | 'uncaught promise rejection, error: \'%s\', stack: \'%s\'',
22 | error.toString(), error.stack
23 | );
24 | logger.error('****TEST_LOGGER:[PROCESS_ON_EXIT_FAILED]****');
25 | process.exit(2);
26 | });
27 |
--------------------------------------------------------------------------------
/src/android/test/io/jxcore/node/ListenerMock.java:
--------------------------------------------------------------------------------
1 | package io.jxcore.node;
2 |
3 | public class ListenerMock implements SocketThreadBase.Listener {
4 |
5 | @Override
6 | public void onListeningForIncomingConnections(int portNumber) {
7 |
8 | }
9 |
10 | @Override
11 | public void onDataTransferred(int numberOfBytes) {
12 |
13 | }
14 |
15 | @Override
16 | public void onDisconnected(SocketThreadBase who, String errorMessage) {
17 |
18 | }
19 |
20 | @Override
21 | public void onDisconnected(SocketThreadBase who, Exception exception) {
22 |
23 | }
24 |
25 | @Override
26 | public void onTransferError(SocketThreadBase who, String errorMessage) {
27 |
28 | }
29 |
30 | @Override
31 | public void onDone(SocketThreadBase who, boolean threadDoneWasSending) {
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/test/TestServer/PerfTestConfig.js:
--------------------------------------------------------------------------------
1 | var config = {
2 |
3 | userConfig : {
4 | "ios" : {
5 | "startTimeout": 120000
6 | },
7 | "android" : {
8 | "startTimeout": 120000
9 | }
10 | },
11 |
12 | testConfig : [
13 | {
14 | "name": "testFindPeers.js",
15 | "serverTimeout": 120000,
16 | "timeout": 100000,
17 | "rounds": 1,
18 | "dataTimeout": 10000,
19 | "dataAmount": 100000,
20 | "conReTryTimeout": 5000,
21 | "conReTryCount": 5
22 | },
23 | {
24 | "name": "testSendData.js",
25 | "serverTimeout": 120000,
26 | "timeout": 100000,
27 | "rounds": 1,
28 | "dataTimeout": 20000,
29 | "dataAmount": 100000,
30 | "conReTryTimeout": 5000,
31 | "conReTryCount": 5
32 | }
33 | ]
34 | };
35 |
36 | module.exports = config;
37 |
--------------------------------------------------------------------------------
/test/TestServer/TestPerfTestConfig2.js:
--------------------------------------------------------------------------------
1 | var config = {
2 |
3 | userConfig : {
4 | "ios" : {
5 | "startTimeout": 3000,
6 | },
7 | "android" : {
8 | "startTimeout": 3000
9 | }
10 | },
11 |
12 | testConfig : [
13 | {
14 | "name": "testSendData.js",
15 | "serverTimeout": 15000,
16 | "timeout": 1000000,
17 | "rounds": 1,
18 | "dataTimeout": 10000,
19 | "dataAmount": 100000,
20 | "conReTryTimeout": 5000,
21 | "conReTryCount": 5
22 | },
23 | {
24 | "name": "testFindPeers.js",
25 | "serverTimeout": 15000,
26 | "timeout": 1000000,
27 | "rounds": 1,
28 | "dataTimeout": 10000,
29 | "dataAmount": 100000,
30 | "conReTryTimeout": 5000,
31 | "conReTryCount": 5
32 | }
33 | ]
34 | };
35 |
36 | module.exports = config;
37 |
--------------------------------------------------------------------------------
/test/www/jxcore/lib/sinonTest.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var sinon = require('sinon');
4 |
5 | function sinonTest (callback) {
6 | return function (t) {
7 | var config = sinon.getConfig(sinon.config);
8 | config.injectInto = config.injectIntoThis && this || config.injectInto;
9 | var sandbox = sinon.sandbox.create(config);
10 | var args = Array.prototype.slice.call(arguments);
11 | var ok;
12 |
13 | if (typeof t.end === 'function') {
14 | t.on('result', function(res) {
15 | ok = res.ok;
16 | });
17 |
18 | t.on('end', function() {
19 | if (!ok) {
20 | sandbox.restore();
21 | } else {
22 | sandbox.verifyAndRestore();
23 | }
24 | });
25 | }
26 |
27 | return callback.apply(this, args.concat(sandbox.args));
28 | };
29 | }
30 |
31 | module.exports = sinonTest;
32 |
--------------------------------------------------------------------------------
/src/android/java/io/jxcore/node/ConnectionData.java:
--------------------------------------------------------------------------------
1 | package io.jxcore.node;
2 |
3 |
4 | import org.thaliproject.p2p.btconnectorlib.PeerProperties;
5 |
6 | import java.util.concurrent.atomic.AtomicInteger;
7 |
8 | public class ConnectionData {
9 | public static AtomicInteger INDEX_ID = new AtomicInteger(1);
10 | public final PeerProperties peerProperties;
11 | public final int id;
12 | public final boolean isIncoming;
13 |
14 | public ConnectionData(PeerProperties peerProperties, boolean isIncoming) {
15 | this.peerProperties = peerProperties;
16 | this.isIncoming = isIncoming;
17 | this.id = INDEX_ID.getAndAdd(1);
18 | }
19 |
20 | @Override
21 | public String toString() {
22 | return "Peer properties: " + peerProperties.toString() + ".\n Is incomming connection: " +
23 | isIncoming + ".\n id: " + id;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/ios/Testing/AppContext+TestRuner.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppContext+TestRuner.swift
3 | // Thali
4 | //
5 | // Copyright (C) Microsoft. All rights reserved.
6 | // Licensed under the MIT license.
7 | // See LICENSE.txt file in the project root for full license information.
8 | //
9 |
10 | import Foundation
11 | import SwiftXCTest
12 | import ThaliCore
13 |
14 | extension AppContext: TestRunnerProtocol {
15 |
16 | func runNativeTests() -> String {
17 | let rootTestSuite = XCTestSuite(name: "All tests")
18 |
19 | let currentTestSuite = XCTestSuite(
20 | name: "All tests",
21 | testCases: [
22 | [testCase(AppContextTests.allTests)]
23 | ].flatMap { $0 }
24 | )
25 |
26 | rootTestSuite.addTest(currentTestSuite)
27 |
28 | let runner = TestRunner(testSuite: rootTestSuite)
29 | runner.runTest()
30 | return runner.resultDescription ?? ""
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/android/test/build-extras.gradle:
--------------------------------------------------------------------------------
1 | dependencies {
2 | compile fileTree(dir: 'libs', include: ['*.jar'])
3 | compile 'com.android.support:appcompat-v7:22.2.0'
4 | compile 'junit:junit:4.12'
5 |
6 | compile 'com.android.support:support-annotations:22.2.0'
7 | compile 'com.android.support.test:runner:0.3'
8 | compile 'com.android.support.test:rules:0.3'
9 | compile 'com.android.support.test.espresso:espresso-core:2.2'
10 | compile 'org.mockito:mockito-core:1.10.19'
11 | compile 'com.crittercism.dexmaker:dexmaker:1.4'
12 | compile 'com.crittercism.dexmaker:dexmaker-dx:1.4'
13 | compile 'com.crittercism.dexmaker:dexmaker-mockito:1.4'
14 | }
15 |
16 | ext.postBuildExtras = {
17 | android {
18 | compileOptions {
19 | sourceCompatibility JavaVersion.VERSION_1_7
20 | targetCompatibility JavaVersion.VERSION_1_7
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/thali/install/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "install",
3 | "version": "0.0.1",
4 | "description": "Used to handle installing the Thali NPM package correctly into Cordova",
5 | "main": "install.js",
6 | "dependencies": {
7 | "child-process-promise": "^1.1.0",
8 | "bluebird": "3.4.6",
9 | "end-with": "1.0.2",
10 | "findit": "2.0.0",
11 | "randomstring": "1.1.5",
12 | "node-uuid": "1.4.7",
13 | "fs-extra-promise": "0.2.0",
14 | "jxc": "1.0.14",
15 | "lie": "3.1.0",
16 | "request": "2.74.0",
17 | "unzip": "0.1.11",
18 | "xcode": "https://github.com/alunny/node-xcode.git#4cca2f6225c391b63324e6eb53421560649d4f98"
19 | },
20 | "scripts": {
21 | "setupUnit": "./setUpTests.sh UnitTest_app.js",
22 | "setupPerf": "./setUpTests.sh PerfTest_app.js",
23 | "setupDesktop": "./setUpDesktop.sh"
24 | },
25 | "author": "Microsoft",
26 | "license": "MIT"
27 | }
28 |
--------------------------------------------------------------------------------
/test/www/jxcore/meta_tests/disabled/testPerfTestFramework.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var PerfTestFramework = require('../../../TestServer/PerfTestFramework.js');
4 | var TestDevice = require('../../../TestServer/TestDevice.js');
5 | var tape = require('../lib/thaliTape');
6 |
7 | var test = tape({
8 | setup: function (t) {
9 | t.end();
10 | },
11 | teardown: function (t) {
12 | t.end();
13 | }
14 | });
15 |
16 | test('should be able to add devices to the framework', function (t) {
17 | var testConfig = {
18 | devices: {
19 | ios: 2
20 | },
21 | honorCount: true
22 | };
23 | var perfTestFramework = new PerfTestFramework(testConfig);
24 | var testDevice = new TestDevice(
25 | null, 'Some name', 'uuid', 'ios', 'perftest', [], true, null
26 | );
27 | perfTestFramework.addDevice(testDevice);
28 | t.equal(perfTestFramework.devices.ios.length, 1);
29 | t.end();
30 | });
31 |
--------------------------------------------------------------------------------
/test/www/jxcore/public/index.css:
--------------------------------------------------------------------------------
1 | .ok {
2 | display:block;
3 | color:grey;
4 | }
5 |
6 | .ok:before {
7 | content: "\2713";
8 | padding:10px 10px 0 20px;
9 | color:green;
10 | }
11 |
12 | .ok:hover, .fail:hover {
13 | background:#333;
14 | cursor:pointer;
15 | }
16 |
17 | .fail {
18 | display:block;
19 | color:grey;
20 | }
21 |
22 | .fail:before {
23 | content: "\2717";
24 | padding:10px 10px 0 20px;
25 | color:red;
26 | }
27 |
28 | .msg {
29 | display:block;
30 | margin-top:20px;
31 | margin-bottom:10px;
32 | color:white;
33 | }
34 |
35 | .total-msg {
36 | display:block;
37 | margin-top:20px;
38 | color:white;
39 | }
40 |
41 | .total-fail {
42 | color:red;
43 | }
44 |
45 | .total-ok {
46 | color:green;
47 | }
48 |
49 | body {
50 | background:black;
51 | margin-left:20px;
52 | font-family: source-code-pro, sans-serif;
53 | user-select:none;
54 | font-size:1.2em;
55 | }
56 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | The information below MUST be provided when filing a bug about a failing test:
2 |
3 | ### URL to the exact commit that you ran the test on. If you haven’t checked in the code that you are testing how is anyone else supposed to figure out what’s going on?
4 | ### The file where the test failed.
5 | ### The test that failed.
6 | ### networkType setting. Did the test fail on wifi, native, both?
7 | ### A link to a gist (or if CI, the GitHub log) with the failure log.
8 | ### Does the test always fail? This is critical. We need to know if the test always fails or sometimes passes. So if a test fails you MUST run it again a few times to be sure.
9 | ### Does the test fail when run on its own? Sometimes we have found that tests fail when run with other tests but don’t fail on their own. So when a test fails you need to run it in isolation (use the .only functionality) to confirm if it behaves the same when run by itself.
10 |
--------------------------------------------------------------------------------
/thali/install/utils/child_process.js:
--------------------------------------------------------------------------------
1 | // Copyright (C) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE.txt file in the project root
3 | // for full license information.
4 | //
5 |
6 | 'use strict';
7 |
8 | var child_process = require('child_process');
9 | var Promise = require('./Promise');
10 |
11 | function exec(command, options) {
12 | return new Promise(function (resolve, reject) {
13 | var childProcess = child_process.exec(command, options);
14 |
15 | childProcess.stdout.on('data', function (data) {
16 | console.log('' + data);
17 | });
18 | childProcess.stderr.on('data', function (data) {
19 | console.log('' + data);
20 | });
21 | childProcess.on('close', function (code) {
22 | if (code !== 0) {
23 | return reject('`' + command + '` (exited with error code' + code + ')');
24 | }
25 | return resolve();
26 | });
27 | });
28 | }
29 |
30 | module.exports.exec = exec;
31 |
--------------------------------------------------------------------------------
/thali/install/prePublishThaliCordovaPlugin.js:
--------------------------------------------------------------------------------
1 | // Copyright (C) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE.txt file in the project root
3 | // for full license information.
4 | //
5 |
6 | 'use strict';
7 |
8 | var fs = require('fs');
9 | var path = require('path');
10 |
11 | // prePublish gets run on 'npm install'
12 | // (e.g. even if you aren't actually publishing)
13 | // so we have to check to make sure that we are in our own directory
14 | // and this isn't some poor user trying to install our package.
15 |
16 | var rootDirectory = path.join(__dirname, '..', '..');
17 | if (path.basename(rootDirectory) !== 'Thali_CordovaPlugin') {
18 | process.exit(0);
19 | }
20 |
21 | var readMeFileName = 'readme.md';
22 | var parentReadMe = path.join(__dirname, '..', '..', readMeFileName);
23 | var localReadMe = path.join(__dirname, '..', readMeFileName);
24 |
25 | fs.writeFileSync(localReadMe, fs.readFileSync(parentReadMe));
26 | process.exit(0);
27 |
--------------------------------------------------------------------------------
/test/www/jxcore/views/ejs/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Thali Cordova Plugin Tests
7 |
8 |
9 |
10 |
11 | <% rows.forEach(function (row) { %>
12 |
13 | <% if (row.type === 'test') { %>
14 |
<%= row.name %>
15 | <% } %>
16 |
17 | <% if (row.type === 'assert') { %>
18 |
19 | <% if (row.ok) { %>
20 |
<%= row.name %>
21 | <% } %>
22 |
23 | <% if (!row.ok) { %>
24 |
<%= row.name %>
25 | <% } %>
26 |
27 | <% }); %>
28 |
29 | <% }); %>
30 |
31 |
<%= total %>
32 |
<%= failed %>
33 |
<%= passed %>
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/disabled/TestThaliMobileNative/QuitSignal.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert');
4 |
5 | var logger = require('../../../lib/testLogger')('QuitSignal');
6 |
7 |
8 | function QuitSignal() {
9 | this.raised = false;
10 | this._handlers = [];
11 | }
12 |
13 | QuitSignal.prototype.bindHandler = function (handler) {
14 | assert(
15 | !this.raised,
16 | 'no calling bindHandler after signal was raised'
17 | );
18 | this._handlers.push(handler);
19 | };
20 |
21 | QuitSignal.prototype.unbindHandler = function (handler) {
22 | var index = this._handlers.indexOf(handler);
23 | assert(
24 | index !== -1,
25 | 'handler should exist while unbinding'
26 | );
27 | this._handlers.splice(index, 1);
28 | };
29 |
30 | QuitSignal.prototype.raise = function () {
31 | if (this.raised) {
32 | return;
33 | }
34 | this.raised = true;
35 |
36 | this._handlers.forEach(function (handler) {
37 | handler();
38 | });
39 | };
40 |
41 | module.exports = QuitSignal;
42 |
--------------------------------------------------------------------------------
/thali/install/include.sh/build-dep.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | log_error() {
4 | local filename=$(basename "$0")
5 | local linenumber=${1}
6 | local code="${2:-1}"
7 |
8 | NORMAL_COLOR='\033[0m'
9 | RED_COLOR='\033[0;31m'
10 |
11 | echo ""
12 | echo -e "${RED_COLOR}error: command '${BASH_COMMAND}' failed with code ${code}, file '${filename}' on line ${linenumber}${NORMAL_COLOR}"
13 | }
14 |
15 | running_on_ci() {
16 | # Check the existence of the script that in CI gives the right test server
17 | # IP address.
18 | if [ -x "$(command -v CIGIVEMEMYIP.sh)" ]; then
19 | return 0
20 | else
21 | return 1
22 | fi
23 | }
24 |
25 | get_ci_ip_address() {
26 | if running_on_ci; then
27 | echo "$(CIGIVEMEMYIP.sh)"
28 | fi
29 | }
30 |
31 | is_darwin_platform() {
32 | if test x"`uname`" = xDarwin ; then
33 | return 0
34 | else
35 | return 1
36 | fi
37 | }
38 |
39 | is_minigw_platform() {
40 | if test x"$(uname -s | cut -c 1-5)" == xMINGW ; then
41 | return 0
42 | else
43 | return 1
44 | fi
45 | }
46 |
--------------------------------------------------------------------------------
/src/android/java/io/jxcore/node/WifiLocker.java:
--------------------------------------------------------------------------------
1 | package io.jxcore.node;
2 |
3 | import android.net.wifi.WifiManager;
4 |
5 | /**
6 | * Created by evabishchevich on 12/14/16.
7 | */
8 |
9 | class WifiLocker {
10 |
11 | private static final String LOCK_TAG = "io.jxcore.node.WifiLocker.LOCK_TAG";
12 | private WifiManager.MulticastLock multicastLock;
13 |
14 | String acquireLock(WifiManager wifiManager) {
15 | String error = null;
16 | try {
17 | if (multicastLock == null) {
18 | multicastLock = wifiManager.createMulticastLock(LOCK_TAG);
19 | multicastLock.setReferenceCounted(false);
20 | }
21 | if (!multicastLock.isHeld()) {
22 | multicastLock.acquire();
23 | }
24 | } catch (Exception e) {
25 | error = e.getMessage();
26 | }
27 | return error;
28 | }
29 |
30 | void releaseLock() {
31 | if (multicastLock != null && multicastLock.isHeld()) {
32 | multicastLock.release();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-2016 Microsoft Corporation.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/testUsn.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var uuid = require('uuid');
4 |
5 | var tape = require('../lib/thaliTape');
6 | var USN = require('thali/NextGeneration/utils/usn');
7 |
8 | var test = tape({});
9 |
10 | test('Correctly parses/stringifies USN', function (t) {
11 | var someUuid = uuid.v4();
12 | var someGeneration = 4;
13 |
14 | var usn = 'data:' + someUuid + ':' + someGeneration;
15 | var invalidPrefix = 'foo:' + someUuid + ':' + someGeneration;
16 | var invalidIdentifier = 'data:a:b:c:0';
17 | var invalidGeneration = 'data:' + someUuid + ':notanumber';
18 |
19 | var peer = {
20 | peerIdentifier: someUuid,
21 | generation: someGeneration
22 | };
23 |
24 | t.deepEqual(USN.parse(usn), peer, 'correctly parses USN string');
25 | t.throws(function () {
26 | USN.parse(invalidPrefix);
27 | }, 'throws if usn has invalid prefix');
28 | t.throws(function () {
29 | USN.parse(invalidIdentifier);
30 | }, 'throws if usn has invalid identifier format');
31 | t.throws(function () {
32 | USN.parse(invalidGeneration);
33 | }, 'throws if usn has invalid generation');
34 |
35 | t.equal(USN.stringify(peer), usn, 'correctly stringifies peer');
36 | t.end();
37 | });
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Mac OS X
2 | *.DS_Store
3 |
4 | # IntelliJ
5 | .idea/
6 | .gradle
7 | gradle/
8 | gradlew
9 | gradlew.bat
10 | *.iml
11 |
12 | # Nodejs
13 | node_modules
14 | npm-debug.log
15 |
16 | # Cordova
17 | out/
18 |
19 | # VS Code
20 | .settings/
21 | .vscode/
22 |
23 | # Testing
24 | test/TestServer/server-address.js
25 | test/www/jxcore/server-address.js
26 |
27 | # Xcode
28 | #
29 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
30 |
31 | ## Build generated
32 | build/
33 | DerivedData/
34 |
35 | ## Carthage
36 | lib/ios/Carthage/Build
37 | lib/ios/Carthage/Checkouts
38 |
39 | ## Various settings
40 | *.pbxuser
41 | !default.pbxuser
42 | *.mode1v3
43 | !default.mode1v3
44 | *.mode2v3
45 | !default.mode2v3
46 | *.perspectivev3
47 | !default.perspectivev3
48 | xcuserdata/
49 |
50 | ## Other
51 | *.moved-aside
52 | *.xcuserstate
53 |
54 | ## Obj-C/Swift specific
55 | *.hmap
56 | *.ipa
57 | *.dSYM.zip
58 | *.dSYM
59 |
60 | ## Playgrounds
61 | timeline.xctimeline
62 | playground.xcworkspace
63 |
64 | # Swift Package Manager
65 | #
66 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
67 | # Packages/
68 | .build/
69 |
70 | # Misc
71 | #
72 |
73 | thali/readme.md
74 |
--------------------------------------------------------------------------------
/test/www/jxcore/lib/testLogger.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Logger = require('thali/ThaliLogger');
4 | var platform = require('thali/NextGeneration/utils/platform');
5 |
6 | var logCallback;
7 | var messages = [];
8 |
9 | var isMobile = platform.isMobile;
10 |
11 | if (isMobile) {
12 | Mobile('setLogCallback').registerAsync(function (callback) {
13 | logCallback = callback;
14 | messages.forEach(function (message) {
15 | logCallback(message);
16 | });
17 | messages = [];
18 | });
19 | }
20 |
21 | /**
22 | * Log a message to the screen - only applies when running on Mobile.
23 | * It assumes we are using our test framework with our Cordova WebView
24 | * who is setup to receive logging messages and display them.
25 | * @param {object} meta Winston's meta object
26 | * @returns {object} A Winston logger object
27 | */
28 | module.exports = function (meta) {
29 | var logger = Logger(meta);
30 | if (isMobile) {
31 | logger._thaliLogger.on('message', function (message) {
32 | // 'logCallback' is required.
33 | // We should save all messages before it will be available.
34 | if (logCallback) {
35 | logCallback(message);
36 | } else {
37 | messages.push(message);
38 | }
39 | });
40 | }
41 | return logger;
42 | };
43 |
--------------------------------------------------------------------------------
/test/www/jxcore/meta_tests/testTestUtils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var path = require('path');
4 | var fs = require('fs');
5 |
6 | var testUtils = require('../lib/testUtils.js');
7 | var tape = require('../lib/thaliTape');
8 |
9 | var test = tape({
10 | setup: function (t) {
11 | t.end();
12 | },
13 | teardown: function (t) {
14 | t.end();
15 | }
16 | });
17 |
18 | test('should return same temporary folder when called multiple times',
19 | function (t) {
20 | var firstDirectory = testUtils.tmpDirectory();
21 | var secondDirectory = testUtils.tmpDirectory();
22 | t.equal(firstDirectory, secondDirectory);
23 | t.end();
24 | });
25 |
26 | test('should be able to write to the temporary folder', function (t) {
27 | var temporaryDirectory = testUtils.tmpDirectory();
28 | console.log(temporaryDirectory);
29 | fs.mkdir(path.join(temporaryDirectory, 'somePath'), function (err) {
30 | t.equal(err, null, 'no error returned when creating a subfolder');
31 | t.end();
32 | });
33 | });
34 |
35 | test('can call hasRequiredHardware', function (t) {
36 | testUtils.hasRequiredHardware()
37 | .then(function (hasRequiredHardware) {
38 | t.ok(hasRequiredHardware === true || hasRequiredHardware === false,
39 | 'resolves with a boolean');
40 | t.end();
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/thali/validations.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var toString = Object.prototype.toString;
4 |
5 | Number.isNaN = Number.isNaN || function(value) {
6 | return toString.call(value) === '[object Number]' && value !== value;
7 | };
8 |
9 | module.exports.ensureValidPort = function ensureValidPort (n) {
10 | if (toString.call(n) !== '[object Number]' || Number.isNaN(n)) { throw new TypeError('port must be a number'); }
11 | if (n > 65536 || n < 0) { throw new Error('port must be greater than 0 and less than or equal 65536'); }
12 | };
13 |
14 | module.exports.ensureNonNullOrEmptyString = function ensureNonNullOrEmptyString (value, param) {
15 | if (toString.call(value) !== '[object String]') { throw new TypeError(param + ' must be a string'); }
16 | if (value.trim().length === 0) { throw new Error(param + ' cannot be empty'); }
17 | };
18 |
19 | module.exports.ensureIsFunction = function ensureIsFunction (value, param) {
20 | if (toString.call(value) !== '[object Function]') { throw new TypeError(param + ' must be a function'); }
21 | };
22 |
23 | module.exports.objectKeysEquals = function (obj, keys) {
24 | var currentKeys = Object.getOwnPropertyNames(obj);
25 | if (currentKeys.length !== keys.length) {
26 | return false;
27 | }
28 | return keys.every(function (key) {
29 | return obj.hasOwnProperty(key);
30 | });
31 | }
32 |
--------------------------------------------------------------------------------
/test/www/jxcore/lib/thaliTape.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /*
3 | Thali unit test implementation of tape.
4 | Highly inspired by wrapping-tape.
5 | Usage is very similar to the wrapping tape:
6 |
7 | var tape = require('thaliTape');
8 |
9 | var test = tape({
10 | setup: function(t) {
11 | // will be called after each test has started to setup the test
12 | // after the next line, the actual test code will be executed
13 | t.end();
14 | },
15 | teardown: function(t) {
16 | // will be called after each device has ended the test
17 | // do any final tear down for the test in here
18 | t.end();
19 | },
20 | emitRetryCount: 120,
21 | emitRetryTimeout: 3 * 1000,
22 | setupTimeout: 1 * 60 * 1000,
23 | testTimeout: 10 * 60 * 1000,
24 | teardownTimeout: 1 * 60 * 1000
25 | });
26 | */
27 |
28 | require('./utils/process');
29 |
30 | var exports;
31 | if (typeof jxcore === 'undefined' || typeof Mobile !== 'undefined') {
32 | // On mobile, or outside of jxcore (some dev scenarios)
33 | // we use the server-coordinated thaliTape.
34 | exports = require('./CoordinatedTape');
35 | exports.coordinated = true;
36 | } else {
37 | // On desktop we just use simple non-coordinated tape.
38 | exports = require('./SimpleTape');
39 | exports.coordinated = false;
40 | }
41 | exports.sinonTest = require('./sinonTest');
42 | module.exports = exports;
43 |
--------------------------------------------------------------------------------
/thali/install/setUpDesktop.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | echo ""
4 | echo "start setUpDesktop.sh"
5 |
6 | SCRIPT_PATH="$(cd "$(dirname "$0")"; pwd -P)"
7 | source "$SCRIPT_PATH/include.sh/build-dep.sh"
8 |
9 | set -euo pipefail
10 |
11 | trap 'log_error $LINENO' ERR
12 |
13 | # These variables are set since a bug in jxcore
14 | # `jx npm install` and `jx install` have different behaviours
15 | NVM_NODEJS_ORG_MIRROR=https://jxcore.azureedge.net
16 | export NVM_NODEJS_ORG_MIRROR
17 | JX_NPM_JXB="${JX_NPM_JXB-jxb311}"
18 | export JX_NPM_JXB
19 |
20 | echo ""
21 | echo "start preparing TestServer"
22 | cd `dirname $0`
23 | cd ../../test/TestServer
24 | npm install --no-optional
25 | node generateServerAddress.js
26 | echo "end preparing TestServer"
27 | echo ""
28 |
29 | echo ""
30 | echo "start installing Thali root"
31 | cd ../../thali
32 | jx npm install --no-optional
33 | npm link
34 | echo "end installing Thali root"
35 | echo ""
36 |
37 | echo ""
38 | echo "start installing Thali install"
39 | cd install
40 | npm install --no-optional
41 | node validateBuildEnvironment.js
42 | echo "end installing Thali install"
43 | echo ""
44 |
45 | echo ""
46 | echo "start preparing 'test/www/jxcore'"
47 | cd ../../test/www/jxcore
48 | npm link thali
49 | node installCustomPouchDB.js
50 | jx npm install --no-optional
51 | echo "end prepating 'test/www/jxcore'"
52 | echo ""
53 |
54 | echo "end setUpDesktop.sh"
55 | echo ""
56 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/disabled/IdentityExchange/identityExchangeTestUtils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var expressPouchDB = require('express-pouchdb');
4 | var express = require('express');
5 | var Promise = require('lie');
6 | var crypto = require('crypto');
7 | var identityExchangeUtils = require('thali/identityExchange/identityExchangeUtils');
8 | var testUtils = require('../lib/testUtils');
9 |
10 | exports.createThaliAppServer = function () {
11 | var app = express();
12 |
13 | app.use('/db', expressPouchDB(testUtils.getLevelDownPouchDb(),
14 | { mode: 'minimumForPouchDB'}));
15 |
16 | return new Promise(function (resolve) {
17 | app.listen(0, function () {
18 | this.on('error', function (err) {
19 | console.log('Server got error event: ' + JSON.stringify(err));
20 | });
21 | resolve({ app: app, server: this });
22 | });
23 | });
24 | };
25 |
26 | exports.createSmallAndBigHash = function () {
27 | var random1 = crypto.randomBytes(identityExchangeUtils.pkBufferLength);
28 | var random2 = crypto.randomBytes(identityExchangeUtils.pkBufferLength);
29 | if (identityExchangeUtils.compareEqualSizeBuffers(random1, random2) > 0) {
30 | return { smallHash: random2, bigHash: random1};
31 | } else {
32 | return { smallHash: random1, bigHash: random2};
33 | }
34 | };
35 |
36 | exports.checkCode = function (t, code) {
37 | t.ok(typeof code === 'number' && code >= 0 && code < 1000000,
38 | 'We got a code, did it check out?');
39 | };
40 |
--------------------------------------------------------------------------------
/thali/install/cordova-hooks/ios/before_plugin_install.js:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt file in the project root
4 | // for full license information.
5 | //
6 |
7 | 'use strict';
8 |
9 | var path = require('path');
10 | var fs = require('fs');
11 |
12 | // Replaces PROJECT_NAME pattern with actual Cordova's project name
13 | function updateJXcoreExtensionImport(context) {
14 | var cordovaUtil =
15 | context.requireCordovaModule('cordova-lib/src/cordova/util');
16 | var ConfigParser = context.requireCordovaModule('cordova-lib').configparser;
17 | var projectRoot = cordovaUtil.isCordova();
18 | var xml = cordovaUtil.projectConfig(projectRoot);
19 | var cfg = new ConfigParser(xml);
20 |
21 | var Q = context.requireCordovaModule('q');
22 | var deferred = new Q.defer();
23 |
24 | var jxcoreExtensionPath = path.join(
25 | context.opts.plugin.dir, 'src', 'ios', 'JXcoreExtension.m');
26 | try {
27 | console.log('Updating JXcoreExtension.m');
28 |
29 | var oldContent = fs.readFileSync(jxcoreExtensionPath, 'utf8');
30 | var newContent = oldContent.replace('%PROJECT_NAME%', cfg.name());
31 | fs.writeFileSync(jxcoreExtensionPath, newContent, 'utf8');
32 |
33 | deferred.resolve();
34 | } catch (error) {
35 | console.log('Failed updating of JXcoreExtension.m');
36 |
37 | deferred.reject(error);
38 | }
39 |
40 | return deferred.promise;
41 | }
42 |
43 | module.exports = function (context) {
44 | return updateJXcoreExtensionImport(context);
45 | };
46 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/disabled/IdentityExchange/testIdentityExchangeUtils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var tape = require('../lib/thaliTape');
4 | var identityExchangeUtils = require('thali/identityExchange/identityExchangeUtils');
5 |
6 | var test = tape({
7 | setup: function (t) {
8 | t.end();
9 | },
10 | teardown: function (t) {
11 | t.end();
12 | }
13 | });
14 |
15 | test('test compareEqualSizeBuffers', function (t) {
16 | var testValues = [
17 | ['', ''],
18 | [null, null],
19 | [new Buffer([0, 0], '')],
20 | ['foo', new Buffer([0, 1])],
21 | [new Buffer([9, 9]), new Buffer([9, 9, 9])]
22 | ];
23 | testValues.forEach(function (testValue) {
24 | t.throws(function () {
25 | identityExchangeUtils.compareEqualSizeBuffers(testValue[0], testValue[1]);
26 | });
27 | });
28 |
29 | var moreTestValues = [
30 | { result: -1, values: [
31 | [[0], [1]],
32 | [[0, 1, 1], [1, 1, 1]],
33 | [[7, 7, 6], [7, 7, 7]]
34 | ]},
35 | { result: 0, values: [
36 | [[0], [0]],
37 | [[1, 1, 1, 1], [1, 1, 1, 1]]
38 | ]},
39 | { result: 1, values: [
40 | [[1], [0]],
41 | [[0, 0, 0, 2], [0, 0, 0, 1]]
42 | ]}
43 | ];
44 | moreTestValues.forEach(function (testPair) {
45 | testPair.values.forEach(function (value) {
46 | var buffer1 = new Buffer(value[0]);
47 | var buffer2 = new Buffer(value[1]);
48 | var result = identityExchangeUtils.compareEqualSizeBuffers(buffer1, buffer2);
49 | t.equal(testPair.result, result);
50 | });
51 | });
52 | t.end();
53 | });
54 |
--------------------------------------------------------------------------------
/test/www/jxcore/meta_tests/testInstall.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var install = require('../../../../thali/install/install.js');
4 | var tape = require('../lib/thaliTape');
5 | var testUtils = require('../lib/testUtils.js');
6 | var exec = require('child_process').exec;
7 | var path = require('path');
8 |
9 | var test = tape({
10 | setup: function(t) {
11 | t.end();
12 | },
13 | teardown: function(t) {
14 | t.end();
15 | }
16 | });
17 |
18 | test('two required plugins should get installed', function (t) {
19 | var tmpDirectory = testUtils.tmpDirectory();
20 | var testAppName = 'TestApp';
21 | var testAppDirectory = path.join(tmpDirectory, testAppName);
22 | var cordovaCreateCommand = 'cordova create ' + testAppName;
23 | exec(cordovaCreateCommand, { cwd: tmpDirectory }, function (err, stdout,
24 | stderr) {
25 | if (err) {
26 | t.fail('Cordova command should not fail!');
27 | t.end();
28 | return;
29 | }
30 | install(function () {
31 | var cordovaPluginsCommand = 'cordova plugins list';
32 | exec(cordovaPluginsCommand, { cwd: testAppDirectory }, function (err,
33 | stdout,
34 | stderr) {
35 | t.ok(stdout.indexOf('io.jxcore.node' >= 0),
36 | 'jxcore cordova plugin is installed');
37 | t.ok(stdout.indexOf('org.thaliproject.p2p' >= 0),
38 | 'thali cordova plugin is installed');
39 | t.end();
40 | });
41 | }, testAppDirectory);
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/thali/NextGeneration/utils/platform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var _platforms = {
4 | ANDROID: 'android',
5 | IOS: 'ios'
6 | };
7 |
8 | var _platform = process.platform;
9 |
10 | // All the properties are in the readonly mode
11 | module.exports = Object.defineProperties({}, {
12 | 'name': {
13 | get: function () {
14 | return _platform;
15 | }
16 | },
17 | 'names' : {
18 | get: function () {
19 | return _platforms;
20 | }
21 | },
22 | 'isMobile': {
23 | get: function () {
24 | return this.isAndroid || this.isIOS;
25 | }
26 |
27 | },
28 | 'isAndroid': {
29 | get: function () {
30 | return _platform === _platforms.ANDROID;
31 | }
32 | },
33 | 'isIOS': {
34 | get: function () {
35 | return _platform === _platforms.IOS;
36 | }
37 | },
38 | // The methods presented below ONLY for testing reasons
39 | '_override': {
40 | value: function (platform) {
41 | return _platform = platform;
42 | }
43 | },
44 | '_restore': {
45 | value: function () {
46 | return _platform = process.platform;
47 | }
48 | },
49 | // Returns REAL values based on `process.platform`
50 | '_realName': {
51 | value: function () {
52 | return process.platform;
53 | }
54 | },
55 | '_isRealMobile': {
56 | get: function () {
57 | return this._isRealAndroid || this._isRealIOS;
58 | }
59 |
60 | },
61 | '_isRealAndroid': {
62 | get: function () {
63 | return process.platform === _platforms.ANDROID;
64 | }
65 | },
66 | '_isRealIOS': {
67 | get: function () {
68 | return process.platform === _platforms.IOS;
69 | }
70 | }
71 | });
72 |
--------------------------------------------------------------------------------
/test/TestServer/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Main entry point for Thali test frameworks coordinator server
4 | // jx index.js "{ 'devices': { 'android': 3, 'ios': 2 } }"
5 |
6 | var util = require('util');
7 | var format = util.format;
8 |
9 | require('./utils/process');
10 | var logger = require('./utils/ThaliLogger')('TestServer');
11 |
12 | var HttpServer = require('./HttpServer');
13 | var UnitTestFramework = require('./UnitTestFramework');
14 |
15 | var DEFAULT_SERVER_PORT = Number(process.env.COORDINATED_PORT) || 3000;
16 | var WAITING_FOR_DEVICES_TIMEOUT = 5 * 60 * 1000;
17 |
18 | var httpServer = new HttpServer({
19 | port: DEFAULT_SERVER_PORT,
20 | transports: ['websocket']
21 | });
22 |
23 | var options = process.argv[2];
24 | if (options) {
25 | options = JSON.parse(options);
26 | }
27 | var unitTestManager = new UnitTestFramework(options);
28 |
29 | httpServer
30 | .on('present', function (device) {
31 | switch (device.type) {
32 | case 'unittest': {
33 | unitTestManager.addDevice(device);
34 | break;
35 | }
36 | default: {
37 | throw new Error(
38 | format('unrecognised device type: \'%s\'', device.type)
39 | );
40 | }
41 | }
42 | });
43 |
44 | var timer = setTimeout(function () {
45 | throw new Error('timeout exceed');
46 | }, WAITING_FOR_DEVICES_TIMEOUT);
47 |
48 | unitTestManager
49 | .once('started', function () {
50 | clearTimeout(timer);
51 | })
52 | .once('completed', function (results) {
53 | logger.debug('completed');
54 |
55 | var isSuccess = results.every(function (result) {
56 | return result;
57 | });
58 | if (isSuccess) {
59 | process.exit(0);
60 | } else {
61 | process.exit(1);
62 | }
63 | });
64 |
--------------------------------------------------------------------------------
/test/www/jxcore/meta_tests/testCanBeSkipped.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Promise = require('bluebird');
4 |
5 | var tape = require('../lib/thaliTape');
6 |
7 |
8 | var test = tape({
9 | setup: function (t) {
10 | t.end();
11 | },
12 | teardown: function (t) {
13 | t.end();
14 | }
15 | });
16 |
17 | var PROMISE_TIMEOUT = 10;
18 |
19 | // These tests should not be skipped.
20 |
21 | test('we should not skip test without \'canBeSkipped\' function', function (t) {
22 | t.pass('passed');
23 | t.end();
24 | });
25 |
26 | test(
27 | 'we should not skip test with \'canBeSkipped\' returned false',
28 | function () {
29 | return false;
30 | },
31 | function (t) {
32 | t.pass('passed');
33 | t.end();
34 | }
35 | );
36 |
37 | test(
38 | 'we should not skip test with \'canBeSkipped\' returned promise with false',
39 | function () {
40 | return new Promise(function (resolve) {
41 | setTimeout(function () {
42 | resolve(false);
43 | }, PROMISE_TIMEOUT);
44 | });
45 | },
46 | function (t) {
47 | t.pass('passed');
48 | t.end();
49 | }
50 | );
51 |
52 | // These tests should be skipped.
53 |
54 | test(
55 | 'we should skip test with \'canBeSkipped\' returned true',
56 | function () {
57 | return true;
58 | },
59 | function (t) {
60 | t.fail('failed');
61 | t.end();
62 | }
63 | );
64 |
65 | test(
66 | 'we should skip test with \'canBeSkipped\' returned promise with true',
67 | function () {
68 | return new Promise(function (resolve) {
69 | setTimeout(function () {
70 | resolve(true);
71 | }, PROMISE_TIMEOUT);
72 | });
73 | },
74 | function (t) {
75 | t.fail('failed');
76 | t.end();
77 | }
78 | );
79 |
--------------------------------------------------------------------------------
/test/www/jxcore/config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | env : {
5 | BLUEBIRD_DEBUG: false
6 | },
7 |
8 | // Tests are ordered in the dependency order to avoid testing modules
9 | // before all its dependencies have been tested.
10 | preferredOrder: [
11 | 'testMakeIntoCloseAllServer.js',
12 | 'testPouchDBCheckpointPlugin.js',
13 | 'testPouchDBGenerator.js',
14 | 'testPromiseQueue.js',
15 | 'testTests.js',
16 | 'testUsn.js',
17 | 'testNativeMethod.js',
18 | 'testThaliMobileNative.js',
19 | 'testThaliMobileNativeAndroid.js',
20 | 'testThaliMobileNativeiOS.js',
21 | 'testThaliMobileNativeDiscoveryCoordinated.js',
22 | 'testCreateNativeListener.js',
23 | 'testCreatePeerListener.js',
24 | 'testThaliTcpServersManager.js',
25 | 'testHttp.js',
26 | 'testThaliMobileNativeWrapper.js',
27 | 'testThaliWifiInfrastructure.js',
28 | 'testThaliMobile.js',
29 | 'testThaliPeerAction.js',
30 | 'testThaliPeerDictionary.js',
31 | 'testThaliPeerPoolDefault.js',
32 | 'testThaliPeerPoolInterface.js',
33 | 'testThaliPeerPoolOneAtATime.js',
34 | 'testThaliNotification.js',
35 | 'testThaliNotificationAction.js',
36 | 'testThaliNotificationBeacons.js',
37 | 'testThaliNotificationClient.js',
38 | 'testThaliNotificationLocal.js',
39 | 'testThaliNotificationServer.js',
40 | 'testThaliPullReplicationFromNotification.js',
41 | 'testThaliPullReplicationFromNotificationCoordinated.js',
42 | 'testThaliReplicationPeerAction.js',
43 | 'testThaliReplicationPeerActionCoordinated.js',
44 | 'testThaliReplicationUtilities.js',
45 | 'testThaliSendNotificationBasedOnReplication.js',
46 | 'testLocalSeqManager.js',
47 | 'testLocalSeqManagerCoordinated.js',
48 | 'testThaliManager.js',
49 | 'testThaliManagerCoordinated.js'
50 | ]
51 | };
52 |
--------------------------------------------------------------------------------
/test/TestServer/IPAddressToFile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs-extra-promise');
4 | var os = require('os');
5 | var path = require('path');
6 |
7 | var Promise = require('./utils/Promise');
8 |
9 |
10 | function writeFiles(address) {
11 | function writeServerAddress(filePath) {
12 | return fs.writeFileAsync(path.join(filePath, 'server-address.js'),
13 | 'module.exports = "' + address + '";');
14 | }
15 |
16 | return writeServerAddress(path.join(__dirname, '../www/jxcore'))
17 | .then(function () {
18 | return writeServerAddress(__dirname);
19 | });
20 | }
21 |
22 | module.exports = function (addressOverride) {
23 | if (addressOverride) {
24 | return writeFiles(addressOverride);
25 | }
26 |
27 | var networkInterfaces = os.networkInterfaces();
28 |
29 | var ipv4address= null;
30 | Object.keys(networkInterfaces).forEach(function (interfaceName) {
31 | networkInterfaces[interfaceName].forEach(function (iface) {
32 | if ('IPv4' !== iface.family || iface.internal !== false) {
33 | // skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses
34 | return;
35 | }
36 |
37 | // We prefer interfaces called Wi-Fi but if we can't find one then we
38 | // will take the first IPv4 address we can find that is not internal.
39 | // The assumption is that the non-Wi-Fi address is connected to a router
40 | // that is connected to Wi-Fi.
41 | if (interfaceName.indexOf('Wi-Fi') > -1){
42 | // this interface has only one ipv4 address
43 | ipv4address = iface.address;
44 | }
45 |
46 | if (!ipv4address) {
47 | ipv4address = iface.address;
48 | }
49 | });
50 | });
51 |
52 | if (!ipv4address) {
53 | return Promise.reject(
54 | new Error('We could not find an IPv4 external facing interface'));
55 | }
56 |
57 | return writeFiles(ipv4address);
58 | };
59 |
--------------------------------------------------------------------------------
/thali/NextGeneration/security/hkdf.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*
4 | Apache 2.0 License
5 |
6 | Originally from https://github.com/benadida/node-hkdf
7 | Forked in https://github.com/zaach/node-hkdf
8 |
9 | changelog:
10 | 12/10/2015 - applied zaach pull request
11 | 12/10/2015 - removed callback requirement
12 | 12/10/2015 - made instanceof check for easier chaining
13 | */
14 |
15 | //
16 | // a straightforward implementation of HKDF
17 | //
18 | // https://tools.ietf.org/html/rfc5869
19 | //
20 |
21 | var crypto = require('crypto');
22 |
23 | function zeros(length) {
24 | var buf = new Buffer(length);
25 |
26 | buf.fill(0);
27 |
28 | return buf.toString();
29 | }
30 |
31 | // ikm is initial keying material
32 | function HKDF(hashAlg, salt, ikm) {
33 | if (!(this instanceof HKDF)) { return new HKDF(hashAlg, salt, ikm); }
34 |
35 | this.hashAlg = hashAlg;
36 |
37 | // create the hash alg to see if it exists and get its length
38 | var hash = crypto.createHash(this.hashAlg);
39 | this.hashLength = hash.digest().length;
40 |
41 | this.salt = salt || zeros(this.hashLength);
42 | this.ikm = ikm;
43 |
44 | // now we compute the PRK
45 | var hmac = crypto.createHmac(this.hashAlg, this.salt);
46 | hmac.update(this.ikm);
47 | this.prk = hmac.digest();
48 | }
49 |
50 | HKDF.prototype.derive = function (info, size) {
51 | var prev = new Buffer(0);
52 |
53 | var buffers = [];
54 | var numBlocks = Math.ceil(size / this.hashLength);
55 |
56 | info = new Buffer(info);
57 |
58 | for (var i=0; i < numBlocks; i++) {
59 | var hmac = crypto.createHmac(this.hashAlg, this.prk);
60 | // XXX is there a more optimal way to build up buffers?
61 | var input = Buffer.concat([
62 | prev,
63 | info,
64 | new Buffer(String.fromCharCode(i + 1))
65 | ]);
66 | hmac.update(input);
67 | prev = hmac.digest();
68 | buffers.push(prev);
69 | }
70 | return Buffer.concat(buffers, size);
71 | };
72 |
73 | module.exports = HKDF;
74 |
--------------------------------------------------------------------------------
/thali/NextGeneration/utils/usn.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var format = require('util').format;
4 |
5 | /**
6 | * @module utils/usn
7 | *
8 | * Decode/encode peer information from/into USN strings used by SSDP discovery
9 | * mechanism
10 | */
11 |
12 | /**
13 | * @typdef {Object} UsnPeer
14 | * @property {string} peerIdentifier - UUID part of USN
15 | * @property {number} generation - generation part of USN
16 | */
17 |
18 | var USN = {
19 | _prefix: 'data:',
20 | };
21 |
22 | /**
23 | * @param {string} usn
24 | * @returns {UsnPeer}
25 | * @throws Will throw when provided usn has an invalid prefix (other than
26 | * 'data:'), has incorrect number of segments or its generation is not a number.
27 | */
28 | USN.parse = function (usn) {
29 | if (usn.indexOf(USN._prefix) !== 0) {
30 | throw new Error(
31 | format('Invalid USN (expected "%s" prefix): %s', USN._prefix, usn)
32 | );
33 | }
34 | var unprefixed = usn.substring(USN._prefix.length);
35 | var segments = unprefixed.split(':');
36 | var peerIdentifier = segments[0];
37 | var generation = Number(segments[1]);
38 |
39 | if (segments.length !== 2) {
40 | throw new Error('Invalid USN (expected 2 segments): ' + usn);
41 | }
42 | if (isNaN(generation)) {
43 | throw new Error('Invalid USN (generation is not a number): ' + usn);
44 | }
45 | return {
46 | peerIdentifier: peerIdentifier,
47 | generation: generation
48 | };
49 | };
50 |
51 | /**
52 | * @param {UsnPeer} peer
53 | * @returns {string}
54 | */
55 | USN.stringify = function (peer) {
56 | return USN._prefix + peer.peerIdentifier + ':' + peer.generation;
57 | };
58 |
59 | /**
60 | * @param {string} usn
61 | * @param {*} errorValue - this value will be returned if usn is invalid
62 | * @returns {UsnPeer|*}
63 | */
64 | USN.tryParse = function (usn, errorValue) {
65 | try {
66 | return USN.parse(usn);
67 | } catch (error) {
68 | return errorValue;
69 | }
70 | };
71 |
72 | module.exports = USN;
73 |
--------------------------------------------------------------------------------
/test/www/jxcore/lib/MockMobile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var next = {};
3 | var registered = {};
4 |
5 | var mocks = {
6 | // Default handlers for mocks.
7 | // If there's an entry in next[key], call that instead
8 | startListeningForAdvertisements : function (cb) {
9 | cb(null);
10 | },
11 | startUpdateAdvertisingAndListening : function (port, cb) {
12 | cb(null);
13 | }
14 | };
15 |
16 | /* jshint -W079 */
17 | var Mobile = function (key) {
18 | /* jshint +W079 */
19 | return {
20 | // Call a native function
21 | callNative: function () {
22 | // If there's a handler specified then call that
23 | if (key in next) {
24 | var fn = next[key].shift();
25 | if (next[key].length === 0) {
26 | delete next[key];
27 | }
28 | fn.apply(this, arguments);
29 | return;
30 | }
31 |
32 | // .. else call the default
33 | if (key in mocks) {
34 | mocks[key].apply(this, arguments);
35 | }
36 | else {
37 | throw new Error('Mock does not implement: ' + key);
38 | }
39 | },
40 |
41 | // Queue up handlers for native calls
42 | nextNative: function (fn) {
43 | if (key in next) {
44 | next[key].push(fn);
45 | }
46 | else {
47 | next[key] = [fn];
48 | }
49 | },
50 |
51 | // Register a function
52 | registerToNative: function (callback) {
53 | registered[key] = callback;
54 | },
55 |
56 | // Call a registered function
57 | callRegistered: function () {
58 | // Call a registered function
59 | if (key in registered) {
60 | registered[key].apply(this, arguments);
61 | }
62 | else {
63 | throw new Error('Function not registered: ', key);
64 | }
65 | }
66 | };
67 | };
68 |
69 | Mobile.createListenerOrIncomingConnection =
70 | function (listeningPort) {
71 | return JSON.stringify({
72 | listeningPort: listeningPort
73 | });
74 | };
75 |
76 | module.exports = Mobile;
77 |
--------------------------------------------------------------------------------
/test/TestServer/utils/ThaliLogger.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 | var inherits = util.inherits;
5 | var format = util.format;
6 |
7 | var winston = require('winston');
8 | var EventEmitter = require('events').EventEmitter;
9 |
10 |
11 | var ThaliLogger = function (logger) {
12 | ThaliLogger.super_.call(this);
13 |
14 | this._logger = logger || ThaliLogger._defaultLogger;
15 | };
16 |
17 | var defaultLogger;
18 | if (
19 | typeof jxcore !== 'undefined' &&
20 | jxcore.utils &&
21 | jxcore.utils.console &&
22 | jxcore.utils.console.log
23 | ) {
24 | ThaliLogger._defaultLogger = jxcore.utils.console.log.bind(jxcore.utils.console);
25 | } else {
26 | ThaliLogger._defaultLogger = console.log.bind(console);
27 | }
28 |
29 | util.inherits(ThaliLogger, EventEmitter);
30 |
31 | ThaliLogger.prototype.name = 'ThaliLogger';
32 |
33 | ThaliLogger.prototype.log = function (level, message, meta, callback) {
34 | var now = new Date().toISOString()
35 | .replace(/T/, ' ')
36 | .replace(/.[^.]+$/, '');
37 | message = format(
38 | '%s - %s %s: \'%s\'',
39 | now, level.toUpperCase(), meta.tag, message
40 | );
41 |
42 | this._logger(message);
43 |
44 | // Emit the `logged` event immediately because the event loop
45 | // will not exit until `process.stdout` has drained anyway.
46 | this.emit('logged');
47 | callback(null, true);
48 |
49 | this.emit('message', message);
50 | };
51 |
52 | module.exports = function (tag, logger) {
53 | if (!tag || typeof tag !== 'string' || tag.length < 3) {
54 | throw new Error(
55 | 'All logging must have a tag that is at least 3 characters long!'
56 | );
57 | }
58 | var thaliLogger = new ThaliLogger(logger);
59 | var logger = new winston.Logger({
60 | transports: [thaliLogger]
61 | });
62 | logger.rewriters.push(function (level, msg, meta) {
63 | if (!meta.tag) {
64 | meta.tag = tag;
65 | }
66 | return meta;
67 | });
68 | logger.level = 'debug';
69 | return logger;
70 | };
71 |
--------------------------------------------------------------------------------
/thali/installCordovaPlugin.js:
--------------------------------------------------------------------------------
1 | // Copyright (C) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE.txt file in the project root
3 | // for full license information.
4 | //
5 |
6 | 'use strict';
7 |
8 | var path = require('path');
9 | var exec = require('./install/utils/child_process').exec;
10 |
11 | // If we are in the test directory inside of the GitHub Repo then we are trying
12 | // to do local development on the desktop and don't need the Cordova
13 | // dependencies
14 | var rootDirectory = path.join(__dirname, '..');
15 | if (path.basename(rootDirectory) === 'Thali_CordovaPlugin') {
16 | console.log('We believe we are in a clone of the GitHub Repo so we will not '+
17 | 'install Cordova dependencies');
18 | process.exit(0);
19 | }
20 |
21 | var installDirectory = path.join(__dirname, 'install');
22 |
23 | // First check that the installation is done to a Cordova project
24 | exec('cordova info')
25 | .catch(function () {
26 | console.log('The installation directory does not seem to be a Cordova ' +
27 | 'project and currently the installation is supported only to ' +
28 | 'Cordova apps. Please see further information from:');
29 | console.log('https://github.com/thaliproject/Thali_CordovaPlugin');
30 |
31 | process.exit(1);
32 | })
33 | .then(function () {
34 | return exec('npm install --no-optional --production',
35 | { cwd: installDirectory });
36 | })
37 | .then(function () {
38 | return exec('find . -name "*.gz" -delete',
39 | { cwd: installDirectory });
40 | })
41 | .catch(function (error) {
42 | console.log('Could not install dependencies for install directory. - ' +
43 | error);
44 | process.exit(1);
45 | })
46 | .then(function () {
47 | require(installDirectory)(function (error) {
48 | if (error) {
49 | console.log('Failed with - ' + error);
50 | process.exit(1);
51 | }
52 |
53 | process.exit(0);
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/thali/ThaliLogger.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 | var format = util.format;
5 |
6 | var winston = require('winston');
7 |
8 |
9 | var ThaliLogger = function (tag) {
10 | ThaliLogger.super_.call(this);
11 | this.tag = tag;
12 | };
13 |
14 | util.inherits(ThaliLogger, winston.Transport);
15 |
16 | ThaliLogger.prototype.name = 'ThaliLogger';
17 |
18 | if (
19 | typeof jxcore !== 'undefined' &&
20 | jxcore.utils &&
21 | jxcore.utils.console &&
22 | jxcore.utils.console.log
23 | ) {
24 | ThaliLogger._logger = jxcore.utils.console.log;
25 | } else {
26 | ThaliLogger._logger = console.log;
27 | }
28 |
29 | // TODO winston is unreliable, we want to find an alternative.
30 | // We can receive last part of message (like errors) in 'meta'.
31 | ThaliLogger.prototype.log = function (level, message, meta, callback) {
32 | if (meta instanceof Error) {
33 | message += ' ' + meta.stack;
34 | }
35 | var now = new Date().toISOString()
36 | .replace(/T/, ' ')
37 | .replace(/.[^.]+$/, '');
38 | message = format(
39 | '%s - %s %s: \'%s\'',
40 | now, level.toUpperCase(), this.tag, message
41 | );
42 |
43 | ThaliLogger._logger(message);
44 |
45 | // Emit the `logged` event immediately because the event loop
46 | // will not exit until `process.stdout` has drained anyway.
47 | this.emit('logged');
48 | callback(null, true);
49 | };
50 |
51 | module.exports = function (tag) {
52 | if (!tag || typeof tag !== 'string' || tag.length < 3) {
53 | throw new Error(
54 | 'All logging must have a tag that is at least 3 characters long!'
55 | );
56 | }
57 | var thaliLogger = new ThaliLogger(tag);
58 | var logger = new winston.Logger({
59 | transports: [thaliLogger]
60 | });
61 | logger._thaliLogger = thaliLogger;
62 | logger.level = 'debug';
63 |
64 | // Node-SSDP uses Bunyan which supports trace, Winston does not. To work
65 | // around this we are hacking in trace support.
66 | logger.trace = logger.silly;
67 | return logger;
68 | };
69 |
--------------------------------------------------------------------------------
/test/www/jxcore/perf_tests/disabled/testNewFindPeers.js:
--------------------------------------------------------------------------------
1 | var ThaliEmitter = require('thali/thaliemitter');
2 |
3 | function testNewFindPeers(testData, name, peerCount, bluetoothAddresses) {
4 | this.deviceName = name;
5 | this.testData = testData;
6 | this.peerCount = peerCount;
7 | this.bluetoothAddresses = bluetoothAddresses;
8 | }
9 |
10 | testNewFindPeers.prototype.start = function() {
11 |
12 | var self = this;
13 |
14 | this.startTime = new Date();
15 | this.emitter = new ThaliEmitter();
16 |
17 | var discoveredPeers = {};
18 | this.emitter.on(ThaliEmitter.events.PEER_AVAILABILITY_CHANGED, function(peers) {
19 | var now = new Date();
20 | peers.forEach(function(peer) {
21 | if (!(peer.peerIdentifier in discoveredPeers) && peer.peerAvailable) {
22 | discoveredPeers[peer.peerIdentifier] = now - startTime;
23 | if (Object.keys(discoveredPeers).length == self.testData.peerCount) {
24 | self.reportResults(discoveredPeers);
25 | self.stop();
26 | }
27 | }
28 | });
29 | });
30 |
31 | this.emitter.startBroadcasting(this.deviceName, 4242, function (err) {
32 | if (err) {
33 | self.reportResults([], err);
34 | self.stop();
35 | }
36 | );
37 | }
38 |
39 | testNewFindPeers.prototype.stop = function() {
40 | this.emitter.stopBroadcasting(function(err) {
41 | console.log(err);
42 | this.emitter = null;
43 | };
44 | }
45 |
46 | testNewFindPeers.prototype.reportResults = function(discoveredPeers, err) {
47 |
48 | var results = [];
49 |
50 | for (var peer in discoveredPeers) {
51 | results.push({
52 | "peerName": peer.peerName,
53 | "peerIdentifier": peer.peerIdentifier,
54 | "peerAvailable": peer.peerAvailable,
55 | "time": discoveredPeers[peer]
56 | });
57 | }
58 |
59 | this.emit('done', JSON.stringify({
60 | "name:": this.deviceName,
61 | "time": new Date() - this.startTime,
62 | "result": "OK",
63 | "peersList": results
64 | }));
65 | }
66 |
67 | module.exports = testNewFindPeers;
68 |
--------------------------------------------------------------------------------
/test/www/jxcore/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "thali-cordova-plugin-jxcore",
3 | "version": "1.0.0",
4 | "description": "Thali Cordova Plugin JXCore",
5 | "main": "runTests.js",
6 | "scripts": {
7 | "test": "jx runTests.js",
8 | "test-meta": "jx runTests.js meta_tests",
9 | "test-coordinated": "jx runCoordinatedTests.js"
10 | },
11 | "keywords": [
12 | "Thali",
13 | "JXCore",
14 | "PouchDB",
15 | "Multiplex"
16 | ],
17 | "author": "Microsoft Corporation",
18 | "license": "MIT",
19 | "dependencies": {
20 | "balanced-match": "0.2.0",
21 | "bluebird": "3.4.6",
22 | "bn.js": "4.10.0",
23 | "body-parser": "1.13.3",
24 | "child-process-promise": "1.1.0",
25 | "concat-map": "0.0.1",
26 | "express": "4.13.3",
27 | "express-pouchdb": "1.0.6-thali",
28 | "forever-agent": "https://github.com/thaliproject/forever-agent.git#f9a92c7a1b7ce4da849beca32b0ec2aeb855e0fd",
29 | "fs-extra-promise": "0.4.0",
30 | "inherits": "2.0.1",
31 | "is-property": "1.0.2",
32 | "js-extend": "1.0.1",
33 | "leveldown-mobile": "1.1.1",
34 | "lie": "3.0.4",
35 | "long": "3.0.3",
36 | "minimist": "1.2.0",
37 | "multiplex": "6.7.0",
38 | "nock": "2.12.0",
39 | "node-ssdp": "https://github.com/thaliproject/node-ssdp.git#3a5909e201aee401f48965e378eb2ff0e2f9e027",
40 | "node-uuid": "1.4.7",
41 | "object-assign": "4.1.0",
42 | "pouchdb": "6.1.1",
43 | "pouchdb-size": "1.2.2",
44 | "proxyquire": "1.7.4",
45 | "randomstring": "1.1.5",
46 | "request": "2.64.0",
47 | "request-promise": "0.4.3",
48 | "salti": "https://github.com/thaliproject/salti.git#master",
49 | "sinon": "1.17.3",
50 | "socket.io-client": "1.4.8",
51 | "stacky": "1.3.1",
52 | "supertest": "1.1.0",
53 | "supertest-as-promised": "2.0.2",
54 | "tape": "4.0.0",
55 | "tape-catch": "1.0.4",
56 | "thali": "*",
57 | "tmp": "0.0.28",
58 | "urlsafe-base64": "1.0.0",
59 | "uuid": "2.0.0",
60 | "uuid-validate": "0.0.2"
61 | },
62 | "devDependencies": {}
63 | }
64 |
--------------------------------------------------------------------------------
/test/www/jxcore/meta_tests/disabled/testPerfTestFrameworkClient.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var originalMobile = typeof Mobile === 'undefined' ? undefined : Mobile;
4 | var mockMobile = require('../bv_tests/disabled/mockmobile.js');
5 | var PerfTestFrameworkClient = require('../perf_tests/PerfTestFrameworkClient.js');
6 | var tape = require('../lib/thaliTape');
7 | var EventEmitter = require("events").EventEmitter;
8 |
9 | var test = tape({
10 | setup: function(t) {
11 | global.Mobile = mockMobile;
12 | t.end();
13 | },
14 | teardown: function(t) {
15 | global.Mobile = originalMobile;
16 | t.end();
17 | }
18 | });
19 |
20 | test('passing wrong test name should throw', function (t) {
21 |
22 | var mockServer = new EventEmitter();
23 | var perfTestFrameworkClient = new PerfTestFrameworkClient('Some device name', null, mockServer);
24 |
25 | mockServer.on("error", function(msg) {
26 | t.ok(msg != null, msg);
27 | t.end();
28 | });
29 |
30 | var testData = {
31 | 'testName': 'testThatDoesNotExist',
32 | 'addressList': []
33 | };
34 |
35 | mockServer.emit("start", testData);
36 | });
37 |
38 | test('own address should be filtered out and try count reseted', function (t) {
39 | var myAddress = 'C0:EE:EE:EE:42:00'
40 | var dummyAddress = 'C0:FF:FF:EE:42:00';
41 |
42 | var mockServer = new EventEmitter();
43 | var perfTestFrameworkClient = new PerfTestFrameworkClient('Some device name', myAddress, mockServer);
44 |
45 | perfTestFrameworkClient.tests = {
46 | 'mockTest': function (testData, deviceName, addressList) {
47 | t.ok(addressList.length === 1, 'own address filtered out');
48 | t.ok(addressList[0].address === dummyAddress, 'other addresses in the address property');
49 | t.ok(addressList[0].tryCount === 0, 'try count is 0 in the beginning');
50 | return {
51 | start: function () {
52 | t.end();
53 | },
54 | on: function () {}
55 | };
56 | }
57 | };
58 |
59 | var testData = {
60 | 'testName': 'mockTest',
61 | 'addressList': [myAddress, dummyAddress]
62 | };
63 |
64 | mockServer.emit('start', testData);
65 | });
66 |
--------------------------------------------------------------------------------
/test/www/jxcore/lib/testLoader.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs-extra-promise');
4 | var path = require('path');
5 | var format = require('util').format;
6 |
7 | var logger = require('./testLogger')('testLoader');
8 |
9 |
10 | function sortFiles(files, preferredOrder) {
11 | if (!Array.isArray(preferredOrder)) {
12 | logger.info('Tests order is not specified. They will be sorted by name');
13 | preferredOrder = [];
14 | }
15 | files.sort(function (f1, f2) {
16 | var f1Name = path.basename(f1);
17 | var f2Name = path.basename(f2);
18 | var index1 = preferredOrder.indexOf(f1Name);
19 | var index2 = preferredOrder.indexOf(f2Name);
20 |
21 | if (index1 === -1 && index2 === -1) {
22 | // compare by name
23 | return f1Name > f2Name ? 1 : f1Name === f2Name ? 0 : -1;
24 | }
25 |
26 | // move unknown tests to the end of the list
27 | if (index1 === -1) { return 1; }
28 | if (index2 === -1) { return -1; }
29 |
30 | return index1 - index2;
31 | });
32 | }
33 |
34 |
35 | function hasJavaScriptSuffix (path) {
36 | return path.indexOf('.js', path.length - 3) !== -1;
37 | };
38 |
39 | function loadFile (filePath) {
40 | logger.info('loading file:', filePath);
41 | try {
42 | require(filePath);
43 | } catch (error) {
44 | var prettyError = format(
45 | 'test load failed, filePath: \'%s\', error: \'%s\', stack: \'%s\'',
46 | filePath, error.toString(), error.stack
47 | );
48 | logger.error(prettyError);
49 | throw new Error(prettyError);
50 | }
51 | };
52 |
53 | module.exports.load = function (testsToRun, preferredOrder) {
54 | if (hasJavaScriptSuffix(testsToRun)) {
55 | loadFile(testsToRun);
56 | } else {
57 | var testFiles = fs.readdirSync(testsToRun).filter(function (fileName) {
58 | return fileName.indexOf('test') === 0 && hasJavaScriptSuffix(fileName);
59 | });
60 | sortFiles(testFiles, preferredOrder);
61 | testFiles.forEach(function (fileName) {
62 | if (fileName.indexOf('test') === 0 && hasJavaScriptSuffix(fileName)) {
63 | var filePath = path.join(testsToRun, fileName);
64 | loadFile(filePath);
65 | }
66 | });
67 | }
68 | };
69 |
--------------------------------------------------------------------------------
/test/www/jxcore/meta_tests/testPouchDBAgent.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var objectAssign = require('object-assign');
4 | var ForeverAgent = require('forever-agent');
5 | var express = require('express');
6 | var expressPouchDB = require('express-pouchdb');
7 | var http = require('http');
8 |
9 | var tape = require('../lib/thaliTape');
10 | var testUtils = require('../lib/testUtils');
11 |
12 | var PouchDB = testUtils.getLevelDownPouchDb();
13 |
14 |
15 | var test = tape({
16 | setup: function (t) {
17 | t.end();
18 | },
19 | teardown: function (t) {
20 | t.end();
21 | }
22 | });
23 |
24 | test('PouchDB agent works as expected', function (t) {
25 | var agent = new ForeverAgent();
26 |
27 | var requestsData = [];
28 | var _addRequest = agent.addRequest;
29 | agent.addRequest = function (data) {
30 | requestsData.push(objectAssign({}, data));
31 | return _addRequest.apply(this, arguments);
32 | };
33 |
34 | var app = express();
35 | app.use('/db', expressPouchDB(PouchDB));
36 |
37 | var server = http.createServer(app);
38 | server.listen(0, function () {
39 | var port = server.address().port;
40 | var url = 'http://localhost:' + port + '/db';
41 | var db = new PouchDB(url, {
42 | ajax: {
43 | agent: agent
44 | }
45 | });
46 |
47 | function query(name) {
48 | return db.get(name)
49 | .then(function () {
50 | t.fail('we should not find a document');
51 | })
52 | .catch(function (error) {
53 | t.ok(error, 'error is not empty');
54 | t.equals(error.status, 404, 'status should be 404');
55 | })
56 | .then(function () {
57 | var lastData = requestsData[requestsData.length - 1];
58 | t.equals(lastData.method, 'GET', 'method is \'get\'');
59 | t.equals(lastData.path, '/db/' + name + '?', 'path is ok');
60 | });
61 | }
62 |
63 | query('fit')
64 | .then(function () {
65 | return query('foo');
66 | })
67 | .then(function () {
68 | t.ok(requestsData.length > 2, 'we should call agent more than twice');
69 | t.end();
70 | });
71 | });
72 | });
73 |
--------------------------------------------------------------------------------
/test/www/jxcore/meta_tests/testResultsProcessor.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var ResultsProcessor = require('../../../TestServer/ResultsProcessor.js');
4 | var tape = require('../lib/thaliTape');
5 |
6 | var test = tape({
7 | setup: function (t) {
8 | t.end();
9 | },
10 | teardown: function (t) {
11 | t.end();
12 | }
13 | });
14 |
15 | test('should be able to process valid results without exceptions', function (t) {
16 | var testResults = [
17 | {
18 | 'data': {
19 | 'name:': 'LGE-Nexus 5_PT7062',
20 | 'result': 'OK',
21 | 'sendList': [
22 | {
23 | 'connections': 3,
24 | 'dataAmount': 100000,
25 | 'dataReceived': 100000,
26 | 'doneRounds': 1,
27 | 'name': '90:E7:C4:FC:13:3C',
28 | 'result': 'OK',
29 | 'time': 57792,
30 | 'tryCount': 1
31 | }
32 | ],
33 | 'time': 119819
34 | },
35 | 'device': 'LGE-Nexus 5_PT7062',
36 | 'test': 0,
37 | 'time': 120073
38 | },
39 | {
40 | 'data': {
41 | 'name:': 'HTC-HTC6535LVW_PT3841',
42 | 'result': 'OK',
43 | 'sendList': [
44 | {
45 | 'connections': 2,
46 | 'dataAmount': 100000,
47 | 'dataReceived': 100000,
48 | 'doneRounds': 5,
49 | 'name': 'F8:95:C7:13:51:1E',
50 | 'result': 'OK',
51 | 'time': 30550,
52 | 'tryCount': 1
53 | }
54 | ],
55 | 'time': 115137
56 | },
57 | 'device': 'HTC-HTC6535LVW_PT3841',
58 | 'test': 0,
59 | 'time': 115231
60 | },
61 | {
62 | 'data': {
63 | 'name:': 'A5-1',
64 | 'time': 10005,
65 | 'result': 'TIMEOUT',
66 | 'sendList': []
67 | },
68 | 'device': 'A5-1',
69 | 'test': 0,
70 | 'time': 100051
71 | }
72 | ];
73 | var testDevices = {
74 | 'LGE-Nexus 5_PT7062': {},
75 | 'HTC-HTC6535LVW_PT3841': {},
76 | 'A5-1': {}
77 | };
78 | var processedResults = ResultsProcessor.process(testResults, testDevices);
79 | t.ok(processedResults, 'received processed results');
80 | t.end();
81 | });
82 |
--------------------------------------------------------------------------------
/thali/NextGeneration/identityExchange/connectionTable.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var EventEmitter = require('events').EventEmitter;
4 | var inherits = require('util').inherits;
5 | var ThaliReplicationManager = require('../thalireplicationmanager');
6 |
7 | inherits(ConnectionTable, EventEmitter);
8 |
9 | ConnectionTable.prototype.thaliReplicationManager = null;
10 | ConnectionTable.prototype.connectionTable = {};
11 | ConnectionTable.prototype.connectionSuccessListener = null;
12 | ConnectionTable.prototype.cleanUpWasCalled = false;
13 | ConnectionTable.prototype.cleanUpCalledErrorMessage =
14 | 'Cleanup was called, this table is no longer live.';
15 |
16 | ConnectionTable.prototype.lookUpPeerId = function (peerId, lastTime) {
17 | if (this.cleanUpWasCalled) {
18 | throw new Error(this.cleanUpCalledErrorMessage);
19 | }
20 |
21 | var tableEntry = this.connectionTable[peerId];
22 |
23 | tableEntry = tableEntry === undefined ? null : tableEntry;
24 |
25 | if (!tableEntry || !lastTime) {
26 | return tableEntry;
27 | }
28 |
29 | return tableEntry.time > lastTime ? tableEntry : null;
30 | };
31 |
32 | ConnectionTable.prototype.cleanUp = function () {
33 | this.cleanUpWasCalled = true;
34 | this.thaliReplicationManager.removeListener(ThaliReplicationManager.events.CONNECTION_SUCCESS,
35 | this.connectionSuccessListener);
36 | };
37 |
38 | /**
39 | * A temporary hack to collect connectionSuccess events. Once we put in ACLs we won't need this hack anymore.
40 | * @param thaliReplicationManager
41 | * @constructor
42 | */
43 | function ConnectionTable(thaliReplicationManager) {
44 | EventEmitter.call(this);
45 | var self = this;
46 | this.thaliReplicationManager = thaliReplicationManager;
47 | this.connectionTable = {};
48 | this.connectionSuccessListener = function (successObject) {
49 | self.connectionTable[successObject.peerIdentifier] = {
50 | muxPort: successObject.muxPort,
51 | time: Date.now()
52 | };
53 |
54 | self.emit(successObject.peerIdentifier, self.connectionTable[successObject.peerIdentifier]);
55 | };
56 | thaliReplicationManager.on(ThaliReplicationManager.events.CONNECTION_SUCCESS, this.connectionSuccessListener);
57 | }
58 |
59 | module.exports = ConnectionTable;
60 |
61 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/disabled/mockmobile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var keys = {};
4 |
5 | // arguments needed to simulate the GetDocumentsPath() function
6 | var errArgGetDocumentsPath;
7 | var fileLocationArgGetDocumentsPath;
8 |
9 | function Mobile(key) {
10 | keys.hasOwnProperty(key) || (keys[key] = new Mobile.NativeCall(key));
11 | return keys[key];
12 | }
13 |
14 | Mobile.iAmAMock = true;
15 |
16 | Mobile.setGetDocumentsPathReturnValues = function (errArg, fileLocationArg) {
17 | errArgGetDocumentsPath = errArg;
18 | fileLocationArgGetDocumentsPath = fileLocationArg;
19 | };
20 |
21 | Mobile.GetDocumentsPath = function (cb) {
22 | cb(errArgGetDocumentsPath, fileLocationArgGetDocumentsPath);
23 | };
24 |
25 | Mobile.invokeNative = function (key, arg) {
26 | keys[key].registerNativeCallback(arg);
27 | };
28 |
29 | function invokeCallback(key, args) {
30 | var localArgs = keys[key].callNativeArguments;
31 | var cb = localArgs[localArgs.length - 1];
32 | cb.apply(null, args);
33 | }
34 |
35 | Mobile.invokeConnect = function () {
36 | var len = arguments.length, args = new Array(len);
37 | for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
38 | invokeCallback('Connect', args);
39 | };
40 |
41 | Mobile.invokeDisconnect = function () {
42 | var len = arguments.length, args = new Array(len);
43 | for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
44 | invokeCallback('Disconnect', args);
45 | };
46 |
47 | Mobile.invokeStartBroadcasting = function () {
48 | var len = arguments.length, args = new Array(len);
49 | for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
50 | invokeCallback('StartBroadcasting', args);
51 | };
52 |
53 | Mobile.invokeStopBroadcasting = function () {
54 | var len = arguments.length, args = new Array(len);
55 | for (var i = 0; i < len; i++) { args[i] = arguments[i]; }
56 | invokeCallback('StopBroadcasting', args);
57 | };
58 |
59 | Mobile.NativeCall = function (key) {
60 | this.key = key;
61 | this.registerNativeCallback = null;
62 | this.callNativeArguments = null;
63 | };
64 |
65 | Mobile.NativeCall.prototype = {
66 | registerToNative: function (cb) {
67 | this.registerNativeCallback = cb;
68 | },
69 | callNative: function () {
70 | this.callNativeArguments = arguments;
71 | }
72 | };
73 |
74 | module.exports = Mobile;
75 |
--------------------------------------------------------------------------------
/test/www/jxcore/readme.md:
--------------------------------------------------------------------------------
1 | # Thali Cordova Plugin Replication Manager Tests #
2 |
3 | ## Overview
4 |
5 | ### Directory structure
6 |
7 | ```
8 | |____bv_tests/ <- Build Verification tests. You should run these often.
9 | |____lib/ <- Support files for running tests.
10 | |____perf_tests/ <- Performance tests. Long running tests. For nightly builds etc.
11 | |____meta_tests/ <- Tests non-production code like test frameworks and installation.
12 | |____readme.md <- This file.
13 | |____runTests.js <- The test runner to run tests stand-alone.
14 | |____runCoordinatedTests.js <- The test runner to run tests with test coordination server.
15 | |____server-address.js <- Contains the IP address of the test coordination server.
16 | |____PerfTest_app.js <- Rename to app.js, build and deploy to run perf tests.
17 | |____UnitTest_app.js <- Rename to app.js, build and deploy to run bv tests.
18 | ```
19 |
20 | ## Running the tests
21 |
22 | ## Contributing
23 |
24 | If you see a mistake, find a bug, or you think there is a better way to do something, feel free to contribute.
25 | Please see our [contribution page](http://thaliproject.org/WaysToContribute) for ways to connect and start
26 | contributing to Thali.
27 |
28 | ## License
29 |
30 | Copyright (c) 2015 Microsoft
31 |
32 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
33 |
34 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
35 |
36 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 |
--------------------------------------------------------------------------------
/src/android/java/io/jxcore/node/SurroundingStateObserver.java:
--------------------------------------------------------------------------------
1 | package io.jxcore.node;
2 |
3 | import org.thaliproject.p2p.btconnectorlib.PeerProperties;
4 |
5 | /**
6 | * Created by evabishchevich on 1/3/17.
7 | */
8 |
9 | public interface SurroundingStateObserver {
10 |
11 | /**
12 | * Notifies node layer about peer changes detected on native Android layer
13 | *
14 | * @param peerProperties Peer properties of new/updated/lost peer.
15 | * @param isAvailable If true, peer is available. False otherwise.
16 | */
17 | void notifyPeerAvailabilityChanged(PeerProperties peerProperties, boolean isAvailable);
18 |
19 | /**
20 | * Notifies about discovery and/or advertising changes
21 | *
22 | * @param isDiscoveryActive We are currently discovering if true. False otherwise.
23 | * @param isAdvertisingActive We are currently advertising if true. False otherwise.
24 | */
25 | void notifyDiscoveryAdvertisingStateUpdateNonTcp(boolean isDiscoveryActive, boolean isAdvertisingActive);
26 |
27 | /**
28 | * @param isBluetoothEnabled If true, Bluetooth is enabled. False otherwise.
29 | * @param isWifiEnabled If true, Wi-Fi is enabled. False otherwise.
30 | * @param bssidName If null this value indicates that either wifiRadioOn is not 'on' or
31 | * that the Wi-Fi isn't currently connected to an access point.
32 | * If non-null then this is the BSSID of the access point that Wi-Fi
33 | * is connected to.
34 | * @param ssidName If null this value indicates that either wifiRadioOn is not 'on' or
35 | * that the Wi-Fi isn't currently connected to an access point.
36 | * If non-null then this is the SSID of the access point that Wi-Fi
37 | * is connected to.
38 | */
39 | void notifyNetworkChanged(boolean isBluetoothEnabled, boolean isWifiEnabled, String bssidName, String ssidName);
40 |
41 | /**
42 | * This event is guaranteed to be not sent more often than every 100 ms.
43 | *
44 | * @param portNumber The 127.0.0.1 port that the TCP/IP bridge tried to connect to.
45 | */
46 | void notifyIncomingConnectionToPortNumberFailed(int portNumber);
47 | }
48 |
--------------------------------------------------------------------------------
/test/www/jxcore/perf_tests/ReConnectTCPServer.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * This test is needing all three files to be present
4 | * - testReConnect.js : the main entry point to the test case
5 | * - ReConnectConnector.js : logic that handles the connection & data sending parts
6 | * - ReConnectTCPServer.js : logic that handles the server endpoint for connections & data receiving/replying for the test
7 | *
8 | * In this test case we try connecting to the remote peer and verify that the connection works by sending small amount of data (that gets echoed back)
9 | * We measure the time it takes to create the connection, and then disconnect and do re-connections as specified by the test data
10 | */
11 | 'use strict';
12 | var net = require('net');
13 |
14 |
15 | function ReConnectTCPServer(port) {
16 | var self = this;
17 | self.port = port;
18 |
19 | this.stopServer();
20 | this.server = net.createServer(function (c) { //'connection' listener
21 | console.log('TCP/IP server connected');
22 |
23 | c.on('end', function () {
24 | console.log('TCP/IP server is ended');
25 | });
26 | c.on('close', function () {
27 | console.log('TCP/IP server is close');
28 | });
29 | c.on('error', function (err) {
30 | console.log('TCP/IP server got error : ' + err);
31 | });
32 |
33 | c.on('data', function (data) {
34 | console.log("TCP/IP server got data - " + data.length);
35 | c.write(data.toString());
36 | });
37 | });
38 |
39 | this.server.on('error', function (data) {
40 | console.log("TCP/IP server error: " + data.toString());
41 | });
42 | this.server.on('close', function () {
43 | console.log('TCP/IP server socket is disconnected');
44 | });
45 |
46 | this.server.listen(port, function() { //'listening' listener
47 | console.log('TCP/IP server is bound to : ' + this.port);
48 | });
49 | }
50 | ReConnectTCPServer.prototype.getServerPort = function() {
51 | return (this.server && this.server.address()) ? this.server.address().port : 0;
52 | }
53 |
54 | ReConnectTCPServer.prototype.stopServer = function() {
55 | if(this.server == null) {
56 | return;
57 | }
58 |
59 | this.server.close();
60 | this.server = null;
61 | }
62 |
63 | module.exports = ReConnectTCPServer;
64 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/testNativeMethod.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var platform = require('thali/NextGeneration/utils/platform');
4 |
5 | var tape = require('../lib/thaliTape');
6 | var thaliMobileNativeWrapper = require('../node_modules/thali/NextGeneration/thaliMobileNativeWrapper');
7 |
8 | var callbackPeer;
9 |
10 | var test = tape({
11 | setup: function (t) {
12 | t.end();
13 | },
14 | teardown: function (t) {
15 | thaliMobileNativeWrapper._registerToNative();
16 | t.end();
17 | }
18 | });
19 |
20 | test('onPeerLost calls jxcore',
21 | function () {
22 | return !platform._isRealAndroid;
23 | },
24 | function (t) {
25 | Mobile('peerAvailabilityChanged').registerToNative(function (peers) {
26 | if (!Array.isArray(peers)) {
27 | peers = [peers];
28 | t.fail('peers callback should be an array!');
29 | }
30 |
31 | t.equals(peers.length, 1, 'There should be exactly one peer');
32 | callbackPeer = peers[0];
33 |
34 | t.equal(callbackPeer.peerIdentifier, '11:22:33:22:11:00',
35 | 'check if callback was fired by onPeerLost');
36 | t.ok(callbackPeer.generation === null, 'check if generation is null');
37 | t.notOk(callbackPeer.peerAvailable, 'check if peerAvailable is false');
38 |
39 | t.end();
40 | });
41 |
42 | Mobile('testNativeMethod').callNative('onPeerLost', function (result) {
43 | t.pass(result.Testing_);
44 | });
45 | });
46 |
47 | test('onPeerDiscovered calls jxcore',
48 | function () {
49 | return !platform._isRealAndroid;
50 | },
51 | function (t) {
52 | Mobile('peerAvailabilityChanged').registerToNative(function (peers) {
53 |
54 | if (!Array.isArray(peers)) {
55 | peers = [peers];
56 | t.fail('peers callback should be an array!');
57 | }
58 |
59 | t.equals(peers.length, 1, 'There should be exactly one peer');
60 | callbackPeer = peers[0];
61 |
62 | t.equal(callbackPeer.peerIdentifier, '33:44:55:44:33:22',
63 | 'check if callback was fired by onPeerDiscovered');
64 | t.equal(callbackPeer.generation, 0, 'check if generation is 0');
65 | t.ok(callbackPeer.peerAvailable, 'check if peerAvailable is true');
66 |
67 | t.end();
68 | });
69 |
70 | Mobile('testNativeMethod').callNative('onPeerDiscovered', function (result) {
71 | t.pass(result.Testing_);
72 | });
73 | });
74 |
--------------------------------------------------------------------------------
/test/www/jxcore/perf_tests/SendDataTCPServer.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var net = require('net');
4 |
5 | var logger = function (value) {
6 | //console.log(new Date().toJSON() + ' SendDataTCPServer.js: ' + value);
7 | };
8 |
9 | function SendDataTCPServer(port) {
10 | var self = this;
11 | self.port = port;
12 |
13 | var limitToReport = 10000;
14 |
15 | this.server = net.createServer(function (c) { //'connection' listener
16 | var receivedDataInBytes = 0;
17 | var lastReportedAmount = 0;
18 |
19 | logger('TCP/IP server connected');
20 |
21 | c.on('end', function () {
22 | logger('TCP/IP server is ended');
23 | c.destroy();
24 | });
25 |
26 | c.on('error', function (err) {
27 | logger('TCP/IP server got error : ' + err);
28 | });
29 |
30 | c.on('data', function (data) {
31 | receivedDataInBytes += data.length;
32 | logger('TCP/IP server has received ' + receivedDataInBytes + ' bytes of data');
33 | var dataSincePreviousReport = receivedDataInBytes - lastReportedAmount;
34 |
35 | if (dataSincePreviousReport >= limitToReport) {
36 | var acknowledgmentCount = Math.round(dataSincePreviousReport / limitToReport);
37 |
38 | for (var i = 0; i < acknowledgmentCount; i++) {
39 | c.write('ACK');
40 | }
41 |
42 | lastReportedAmount += acknowledgmentCount * limitToReport;
43 | }
44 | });
45 | });
46 |
47 | this.server.on('error', function (data) {
48 | logger("TCP/IP server error: " + data.toString());
49 | });
50 | this.server.on('close', function () {
51 | logger('TCP/IP server socket is disconnected');
52 | });
53 |
54 | this.server.listen(port, function () {
55 | logger('TCP/IP server is bound to port: ' + self.getServerPort());
56 | });
57 | }
58 | SendDataTCPServer.prototype.getServerPort = function() {
59 | return (this.server && this.server.address()) ? this.server.address().port : 0;
60 | }
61 |
62 | SendDataTCPServer.prototype.stopServer = function (callback) {
63 | if (this.server == null) {
64 | if (callback) callback();
65 | return;
66 | }
67 | this.server.close(callback);
68 | this.server = null;
69 | }
70 |
71 | module.exports = SendDataTCPServer;
72 |
--------------------------------------------------------------------------------
/thali/install/ios/build-ci-no-tests.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed to the Apache Software Foundation (ASF) under one
3 | // or more contributor license agreements. See the NOTICE file
4 | // distributed with this work for additional information
5 | // regarding copyright ownership. The ASF licenses this file
6 | // to you under the Apache License, Version 2.0 (the
7 | // "License"); you may not use this file except in compliance
8 | // with the License. You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing,
13 | // software distributed under the License is distributed on an
14 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | // KIND, either express or implied. See the License for the
16 | // specific language governing permissions and limitations
17 | // under the License.
18 | //
19 |
20 | //
21 | // XCode Build settings for "Release" Build Configuration.
22 | //
23 |
24 | HEADER_SEARCH_PATHS = "$(TARGET_BUILD_DIR)/usr/local/lib/include" "$(OBJROOT)/UninstalledProducts/include" "$(OBJROOT)/UninstalledProducts/$(PLATFORM_NAME)/include" "$(BUILT_PRODUCTS_DIR)"
25 | IPHONEOS_DEPLOYMENT_TARGET = 10.0
26 | OTHER_LDFLAGS = -ObjC
27 | TARGETED_DEVICE_FAMILY = 1,2
28 | SWIFT_VERSION = 3.0
29 |
30 | // Type of signing identity used for codesigning, resolves to first match of given type.
31 | // "iPhone Developer": Development builds (default, local only; iOS Development certificate) or "iPhone Distribution": Distribution builds (Adhoc/In-House/AppStore; iOS Distribution certificate)
32 | CODE_SIGN_IDENTITY = iPhone Developer
33 | CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer
34 |
35 | // (CB-9721) Set ENABLE_BITCODE to NO in build.xcconfig
36 | ENABLE_BITCODE = NO
37 |
38 | // (CB-9719) Set CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES to YES in build.xcconfig
39 | CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES
40 |
41 | // (CB-10072)
42 | SWIFT_OBJC_BRIDGING_HEADER = $(PROJECT_DIR)/$(PROJECT_NAME)/Bridging-Header.h
43 |
44 | // CI Required
45 |
46 | // BluetoothManager private API requires build with embedded arm64 architecture
47 | ONLY_ACTIVE_ARCH = NO
48 |
49 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
50 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1
51 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks
52 | OTHER_SWIFT_FLAGS = $(inherited)
53 |
--------------------------------------------------------------------------------
/thali/install/ios/build-ci.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Licensed to the Apache Software Foundation (ASF) under one
3 | // or more contributor license agreements. See the NOTICE file
4 | // distributed with this work for additional information
5 | // regarding copyright ownership. The ASF licenses this file
6 | // to you under the Apache License, Version 2.0 (the
7 | // "License"); you may not use this file except in compliance
8 | // with the License. You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing,
13 | // software distributed under the License is distributed on an
14 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | // KIND, either express or implied. See the License for the
16 | // specific language governing permissions and limitations
17 | // under the License.
18 | //
19 |
20 | //
21 | // XCode Build settings for "Debug" Build Configuration.
22 | //
23 |
24 | HEADER_SEARCH_PATHS = "$(TARGET_BUILD_DIR)/usr/local/lib/include" "$(OBJROOT)/UninstalledProducts/include" "$(OBJROOT)/UninstalledProducts/$(PLATFORM_NAME)/include" "$(BUILT_PRODUCTS_DIR)"
25 | IPHONEOS_DEPLOYMENT_TARGET = 10.0
26 | OTHER_LDFLAGS = -ObjC
27 | TARGETED_DEVICE_FAMILY = 1,2
28 | SWIFT_VERSION = 3.0
29 |
30 | // Type of signing identity used for codesigning, resolves to first match of given type.
31 | // "iPhone Developer": Development builds (default, local only; iOS Development certificate) or "iPhone Distribution": Distribution builds (Adhoc/In-House/AppStore; iOS Distribution certificate)
32 | CODE_SIGN_IDENTITY = iPhone Developer
33 | CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer
34 |
35 | // (CB-9721) Set ENABLE_BITCODE to NO in build.xcconfig
36 | ENABLE_BITCODE = NO
37 |
38 | // (CB-9719) Set CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES to YES in build.xcconfig
39 | CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES
40 |
41 | // (CB-10072)
42 | SWIFT_OBJC_BRIDGING_HEADER = $(PROJECT_DIR)/$(PROJECT_NAME)/Bridging-Header.h
43 |
44 | // CI Required
45 |
46 | // BluetoothManager private API requires build with embedded arm64 architecture
47 | ONLY_ACTIVE_ARCH = NO
48 |
49 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
50 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1 TEST=1
51 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks
52 | OTHER_SWIFT_FLAGS = $(inherited) '-DTEST'
53 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/testPouchDBGenerator.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var tape = require('../lib/thaliTape');
4 | var testUtils = require('../lib/testUtils.js');
5 |
6 | var fs = require('fs-extra-promise');
7 | var path = require('path');
8 | var PouchDB = require('pouchdb');
9 | var PouchDBGenerator = require('thali/NextGeneration/utils/pouchDBGenerator');
10 | var leveldownMobile = require('leveldown-mobile');
11 |
12 | // DB defaultDirectory should be unique among all tests
13 | // and any instance of this test.
14 | // This is especially required for tape.coordinated.
15 | var defaultDirectory = path.join(
16 | testUtils.getPouchDBTestDirectory(),
17 | 'pouch-db-generator-db-' + testUtils.getRandomPouchDBName()
18 | );
19 |
20 | var test = tape({
21 | setup: function (t) {
22 | fs.ensureDirSync(defaultDirectory);
23 | t.end();
24 | },
25 | teardown: function (t) {
26 | fs.removeSync(defaultDirectory);
27 | t.end();
28 | }
29 | });
30 |
31 | test('test defaultDirectory', function (t) {
32 | var LocalPouchDB = PouchDBGenerator(PouchDB, defaultDirectory, {
33 | defaultAdapter: leveldownMobile
34 | });
35 |
36 | var db = LocalPouchDB('https://localhost:3000');
37 | t.equals(db.__opts.prefix, undefined);
38 |
39 | db = LocalPouchDB('http://localhost:3000');
40 | t.equals(db.__opts.prefix, undefined);
41 |
42 | db = LocalPouchDB('dbname');
43 | t.equals(db.__opts.prefix, defaultDirectory);
44 |
45 | t.end();
46 | });
47 |
48 | test('test defaultAdapter', function (t) {
49 | var LocalPouchDB = PouchDBGenerator(PouchDB, defaultDirectory, {
50 | defaultAdapter: leveldownMobile
51 | });
52 |
53 | var db = LocalPouchDB('https://localhost:3000');
54 | t.equals(db._adapter, 'https');
55 | t.equals(db.__opts.db, undefined);
56 |
57 | db = LocalPouchDB('http://localhost:3000');
58 | t.equals(db._adapter, 'http');
59 | t.equals(db.__opts.db, undefined);
60 |
61 | db = LocalPouchDB('dbname');
62 | t.equals(db._adapter, 'leveldb-mobile');
63 | t.equals(db.__opts.db, leveldownMobile);
64 |
65 | // Passing an empty function as defaultAdapter has no sense. This is just for testing.
66 | var obj = function () {
67 | return {
68 | open: function () {}
69 | };
70 | };
71 | LocalPouchDB = PouchDBGenerator(PouchDB, defaultDirectory, {
72 | defaultAdapter: obj
73 | });
74 | db = LocalPouchDB('dbname');
75 | t.equals(db._adapter, 'leveldb-mobile');
76 | t.equals(db.__opts.db, obj);
77 |
78 | t.end();
79 | });
80 |
--------------------------------------------------------------------------------
/test/www/jxcore/UnitTest_app.js:
--------------------------------------------------------------------------------
1 | /*
2 | * This file needs to be renamed as app.js when we want to run unit tests
3 | * in order this to get loaded by the jxcore ready event.
4 | * This effectively acts as main entry point to the unit test app
5 | */
6 |
7 | 'use strict';
8 |
9 | var Promise = require('bluebird');
10 | Promise.config({
11 | cancellation: true
12 | });
13 |
14 | var platform = require('thali/NextGeneration/utils/platform');
15 |
16 | if (typeof Mobile === 'undefined') {
17 | var mockPlatform = require('./lib/parsePlatformArg')();
18 | global.Mobile = require('./lib/wifiBasedNativeMock.js')(mockPlatform);
19 | }
20 |
21 | var config = require('./config');
22 | var objectAssign = require('object-assign');
23 | process.env = objectAssign(process.env, config.env);
24 |
25 | var logger = require('./lib/testLogger')('UnitTest_app');
26 | var testUtils = require('./lib/testUtils');
27 | var ThaliMobile = require('thali/NextGeneration/thaliMobile');
28 |
29 | var utResult = false;
30 |
31 | if (platform._isRealMobile) {
32 | Mobile('executeNativeTests').callNative(function (result) {
33 | logger.debug('Running unit tests');
34 | if (result) {
35 | if (!result.executed) {
36 | console.log('*Native tests were not executed*');
37 |
38 | utResult = false;
39 | } else {
40 | console.log('*Native tests were executed*');
41 |
42 | utResult = result.failed <= 0;
43 | }
44 |
45 | console.log('Total number of executed tests: ', result.total);
46 | console.log('Number of passed tests: ', result.passed);
47 | console.log('Number of failed tests: ', result.failed);
48 | console.log('Number of ignored tests: ', result.ignored);
49 | console.log('Total duration: ', result.duration);
50 | } else {
51 | console.log('*Native tests results are empty*');
52 |
53 | utResult = false;
54 | }
55 | });
56 |
57 | if (!utResult) {
58 | console.log('Failed to execute UT.');
59 | global.nativeUTFailed = true;
60 |
61 | }
62 | } else {
63 | // We aren't on a device so we can't run those tests anyway
64 | utResult = true;
65 | }
66 |
67 | if (!utResult) {
68 | logger.debug('Failed to execute UT.');
69 | global.nativeUTFailed = true;
70 | }
71 |
72 | global.NETWORK_TYPE = ThaliMobile.networkTypes.NATIVE;
73 |
74 | Mobile('GetDeviceName').callNative(function (name) {
75 | logger.debug('My device name is: \'%s\'', name);
76 | testUtils.setName(name);
77 | require('./runTests.js');
78 | });
79 |
80 | logger.debug('Unit Test app is loaded');
81 |
--------------------------------------------------------------------------------
/src/android/test/io/jxcore/node/IncomingSocketThreadMock.java:
--------------------------------------------------------------------------------
1 | package io.jxcore.node;
2 |
3 | import android.bluetooth.BluetoothSocket;
4 | import android.util.Log;
5 |
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.io.OutputStream;
9 | import java.net.Inet4Address;
10 | import java.net.Socket;
11 | import org.thaliproject.p2p.btconnectorlib.PeerProperties;
12 |
13 | public class IncomingSocketThreadMock extends IncomingSocketThread {
14 | Long threadId = 4321L;
15 | int port;
16 | boolean closeCalled = false;
17 | InputStream tempInputStream = null;
18 | OutputStream tempOutputStream = null;
19 | boolean localStreamsCreatedSuccessfully = false;
20 |
21 | public IncomingSocketThreadMock(BluetoothSocket bluetoothSocket, Listener listener,
22 | InputStream inputStream, OutputStream outputStream)
23 | throws IOException {
24 | super(bluetoothSocket, listener, inputStream, outputStream);
25 | }
26 |
27 | public void setPort(int _port){
28 | port = _port;
29 | }
30 |
31 | @Override
32 | public void close() {
33 | closeCalled = true;
34 | }
35 |
36 | @Override
37 | public long getId() {
38 | return threadId;
39 | }
40 |
41 | @Override
42 | public void run() {
43 | mIsClosing = false;
44 | try {
45 | Inet4Address mLocalHostAddress = (Inet4Address) Inet4Address.getByName("localhost");
46 |
47 | mLocalhostSocket = new Socket(mLocalHostAddress, port);
48 |
49 | Log.i(mTag, "Local host address: " + getLocalHostAddressAsString() + ", port: " +
50 | getLocalHostPort());
51 |
52 | tempInputStream = mLocalhostSocket.getInputStream();
53 | tempOutputStream = mLocalhostSocket.getOutputStream();
54 | localStreamsCreatedSuccessfully = true;
55 | } catch (IOException e) {
56 | Log.e(mTag, "Failed to create the local streams: " + e.getMessage(), e);
57 | mListener.onDisconnected(this, "Failed to create the local streams: " + e.getMessage());
58 | }
59 |
60 | if (localStreamsCreatedSuccessfully) {
61 | Log.d(mTag, "Setting local streams and starting stream copying threads...");
62 | mLocalInputStream = tempInputStream;
63 | mLocalOutputStream = tempOutputStream;
64 |
65 | startStreamCopyingThreads(new ConnectionData(
66 | new PeerProperties(PeerProperties.BLUETOOTH_MAC_ADDRESS_UNKNOWN), true));
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/thali/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "thali",
3 | "version": "2.1.0",
4 | "description": "Thali Cordova Plugin",
5 | "main": "thalireplicationmanager.js",
6 | "dependencies": {
7 | "bluebird": "3.4.6",
8 | "body-parser": "1.13.3",
9 | "express": "4.13.3",
10 | "forever-agent": "https://github.com/thaliproject/forever-agent.git#f9a92c7a1b7ce4da849beca32b0ec2aeb855e0fd",
11 | "ip": "1.0.1",
12 | "javascript-state-machine": "2.3.5",
13 | "lie": "3.1.0",
14 | "long": "3.0.3",
15 | "multiplex": "6.7.0",
16 | "node-ssdp": "https://github.com/thaliproject/node-ssdp.git#3a5909e201aee401f48965e378eb2ff0e2f9e027",
17 | "object-assign": "4.1.0",
18 | "pouchdb-adapter-leveldb-core": "6.1.1",
19 | "request": "2.64.0",
20 | "salti": "https://github.com/thaliproject/salti.git#master",
21 | "urlsafe-base64": "1.0.0",
22 | "uuid": "2.0.2",
23 | "winston": "2.2.0"
24 | },
25 | "devDependencies": {
26 | "jsdoc": "3.3.3",
27 | "eslint": "3.11.1"
28 | },
29 | "thaliInstall": {
30 | "thali": {
31 | "projectName": "thaliproject",
32 | "depotName": "Thali_CordovaPlugin",
33 | "branchName": "iOS"
34 | },
35 | "androidConfig": {
36 | "minSdkVersion": "21",
37 | "buildToolsVersion": "25.0.2",
38 | "compileSdkVersion": "android-25"
39 | },
40 | "btconnectorlib2": "0.3.9",
41 | "jxcore-cordova": "0.1.14",
42 | "jxcore-cordova-url": "http://jxcore.azureedge.net/jxcore-cordova/0.1.14/release/io.jxcore.node.jx"
43 | },
44 | "scripts": {
45 | "prepublish": "node install/prePublishThaliCordovaPlugin.js",
46 | "postpublish": "node install/postPublishThaliCordovaPlugin.js",
47 | "postinstall": "node installCordovaPlugin.js",
48 | "createPublicDocs": "./node_modules/.bin/jsdoc -c conf.json .",
49 | "createInternalDocs": "./node_modules/.bin/jsdoc -c conf.json -p ."
50 | },
51 | "repository": {
52 | "type": "git",
53 | "url": "git+https://github.com/thaliproject/Thali_CordovaPlugin.git"
54 | },
55 | "keywords": [
56 | "Thali",
57 | "JXCore",
58 | "PouchDB",
59 | "Multiplex",
60 | "cordova",
61 | "Plugin",
62 | "P2P",
63 | "BlueTooth",
64 | "BLE",
65 | "Multipeer Connectivity Framework",
66 | "node.js",
67 | "Android",
68 | "iOS",
69 | "Cordova"
70 | ],
71 | "author": "Microsoft Corporation",
72 | "license": "MIT",
73 | "bugs": {
74 | "url": "https://github.com/thaliproject/Thali_CordovaPlugin/issues"
75 | },
76 | "homepage": "https://github.com/thaliproject/Thali_CordovaPlugin/tree/story_00#readme"
77 | }
78 |
--------------------------------------------------------------------------------
/test/www/index.html:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
31 |
32 |
33 |
34 |
35 |
36 | Hello World
37 |
38 |
39 |
40 |
Thali Test App
41 |
42 |
43 |
44 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/disabled/testMultiplex.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var tcpmultiplex = require('thali/tcpmultiplex');
4 | var tape = require('../../lib/thaliTape');
5 | var net = require('net');
6 | var randomstring = require('randomstring');
7 | var multiplex = require('multiplex');
8 |
9 | var test = tape({
10 | setup: function(t) {
11 | t.end();
12 | },
13 | teardown: function(t) {
14 | t.end();
15 | }
16 | });
17 |
18 | test('multiplex can send data', function (t) {
19 | var len = 200;
20 | var testMessage = randomstring.generate(len);
21 |
22 | var server = net.createServer(function (socket) {
23 | var plex1 = multiplex(function (stream) {
24 | stream.on('data', function (data) {
25 | t.equal(testMessage, String(data), 'String should be length:' + testMessage.length);
26 | t.end();
27 |
28 | socket.destroy();
29 | server.close();
30 | });
31 | });
32 |
33 | socket.pipe(plex1).pipe(socket);
34 | });
35 |
36 | server.listen(0, function () {
37 | var serverPort = server.address().port;
38 | var socket = net.createConnection({port: serverPort}, function () {
39 | var plex2 = multiplex();
40 | var stream = plex2.createStream();
41 | stream.write(new Buffer(testMessage));
42 |
43 | plex2.pipe(socket).pipe(plex2);
44 | });
45 | });
46 | });
47 | /*
48 | test('muxServerBridge', function (t) {
49 | var len = 200;
50 | var testMessage = randomstring.generate(len);
51 |
52 | var testServer = net.createServer(function (socket) {
53 | socket.pipe(socket);
54 | });
55 |
56 | testServer.listen(0, function () {
57 | var testServerPort = testServer.address().port;
58 | var muxServerBridge = tcpmultiplex.muxServerBridge(testServerPort);
59 | muxServerBridge.listen(function () {
60 | var serverPort = muxServerBridge.address().port;
61 |
62 | var muxClientBridge = tcpmultiplex.muxClientBridge(serverPort, function (err) {
63 |
64 | muxClientBridge.listen(function () {
65 | var clientPort = muxClientBridge.address().port;
66 |
67 | var socket = net.createConnection({port: clientPort}, function () {
68 | socket.end(new Buffer(testMessage));
69 | });
70 |
71 | socket.on('data', function (data) {
72 | t.equal(testMessage, String(data), 'String should be length:' + testMessage.length);
73 | t.end();
74 |
75 | muxClientBridge.on('close', function () {
76 | console.log('closed');
77 | });
78 |
79 | muxClientBridge.close();
80 | muxServerBridge.close();
81 | server.close();
82 | });
83 | });
84 | });
85 | });
86 | });
87 | });
88 | */
89 |
--------------------------------------------------------------------------------
/thali/NextGeneration/thaliConfig.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint multistr: true */
4 |
5 | var BOGUS_CERT_PEM = '-----BEGIN CERTIFICATE-----\n\
6 | MIICKjCCAZMCCQDQ8o4kHKdCPDANBgkqhkiG9w0BAQUFADB6MQswCQYDVQQGEwJV\n\
7 | UzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQKEwZKb3llbnQxEDAO\n\
8 | BgNVBAsTB05vZGUuanMxDDAKBgNVBAMTA2NhMTEgMB4GCSqGSIb3DQEJARYRcnlA\n\
9 | dGlueWNsb3Vkcy5vcmcwHhcNMTEwMzE0MTgyOTEyWhcNMzgwNzI5MTgyOTEyWjB9\n\
10 | MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQK\n\
11 | EwZKb3llbnQxEDAOBgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MTEgMB4G\n\
12 | CSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwXDANBgkqhkiG9w0BAQEFAANL\n\
13 | ADBIAkEAnzpAqcoXZxWJz/WFK7BXwD23jlREyG11x7gkydteHvn6PrVBbB5yfu6c\n\
14 | bk8w3/Ar608AcyMQ9vHjkLQKH7cjEQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAKha\n\
15 | HqjCfTIut+m/idKy3AoFh48tBHo3p9Nl5uBjQJmahKdZAaiksL24Pl+NzPQ8LIU+\n\
16 | FyDHFp6OeJKN6HzZ72Bh9wpBVu6Uj1hwhZhincyTXT80wtSI/BoUAW8Ls2kwPdus\n\
17 | 64LsJhhxqj2m4vPKNRbHB2QxnNrGi30CUf3kt3Ia\n\
18 | -----END CERTIFICATE-----';
19 |
20 | var BOGUS_KEY_PEM = '-----BEGIN RSA PRIVATE KEY-----\n\
21 | MIIBOwIBAAJBAJ86QKnKF2cVic/1hSuwV8A9t45URMhtdce4JMnbXh75+j61QWwe\n\
22 | cn7unG5PMN/wK+tPAHMjEPbx45C0Ch+3IxECAwEAAQJBAI2cU1IuR+4IO87WPyAB\n\
23 | 76kruoo87AeNQkjjvuQ/00+b/6IS45mcEP5Kw0NukbqBhIw2di9uQ9J51DJ/ZfQr\n\
24 | +YECIQDUHaN3ZjIdJ7/w8Yq9Zzz+3kY2F/xEz6e4ftOFW8bY2QIhAMAref+WYckC\n\
25 | oECgOLAvAxB1lI4j7oCbAaawfxKdnPj5AiEAi95rXx09aGpAsBGmSdScrPdG1v6j\n\
26 | 83/2ebrvoZ1uFqkCIB0AssnrRVjUB6GZTNTyU3ERfdkx/RX1zvr8WkFR/lXpAiB7\n\
27 | cUZ1i8ZkZrPrdVgw2cb28UJM7qZHQnXcMHTXFFvxeQ==\n\
28 | -----END RSA PRIVATE KEY-----';
29 |
30 | module.exports = {
31 | SSDP_IP: '228.227.226.225',
32 | SSDP_NT: process.env.SSDP_NT || 'http://www.thaliproject.org/ssdp',
33 | SSDP_ADVERTISEMENT_INTERVAL: 500,
34 | SSDP_OWN_PEERS_HISTORY_SIZE: 10,
35 | PEER_AVAILABILITY_WATCHER_INTERVAL: 1000,
36 | TCP_PEER_UNAVAILABILITY_THRESHOLD: 5 * 500,
37 | TCP_TIMEOUT_WIFI: 1000,
38 | TCP_TIMEOUT_BLUETOOTH: 5000,
39 | TCP_TIMEOUT_MPCF: 5000,
40 | NOTIFICATION_BEACON_PATH: '/NotificationBeacons',
41 | BEACON_MILLISECONDS_TO_EXPIRE: 60 * 60 * 1000,
42 | BASE_DB_PATH: '/db',
43 | SUPPORTED_PSK_CIPHERS: 'PSK-AES256-CBC-SHA',
44 | BEACON_CURVE: 'secp256k1',
45 | MAXIMUM_NATIVE_PEERS_CREATE_PEER_LISTENER_ADVERTISES: 20,
46 | BOGUS_CERT_PEM: BOGUS_CERT_PEM,
47 | BOGUS_KEY_PEM: BOGUS_KEY_PEM,
48 | BEACON_PSK_IDENTITY: 'Beacon Please',
49 | BEACON_KEY: new Buffer('Let me in please!!'),
50 | MAX_NOTIFICATIONSERVER_PSK_MAP_CACHE_SIZE: 50,
51 | LOCAL_SEQ_POINT_PREFIX: 'thali_',
52 | UPDATE_WINDOWS_FOREGROUND_MS: 1000,
53 | UPDATE_WINDOWS_BACKGROUND_MS: 10000,
54 | MAXIMUM_NUMBER_OF_PEERS_TO_NOTIFY: 15,
55 | MULTI_PEER_CONNECTIVITY_FRAMEWORK_PEERS_LIMIT: 200,
56 | BLUETOOTH_PEERS_LIMIT: 200,
57 | TCP_NATIVE_PEERS_LIMIT: 200
58 | };
59 |
--------------------------------------------------------------------------------
/src/android/java/io/jxcore/node/JXcoreThaliCallback.java:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2016 Microsoft Corporation. This software is licensed under the MIT License.
2 | * See the license file delivered with this project for further information.
3 | */
4 | package io.jxcore.node;
5 |
6 | /**
7 | * A utility class for delayed/asynchronous JXcore callbacks.
8 | */
9 | abstract class JXcoreThaliCallback {
10 | private final ListenerOrIncomingConnection mListenerOrIncomingConnection = new ListenerOrIncomingConnection();
11 | private String mErrorMessage = null;
12 |
13 | /**
14 | * @return The ListenerOrIncomingConnection instance. Guaranteed not be null.
15 | */
16 | public ListenerOrIncomingConnection getListenerOrIncomingConnection() {
17 | return mListenerOrIncomingConnection;
18 | }
19 |
20 | public String getErrorMessage() {
21 | return mErrorMessage;
22 | }
23 |
24 | public void setErrorMessage(String errorMessage) {
25 | mErrorMessage = errorMessage;
26 | }
27 |
28 | public void callOnConnectCallback(
29 | final String errorMessage, final ListenerOrIncomingConnection listenerOrIncomingConnection) {
30 | jxcore.activity.runOnUiThread(new Runnable() {
31 | @Override
32 | public void run() {
33 | onConnectCallback(errorMessage, listenerOrIncomingConnection);
34 | }
35 | });
36 | }
37 |
38 | public void callOnStartStopCallback(final String errorMessage) {
39 | jxcore.activity.runOnUiThread(new Runnable() {
40 | @Override
41 | public void run() {
42 | onStartStopCallback(errorMessage);
43 | }
44 | });
45 | }
46 |
47 | /**
48 | * If err is not NULL then listenerOrIncomingConnection MUST be null and vice
49 | * versa.
50 | *
51 | * @param errorMessage If null then the call the callback was submitted to was
52 | * successful. If not null then it will be an Error object that will define what
53 | * went wrong.
54 | * @param listenerOrIncomingConnection If null then the call the callback was
55 | * submitted to failed. Otherwise this
56 | * contains the success results.
57 | */
58 | protected void onConnectCallback(
59 | String errorMessage, ListenerOrIncomingConnection listenerOrIncomingConnection) {
60 | // No default implementation
61 | }
62 |
63 | /**
64 | * @param errorMessage If null, the operation was successful.
65 | */
66 | protected void onStartStopCallback(String errorMessage) {
67 | // No default implementation
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/test/www/jxcore/perf_tests/BluetoothConnectionLimits.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var events = require('events');
4 | var ThaliEmitter = require('thali/thaliemitter');
5 |
6 | /** @module BluetoothConnectionLimits */
7 |
8 | /**
9 | * @file
10 | *
11 | * The problem we face is that we fundamentally don't know how the heck Bluetooth actually works on Android phones.
12 | * By way of background Bluetooth is based on something called a piconet. A piconet consists of a boss with up to 7
13 | * workers. Bluetooth is a time division multiplexing protocol and all the devices in the same piconet use the boss's
14 | * clock to decide how to grab time slots and the boss tells the workers when they are allowed to speak. To complicate
15 | * matters further there can actually be up to 256 devices in a piconet but beyond those 8 the rest have to be
16 | * inactive. This means in effective they are asleep. The boss is allowed to wake up devices but if they are at
17 | * the maximum of 7 active devices then they have to move an active device to being inactive.
18 | *
19 | * A single device can be boss on exactly one piconet but it can be a worker on a theoretically unlimited number of
20 | * piconets. In practice however the probability of message collisions go up the more devices and piconets there are
21 | * so at some point the density of devices would get high enough to seriously interfere with communications.
22 | *
23 | * So here is what we don't know:
24 | * - When device A and device B establish an insecure RFCOMM connection how do they decide what piconet to use?
25 | * - If device A already has a connection with device B and then device B establishes a connection with device A does
26 | * this go over the existing insecure RFCOMM connection or is a new connection created? If a new connection is created
27 | * does it go over the existing piconet or on a new piconet?
28 | * - How many piconets can a device support being a worker on?
29 | *
30 | * We can boil this down to a set of specific questions we need answers to:
31 | * 1. How many simultaneous incoming connections can we support?
32 | * 2. How many simultaneous outgoing connections can we support?
33 | * 3. Are the answers to questions 1 and 2 related, that is, is the right question "how many connections of any type
34 | * can we simultaneously support"?
35 | * 4. If we allow a connection to go quiet will it become an inactive connection and affect the answers to questions
36 | * 1-3?
37 | * 5. Are the answers to questions 1-3 different depending on the hardware and OS we are using on the devices?
38 | */
39 |
40 | /**
41 | * This function will determine for a device what is the maximum number of simultaneous active incoming connections
42 | * each of the devices in the test can handle.
43 | */
44 | function testMaxIncomingActiveConnections() {
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/test/www/jxcore/meta_tests/testSync.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 | var format = util.format;
5 |
6 | var Promise = require('bluebird');
7 | var path = require('path');
8 | var fs = require('fs');
9 |
10 | var tape = require('../lib/thaliTape');
11 | var testUtils = require('../lib/testUtils');
12 | var logger = require('../lib/testLogger')('testSync');
13 |
14 | if (!tape.coordinated) {
15 | return;
16 | }
17 |
18 |
19 | // We will use a files for data verification.
20 | var localData = {
21 | path: path.join(testUtils.tmpDirectory(), 'testSync.txt'),
22 | timeout: Math.floor(Math.random() * 100)
23 | };
24 |
25 | var test = tape({
26 | setup: function (t) {
27 | t.data = localData;
28 | t.end();
29 | },
30 | teardown: function (t) {
31 | t.end();
32 | }
33 | });
34 |
35 | function checkAllFiles(participants) {
36 | var promises = participants.map(function (participant) {
37 | var path = participant.data.path;
38 | return new Promise(function (resolve, reject) {
39 | fs.stat(path, function (error, stats) {
40 | if (error || !stats.isFile()) {
41 | reject(new Error(
42 | format('file does not exist, path: \'%s\'', path)
43 | ));
44 | } else {
45 | logger.debug('file exist, path: \'%s\'', path);
46 | resolve();
47 | }
48 | });
49 | });
50 | });
51 | return Promise.all(promises);
52 | }
53 |
54 | function syncWorks (t) {
55 | return new Promise(function (resolve) {
56 | setTimeout(resolve, localData.timeout);
57 | })
58 | .then(function () {
59 | // we are creating local file at random period of time.
60 | return fs.writeFile(localData.path, '');
61 | })
62 | .then(function () {
63 | logger.debug('file created, path: \'%s\'', localData.path);
64 | return t.sync();
65 | })
66 | .then(function () {
67 | return checkAllFiles(t.participants);
68 | })
69 | .then(function () {
70 | return t.sync();
71 | })
72 | .then(function () {
73 | fs.unlinkSync(localData.path);
74 | logger.debug('file removed, path: \'%s\'', localData.path);
75 | });
76 | }
77 |
78 | test('test sync works', function (t) {
79 | syncWorks(t)
80 | .then(function () {
81 | t.pass('passed');
82 | })
83 | .catch(function (error) {
84 | t.fail('failed with ' + error.toString());
85 | })
86 | .then(function () {
87 | t.end();
88 | });
89 | });
90 |
91 | test('test multiple syncs works', function (t) {
92 | syncWorks(t)
93 | .then(function () {
94 | return syncWorks(t);
95 | })
96 | .then(function () {
97 | t.pass('passed');
98 | })
99 | .catch(function (error) {
100 | t.fail('failed with ' + error.toString());
101 | })
102 | .then(function () {
103 | t.end();
104 | });
105 | });
106 |
--------------------------------------------------------------------------------
/www/android/thaliPermissions.js:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015-2016 Microsoft
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in
13 | // all copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | // THE SOFTWARE.
22 | //
23 | // Permissions Cordova Plugin
24 | // ThaliPermissions.js
25 |
26 | 'use strict';
27 |
28 | /** @module thaliPermissions */
29 |
30 | /**
31 | * Response codes for the permission request.
32 | * @readonly
33 | * @enum {string}
34 | */
35 | module.exports.responseCodes = {
36 | /** User has denied access to requested permission */
37 | 'PERMISSION_DENIED': 'PERMISSION_DENIED',
38 | /** Concurrent request are not supported*/
39 | 'RESPONSE_CONCURRENT_PERMISSION_REQUESTS_NOT_SUPPORTED':
40 | 'RESPONSE_CONCURRENT_PERMISSION_REQUESTS_NOT_SUPPORTED'
41 | };
42 |
43 | /**
44 | * This callback function is called if the location permission is granted.
45 | * @public
46 | * @callback successCallbackFn
47 | */
48 |
49 | /**
50 | * This callback function is called if the location permission is not granted.
51 | * @public
52 | * @callback errorCallbackFn
53 | * @param {module:thaliPermissions~responseCodes}
54 | */
55 |
56 | /**
57 | * Beginning in Android 6.0, users grant permissions to apps while the app is
58 | * running. This function can be used to check whether the user has
59 | * granted the location permission for the application.
60 | * If the location permission is not granted, and the user hasn't checked
61 | * "Never ask again" for a permission query dialog system will display
62 | * the permission query dialog for the user.
63 | * @param {module:thaliPermissions~successCallbackFn} successFn
64 | * @param {module:thaliPermissions~errorCallbackFn} errorFn
65 | */
66 | module.exports.requestLocationPermission = function (successFn, errorFn) {
67 | cordova.exec(successFn, errorFn, 'ThaliPermissions',
68 | 'REQUEST_ACCESS_COARSE_LOCATION', []);
69 | };
70 |
--------------------------------------------------------------------------------
/test/TestServer/HttpServer.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 | var inherits = util.inherits;
5 |
6 | var http = require('http');
7 | var socketIO = require('socket.io');
8 | var objectAssign = require('object-assign');
9 | var EventEmitter = require('events').EventEmitter;
10 |
11 | var asserts = require('./utils/asserts');
12 | var logger = require('./utils/ThaliLogger')('HttpServer');
13 |
14 | var TestDevice = require('./TestDevice');
15 |
16 |
17 | function Server (options) {
18 | var self = this;
19 |
20 | this._setOptions(options);
21 |
22 | var server = http.createServer();
23 | this._io = socketIO(server, {
24 | transports: this._options.transports
25 | });
26 | server.listen(this._options.port, function () {
27 | logger.info('listening on *:' + self._options.port);
28 | });
29 |
30 | this._bind();
31 | }
32 |
33 | inherits(Server, EventEmitter);
34 |
35 | Server.prototype.defaults = {
36 | transports: ['websocket']
37 | };
38 |
39 | Server.prototype._setOptions = function (options) {
40 | asserts.isObject(options, 'Server._setOptions');
41 |
42 | this._options = objectAssign({}, this.defaults, options);
43 |
44 | asserts.isNumber(this._options.port);
45 | asserts.isArray(this._options.transports);
46 | this._options.transports.forEach(function (transport) {
47 | asserts.isString(transport);
48 | });
49 | };
50 |
51 | Server.prototype._bind = function () {
52 | process.once('exit', this._exit.bind(this));
53 | this._io.on('connect', this._connect.bind(this));
54 | };
55 |
56 | Server.prototype._connect = function (socket) {
57 | asserts.exists(socket);
58 | socket.deviceName = 'device that was not presented yet';
59 |
60 | socket
61 | .on('disconnect', this._disconnect.bind(this, socket))
62 | .on('error', this._error.bind(this, socket))
63 | .on('present', this._present.bind(this, socket));
64 | };
65 |
66 | Server.prototype._disconnect = function (socket, reason) {
67 | logger.info(
68 | 'Socket to device name: \'%s\' disconnected, reason: \'%s\'',
69 | socket.deviceName, reason
70 | );
71 | };
72 |
73 | Server.prototype._error = function (socket, error) {
74 | logger.error(
75 | 'unexpected server error: \'%s\'',
76 | error.content
77 | );
78 | throw new Error(error.content);
79 | };
80 |
81 | Server.prototype._present = function (socket, deviceInfo) {
82 | var device = new TestDevice(socket, deviceInfo);
83 | socket.deviceName = device.name;
84 |
85 | logger.debug(
86 | 'device presented, name: \'%s\', uuid: \'%s\', platformName: \'%s\', ' +
87 | 'type: \'%s\', hasRequiredHardware: \'%s\', nativeUTFailed: \'%s\'',
88 | device.name, device.uuid, device.platformName, device.type,
89 | device.hasRequiredHardware, device.nativeUTFailed
90 | );
91 |
92 | this.emit('present', device);
93 | };
94 |
95 | Server.prototype._exit = function () {
96 | this._io.close();
97 | };
98 |
99 | module.exports = Server;
100 |
--------------------------------------------------------------------------------
/test/www/jxcore/lib/utils/asserts.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var format = require('util').format;
4 | var assert = require('assert');
5 |
6 |
7 | function exists(value) {
8 | return value !== undefined && value !== null;
9 | }
10 | module.exports.exists = function (value) {
11 | assert(
12 | exists(value),
13 | format('existing value expected, received: \'%s\'', value)
14 | );
15 | };
16 |
17 | function isString(value) {
18 | return exists(value) && typeof value === 'string';
19 | }
20 | module.exports.isString = function (value) {
21 | assert(
22 | isString(value),
23 | format('string expected, received: \'%s\'', value)
24 | );
25 | };
26 |
27 | function isArray(value) {
28 | return exists(value) && Array.isArray(value);
29 | }
30 | module.exports.isArray = function (value) {
31 | assert(
32 | isArray(value),
33 | format('array expected, received: \'%s\'', value)
34 | );
35 | };
36 |
37 | function isBool(value) {
38 | return value === true || value === false;
39 | }
40 | module.exports.isBool = function (value) {
41 | assert(
42 | isBool(value),
43 | format('bool expected, received: \'%s\'', value)
44 | );
45 | };
46 |
47 | function isNumber(value) {
48 | return exists(value) && typeof value === 'number';
49 | }
50 | module.exports.isNumber = function (value) {
51 | assert(
52 | isNumber(value),
53 | format('number expected, received: \'%s\'', value)
54 | );
55 | };
56 |
57 | function arrayEquals(a1, a2) {
58 | if (
59 | !isArray(a1) || !isArray(a2) ||
60 | a1.length !== a2.length
61 | ) {
62 | return false;
63 | }
64 | return a1.every(function (value, key) {
65 | return value === a2[key];
66 | });
67 | }
68 | module.exports.arrayEquals = function (a1, a2) {
69 | assert(
70 | arrayEquals(a1, a2),
71 | format('equals arrays expected, received array 1: \'%s\', array 2: \'%s\'',
72 | a1, a2)
73 | );
74 | };
75 |
76 | function isObject(value) {
77 | return exists(value) && typeof value === 'object';
78 | }
79 | module.exports.isObject = function (value) {
80 | assert(
81 | isObject(value),
82 | format('object expected, received: \'%s\'', value)
83 | );
84 | };
85 |
86 | function instanceOf(value, base) {
87 | return isObject(value) && value instanceof base;
88 | }
89 | module.exports.instanceOf = function (value, base) {
90 | assert(
91 | instanceOf(value, base),
92 | format('\'%s\' should be an instance of \'%s\'', value, base)
93 | );
94 | };
95 |
96 | module.exports.equals = function (value1, value2) {
97 | assert(
98 | value1 === value2,
99 | format('equals values expected, received value 1: \'%s\', value 2: \'%s\'',
100 | value1, value2)
101 | );
102 | };
103 |
104 | function isFunction(fun) {
105 | return exists(fun) && typeof fun === 'function';
106 | }
107 | module.exports.isFunction = function (value) {
108 | assert(
109 | isFunction(value),
110 | format('function expected, received: \'%s\'', value)
111 | );
112 | };
113 |
--------------------------------------------------------------------------------
/test/TestServer/utils/asserts.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var format = require('util').format;
4 | var assert = require('assert');
5 |
6 |
7 | function exists(value) {
8 | return value !== undefined && value !== null;
9 | }
10 | module.exports.exists = function (value) {
11 | assert(
12 | exists(value),
13 | format('existing value expected, received: \'%s\'', value)
14 | );
15 | };
16 |
17 | function isString(value) {
18 | return exists(value) && typeof value === 'string';
19 | }
20 | module.exports.isString = function (value) {
21 | assert(
22 | isString(value),
23 | format('string expected, received: \'%s\'', value)
24 | );
25 | };
26 |
27 | function isArray(value) {
28 | return exists(value) && Array.isArray(value);
29 | }
30 | module.exports.isArray = function (value) {
31 | assert(
32 | isArray(value),
33 | format('array expected, received: \'%s\'', value)
34 | );
35 | };
36 |
37 | function isBool(value) {
38 | return value === true || value === false;
39 | }
40 | module.exports.isBool = function (value) {
41 | assert(
42 | isBool(value),
43 | format('bool expected, received: \'%s\'', value)
44 | );
45 | };
46 |
47 | function isNumber(value) {
48 | return exists(value) && typeof value === 'number';
49 | }
50 | module.exports.isNumber = function (value) {
51 | assert(
52 | isNumber(value),
53 | format('number expected, received: \'%s\'', value)
54 | );
55 | };
56 |
57 | function arrayEquals(a1, a2) {
58 | if (
59 | !isArray(a1) || !isArray(a2) ||
60 | a1.length !== a2.length
61 | ) {
62 | return false;
63 | }
64 | return a1.every(function (value, key) {
65 | return value === a2[key];
66 | });
67 | }
68 | module.exports.arrayEquals = function(a1, a2) {
69 | assert(
70 | arrayEquals(a1, a2),
71 | format('equals arrays expected, received array 1: \'%s\', array 2: \'%s\'', a1, a2)
72 | );
73 | }
74 |
75 | function isObject(value) {
76 | return exists(value) && typeof value === 'object';
77 | }
78 | module.exports.isObject = function (value, message) {
79 | assert(
80 | isObject(value),
81 | format('object expected, received: \'%s\' \'%s\'', value,
82 | message ? ('-' + message) : '')
83 | );
84 | };
85 |
86 | function instanceOf(value, base) {
87 | return isObject(value) && value instanceof base;
88 | }
89 | module.exports.instanceOf = function (value, base) {
90 | assert(
91 | instanceOf(value, base),
92 | format('\'%s\' should be an instance of \'%s\'', value, base)
93 | );
94 | };
95 |
96 | module.exports.equals = function (value1, value2) {
97 | assert(
98 | value1 === value2,
99 | format('equals values expected, received value 1: \'%s\', value 2: \'%s\'', value1, value2)
100 | );
101 | }
102 |
103 | function isFunction(fun) {
104 | return exists(fun) && typeof fun === 'function';
105 | }
106 | module.exports.isFunction = function (value) {
107 | assert(
108 | isFunction(value),
109 | format('function expected, received: \'%s\'', value)
110 | );
111 | };
112 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/disabled/IdentityExchange/testConnectionTable.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var tape = require('../lib/thaliTape');
4 | var ConnectionTable = require('thali/identityExchange/connectionTable');
5 | var ThaliReplicationManager = require('thali/thalireplicationmanager');
6 |
7 | // test setup & teardown activities
8 | var test = tape({
9 | setup: function (t) {
10 | t.end();
11 | },
12 | teardown: function(t) {
13 | t.end();
14 | }
15 | });
16 |
17 | function createAnnounce(peerId, muxPort) {
18 | return { peerIdentifier: peerId, muxPort: muxPort };
19 | }
20 |
21 | var peersToAnnounce = [
22 | createAnnounce("a", 30),
23 | createAnnounce("b", 40),
24 | createAnnounce("a", 50),
25 | createAnnounce("c", 60)
26 | ];
27 |
28 | var results = [
29 | { peerId: "a", port: 50 },
30 | { peerId: "b", port: 40 },
31 | { peerId: "c", port: 60 }
32 | ];
33 |
34 | test('test connectionTable table building and cleanup', function (t) {
35 | var thaliReplicationManager = new ThaliReplicationManager("bogus", "bogus");
36 | var connectionTable = new ConnectionTable(thaliReplicationManager);
37 |
38 | var timeBeforeEmit = Date.now();
39 |
40 | peersToAnnounce.forEach(function(announce) {
41 | thaliReplicationManager.emit(ThaliReplicationManager.events.CONNECTION_SUCCESS, announce);
42 | });
43 |
44 | var timeAfterEmit = Date.now();
45 |
46 | results.forEach(function(result) {
47 | var lookup = connectionTable.lookUpPeerId(result.peerId);
48 | t.equal(lookup.muxPort, result.port);
49 | t.ok(lookup.time >= timeBeforeEmit && lookup.time <= timeAfterEmit);
50 | });
51 |
52 | t.equal(null, connectionTable.lookUpPeerId("d"));
53 | t.equal(null, connectionTable.lookUpPeerId("a", Date.now() + 100));
54 | t.ok(connectionTable.lookUpPeerId("c", 0));
55 |
56 | connectionTable.cleanUp();
57 | t.throws(function() { connectionTable.lookUpPeerId("a") }, connectionTable.cleanUpCalledErrorMessage);
58 | t.end();
59 | });
60 |
61 | test('test connectionTable emitting events for peerIds', function(t) {
62 | var thaliReplicationManager = new ThaliReplicationManager("bogus", "bogus");
63 | var connectionTable = new ConnectionTable(thaliReplicationManager);
64 |
65 | var connectionTableListenersThatRan = 0;
66 |
67 | peersToAnnounce.forEach(function(announce) {
68 | var timeBeforeEmit = Date.now()
69 | var listener = function(tableEntry) {
70 | t.equal(announce.muxPort, tableEntry.muxPort);
71 | t.ok(tableEntry.time >= timeBeforeEmit && tableEntry.time <= timeBeforeEmit + 100);
72 |
73 | connectionTable.removeListener(announce.peerIdentifier, listener);
74 |
75 | connectionTableListenersThatRan += 1;
76 | if (connectionTableListenersThatRan == peersToAnnounce.length) {
77 | t.end();
78 | }
79 | };
80 | connectionTable.on(announce.peerIdentifier, listener);
81 | thaliReplicationManager.emit(ThaliReplicationManager.events.CONNECTION_SUCCESS, announce);
82 | });
83 | });
84 |
--------------------------------------------------------------------------------
/test/www/jxcore/PerfTest_app.js:
--------------------------------------------------------------------------------
1 | /*
2 | * This file needs to be renamed as app.js when we want to run performance tests
3 | * in order this to get loaded by the jxcore ready event.
4 | * This effectively acts as main entry point to the performance test app
5 | */
6 |
7 | 'use strict';
8 |
9 | var testUtils = require('./lib/testUtils');
10 | var TestFrameworkClient = require('./perf_tests/PerfTestFrameworkClient');
11 | var platform = require('thali/NextGeneration/utils/platform');
12 |
13 | /* -----------------------------------------------------------------------------
14 | code for connecting to the coordinator server
15 | -----------------------------------------------------------------------------*/
16 |
17 | function getDeviceCharacteristics(cb) {
18 |
19 | if (typeof jxcore === 'undefined') {
20 | cb('PERF_TEST-' + Math.random(), null);
21 | }
22 | else if (platform.isAndroid) {
23 | Mobile('GetBluetoothAddress').callNative(
24 | function (bluetoothAddressError, bluetoothAddress) {
25 | Mobile('GetBluetoothName').callNative(
26 | function (bluetoothNameError, bluetoothName) {
27 | Mobile('GetDeviceName').callNative(
28 | function (deviceName) {
29 | console.log('Received device characteristics:\n' +
30 | 'Bluetooth address: ' + bluetoothAddress + '\n' +
31 | 'Bluetooth name: ' + bluetoothName + '\n' +
32 | 'Device name: ' + deviceName);
33 | // In case of Android, the name used is first checked from the
34 | // Bluetooth name, because that is one that user can set. If that is
35 | // not set, the returned device name is used. The device name is not
36 | // guaranteed to be unique, because it is concatenated from device
37 | // manufacturer and model and will thus be the same in case of
38 | // identical devices.
39 | var myName = bluetoothName || deviceName;
40 | if (!myName || !bluetoothAddress) {
41 | console.log('An error while getting the device characteristics!');
42 | }
43 | testUtils.setName(myName);
44 | cb(myName, bluetoothAddress);
45 | });
46 | });
47 | });
48 | } else {
49 | Mobile('GetDeviceName').callNative(function (deviceName) {
50 | // In case of iOS, the device name is used directly, because
51 | // the one returned in the one that user can set.
52 | testUtils.setName(deviceName);
53 | cb(deviceName, null);
54 | });
55 | }
56 | }
57 |
58 | /* -----------------------------------------------------------------------------
59 | code for handling test communications
60 | -----------------------------------------------------------------------------*/
61 |
62 | var testFramework;
63 | getDeviceCharacteristics(function (deviceName, bluetoothAddress) {
64 | // The test framework client will coordinate everything from here..
65 | process.nextTick(function () {
66 | testFramework = new TestFrameworkClient(deviceName, bluetoothAddress);
67 | });
68 | });
69 |
70 | console.log('Perf Test app is loaded');
71 |
--------------------------------------------------------------------------------
/thali/install/cordova-hooks/ios/after_plugin_install.js:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt file in the project root
4 | // for full license information.
5 | //
6 |
7 | 'use strict';
8 |
9 | var fs = require('fs');
10 | var nativeInstaller = require('../../ios/nativeInstaller');
11 | var path = require('path');
12 |
13 | function loadIsTestEnvironment() {
14 | var utFlagFilePath = 'platforms/ios/unittests';
15 |
16 | try {
17 | var utFlag = fs.lstatSync(utFlagFilePath);
18 |
19 | try {
20 | console.log('Removing UT flag');
21 |
22 | fs.unlinkSync(utFlagFilePath);
23 | } catch (error) {
24 | console.log(error);
25 | console.log('Failed to remove the UT flag file, continuing anyway');
26 | }
27 |
28 | return utFlag.isFile();
29 | } catch (error) {
30 | console.log(error);
31 | console.log('Not a test environment, continue normally.');
32 | }
33 |
34 | return false;
35 | }
36 |
37 | module.exports = function (context) {
38 |
39 | var isTestEnvironment = loadIsTestEnvironment();
40 |
41 | // Need a promise so that
42 | // the install waits for us to complete our project modifications
43 | // before the plugin gets installed.
44 | var Q = context.requireCordovaModule('q');
45 | var deferred = new Q.defer();
46 |
47 | // Only bother if we're on macOS
48 | if (process.platform !== 'darwin') {
49 | deferred.resolve();
50 | return deferred.promise;
51 | }
52 |
53 | var platforms = context.opts.cordova.platforms;
54 |
55 | // We can bail out if the iOS platform isn't present.
56 | if (platforms.indexOf('ios') === -1) {
57 | deferred.resolve();
58 | return deferred.promise;
59 | }
60 |
61 | // We need to build ThaliCore.framework before embedding it into the project
62 | var iOSInfrastructureFolder = path.join(
63 | context.opts.plugin.dir, 'lib', 'ios');
64 | var testingInfrastructureForlder = path.join(
65 | context.opts.plugin.dir, 'src', 'ios', 'Testing');
66 | var thaliCoreProjectFolder = path.join(
67 | context.opts.plugin.dir, 'lib', 'ios', 'Carthage', 'Checkouts', 'thali-ios');
68 |
69 | // We need to embded frameworks to the project here.
70 | // They need to be embedded binaries and cordova does not yet support that.
71 | // We will use node-xcode directy to add them since that library has
72 | // been upgraded to support embedded binaries.
73 |
74 | // Cordova libs to get the project path and project name
75 | // so we can locate the xcode project file.
76 | var cordovaUtil =
77 | context.requireCordovaModule('cordova-lib/src/cordova/util');
78 | var ConfigParser = context.requireCordovaModule('cordova-lib').configparser;
79 | var projectRoot = cordovaUtil.isCordova();
80 | var xml = cordovaUtil.projectConfig(projectRoot);
81 | var cfg = new ConfigParser(xml);
82 |
83 | var projectPath = path.join(
84 | projectRoot, 'platforms', 'ios', cfg.name() + '.xcodeproj');
85 |
86 | return nativeInstaller.addFramework(projectPath, thaliCoreProjectFolder,
87 | iOSInfrastructureFolder, isTestEnvironment, testingInfrastructureForlder);
88 | };
89 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "node": true
4 | },
5 | "globals": {
6 | "Mobile": true
7 | },
8 | "rules": {
9 | "no-cond-assign": 2,
10 | "eqeqeq": 2,
11 | "no-caller": 2,
12 | "no-undef": 2,
13 | "no-unused-vars": [
14 | 2,
15 | {
16 | "vars": "local",
17 | "args": "after-used"
18 | }
19 | ],
20 | "no-eq-null": 2,
21 | "strict": [
22 | 2,
23 | "safe"
24 | ],
25 | "no-irregular-whitespace": 2,
26 | "guard-for-in": 2,
27 | "no-unused-expressions": [
28 | 2,
29 | {
30 | "allowShortCircuit": true,
31 | "allowTernary": true
32 | }
33 | ],
34 | "no-new": 2,
35 | "no-extra-semi": 2,
36 | "no-use-before-define": [
37 | 2,
38 | {
39 | "functions": false
40 | }
41 | ],
42 | "no-extend-native": 2,
43 | "max-depth": [
44 | 2,
45 | 3
46 | ],
47 | "valid-jsdoc": [
48 | 2,
49 | {
50 | "requireReturn": false,
51 | "requireParamDescription": false,
52 | "requireReturnDescription": false
53 | }
54 | ],
55 | "max-len": [
56 | 2,
57 | 80,
58 | 2,
59 | {
60 | "ignoreTrailingComments": true,
61 | "ignoreUrls": true,
62 | "ignoreStrings": true,
63 | "ignorePattern": getMaxLenPatterns()
64 | }
65 | ],
66 | "camelcase": [
67 | 2,
68 | {
69 | "properties": "never"
70 | }
71 | ],
72 | "comma-style": [
73 | 2,
74 | "last"
75 | ],
76 | "curly": [
77 | 2,
78 | "all"
79 | ],
80 | "dot-notation": [
81 | 2,
82 | {
83 | "allowKeywords": true
84 | }
85 | ],
86 | "operator-linebreak": [
87 | 2,
88 | "after"
89 | ],
90 | "semi": [
91 | 2,
92 | "always"
93 | ],
94 | "keyword-spacing": [
95 | 2,
96 | {}
97 | ],
98 | "comma-spacing": [
99 | 2,
100 | {
101 | "after": true
102 | }
103 | ],
104 | "spaced-comment": [
105 | 2,
106 | "always"
107 | ],
108 | "consistent-this": [
109 | 2,
110 | "self"
111 | ],
112 | "indent": [
113 | 2,
114 | 2,
115 | {
116 | "SwitchCase": 1
117 | }
118 | ],
119 | "quotes": [
120 | 2,
121 | "single"
122 | ]
123 | }
124 | };
125 |
126 | function getMaxLenPatterns() {
127 | var patterns = [
128 | // /**
129 | // * @param {type} identifier
130 | // */
131 | /^\s+?\* @(param|arg|argument|prop|property) \{.+?\} (\[.+?\]|[\w\d_\.\[\]]+)$/,
132 |
133 | // /**
134 | // * {@link location}
135 | // */
136 | /^\s+?\* \{@link .+?\}$/,
137 |
138 | // /**
139 | // * @function functionName
140 | // * @function external:"Mobile('realyLongMobileMethod')".registerToNative
141 | // */
142 | /^\s+?\* @(function|func|method) \S+$/,
143 |
144 | // /**
145 | // * | cell1 | cell2 |
146 | // */
147 | /^\s+?\* \|.*\|$/
148 | ];
149 |
150 | return patterns.map(re => `(${re.source})`).join('|');
151 | }
152 |
153 |
--------------------------------------------------------------------------------
/test/www/js/thali_main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | //
4 | // The MIT License (MIT)
5 | //
6 | // Copyright (c) 2015-2016 Microsoft
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to
10 | // deal in the Software without restriction, including without limitation the
11 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 | // sell copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in
16 | // all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 | // IN THE SOFTWARE.
25 | //
26 | //
27 | // Thali Cordova Plugin thali_main.js
28 | //
29 |
30 | (function () {
31 | var inter = setInterval(function () {
32 | if (typeof jxcore === 'undefined') { return; }
33 |
34 | clearInterval(inter);
35 |
36 | jxcore.isReady(function () {
37 | if (window.ThaliPermissions) {
38 | // requestLocationPermission ensures that the application has
39 | // the required ACCESS_COARSE_LOCATION permission in Android.
40 | window.ThaliPermissions.requestLocationPermission(function () {
41 | console.log('Application has the required permission.');
42 | loadMainFile();
43 | }, function (error) {
44 | console.log('Location permission not granted. Error: ' + error);
45 | exitWithFailureLog();
46 | });
47 | } else {
48 | loadMainFile();
49 | }
50 | });
51 | }, 5);
52 |
53 | function loadMainFile() {
54 | jxcore('app.js').loadMainFile(function (ret, err) {
55 | if (err) {
56 | console.log('app.js file failed to load : ' + JSON.stringify(err));
57 | exitWithFailureLog();
58 | } else {
59 | jxcore_ready();
60 | }
61 | });
62 | }
63 |
64 | function jxcore_ready() {
65 | jxcore('setMyNameCallback').call(nameCallback);
66 | jxcore('setLogCallback').call(logCallback);
67 | document.getElementById('ClearLogButton').addEventListener('click', ClearLog);
68 | console.log('UIApp is all set and ready!');
69 | }
70 |
71 | function exitWithFailureLog() {
72 | console.log('****TEST_LOGGER:[PROCESS_ON_EXIT_FAILED]****');
73 | navigator.app.exitApp();
74 | }
75 |
76 | function nameCallback(name) {
77 | document.getElementById('nameTag').innerHTML = name;
78 | }
79 |
80 | function ClearLog() {
81 | document.getElementById('LogBox').value = '';
82 | }
83 |
84 | function logCallback(data) {
85 | var logBox = document.getElementById('LogBox');
86 | logBox.value = data + '\n' + logBox.value;
87 | }
88 | }());
89 |
--------------------------------------------------------------------------------
/test/www/jxcore/lib/CoordinatedTape.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 | var inherits = util.inherits;
5 |
6 | var objectAssign = require('object-assign');
7 | var assert = require('assert');
8 | var uuid = require('node-uuid');
9 |
10 | var Promise = require('./utils/Promise');
11 |
12 | var SimpleThaliTape = require('./SimpleTape');
13 | var CoordinatedClient = require('./CoordinatedClient');
14 |
15 | var logger = require('./testLogger')('CoordinatedThaliTape');
16 |
17 |
18 | function CoordinatedThaliTape (options) {
19 | // We are calling this function directly without 'new'.
20 | if (!this) {
21 | return new CoordinatedThaliTape(options);
22 | }
23 |
24 | return CoordinatedThaliTape.super_.call(this, options);
25 | }
26 |
27 | inherits(CoordinatedThaliTape, SimpleThaliTape);
28 |
29 | CoordinatedThaliTape.states = SimpleThaliTape.states;
30 | CoordinatedThaliTape.instances = SimpleThaliTape.instances;
31 | CoordinatedThaliTape.begin = SimpleThaliTape.begin;
32 |
33 | // 'tape.uuid' here.
34 | CoordinatedThaliTape.uuid = uuid.v4();
35 |
36 | CoordinatedThaliTape.prototype.defaults = objectAssign(
37 | {},
38 | CoordinatedThaliTape.prototype.defaults,
39 | {
40 | emitRetryCount: 100,
41 | emitRetryTimeout: 2000
42 | }
43 | );
44 |
45 | CoordinatedThaliTape.prototype._begin = function () {
46 | assert(
47 | this._state === CoordinatedThaliTape.states.created,
48 | 'we should be in created state'
49 | );
50 | this._state = CoordinatedThaliTape.states.started;
51 | };
52 |
53 | CoordinatedThaliTape.prototype._getTests = function () {
54 | var self = this;
55 | return this._tests.map(function (test) {
56 | // We don't need to copy '_options', it will be used readonly.
57 | test.options = self._options;
58 | return test;
59 | });
60 | };
61 |
62 | CoordinatedThaliTape.begin = function (platform, version, hasRequiredHardware,
63 | nativeUTFailed) {
64 | var tests = CoordinatedThaliTape.instances.reduce(function (tests, thaliTape)
65 | {
66 | thaliTape._begin();
67 | return tests.concat(thaliTape._getTests());
68 | }, []);
69 | CoordinatedThaliTape.instances = [];
70 |
71 | var _testClient = new CoordinatedClient(
72 | tests,
73 | CoordinatedThaliTape.uuid,
74 | platform,
75 | version,
76 | hasRequiredHardware,
77 | !!nativeUTFailed
78 | );
79 |
80 | // Only used for testing purposes.
81 | CoordinatedThaliTape._testServer = _testClient._io;
82 |
83 | return new Promise(function (resolve, reject) {
84 | _testClient.once('finished', function (error) {
85 | if (error) {
86 | reject(error);
87 | } else {
88 | resolve();
89 | }
90 | });
91 | })
92 | .then(function () {
93 | logger.debug('all tests succeed');
94 | logger.debug('****TEST_LOGGER:[PROCESS_ON_EXIT_SUCCESS]****');
95 | })
96 | .catch(function (error) {
97 | logger.error(
98 | 'tests failed, error: \'%s\', stack: \'%s\'',
99 | error.toString(), error.stack
100 | );
101 | logger.debug('****TEST_LOGGER:[PROCESS_ON_EXIT_FAILED]****');
102 | return Promise.reject(error);
103 | });
104 | };
105 |
106 | module.exports = CoordinatedThaliTape;
107 |
--------------------------------------------------------------------------------
/thali/NextGeneration/utils/common.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Promise = require('bluebird');
4 |
5 | /** @module utils/common */
6 |
7 | module.exports.serializePouchError = function (err) {
8 | if (err) {
9 | return (err.status || '') + ' ' + (err.message || '');
10 | } else {
11 | return '';
12 | }
13 | };
14 |
15 | /**
16 | * Make function async as if it is always wrapped into setImmediate.
17 | *
18 | * For example:
19 | *
20 | * ```
21 | * function emit(x) {
22 | * console.log(this.name + ':', 'emitting', x);
23 | * }
24 | * var emitter = {
25 | * name: 'Test emitter',
26 | * emit: emit,
27 | * emitAsync: makeAsync(emit)
28 | * };
29 | * ```
30 | *
31 | * is equivalent to:
32 | *
33 | * ```
34 | * function emit(x) {
35 | * console.log(this.name + ':', 'emitting', x);
36 | * }
37 | * var emitter = {
38 | * name: 'Test emitter',
39 | * emit: emit,
40 | * emitAsync: function () {
41 | * var self = this;
42 | * var args = arguments;
43 | * setImmediate(function () {
44 | * emit.apply(self, args);
45 | * });
46 | * }
47 | * };
48 | * ```
49 | *
50 | * @param {function} fn
51 | * @returns {function} new function which, when invoked, executes original `fn`
52 | * asynchronously (via setImmediate). Preserves context and arguments, but
53 | * return value is ignored.
54 | */
55 | module.exports.makeAsync = function (fn) {
56 | var apply = Function.prototype.apply.bind(fn);
57 | return function () {
58 | setImmediate(apply, this, arguments);
59 | };
60 | };
61 |
62 | /**
63 | * @private
64 | */
65 | var enqueued = function (atTop, fn) {
66 | return function enqeuedMethod () {
67 | var self = this;
68 | var args = arguments;
69 | var method = atTop ? 'enqueueAtTop' : 'enqueue';
70 | return self._promiseQueue[method](function (resolve, reject) {
71 | var result = fn.apply(self, args);
72 | Promise.resolve(result).then(resolve, reject);
73 | });
74 | };
75 | };
76 |
77 | /**
78 | * Wraps provided function into
79 | * {@link module:promiseQueue~PromiseQueue#enqueue}.
80 | *
81 | * It should be used only for methods and it expects that the class has
82 | * `_promiseQueue` property.
83 | *
84 | * Example:
85 | * ```
86 | * function WifiListener() {
87 | * this._promiseQueue = new PromiseQueue();
88 | * this._isStarted = false;
89 | * }
90 | *
91 | * WifiListener.prototype.start = enqueuedMethod(function () {
92 | * return this.performAsyncLogic().then(function () {
93 | * this._isStarted = true
94 | * }.bind(this));
95 | * });
96 | * ```
97 | *
98 | * @method
99 | * @static
100 | * @param {function} fn - function to wrap. MUST be either synchronous or return
101 | * a Promise
102 | * @returns {Promise}
103 | */
104 | module.exports.enqueuedMethod = enqueued.bind(null, false);
105 |
106 | /**
107 | * The same as [enqueuedMethod]{@link module:utils/common.enqueuedMethod} but
108 | * uses [enqueueAtTop]{@link module:promiseQueue~PromiseQueue#enqueueAtTop}
109 | * instead.
110 | *
111 | * @method
112 | * @static
113 | * @param {function} fn - function to wrap. MUST be either synchronous or return
114 | * a Promise
115 | * @returns {Promise}
116 | */
117 | module.exports.enqueuedAtTopMethod = enqueued.bind(null, true);
118 |
--------------------------------------------------------------------------------
/thali/NextGeneration/notification/thaliPskMapCache.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var thaliConfig = require('../thaliConfig');
3 |
4 | /** @module thaliPskMapCache */
5 |
6 | /**
7 | * @classdesc A class that stores PskMaps. When new entries are added into the
8 | * cache object or existing entries are fetched from it we always check if
9 | * there are expired items. If expired items are found they will be removed.
10 | *
11 | * @public
12 | * @constructor
13 | * @param {number} millisecondsUntilExpiration The number of milliseconds into
14 | * the future after which the dictionary should expire.
15 | */
16 | function ThaliPskMapCache(millisecondsUntilExpiration) {
17 | this._queue = [];
18 | this._millisecondsUntilExpiration = millisecondsUntilExpiration;
19 | }
20 |
21 | // jscs:disable maximumLineLength
22 | /**
23 | * Stores the dictionary into the cache. And removes expired items.
24 | *
25 | * @public
26 | * @param {module:thaliNotificationBeacons~beaconStreamAndSecretDictionary} dictionary
27 | */
28 | // jscs:enable maximumLineLength
29 | ThaliPskMapCache.prototype.push = function (dictionary) {
30 | this.clean(true);
31 | var item = { keySecret: dictionary, expiration : Date.now() +
32 | this._millisecondsUntilExpiration - 200};
33 | this._queue.push(item);
34 | };
35 |
36 | /**
37 | * Returns the secret key associated with the ID or null if there is no match.
38 | * And removes expired items.
39 | *
40 | * @public
41 | * @param {string} id
42 | * @returns {?Buffer} The secret key associated with the ID or null if there
43 | * is no match.
44 | */
45 | ThaliPskMapCache.prototype.getSecret = function (id) {
46 | this.clean(false);
47 | for (var i = this._queue.length - 1 ; i >= 0 ; i--) {
48 | if (this._queue[i].keySecret[id] &&
49 | this._queue[i].keySecret[id].pskSecret) {
50 | return this._queue[i].keySecret[id].pskSecret;
51 | }
52 | }
53 | return null;
54 | };
55 |
56 | /**
57 | * Returns the public key associated with the ID or null if there is no match.
58 | * And removes expired items.
59 | *
60 | * @public
61 | * @param {string} id
62 | * @returns {?Buffer} The public key associated with the ID or null if there
63 | * is no match.
64 | */
65 | ThaliPskMapCache.prototype.getPublic = function (id) {
66 | this.clean(false);
67 | for (var i = this._queue.length - 1 ; i >= 0 ; i--) {
68 | if (this._queue[i].keySecret[id] &&
69 | this._queue[i].keySecret[id].publicKey) {
70 | return this._queue[i].keySecret[id].publicKey;
71 | }
72 | }
73 | return null;
74 | };
75 |
76 | /**
77 | * Cleans expired items from the dictionary.
78 | *
79 | * @public
80 | * @param {?boolean} forceRemove Forces to remove at least one item from the
81 | * dictionary, if it is full.
82 | */
83 | ThaliPskMapCache.prototype.clean = function (forceRemove) {
84 | var clearCount = 0;
85 | var now = Date.now();
86 |
87 | for ( var i = 0 ; i < this._queue.length ; i++) {
88 | if (this._queue[i].expiration < now ) {
89 | clearCount = i+1;
90 | } else {
91 | break;
92 | }
93 | }
94 |
95 | if (clearCount > 0 ) {
96 | this._queue.splice(0, clearCount);
97 | return;
98 | }
99 |
100 | if (forceRemove && this._queue.length >=
101 | thaliConfig.MAX_NOTIFICATIONSERVER_PSK_MAP_CACHE_SIZE) {
102 | this._queue.shift();
103 | }
104 | };
105 |
106 | module.exports = ThaliPskMapCache;
107 |
--------------------------------------------------------------------------------
/thali/NextGeneration/utils/pouchDBCheckpointsPlugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Promise = require('lie');
4 | var logger = require('../../ThaliLogger')('pouchDBCheckpointsPlugin');
5 | var makeAsync = require('./common').makeAsync;
6 |
7 | module.exports.onCheckpointReached = function (handler) {
8 | var db = this;
9 | var plugin = db.__checkpointPlugin;
10 |
11 | if (!plugin) {
12 | plugin = db.__checkpointPlugin = new CheckpointPlugin(db);
13 | }
14 |
15 | plugin.registerHandler(handler);
16 | };
17 |
18 | var DEFAULT_DELAY = 200;
19 |
20 | var CheckpointPlugin = function (_db) {
21 | // Private data
22 | var db = _db;
23 | var checkpoint = db.__opts.checkpoint;
24 | var delay = db.__opts.checkpointDelay || DEFAULT_DELAY;
25 | var handlers = [];
26 | var destroyed = false;
27 |
28 | // Private methods
29 | function checkDBSize () {
30 | if (destroyed) {
31 | logger.warn('Couldn\'t check db size after destroy');
32 | return Promise.resolve();
33 | }
34 |
35 | return db.info()
36 | .then(function (response) {
37 | if (!response) return;
38 |
39 | // We want to call 'getDiskSize' directly without ignoring errors.
40 | // https://github.com/pouchdb/pouchdb-size/issues/22
41 | return db.getDiskSize()
42 | .then(function (diskSize) {
43 | // Handlers should be called only once
44 | // after the first reaching of a checkpoint.
45 | if (diskSize >= checkpoint) {
46 | handlers.forEach(function (handler) {
47 | handler(checkpoint);
48 | });
49 | }
50 | });
51 | })
52 | .catch(function (error) {
53 | logger.error(
54 | 'Error while fetching db info: \'%s\', stack: \'%s\'',
55 | String(error), error.stack
56 | );
57 | db.emit('error', error);
58 | });
59 | }
60 |
61 | // Public constructor
62 | function CheckpointPlugin () {
63 | if (!db.getDiskSize) {
64 | throw new Error(
65 | 'This plugin depends on pouchdb-size plugin. ' +
66 | 'Please add pouchdb-size plugin befor this one.'
67 | );
68 | }
69 |
70 | var changes = db.changes({
71 | live: true,
72 | since: 'now'
73 | })
74 | .on('error', function (error) {
75 | logger.error(
76 | 'Error while fetching db changes: \'%s\', stack: \'%s\'',
77 | String(error), error.stack
78 | );
79 | changes.cancel();
80 | db.emit('error', error);
81 | })
82 | .on('change', executeOnce(checkDBSize, delay));
83 |
84 | db.on('destroyed', function () {
85 | destroyed = true;
86 | changes.cancel();
87 | });
88 | }
89 |
90 | // Public methods
91 | CheckpointPlugin.prototype.registerHandler = function (handler) {
92 | // It might be better for performance
93 | // to execute handlers asynchronously.
94 | handlers.push(makeAsync(handler));
95 | };
96 |
97 | return new CheckpointPlugin();
98 | };
99 |
100 | var executeOnce = function (fn, delay) {
101 | var timeout = null;
102 | return function () {
103 | var self = this;
104 | var args = arguments;
105 | if (!timeout) {
106 | timeout = setTimeout(function () {
107 | fn.apply(self, args);
108 | clearTimeout(timeout);
109 | timeout = null;
110 | }, delay);
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/disabled/IdentityExchange/testLiveIdentityExchange.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var tape = require('../lib/thaliTape');
4 | var IdentityExchange = require('thali/identityExchange/identityexchange');
5 | var identityExchangeTestUtils = require('./identityExchangeTestUtils');
6 | var ThaliReplicationManager = require('thali/thalireplicationmanager');
7 | var ThaliEmitter = require('thali/thaliemitter');
8 | var testUtils = require('../lib/testUtils');
9 |
10 | var thaliApp = null;
11 | var thaliServer = null;
12 |
13 | function setUpServer() {
14 | return identityExchangeTestUtils.createThaliAppServer()
15 | .then(function (appAndServer) {
16 | thaliApp = appAndServer.app;
17 | thaliServer = appAndServer.server;
18 | }).catch(function (err) {
19 | throw err;
20 | });
21 | }
22 |
23 | var test = tape({
24 | setup: function (t) {
25 | setUpServer().then(function () {t.end(); });
26 | },
27 | teardown: function (t) {
28 | if (thaliServer) {
29 | thaliServer.close();
30 | }
31 | thaliServer = null;
32 | thaliApp = null;
33 | t.end();
34 | }
35 | });
36 |
37 |
38 | test('Now do an identity Exchange with the real live system!', function (t) {
39 | if (!jxcore.utils.OSInfo().isMobile) {
40 | t.pass('Skipping test because we aren\'t running on a mobile platform');
41 | t.end();
42 | return;
43 | }
44 |
45 | var dbName = 'thali';
46 | var LevelDownPouchDB = testUtils.LevelDownPouchDB();
47 | var thaliReplicationManager =
48 | new ThaliReplicationManager(new LevelDownPouchDB(dbName));
49 | var identityExchange = new IdentityExchange(thaliApp,
50 | thaliServer.address().port, thaliReplicationManager,
51 | dbName);
52 | thaliReplicationManager._emitter.on(
53 | ThaliEmitter.events.PEER_AVAILABILITY_CHANGED, function (peer) {
54 | t.pass('We found a peer - ' + JSON.stringify(peer));
55 | });
56 | var peerIdentityExchangeHandler = function (peer) {
57 | t.pass('We got a peer to do identity exchange with! - ' +
58 | JSON.stringify(peer));
59 | if (peer.peerAvailable) {
60 | identityExchange.removeListener(
61 | IdentityExchange.Events.PeerIdentityExchange,
62 | peerIdentityExchangeHandler);
63 | t.pass('We are going to try and do an identity exchange with the peer');
64 | identityExchange.executeIdentityExchange(peer.peerIdentifier,
65 | peer.peerName, function (err, code) {
66 | t.notOk(err, 'Did we get an error on executeIdentityExchange?');
67 | identityExchangeTestUtils.checkCode(t, code);
68 | // The side with the larger hash can end up quiting fast enough to
69 | // kill the connection before the response goes back causing a hang on
70 | // the side with the smaller hash. So we put in a delay to make sure
71 | // everything gets through.
72 | setTimeout(function () {
73 | identityExchange.stopExecutingIdentityExchange();
74 | identityExchange.stopIdentityExchange(function (err) {
75 | t.notOk(err, 'Did we get a problem in calling stop Identity ' +
76 | 'Exchange?');
77 | t.end();
78 | });
79 | }, 200);
80 | });
81 | }
82 | };
83 | identityExchange.on(IdentityExchange.Events.PeerIdentityExchange,
84 | peerIdentityExchangeHandler);
85 | identityExchange.startIdentityExchange('Sreejumon', function (err) {
86 | t.notOk(err, 'Did we successfully get a callback from start?');
87 | });
88 | });
89 |
--------------------------------------------------------------------------------
/test/www/jxcore/meta_tests/testTestSendData.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var originalMobile = typeof Mobile === 'undefined' ? undefined : Mobile;
4 | var SendDataConnector = require('../perf_tests/SendDataConnector.js');
5 | var SendDataTCPServer = require('../perf_tests/SendDataTCPServer.js');
6 | var TestSendData = require('../perf_tests/testSendData.js');
7 | var tape = require('../lib/thaliTape');
8 |
9 | var testPort = 8889;
10 |
11 | var test = tape({
12 | setup: function(t) {
13 | global.Mobile = function (key) {
14 | return {
15 | 'callNative': function () {
16 | var cb = arguments[arguments.length - 1];
17 |
18 | if (typeof cb !== 'function') {
19 | throw new Error('The last argument of the Mobile callNative ' +
20 | 'method must be a callback');
21 | }
22 |
23 | if (key === 'Connect') {
24 | setTimeout(function () {
25 | cb(null, testPort);
26 | }, 100);
27 | } else {
28 | setTimeout(function () {
29 | cb(null);
30 | }, 100);
31 | }
32 | },
33 | 'registerToNative': function () {}
34 | };
35 | };
36 | t.end();
37 | },
38 | teardown: function(t) {
39 | global.Mobile = originalMobile;
40 | t.end();
41 | }
42 | });
43 |
44 | var somePeer = {
45 | 'peerIdentifier': 'some-peer-identifier'
46 | };
47 |
48 | test('connector should fail if server not running', function (t) {
49 | var retryCount = 0; // Make it 0 so that we fail after first attempt
50 | var sendDataConnector = new SendDataConnector(1, 0, 0, retryCount, 0);
51 |
52 | sendDataConnector.on('done', function (result) {
53 | t.ok(result, 'received a result to the done event');
54 | sendDataConnector.Stop(function () {
55 | t.end();
56 | });
57 | });
58 | sendDataConnector.Start(somePeer);
59 | });
60 |
61 | test('connector should be able to send data to a running server', function (t) {
62 | var retryTimeout = 200;
63 | var dataAmount = 1000000; // amount in bytes
64 | var sendDataConnector = new SendDataConnector(1, dataAmount, retryTimeout, 0,
65 | 0);
66 |
67 | var sendDataTCPServer = new SendDataTCPServer(testPort);
68 |
69 | sendDataConnector.on('done', function (result) {
70 | t.ok(result, 'received a result to the done event');
71 | sendDataTCPServer.stopServer(function () {
72 | t.end();
73 | });
74 | });
75 | sendDataConnector.Start(somePeer);
76 | });
77 |
78 | var numberOfPeers = 5;
79 |
80 | test('should run test with ' + numberOfPeers + ' peers', function (t) {
81 | var testData = {
82 | 'timeout': 1500000,
83 | 'rounds': 1,
84 | 'dataTimeout': 10000,
85 | 'dataAmount': 1000000,
86 | 'conReTryTimeout': 50,
87 | 'conReTryCount': 5,
88 | 'peerCount' : numberOfPeers
89 | };
90 |
91 | var testPeerList = [];
92 | for (var i = 0; i < numberOfPeers; i++) {
93 | testPeerList.push({
94 | 'address': 'device-address-' + i
95 | });
96 | }
97 | var testSendData = new TestSendData(testData, 'device-identifier-me', testPeerList);
98 | testSendData.start(testPort);
99 |
100 | testSendData.on('done', function (resultString) {
101 | t.ok(resultString, 'received a result to the done event');
102 | var resultData = JSON.parse(resultString);
103 | t.equal(resultData.sendList.length, numberOfPeers);
104 | testSendData.stop(false);
105 | t.end();
106 | });
107 | });
108 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/disabled/TestThaliMobileNative/Message.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert');
4 | var Promise = require('lie');
5 |
6 | var objectKeysEquals = require('thali/validations').objectKeysEquals;
7 |
8 | var logger = require('../../../lib/testLogger')('Message');
9 |
10 |
11 | function Message (uuid, code, bulkData) {
12 | assert(!isNaN(code), 'code should be a number');
13 |
14 | this.uuid = uuid;
15 | this.code = code;
16 | this.bulkData = bulkData || Message.bulkData;
17 | }
18 |
19 | var bulkData = new Buffer(100000);
20 | bulkData.fill(1);
21 | Message.bulkData = bulkData;
22 |
23 | Message.codes = {
24 | // The sender is not in the same generation as the receiver
25 | WRONG_GEN: 0,
26 | // The sender is not in the participants list for the receiver
27 | WRONG_TEST: 1,
28 | // Everything matched
29 | SUCCESS: 2,
30 | // We got an old advertisement for ourselves!
31 | WRONG_ME: 3,
32 | // A peer on our list gave us bad syntax, no hope of test passing
33 | WRONG_SYNTAX: 4
34 | };
35 |
36 | Message.prototype.toString = function () {
37 | return JSON.stringify({
38 | uuid: this.uuid,
39 | code: this.code,
40 | bulkData: this.bulkData.toString()
41 | });
42 | }
43 |
44 | Message.prototype.writeTo = function (socket) {
45 | var self = this;
46 |
47 | return new Promise(function (resolve, reject) {
48 | var str = self.toString();
49 |
50 | // We will send message's length in first 4 bytes.
51 | var length = str.length;
52 | var data = new Buffer(4);
53 | data.writeUInt32BE(length, 0);
54 | socket.write(data);
55 |
56 | // Than we will send the message itself.
57 | socket.write(str, resolve);
58 | })
59 | }
60 |
61 | Message.fromString = function (str) {
62 | var data = JSON.parse(str);
63 | assert(
64 | objectKeysEquals(data, ['uuid', 'code', 'bulkData']),
65 | 'message should include uuid, code and bulkData and nothing else'
66 | );
67 | assert(!isNaN(data.code), 'code should be a number');
68 | data.code = parseInt(data.code, 10);
69 | return new Message(data.uuid, data.code, data.bulkData);
70 | }
71 |
72 | Message.read = function (socket) {
73 | return new Promise(function (resolve, reject) {
74 | var targetLength = null;
75 | var currentData = new Buffer(0);
76 |
77 | function handler (data) {
78 | currentData = Buffer.concat([currentData, data]);
79 |
80 | // We will read message length from the first 4 bytes.
81 | if (!targetLength) {
82 | if (currentData.length < 4) {
83 | // We need more data.
84 | socket.once('data', handler);
85 | return;
86 | } else {
87 | targetLength = currentData.readUInt32BE(0);
88 | assert(!isNaN(targetLength), 'target length should exist');
89 | targetLength += 4;
90 | }
91 | }
92 | if (currentData.length === targetLength) {
93 | resolve(
94 | Message.fromString(
95 | currentData.toString('utf8', 4)
96 | )
97 | );
98 | } else if (currentData.length < targetLength) {
99 | // We need more data.
100 | socket.once('data', handler);
101 | } else {
102 | reject(new Error(
103 | 'data is too long, length is: ' + currentData.length +
104 | ', expected length: ' + targetLength
105 | ));
106 | }
107 | }
108 | socket.once('data', handler);
109 | });
110 | }
111 |
112 | module.exports = Message;
113 |
--------------------------------------------------------------------------------
/thali/NextGeneration/makeIntoCloseAllServer.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert');
4 | var Promise = require('lie');
5 | var logger = require('../ThaliLogger')('makeIntoCloseAllServer');
6 |
7 | /** @module makeIntoCloseAllServer */
8 |
9 | /**
10 | * @public
11 | * @callback thunk
12 | */
13 |
14 | /**
15 | * Takes any of the NET server object types (such as HTTP, HTTPS and NET itself
16 | * which we use for TCP) and calls their createServer method with the submitted
17 | * options and connectionListener. It's job is to add a closeAll method that
18 | * if called will destroy any outstanding connections to the server as well
19 | * as close the server itself.
20 | *
21 | * @public
22 | * @param {net.Server} server Server object
23 | * @param {boolean} [eatNotRunning] Will consume a not running error when
24 | * calling one of our close methods rather than throwing it.
25 | * @returns {net.Server} Wrapper making the server support close all
26 | */
27 | function makeIntoCloseAllServer(server, eatNotRunning) {
28 | var connections = [];
29 |
30 | var _connectionHandler = function (socket) {
31 | // Add to the list of connections.
32 | connections.push(socket);
33 | // Remove from list of connections in case
34 | // socket is closed.
35 | socket.once('close', function () {
36 | var index = connections.indexOf(socket);
37 | if (index === -1) {
38 | assert('socket not found from the list of connections');
39 | }
40 | connections.splice(index, 1);
41 | });
42 | }
43 | .bind(this);
44 | server.on('connection', _connectionHandler);
45 |
46 | /**
47 | * Closes the server and then closes all incoming connections to the server.
48 | *
49 | * @param {thunk} [callback] Callback
50 | */
51 | server.closeAll = function (callback) {
52 | logger.debug('closeAll called on server');
53 | var forceCallback = false;
54 | // By closing the server first we prevent any new incoming connections
55 | // to the server.
56 | // Also note that the callback won't be called until all the connections
57 | // are destroyed because the destroy calls are synchronous.
58 | try {
59 | server.close(callback);
60 | } catch (err){
61 | if (!eatNotRunning || !(err instanceof Error) ||
62 | (err && err.message !== 'Not running')) {
63 | throw err;
64 | }
65 | forceCallback = true;
66 | }
67 |
68 | connections.forEach(function (connection) {
69 | connection.destroy();
70 | });
71 |
72 | if (forceCallback && callback) {
73 | callback();
74 | }
75 | };
76 |
77 | /**
78 | * Same as closeAll but returns a promise.
79 | *
80 | * @returns {Promise}
81 | */
82 | server.closeAllPromise = function () {
83 | var self = this;
84 | return new Promise(function (resolve, reject) {
85 | self.closeAll(function (err) {
86 | if (err) {
87 | return reject(err);
88 | }
89 | resolve();
90 | });
91 | });
92 | };
93 |
94 | var _removeAllListeners = server.removeAllListeners;
95 | server.removeAllListeners = function (eventName) {
96 | var result = _removeAllListeners.apply(this, arguments);
97 | if (eventName === 'connection') {
98 | // We can protect out connection handler
99 | server.on('connection', _connectionHandler);
100 | }
101 | return result;
102 | }
103 |
104 | return server;
105 | }
106 |
107 | module.exports = makeIntoCloseAllServer;
108 |
--------------------------------------------------------------------------------
/src/android/test/io/jxcore/node/OutgoingSocketThreadMock.java:
--------------------------------------------------------------------------------
1 | package io.jxcore.node;
2 |
3 | import android.bluetooth.BluetoothSocket;
4 | import android.util.Log;
5 |
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.io.OutputStream;
9 | import java.net.ServerSocket;
10 | import org.thaliproject.p2p.btconnectorlib.PeerProperties;
11 |
12 | public class OutgoingSocketThreadMock extends OutgoingSocketThread {
13 | Long threadId = 1234L;
14 | int port;
15 | boolean closeCalled = false;
16 | InputStream tempInputStream = null;
17 | OutputStream tempOutputStream = null;
18 | boolean localStreamsCreatedSuccessfully = false;
19 | ServerSocket mServerSocket = null;
20 | int mListeningOnPortNumber = ConnectionHelper.NO_PORT_NUMBER;
21 |
22 | public OutgoingSocketThreadMock(BluetoothSocket bluetoothSocket, Listener listener,
23 | InputStream inputStream, OutputStream outputStream)
24 | throws IOException {
25 | super(bluetoothSocket, listener, inputStream, outputStream);
26 | }
27 |
28 | public void setPort(int _port){
29 | port = _port;
30 | }
31 |
32 | @Override
33 | public void close() {
34 | closeCalled = true;
35 | }
36 |
37 | @Override
38 | public long getId() {
39 | return threadId;
40 | }
41 |
42 | @Override
43 | public void run() {
44 | mIsClosing = false;
45 |
46 | try {
47 | mServerSocket = new ServerSocket(port);
48 | Log.d(mTag, "Server socket local port: " + mServerSocket.getLocalPort());
49 | } catch (IOException e) {
50 | Log.e(mTag, "Failed to create a server socket instance: " + e.getMessage(), e);
51 | mServerSocket = null;
52 | mListener.onDisconnected(this, "Failed to create a server socket instance: " +
53 | e.getMessage());
54 | }
55 |
56 | if (mServerSocket != null) {
57 | try {
58 | Log.i(mTag, "Now accepting connections...");
59 |
60 | if (mListener != null) {
61 | mListeningOnPortNumber = mServerSocket.getLocalPort();
62 | mListener.onListeningForIncomingConnections(mListeningOnPortNumber);
63 | }
64 |
65 | mLocalhostSocket = mServerSocket.accept(); // Blocking call
66 |
67 | Log.i(mTag, "Incoming data from address: " + getLocalHostAddressAsString()
68 | + ", port: " + mServerSocket.getLocalPort());
69 |
70 | tempInputStream = mLocalhostSocket.getInputStream();
71 | tempOutputStream = mLocalhostSocket.getOutputStream();
72 | localStreamsCreatedSuccessfully = true;
73 | } catch (IOException e) {
74 | if (!mIsClosing) {
75 | String errorMessage = "Failed to create local streams: " + e.getMessage();
76 | Log.e(mTag, errorMessage, e);
77 | mListener.onDisconnected(this, errorMessage);
78 | }
79 | }
80 |
81 | if (localStreamsCreatedSuccessfully) {
82 | Log.d(mTag, "Setting local streams and starting stream copying threads...");
83 | mLocalInputStream = tempInputStream;
84 | mLocalOutputStream = tempOutputStream;
85 |
86 | startStreamCopyingThreads(new ConnectionData(
87 | new PeerProperties(PeerProperties.BLUETOOTH_MAC_ADDRESS_UNKNOWN), false));
88 | }
89 | }
90 | }
91 | }
92 |
93 |
94 |
--------------------------------------------------------------------------------
/src/android/java/io/jxcore/node/ListenerOrIncomingConnection.java:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2016 Microsoft Corporation. This software is licensed under the MIT License.
2 | * See the license file delivered with this project for further information.
3 | */
4 | package io.jxcore.node;
5 |
6 | import android.util.Log;
7 | import org.json.JSONException;
8 | import org.json.JSONObject;
9 |
10 | /**
11 | * Utility class for JXcoreThaliCallback.
12 | */
13 | class ListenerOrIncomingConnection {
14 | private static final String TAG = ListenerOrIncomingConnection.class.getSimpleName();
15 | private int mListeningOnPortNumber = 0;
16 | private int mClientPortNumber = 0;
17 | private int mServerPortNumber = 0;
18 |
19 | /**
20 | * Constructor.
21 | *
22 | * @param listeningOnPortNumber The port on which the native layer is listening on 127.0.0.1 for
23 | * an incoming TCP/IP connection that the native layer will then
24 | * relay to the remote peer.
25 | * @param clientPortNumber clientPort The port that the native layer's TCP/IP client uses to
26 | * connect to the `portNumber` submitted by the Thali application.
27 | * @param serverPortNumber The port that the native layer's TCP/IP client connected to. The
28 | * reason we include it here is because there is a potential race
29 | * condition where between the time we created the response to the
30 | * connect request and when it was actually sent to Node.js in theory we
31 | * could have received a stop and start that switched us to a different
32 | * `portNumber`. So by including `serverPort` we can catch those race
33 | * conditions.
34 | */
35 | public ListenerOrIncomingConnection(int listeningOnPortNumber, int clientPortNumber, int serverPortNumber) {
36 | mListeningOnPortNumber = listeningOnPortNumber;
37 | mClientPortNumber = clientPortNumber;
38 | mServerPortNumber = serverPortNumber;
39 | }
40 |
41 | /**
42 | * Constructor.
43 | */
44 | public ListenerOrIncomingConnection() {
45 | mListeningOnPortNumber = ConnectionHelper.NO_PORT_NUMBER;
46 | mClientPortNumber = ConnectionHelper.NO_PORT_NUMBER;
47 | mServerPortNumber = ConnectionHelper.NO_PORT_NUMBER;
48 | }
49 |
50 | public int getListeningOnPortNumber() {
51 | return mListeningOnPortNumber;
52 | }
53 |
54 | public void setListeningOnPortNumber(int listeningOnPortNumber) {
55 | mListeningOnPortNumber = listeningOnPortNumber;
56 | }
57 |
58 | public JSONObject toJsonObject() {
59 | try {
60 | JSONObject jsonObject = new JSONObject();
61 | jsonObject.put(JXcoreExtension.CALLBACK_VALUE_LISTENING_ON_PORT_NUMBER, mListeningOnPortNumber);
62 | jsonObject.put(JXcoreExtension.CALLBACK_VALUE_CLIENT_PORT_NUMBER, mClientPortNumber);
63 | jsonObject.put(JXcoreExtension.CALLBACK_VALUE_SERVER_PORT_NUMBER, mServerPortNumber);
64 | return jsonObject;
65 | } catch (JSONException e) {
66 | Log.e(TAG, "toJsonObject: Failed to populate the JSON object: " + e.getMessage(), e);
67 | }
68 |
69 | return null;
70 | }
71 |
72 | public String toString() {
73 | JSONObject jsonObject = toJsonObject();
74 |
75 | if (jsonObject != null) {
76 | return jsonObject.toString();
77 | }
78 |
79 | return null;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/test/www/jxcore/CITestMode.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* CI Test mode - script which purpose is to test if CI enviroment is working
4 | * properly by running one simple test for android and ios native layer and
5 | * node layer.
6 | */
7 |
8 | const fs = require('fs-extra-promise');
9 |
10 | var setUpFunctions = {
11 |
12 | updateUnitTestConfig: () => {
13 | const locationOfUnitTestConfig = '../../TestServer/UnitTestConfig.js';
14 |
15 | let originalContent = fs.readFileSync(locationOfUnitTestConfig);
16 | let newContent = originalContent.toString().replace(/numDevices: -?[0-9]/g, 'numDevices: -1');
17 |
18 | if (originalContent === newContent) {
19 | throw new Error('Replace function with regex didn\'t worked properly!');
20 | }
21 |
22 | fs.writeFileSync(locationOfUnitTestConfig, newContent);
23 | },
24 |
25 | updateThaliTestSuiteFunction: () => {
26 | const locationOfAndroidBeforeCompile = '../../../scripts/android/before_compile.js';
27 |
28 | let originalContent = fs.readFileSync(locationOfAndroidBeforeCompile);
29 | let newContent = originalContent.toString().replace('Test.java', 'CITest');
30 |
31 | fs.writeFileSync(locationOfAndroidBeforeCompile, newContent, 'utf-8');
32 | },
33 |
34 | copyCINativeTestClass: () => {
35 | const path = '../../../scripts/android/before_compile.js';
36 |
37 | let originalContent = fs.readFileSync(path);
38 | let oldFunc = 'var i, testClassName;';
39 | let newFunc = oldFunc + '\nfs.copySync(appRoot + \'/plugins/org.thaliproject.p2p/src/android/test/io/jxcore/node/CITestClass.java\', appRoot + \'/platforms/android/src/io/jxcore/node/CITestClass.java\');';
40 | let newContent = originalContent.toString().replace(oldFunc, newFunc);
41 |
42 | fs.writeFileSync(path, newContent);
43 | },
44 |
45 | updateRunTestsToRunOnlyOneNodeTest: () => {
46 | const locationOfRunTests = './runTests.js';
47 |
48 | let originalContent = fs.readFileSync(locationOfRunTests);
49 | let newContent = originalContent.toString().replace('fileName.indexOf(\'test\') === 0)', 'fileName.indexOf(\'CITest\') === 0)');
50 |
51 | fs.writeFileSync(locationOfRunTests, newContent);
52 | },
53 |
54 | copyCINodeTestClass: () => {
55 | fs.renameSync('bv_tests/disabled/CITestClass.js', 'bv_tests/CITestClass.js');
56 | },
57 |
58 | emptyAlliOSTestFilesButOne: (pathParam) => {
59 | let path;
60 |
61 | path = pathParam || '../../../lib/ios/ThaliCore/ThaliCoreTests';
62 |
63 | if (path === '../../../lib/ios/ThaliCore/ThaliCoreTests' && !fs.existsSync(path + '/SimpleTestCase.swift')) {
64 | throw new Error('SimpleTestCase test file was not found!');
65 | }
66 |
67 | const filesArray = fs.readdirSync(path);
68 | let currentFilePath, i;
69 |
70 | for (i = 0; i < filesArray.length; i++) {
71 | if (filesArray[i].indexOf('SimpleTestCase') === -1) {
72 | currentFilePath = path + '/' + filesArray[i].toString();
73 | if (!fs.lstatSync(currentFilePath).isDirectory()) {
74 | fs.writeFileSync(currentFilePath, 'import Foundation\n');
75 | } else {
76 | setUpFunctions.emptyAlliOSTestFilesButOne(currentFilePath);
77 | }
78 | }
79 | }
80 | },
81 | };
82 |
83 | function runFunctionAndCheckFailures(func, errStr) {
84 | try {
85 | func();
86 | } catch (e) {
87 | console.log(e);
88 | console.log(errStr);
89 | process.exit(-1);
90 | }
91 | }
92 |
93 | for (let name in setUpFunctions) {
94 | if (setUpFunctions.hasOwnProperty(name)) {
95 | runFunctionAndCheckFailures(setUpFunctions[name], name);
96 | }
97 | }
98 |
99 | process.exit(0);
100 |
--------------------------------------------------------------------------------
/test/www/jxcore/runTests.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var path = require('path');
4 | var randomString = require('randomstring');
5 | var testLoader = require('./lib/testLoader');
6 | var config = require('./config');
7 |
8 | // Before including anything serious from thali we want to ensure
9 | // that we have SSDP_NT env defined.
10 | if (!process.env.SSDP_NT) {
11 | // We want to provide a new random value.
12 | process.env.SSDP_NT = randomString.generate({
13 | length: 'http://www.thaliproject.org/ssdp'.length
14 | });
15 | }
16 | // Override sinon timers
17 | // issue https://github.com/thaliproject/jxcore/issues/86
18 | var sinon = require('sinon');
19 | sinon.config = {
20 | useFakeTimers: false
21 | };
22 |
23 | var thaliTape = require('./lib/thaliTape');
24 | var testUtils = require('./lib/testUtils');
25 | var logger = require('./lib/testLogger')('runTests');
26 |
27 | var platform = require('thali/NextGeneration/utils/platform');
28 |
29 | var DEFAULT_PLATFORM = platform.names.ANDROID;
30 | var mockPlatform;
31 |
32 | var argv = require('minimist')(process.argv.slice(2), {
33 | string: ['platform', 'networkType'],
34 | default: {
35 | 'platform': DEFAULT_PLATFORM
36 | }
37 | });
38 |
39 | // The global.Mobile object is replaced here after thaliTape
40 | // has been required so that thaliTape can pick up the right
41 | // test framework to be used.
42 | if (typeof Mobile === 'undefined') {
43 | mockPlatform = require('./lib/parsePlatformArg')() || DEFAULT_PLATFORM;
44 | global.Mobile = require('./lib/wifiBasedNativeMock.js')(mockPlatform);
45 | } else {
46 | mockPlatform = Mobile._platform; // mock may be created in UnitTest_app.js
47 | }
48 |
49 | var networkTypes = require('thali/NextGeneration/thaliMobile').networkTypes;
50 |
51 | if (argv.networkType) {
52 | var networkType = argv.networkType.toUpperCase();
53 | switch (networkType) {
54 | case networkTypes.WIFI:
55 | case networkTypes.NATIVE:
56 | case networkTypes.BOTH: {
57 | global.NETWORK_TYPE = networkType;
58 | break;
59 | }
60 | default: {
61 | logger.warn(
62 | 'Unrecognized network type: ' + networkType + '. ' +
63 | 'Available network types: ' + [
64 | networkTypes.WIFI,
65 | networkTypes.NATIVE,
66 | networkTypes.BOTH,
67 | ].join(', ')
68 | );
69 | process.exit(1);
70 | }
71 | }
72 | }
73 |
74 | var currentPlatform = platform.name;
75 | // Our current platform can be 'darwin', 'linux', 'windows', etc.
76 | // Our 'thaliTape' expects all these platforms will be named as 'desktop'.
77 | if (!platform.isMobile) {
78 | currentPlatform = 'desktop';
79 | }
80 |
81 | logger.info(
82 | 'Starting tests. ' +
83 | 'Network type: ' + global.NETWORK_TYPE + '. ' +
84 | 'Platform: ' + (mockPlatform || currentPlatform)
85 | );
86 |
87 | var testsToRun = argv._[0] || 'bv_tests';
88 | var testsPath = path.join(__dirname, testsToRun);
89 | testLoader.load(testsPath, config.preferredOrder);
90 |
91 | testUtils.hasRequiredHardware()
92 | .then(function (hasRequiredHardware) {
93 |
94 | return testUtils.enableRequiredHardware()
95 | .then(function (enableRequiredHardware) {
96 |
97 | return testUtils.getOSVersion()
98 | .then(function (version) {
99 |
100 | return thaliTape.begin(
101 | currentPlatform, version,
102 | hasRequiredHardware || enableRequiredHardware,
103 | global.nativeUTFailed
104 | );
105 | });
106 | });
107 | })
108 | .then(function () {
109 | logger.info('Finished');
110 | process.exit(0);
111 | })
112 | .catch(function (error) {
113 | logger.error(error.message + '\n' + error.stack);
114 | process.exit(1);
115 | });
116 |
--------------------------------------------------------------------------------
/thali/thalicryptomanager.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var crypto = require('crypto');
4 | var fs = require('fs');
5 | var path = require('path');
6 | var urlSafeBase64 = require('urlsafe-base64');
7 |
8 | // The password is not secure because anyone who can get to the file can get
9 | // to the app and thus can get the password. The password is used here only to
10 | // satisfy the crypto/PKCS12 APIs.
11 | var password = 'password';
12 | var certname = 'certname';
13 | var country = 'country';
14 | var organization = 'organization';
15 | var pkcs12FileName = '/pkcs12.pfx';
16 | var macName = 'SHA256';
17 | var hashSizeInBytes = 16;
18 |
19 | var generateSlicedSHA256Hash = module.exports.generateSlicedSHA256Hash =
20 | function(
21 | bufferValueToHash,
22 | hashSizeInBytes) {
23 |
24 | var hash = crypto.createHash(macName);
25 | hash.update(bufferValueToHash);
26 | var fullSizeKeyHashBuffer = hash.digest();
27 | var slicedBuffer = fullSizeKeyHashBuffer.slice(0, hashSizeInBytes);
28 |
29 | return urlSafeBase64.encode(slicedBuffer);
30 | };
31 |
32 | /**
33 | * Reads the PKCS12 content from the given file if it exists. If not,
34 | * the PKCS12 content is generated, saved to a file and the content is
35 | * returned.
36 | * @param {String} fileNameWithPath the file which has the PKCS12 content.
37 | * @param {Function} cb the callback which returns an error or PKCS12 content.
38 | */
39 | function getPKCS12Content(fileNameWithPath, cb) {
40 | fs.exists(fileNameWithPath, function (exists) {
41 | if(exists) {
42 | fs.readFile(fileNameWithPath, function (err, pkcs12Content) {
43 | if (err) {
44 | cb(err);
45 | return;
46 | }
47 | cb(null, pkcs12Content);
48 | });
49 | } else {
50 | var pkcs12Content = crypto.pkcs12
51 | .createBundle(password, certname, country, organization);
52 |
53 | if (pkcs12Content.length <= 0) {
54 | return cb(new Error('failed to create pkcs12Content'));
55 | }
56 |
57 | fs.writeFile(
58 | fileNameWithPath,
59 | pkcs12Content,
60 | {flags: 'wx'},
61 | function (err) {
62 |
63 | if (err) {
64 | return cb(err);
65 | }
66 | cb(null, pkcs12Content);
67 | });
68 | }
69 | });
70 | }
71 |
72 | /**
73 | * Checks if a PKCS12 file exists in a known location and if not present, it is
74 | * created. The public key is extracted from the PKCS12 content and it's SHA256
75 | * hash value is returned.
76 | * @param {Function} cb the callback which returns an error or the hash value.
77 | */
78 | module.exports.getPublicKeyHash = function (cb) {
79 | Mobile.GetDocumentsPath(function (err, fileLocation) {
80 | if (err) {
81 | return cb(err);
82 | }
83 |
84 | var file = path.join(fileLocation, pkcs12FileName);
85 | getPKCS12Content(file, function(err, pkcs12Content) {
86 | if (err) {
87 | return cb(err);
88 | }
89 |
90 | try {
91 | var publicKey = crypto.pkcs12
92 | .extractPublicKey(password, pkcs12Content);
93 | if (!publicKey || publicKey.length <= 0) {
94 | return cb(new Error('extracted public key is invalid'));
95 | }
96 | var hash = generateSlicedSHA256Hash(publicKey, hashSizeInBytes);
97 | cb(null, hash);
98 | } catch(e) {
99 | return cb(new Error('error thrown by extractPublicKey() function'));
100 | }
101 | });
102 | });
103 | };
104 |
105 | module.exports.getConfigValuesForTestingOnly = function() {
106 | return {
107 | password: password,
108 | certname: certname,
109 | country: country,
110 | organization: organization,
111 | pkcs12FileName: pkcs12FileName,
112 | hashSizeInBytes: hashSizeInBytes
113 | };
114 | };
115 |
--------------------------------------------------------------------------------
/thali/thaliemitter.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var EventEmitter = require('events').EventEmitter;
4 | var inherits = require('util').inherits;
5 | var validations = require('./validations');
6 |
7 | function thrower(err) {
8 | if (err) { throw err; }
9 | }
10 |
11 | /**
12 | * Creates a new instance of the ThaliEmitter which is an EventEmitter to call the underlying native layer.
13 | */
14 | function ThaliEmitter() {
15 | EventEmitter.call(this);
16 | this._init();
17 | }
18 |
19 | inherits(ThaliEmitter, EventEmitter);
20 |
21 | ThaliEmitter.events = {
22 | PEER_AVAILABILITY_CHANGED: 'peerAvailabilityChanged',
23 | NETWORK_CHANGED: 'networkChanged',
24 | CONNECTION_ERROR: 'connectionError'
25 | };
26 |
27 | ThaliEmitter.prototype._init = function () {
28 | var self = this;
29 |
30 | function registerMobilePeerEvent(eventName) {
31 | function emitEvent(eventName) {
32 | return function handler(arg) {
33 | self.emit(eventName, arg);
34 | };
35 | }
36 |
37 | Mobile(eventName).registerToNative(emitEvent(eventName));
38 | }
39 |
40 | Object.keys(ThaliEmitter.events)
41 | .forEach(function (key) {
42 | registerMobilePeerEvent(ThaliEmitter.events[key]);
43 | });
44 | };
45 |
46 | /**
47 | * Starts broadcasting with the given device name, port and a callback
48 | * @param {String} deviceName the device name to broadcast.
49 | * @param {Number} port the port number to broadcast.
50 | * @param {Function} cb the callback which returns an error if one has occurred.
51 | */
52 | ThaliEmitter.prototype.startBroadcasting = function(deviceName, port, cb) {
53 | validations.ensureNonNullOrEmptyString(deviceName, 'deviceName');
54 | validations.ensureValidPort(port);
55 | cb || (cb = thrower);
56 |
57 | Mobile('StartBroadcasting').callNative(deviceName, port, function (err) {
58 | if (err) {
59 | cb(new Error(err));
60 | } else {
61 | cb();
62 | }
63 | });
64 | };
65 |
66 | /**
67 | * Starts broadcasting the availability of the current device.
68 | * @param {Function} cb the callback which returns an error if one has occurred.
69 | */
70 | ThaliEmitter.prototype.stopBroadcasting = function(cb) {
71 | cb || (cb = thrower);
72 |
73 | Mobile('StopBroadcasting').callNative(function (err) {
74 | if (err) {
75 | cb(new Error(err));
76 | } else {
77 | cb();
78 | }
79 | });
80 | };
81 |
82 | /**
83 | * Connects to the given peer by the given peer identifier.
84 | * @param {String} peerIdentifier the peer identifier of the device to connect to.
85 | * @param {Function} cb the callback which returns an error if one occurred and a port number used for synchronization.
86 | */
87 | ThaliEmitter.prototype.connect = function (peerIdentifier, cb) {
88 | validations.ensureNonNullOrEmptyString(peerIdentifier, 'peerIdentifier');
89 | validations.ensureIsFunction(cb);
90 |
91 | Mobile('Connect').callNative(peerIdentifier, function (err, port) {
92 | if (err) {
93 | cb(new Error(err));
94 | } else {
95 | cb(null, port);
96 | }
97 | });
98 | };
99 |
100 | /**
101 | * Disconnects from the given peer by the peer identifier. Note if the peer has already been disconnected, no error should be thrown.
102 | * @param {String} peerIdentifier the peer identifier of the device to disconnect from.
103 | * @param {Function} cb the callback which returns an error if one occurred.
104 | */
105 | ThaliEmitter.prototype.disconnect = function (peerIdentifier, cb) {
106 | validations.ensureNonNullOrEmptyString(peerIdentifier, 'peerIdentifier');
107 | cb || (cb = thrower);
108 |
109 | Mobile('Disconnect').callNative(peerIdentifier, function (err) {
110 | if (err) {
111 | cb(new Error(err));
112 | } else {
113 | cb();
114 | }
115 | });
116 | };
117 |
118 | module.exports = ThaliEmitter;
119 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/disabled/testThaliManagerStopCoordinated.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var tape = require('../../lib/thaliTape');
4 | if (!tape.coordinated) {
5 | return;
6 | }
7 |
8 | var testUtils = require('../../lib/testUtils.js');
9 |
10 | var fs = require('fs-extra-promise');
11 | var path = require('path');
12 | var crypto = require('crypto');
13 | var Promise = require('bluebird');
14 | var PouchDB = require('pouchdb');
15 | var ExpressPouchDB = require('express-pouchdb');
16 |
17 | var sinon = require('sinon');
18 | var proxyquire = require('proxyquire').noCallThru();
19 |
20 | var salti = require('salti');
21 | var PouchDBGenerator = require('thali/NextGeneration/utils/pouchDBGenerator');
22 | var thaliConfig = require('thali/NextGeneration/thaliConfig');
23 | var ThaliManager = require('thali/NextGeneration/thaliManager');
24 | var ThaliPeerPoolDefault =
25 | require('thali/NextGeneration/thaliPeerPool/thaliPeerPoolDefault');
26 |
27 | // Public base64 key for local device should be passed
28 | // to the tape 'setup' as 'tape.data'.
29 | // This is required for tape.coordinated server to generate participants.
30 | var ecdhForLocalDevice = crypto.createECDH(thaliConfig.BEACON_CURVE);
31 | var publicKeyForLocalDevice = ecdhForLocalDevice.generateKeys();
32 | var publicBase64KeyForLocalDevice = ecdhForLocalDevice.getPublicKey('base64');
33 |
34 | // PouchDB name should be the same between peers.
35 | var DB_NAME = 'ThaliManagerCoordinated';
36 |
37 | PouchDB = testUtils.getLevelDownPouchDb();
38 |
39 | var thaliManager;
40 |
41 | var test = tape({
42 | setup: function (t) {
43 | t.data = publicKeyForLocalDevice.toJSON();
44 | t.end();
45 | },
46 | teardown: function (t) {
47 | thaliManager.stop()
48 | .then(function () {
49 | t.end();
50 | });
51 | }
52 | });
53 |
54 | test('test uncaught exception', function (t) {
55 | var spySalti;
56 | var allRequestsStarted = new Promise(function (resolve) {
57 | spySalti = sinon.spy(function () {
58 | var saltiFilter = salti.apply(this, arguments);
59 |
60 | // We will wait untill all these requests will be started.
61 | var dbPrefix = thaliConfig.BASE_DB_PATH + '/' + DB_NAME + '/';
62 | var done = 0;
63 | return function (req) {
64 | if (req.path === '/NotificationBeacons') {
65 | done |= 1;
66 | } else if (req.path === dbPrefix + '_changes') {
67 | done |= 1 << 1;
68 | } else if (req.path === dbPrefix + '_bulk_docs') {
69 | done |= 1 << 2;
70 | } else if (req.path.indexOf(dbPrefix + '_local') === 0) {
71 | done |= 1 << 3;
72 | }
73 | if (done === 0xf) {
74 | done = -1;
75 | setImmediate(function () {
76 | resolve();
77 | });
78 | }
79 | return saltiFilter.apply(this, arguments);
80 | };
81 | });
82 | });
83 |
84 | var ThaliManagerProxyquired =
85 | proxyquire('thali/NextGeneration/thaliManager', {
86 | 'salti': spySalti
87 | });
88 |
89 | thaliManager = new ThaliManagerProxyquired(
90 | ExpressPouchDB,
91 | PouchDB,
92 | DB_NAME,
93 | ecdhForLocalDevice,
94 | new ThaliPeerPoolDefault()
95 | );
96 |
97 | // This function will return all participant's public keys
98 | // except local 'publicKeyForLocalDevice' one.
99 | var partnerKeys = testUtils.turnParticipantsIntoBufferArray(
100 | t, publicKeyForLocalDevice
101 | );
102 |
103 | // We are creating a local db for each participant.
104 | var pouchDB = new PouchDB(DB_NAME);
105 |
106 | pouchDB.put({
107 | _id: publicBase64KeyForLocalDevice
108 | })
109 | .then(function () {
110 | return thaliManager.start(partnerKeys);
111 | })
112 | .then(function () {
113 | return allRequestsStarted;
114 | })
115 | .then(function () {
116 | t.end();
117 | })
118 | });
119 |
--------------------------------------------------------------------------------
/test/www/jxcore/bv_tests/disabled/testThaliCryptoManager.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var originalMobile = typeof Mobile === "undefined" ? undefined : Mobile;
4 | var mockMobile = require('./mockmobile');
5 | var fs = require('fs-extra-promise');
6 | var path = require('path');
7 | var crypto = require('crypto');
8 | var tape = require('../lib/thaliTape');
9 | var cryptomanager = require('thali/thalicryptomanager');
10 | var testUtils = require('../lib/testUtils.js');
11 |
12 | // get the values needed for running the tests
13 | var configValues = cryptomanager.getConfigValuesForTestingOnly();
14 |
15 | var fileLocation = path.join(testUtils.tmpDirectory(), './pkcs12folder');
16 |
17 | // test setup & teardown activities
18 | var test = tape({
19 | setup: function(t) {
20 | fs.ensureDirSync(fileLocation);
21 | global.Mobile = mockMobile;
22 | t.end();
23 | },
24 | teardown: function(t) {
25 | global.Mobile = originalMobile;
26 | fs.removeSync(fileLocation);
27 | t.end();
28 | }
29 | });
30 |
31 | test('successfully create a new pkcs12 file and return hash value',
32 | function(t) {
33 | var errorMessage = null;
34 |
35 | Mobile.setGetDocumentsPathReturnValues(errorMessage, fileLocation);
36 |
37 | cryptomanager.getPublicKeyHash(function (err, publicKeyHash) {
38 | t.equal(err, null);
39 |
40 | var file = path.join(fileLocation, configValues.pkcs12FileName);
41 | fs.readFile(file, function (err, pkcs12Content) {
42 | t.ifError(err);
43 | t.doesNotThrow(function() {
44 | var publicKey = crypto.pkcs12.
45 | extractPublicKey(configValues.password, pkcs12Content);
46 | t.ok(publicKey && publicKey.length > 0);
47 | t.equal(publicKeyHash, cryptomanager.
48 | generateSlicedSHA256Hash(
49 | publicKey,
50 | configValues.hashSizeInBytes));
51 | t.end();
52 | });
53 | });
54 | });
55 | }
56 | );
57 |
58 | test('successfully read a previous pkcs12 file and return hash value',
59 | function (t) {
60 | var errorMessage = null;
61 |
62 | Mobile.setGetDocumentsPathReturnValues(errorMessage, fileLocation);
63 |
64 | var pkcs12Content = crypto.pkcs12.createBundle(configValues.password,
65 | configValues.certname, configValues.country, configValues.organization);
66 | t.ok(pkcs12Content.length > 0);
67 |
68 | var file = path.join(fileLocation, configValues.pkcs12FileName);
69 | fs.writeFileSync(file, pkcs12Content, {flags: 'wx'});
70 | t.doesNotThrow(function() {
71 | var publicKey = crypto.pkcs12.
72 | extractPublicKey(configValues.password, pkcs12Content);
73 | t.ok(publicKey && publicKey.length > 0);
74 | cryptomanager.getPublicKeyHash(function (err, publicKeyHash) {
75 | t.equal(err, null);
76 | t.equal(publicKeyHash, cryptomanager.
77 | generateSlicedSHA256Hash(publicKey, configValues.hashSizeInBytes));
78 | t.end();
79 | });
80 | });
81 | }
82 | );
83 |
84 | test('failed to extract public key because of corrupt pkcs12 file',
85 | function (t) {
86 | var errorMessage = null,
87 | badFileLocation = path.join(__dirname, 'pkcs12folderbad');
88 |
89 | var cryptoErrorMessage = 'error thrown by extractPublicKey() function';
90 |
91 | Mobile.setGetDocumentsPathReturnValues(errorMessage, badFileLocation);
92 |
93 | cryptomanager.getPublicKeyHash(function (err, publicKeyHash) {
94 | t.equal(err.message, cryptoErrorMessage);
95 | t.end();
96 | });
97 | });
98 |
99 | test('failed to get mobile documents path', function(t) {
100 | var errorMessage = 'GetDocumentsPath error',
101 | noFileLocation = null;
102 | Mobile.setGetDocumentsPathReturnValues(errorMessage, noFileLocation);
103 | cryptomanager.getPublicKeyHash(function (err, publicKeyHash) {
104 | t.equal(err, errorMessage);
105 | t.end();
106 | });
107 | });
108 |
--------------------------------------------------------------------------------