Swift Search to Master (#405)

* SEARCH-627 & SEARCH-628

- Add implementation for memory indexing
- Batch indexing and Real-time indexing

* ELECTRON-426 (#345)

- Changes innerHTML to innerText
- Removes 'replaceStrongTag' and 'replaceHTMLTags' function and changing to innerHTML to innerText

* SEARCH-764

- Rework "deleteIndexFolders" in the Electron Preload Script
- Fixes the Security Vulnerability

* SEARCH-764

- Updates spectron test preload api version

* SEARCH-766

- Rework "readFile" in Electron Preload Script
- Removing this method as this is only for the demo app

* SEARCH-766

- Removes merge method

* SEARCH-767

- Rework "path" in Electron Preload Script
- Removes the constructor to use hardcoded path

* SEARCH-767

- Updates unit test

* SEARCH-775

- Adds search api version to match with the client app

* SEARCH-775

- Spectron test fix

* SEARCH-770 (#391)

- constructor is required which was removed as part of SEARCH-767
This commit is contained in:
Keerthi Niranjan 2018-06-27 14:12:16 +05:30 committed by Vishwas Shashidhar
parent 65c304766f
commit 4aaa9ac539
10 changed files with 210 additions and 209 deletions

View File

@ -92,12 +92,14 @@
<th>Container Identifier</th>
<th>Container Version</th>
<th>Build Number</th>
<th>Search Api Version</th>
</tr>
<tr>
<td id="api-version"></td>
<td id="container-identifier"></td>
<td id="container-ver"></td>
<td id="build-number"></td>
<td id="search-api-ver"></td>
</tr>
</table>
</body>
@ -250,11 +252,13 @@
let containerIdentifier = document.getElementById('container-identifier');
let version = document.getElementById('container-ver');
let buildNumber = document.getElementById('build-number');
let searchApiVer = document.getElementById('search-api-ver');
apiVersionInfo.innerText = verInfo.apiVer;
containerIdentifier.innerText = verInfo.containerIdentifier;
version.innerText = verInfo.containerVer;
buildNumber.innerText = verInfo.buildNumber;
searchApiVer.innerText = verInfo.searchApiVer;
});
});

View File

@ -79,13 +79,7 @@
</div>
<br>
<div>
<label for="batchNumber">Batch Number: </label><input placeholder="Ex: batch1, batch2" id="batchNumber">
<button id='index'>Index Messages</button>
<button id='merge'>Merge</button>
</div>
<br>
<div>
<label for="batchNumber">Get Latest Message Timestamp</label>
<label for="getLatestMessageTimestamp">Get Latest Message Timestamp</label>
<button id='getLatestMessageTimestamp'>Click</button>
</div>
<br>
@ -125,8 +119,6 @@
var search = new ssf.Search("12345678910112", "jjjehdnctsjyieoalskcjdhsnahsadndfnusdfsdfsd=");
var searchUtils = new ssf.SearchUtils();
var buttonEl = document.getElementById('search');
var merge = document.getElementById('merge');
var buttonIndex = document.getElementById('index');
var queryEl = document.getElementById('query');
var offsetEl = document.getElementById('offset');
var limitEl = document.getElementById('limit');
@ -139,7 +131,6 @@
var table = document.getElementById('table');
var sendMessage = document.getElementById('sendMessage');
var realTimeIndexing = document.getElementById('realTimeIndexing');
var batchNumber = document.getElementById('batchNumber');
var timestamp = document.getElementById('getLatestMessageTimestamp');
var has = document.getElementById('has');
var checkFreeSpace = document.getElementById('checkFreeSpace');
@ -148,18 +139,6 @@
var rotationId = document.getElementById('rotationId');
var updateUserConfig = document.getElementById('updateUserConfig');
buttonIndex.addEventListener('click', function () {
let batchIndex = batchNumber.value;
search.readJson(batchIndex).then(function (res) {
search.indexBatch(JSON.stringify(res)).then(function () {
resultsEl.innerHTML = "Index created";
});
}).catch(function (err) {
console.log(err);
});
});
buttonEl.addEventListener('click', function () {
if (!search.isLibInit()) {
search.init();
@ -238,20 +217,6 @@
}
});
merge.addEventListener('click', function () {
search.mergeIndexBatches().then(function () {
search.encryptIndex('jjjehdnctsjyieoalskcjdhsnahsadndfnusdfsdfsd=').then(function () {
searchUtils.updateUserConfig(12345678910112, {rotationId:0, version: 1}).then(function (res) {
resultsEl.innerHTML = JSON.stringify(res);
}).catch(function (err) {
resultsEl.innerHTML = JSON.stringify(err);
});
});
}).catch(function (err) {
resultsEl.innerHTML = 'Error: ' + err;
});
});
timestamp.addEventListener('click', function () {
search.getLatestMessageTimestamp().then(function (res) {
resultsEl.innerHTML = res;
@ -289,4 +254,4 @@
});
</script>
</body>
</html>
</html>

View File

@ -110,7 +110,8 @@ function createAPI() {
containerIdentifier: appName,
containerVer: appVer,
buildNumber: buildNumber,
apiVer: '1.0.0'
apiVer: '2.0.0',
searchApiVer: '2.0.0'
};
resolve(verInfo);
});
@ -448,4 +449,4 @@ function createAPI() {
window.addEventListener('beforeunload', sanitize, false);
updateOnlineStatus();
}
}

View File

@ -1,7 +1,7 @@
'use strict';
const fs = require('fs');
const { randomString } = require('../search/utils/randomString.js');
const ref = require('ref');
const childProcess = require('child_process');
const path = require('path');
const isDevEnv = require('../utils/misc.js').isDevEnv;
@ -17,6 +17,7 @@ const Crypto = require('../cryptoLib');
const INDEX_VALIDATOR = searchConfig.LIBRARY_CONSTANTS.INDEX_VALIDATOR;
/*eslint class-methods-use-this: ["error", { "exceptMethods": ["deleteRealTimeFolder"] }] */
/**
* This search class communicates with the SymphonySearchEngine C library via node-ffi.
* There should be only 1 instance of this class in the Electron
@ -67,16 +68,18 @@ class Search {
* and creates a folder in the userData
*/
init() {
libSymphonySearch.symSEDestroy();
libSymphonySearch.symSEInit();
libSymphonySearch.symSEClearMainRAMIndex();
libSymphonySearch.symSEClearRealtimeRAMIndex();
libSymphonySearch.symSEEnsureFolderExists(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH);
Search.deleteIndexFolders(searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX);
Search.deleteIndexFolders(searchConfig.FOLDERS_CONSTANTS.TEMP_BATCH_INDEX_FOLDER);
Search.indexValidator(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`);
Search.indexValidator(searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX);
let indexDateStartFrom = new Date().getTime() - searchConfig.SEARCH_PERIOD_SUBTRACTOR;
libSymphonySearch.symSEMainFSIndexToRAMIndex(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`);
// Deleting all the messages except 3 Months from now
libSymphonySearch.symSEDeleteMessages(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`, null,
libSymphonySearch.symSEDeleteMessagesFromRAMIndex(null,
searchConfig.MINIMUM_DATE, indexDateStartFrom.toString());
Search.deleteIndexFolders();
this.isInitialized = true;
}
@ -113,17 +116,10 @@ class Search {
return;
}
if (!fs.existsSync(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH)) {
log.send(logLevels.ERROR, 'User index folder not found');
reject(new Error('User index folder not found'));
return;
}
const indexId = randomString();
libSymphonySearch.symSECreatePartialIndexAsync(searchConfig.FOLDERS_CONSTANTS.TEMP_BATCH_INDEX_FOLDER, indexId, messages, (err, res) => {
libSymphonySearch.symSEIndexMainRAMAsync(messages, function (err, res) {
if (err) {
log.send(logLevels.ERROR, 'Batch Indexing: error ->' + err);
reject(new Error(err));
log.send(logLevels.ERROR, `IndexBatch: Error indexing messages to memory : ${err}`);
reject(new Error('IndexBatch: Error indexing messages to memory '));
return;
}
resolve(res);
@ -135,22 +131,24 @@ class Search {
* Merging the temporary
* created from indexBatch()
*/
mergeIndexBatches() {
memoryIndexToFSIndex() {
return new Promise((resolve, reject) => {
Search.deleteIndexFolders();
libSymphonySearch.symSEEnsureFolderExists(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH);
if (!fs.existsSync(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH)) {
log.send(logLevels.ERROR, 'User index folder not found');
reject(new Error('User index folder not found'));
return;
}
libSymphonySearch.symSEMergePartialIndexAsync(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`, searchConfig.FOLDERS_CONSTANTS.TEMP_BATCH_INDEX_FOLDER, (err, res) => {
libSymphonySearch.symSEMainRAMIndexToFSIndexAsync(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`, (err, res) => {
if (err) {
log.send(logLevels.ERROR, 'Error merging the index ->' + err);
reject(new Error(err));
return;
}
Search.deleteIndexFolders(searchConfig.FOLDERS_CONSTANTS.TEMP_BATCH_INDEX_FOLDER);
resolve(res);
});
});
@ -197,13 +195,8 @@ class Search {
throw new Error('Library not initialized');
}
if (!fs.existsSync(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH)) {
log.send(logLevels.ERROR, 'User index folder not found');
throw new Error('User index folder not found');
}
this.isRealTimeIndexing = true;
return libSymphonySearch.symSEIndexRealTimeAsync(searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX, message, (err, result) => {
return libSymphonySearch.symSEIndexRealtimeRAMAsync(message, (err, result) => {
this.isRealTimeIndexing = false;
if (err) {
log.send(logLevels.ERROR, 'RealTime Indexing: error -> ' + err);
@ -213,16 +206,6 @@ class Search {
});
}
/**
* Reading a json file
* for the demo search app only
* @param {String} batch
* @returns {Promise}
*/
readJson(batch) {
return readFile.call(this, batch);
}
/**
* Encrypting the index after the merging the index
* to the main user index
@ -259,12 +242,6 @@ class Search {
return;
}
if (!fs.existsSync(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`) || !fs.existsSync(searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX)) {
log.send(logLevels.ERROR, 'Index folder does not exist.');
reject(new Error('Index folder does not exist.'));
return;
}
let q = Search.constructQuery(query, senderIds, threadIds, fileType);
if (q === undefined) {
@ -301,9 +278,9 @@ class Search {
_sortOrder = searchConfig.SORT_BY_SCORE;
}
const returnedResult = libSymphonySearch.symSESearch(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`, searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX, q, startDateTime.toString(), endDateTime.toString(), _offset, _limit, _sortOrder);
const returnedResult = libSymphonySearch.symSERAMIndexSearch(q, startDateTime.toString(), endDateTime.toString(), _offset, _limit, _sortOrder);
try {
let ret = returnedResult.readCString();
let ret = ref.readCString(returnedResult);
resolve(JSON.parse(ret));
} finally {
libSymphonySearch.symSEFreeResult(returnedResult);
@ -324,20 +301,14 @@ class Search {
return;
}
if (!fs.existsSync(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`)) {
log.send(logLevels.ERROR, 'Index folder does not exist.');
reject(new Error('Index folder does not exist.'));
return;
}
libSymphonySearch.symSEGetLastMessageTimestampAsync(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`, (err, res) => {
libSymphonySearch.symSEMainRAMIndexGetLastMessageTimestampAsync((err, res) => {
if (err) {
log.send(logLevels.ERROR, 'Error getting the index timestamp ->' + err);
reject(new Error(err));
}
const returnedResult = res;
try {
let ret = returnedResult.readCString();
let ret = ref.readCString(returnedResult);
resolve(ret);
} finally {
libSymphonySearch.symSEFreeResult(returnedResult);
@ -346,10 +317,8 @@ class Search {
});
}
/*eslint class-methods-use-this: ["error", { "exceptMethods": ["deleteRealTimeFolder"] }] */
deleteRealTimeFolder() {
Search.deleteIndexFolders(searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX);
Search.indexValidator(searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX);
libSymphonySearch.symSEClearRealtimeRAMIndex();
}
/**
@ -541,20 +510,22 @@ class Search {
/**
* Removing all the folders and files inside the data folder
* @param location
*/
static deleteIndexFolders(location) {
if (fs.existsSync(location)) {
fs.readdirSync(location).forEach((file) => {
let curPath = location + "/" + file;
if (fs.lstatSync(curPath).isDirectory()) {
Search.deleteIndexFolders(curPath);
} else {
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(location);
static deleteIndexFolders() {
function removeFiles(filePath) {
if (fs.existsSync(filePath)) {
fs.readdirSync(filePath).forEach((file) => {
let curPath = filePath + "/" + file;
if (fs.lstatSync(curPath).isDirectory()) {
removeFiles(curPath);
} else {
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(filePath);
}
}
removeFiles(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH);
}
}
@ -562,39 +533,16 @@ class Search {
/**
* Deleting the data index folder
* when the app is closed/signed-out/navigates
* isEncryption if that is true
* will not clear the memory index
*/
function deleteIndexFolder() {
Search.deleteIndexFolders(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH);
function deleteIndexFolder(isEncryption) {
if (!isEncryption) {
libSymphonySearch.symSEDestroy();
}
Search.deleteIndexFolders();
}
/**
* Reads the file from the msgjson
* this is only for the demo page
* @param batch
* @returns {Promise<Array>}
*/
function readFile(batch) {
return new Promise((resolve, reject) => {
let dirPath = path.join(searchConfig.FOLDERS_CONSTANTS.EXEC_PATH, isMac ? '..' : '', 'msgsjson', batch);
let messageFolderPath = isDevEnv ? path.join('./msgsjson', batch) : dirPath;
let files = fs.readdirSync(messageFolderPath);
this.messageData = [];
files.forEach((file) => {
let tempPath = path.join(messageFolderPath, file);
let data = fs.readFileSync(tempPath, "utf8");
if (data) {
try {
this.messageData.push(JSON.parse(data));
} catch (err) {
reject(new Error(err))
}
} else {
reject(new Error('Error reading batch'))
}
});
resolve(this.messageData);
});
}
/**
* Creating launch agent for handling the deletion of

View File

@ -53,7 +53,6 @@ const libraryPaths = {
const folderPaths = {
INDEX_PATH: indexFolderPath,
TEMP_BATCH_INDEX_FOLDER: indexFolderPath + '/temp_batch_indexes',
TEMP_REAL_TIME_INDEX: indexFolderPath + '/temp_realtime_index',
PREFIX_NAME: 'search_index',
PREFIX_NAME_PATH: indexFolderPath + '/search_index',
EXEC_PATH: execPath,

View File

@ -13,6 +13,22 @@ const symLucyIndexerPtr = ref.refType(symLucyIndexer);
* using the node-ffi
*/
let libSymphonySearch = ffi.Library(searchConfig.LIBRARY_CONSTANTS.SEARCH_LIBRARY_PATH, {
//New Memory Indexing API
'symSE_index_main_RAM': ['int', [ 'string' ] ],
'symSE_index_realtime_RAM': ['int', [ 'string' ] ],
'symSE_main_RAM_index_to_FS_index': ['int', [ 'string' ] ],
'symSE_realtime_RAM_index_to_FS_index': ['int', [ 'string' ] ],
'symSE_main_RAM_index_get_last_message_timestamp': ['char *', [] ],
'symSE_RAM_index_search': ['char *', [ 'string', 'string', 'string', 'int', 'int', 'int' ] ],
'symSE_main_FS_index_to_RAM_index': ['int', [ 'string' ] ],
'symSE_realtime_FS_index_to_RAM_index': ['int', [ 'string' ] ],
'symSE_clear_realtime_RAM_index': ['int', [] ],
'symSE_clear_main_RAM_index': ['int', [] ],
'symSE_delete_messages_from_RAM_index': ['int', [ 'string', 'string', 'string' ] ],
'symSE_destroy': ['int', [] ],
//init
'symSE_init': ['void', []],
'symSE_remove_folder': ['int', ['string']],
@ -40,6 +56,32 @@ let libSymphonySearch = ffi.Library(searchConfig.LIBRARY_CONSTANTS.SEARCH_LIBRAR
});
module.exports = {
// New Memory Indexing API
symSEIndexMainRAM: libSymphonySearch.symSE_index_main_RAM,
symSEIndexRealtimeRAM: libSymphonySearch.symSE_index_realtime_RAM,
symSEMainRAMIndexToFSIndex: libSymphonySearch.symSE_main_RAM_index_to_FS_index,
symSERealtimeRAMIndexToFSIndex: libSymphonySearch.symSE_realtime_RAM_index_to_FS_index,
symSEMainRAMIndexGetLastMessageTimestamp: libSymphonySearch.symSE_main_RAM_index_get_last_message_timestamp,
symSERAMIndexSearch: libSymphonySearch.symSE_RAM_index_search,
symSEMainFSIndexToRAMIndex: libSymphonySearch.symSE_main_FS_index_to_RAM_index,
symSERealtimeFSIndexToRAMIndex: libSymphonySearch.symSE_realtime_FS_index_to_RAM_index,
symSEClearRealtimeRAMIndex: libSymphonySearch.symSE_clear_realtime_RAM_index,
symSEClearMainRAMIndex: libSymphonySearch.symSE_clear_main_RAM_index,
symSEDeleteMessagesFromRAMIndex: libSymphonySearch.symSE_delete_messages_from_RAM_index,
symSEDestroy: libSymphonySearch.symSE_destroy,
symSEIndexMainRAMAsync: libSymphonySearch.symSE_index_main_RAM.async,
symSEIndexRealtimeRAMAsync: libSymphonySearch.symSE_index_realtime_RAM.async,
symSEMainRAMIndexToFSIndexAsync: libSymphonySearch.symSE_main_RAM_index_to_FS_index.async,
symSERealtimeRAMIndexToFSIndexAsync: libSymphonySearch.symSE_realtime_RAM_index_to_FS_index.async,
symSEMainRAMIndexGetLastMessageTimestampAsync: libSymphonySearch.symSE_main_RAM_index_get_last_message_timestamp.async,
symSERAMIndexSearchAsync: libSymphonySearch.symSE_RAM_index_search.async,
symSEMainFSIndexToRAMIndexAsync: libSymphonySearch.symSE_main_FS_index_to_RAM_index.async,
symSERealtimeFSIndexToRAMIndexAsync: libSymphonySearch.symSE_realtime_FS_index_to_RAM_index.async,
symSEClearRealtimeRAMIndexAsync: libSymphonySearch.symSE_clear_realtime_RAM_index.async,
symSEClearMainRAMIndexAsync: libSymphonySearch.symSE_clear_main_RAM_index.async,
symSEDeleteMessagesFromRAMIndexAsync: libSymphonySearch.symSE_delete_messages_from_RAM_index.async,
symSEDestroyAsync: libSymphonySearch.symSE_destroy.async,
symSEInit: libSymphonySearch.symSE_init,
symSERemoveFolder: libSymphonySearch.symSE_remove_folder,
symSEEnsureIndexExists: libSymphonySearch.symSE_ensure_index_exists,
@ -69,5 +111,5 @@ module.exports = {
symSEDeleteMessagesAsync: libSymphonySearch.symSE_delete_messages.async,
symSECommitIndexAsync: libSymphonySearch.symSE_commit_index.async,
symSEFreeResultAsync: libSymphonySearch.symSE_free_results.async,
symSEGetLastMessageTimestampAsync: libSymphonySearch.symSE_get_last_message_timestamp.async
symSEGetLastMessageTimestampAsync: libSymphonySearch.symSE_get_last_message_timestamp.async,
};

View File

@ -7,12 +7,12 @@ const { isMac } = require('../utils/misc.js');
* Utils to validate users config data and
* available disk space to enable electron search
*/
/*eslint class-methods-use-this: ["error", { "exceptMethods": ["checkFreeSpace"] }] */
class SearchUtils {
constructor() {
this.path = searchConfig.FOLDERS_CONSTANTS.USER_DATA_PATH;
this.indexVersion = searchConfig.INDEX_VERSION;
}
/**
* This function returns true if the available disk space
* is more than the constant MINIMUM_DISK_SPACE
@ -20,14 +20,15 @@ class SearchUtils {
*/
checkFreeSpace() {
return new Promise((resolve, reject) => {
let userDataPath = searchConfig.FOLDERS_CONSTANTS.USER_DATA_PATH;
if (!isMac) {
try {
this.path = this.path.substring(0, 1);
userDataPath = userDataPath.substring(0, 1);
} catch (e) {
reject(new Error('Invalid Path : ' + e));
}
}
checkDiskSpace(this.path, resolve, reject);
checkDiskSpace(userDataPath, resolve, reject);
});
}
@ -120,7 +121,7 @@ function createUserConfigFile(userId, data) {
let createStream = fs.createWriteStream(searchConfig.FOLDERS_CONSTANTS.USER_CONFIG_FILE);
if (userData) {
if (!userData.indexVersion) {
userData.indexVersion = searchConfig.INDEX_VERSION;
userData.indexVersion = this.indexVersion;
}
try {
userData = JSON.stringify(userData);
@ -146,7 +147,7 @@ function updateConfig(userId, data, resolve, reject) {
let userData = data;
if (userData && !userData.indexVersion) {
userData.indexVersion = searchConfig.INDEX_VERSION;
userData.indexVersion = this.indexVersion;
}
let configPath = searchConfig.FOLDERS_CONSTANTS.USER_CONFIG_FILE;

View File

@ -7,6 +7,7 @@ let userConfigDir = null;
let searchConfig;
let SearchApi;
let libSymphonySearch;
jest.mock('electron', function() {
return {
@ -37,9 +38,6 @@ describe('Tests for Search', function() {
let userId;
let key;
let dataFolderPath;
let realTimeIndexPath;
let tempBatchPath;
let launchAgent;
let currentDate = new Date().getTime();
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;
@ -48,28 +46,32 @@ describe('Tests for Search', function() {
userId = 12345678910112;
key = 'jjjehdnctsjyieoalskcjdhsnahsadndfnusdfsdfsd=';
executionPath = path.join(__dirname, 'library');
if (isWindowsOS) {
executionPath = path.join(__dirname, '..', 'library');
}
userConfigDir = path.join(__dirname, '..');
executionPath = path.join(__dirname, 'library');
if (isWindowsOS) {
executionPath = path.join(__dirname, '..', 'library');
}
userConfigDir = path.join(__dirname, '..');
libSymphonySearch = require('../js/search/searchLibrary.js');
searchConfig = require('../js/search/searchConfig.js');
let root = path.join(userConfigDir, `${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME}_${userId}.enc`);
if (fs.existsSync(root)) {
fs.unlinkSync(root);
}
const { Search } = require('../js/search/search.js');
SearchApi = new Search(userId, key);
searchConfig = require('../js/search/searchConfig.js');
const { Search } = require('../js/search/search.js');
SearchApi = new Search(userId, key);
launchAgent = require('../js/search/utils/search-launchd.js');
realTimeIndexPath = path.join(userConfigDir, 'data', 'temp_realtime_index');
tempBatchPath = path.join(userConfigDir, 'data', 'temp_batch_indexes');
dataFolderPath = path.join(userConfigDir, 'data');
if (fs.existsSync(dataFolderPath)) {
deleteIndexFolders(dataFolderPath);
}
done();
libSymphonySearch.symSEDestroy();
dataFolderPath = path.join(userConfigDir, 'data');
if (fs.existsSync(dataFolderPath)) {
deleteIndexFolders(dataFolderPath)
}
done();
});
afterAll(function (done) {
setTimeout(function () {
libSymphonySearch.symSEDestroy();
deleteIndexFolders(dataFolderPath);
let root = path.join(userConfigDir, `${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME}_${userId}.enc`);
if (fs.existsSync(root)) {
@ -83,12 +85,15 @@ describe('Tests for Search', function() {
}, 3000);
});
function deleteIndexFolders(location) {
function deleteIndexFolders(location, isEncryption) {
if (!isEncryption) {
libSymphonySearch.symSEDestroy();
}
if (fs.existsSync(location)) {
fs.readdirSync(location).forEach(function(file) {
let curPath = path.join(location, file);
if (fs.lstatSync(curPath).isDirectory()) {
deleteIndexFolders(curPath);
deleteIndexFolders(curPath, true);
} else {
fs.unlinkSync(curPath);
}
@ -123,13 +128,9 @@ describe('Tests for Search', function() {
});
it('should exist index folder', function() {
expect(fs.existsSync(path.join(userConfigDir, 'data', 'search_index_12345678910112'))).toBe(true);
expect(fs.existsSync(realTimeIndexPath)).toBe(true);
expect(fs.existsSync(path.join(userConfigDir, 'data', 'search_index_12345678910112'))).toBe(false);
});
it('should not exist index folder', function() {
expect(fs.existsSync(tempBatchPath)).toBe(false);
});
});
describe('Batch indexing process tests', function () {
@ -165,7 +166,6 @@ describe('Tests for Search', function() {
}];
const indexBatch = jest.spyOn(SearchApi, 'indexBatch');
SearchApi.indexBatch(JSON.stringify(messages)).then(function () {
expect(fs.existsSync(tempBatchPath)).toBe(true);
expect(indexBatch).toHaveBeenCalledWith(JSON.stringify(messages));
done();
});
@ -232,28 +232,22 @@ describe('Tests for Search', function() {
it('should match messages length after batch indexing', function (done) {
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
SearchApi.searchQuery('it works', [], [], '', undefined, undefined, 25, 0, 0).then(function (res) {
expect(res.messages.length).toEqual(0);
expect(res.messages.length).toEqual(3);
expect(searchQuery).toHaveBeenCalled();
done()
});
});
it('should merge batch index to user index', function (done) {
const mergeIndexBatches = jest.spyOn(SearchApi, 'mergeIndexBatches');
SearchApi.mergeIndexBatches().then(function () {
expect(fs.existsSync(tempBatchPath)).toBe(false);
expect(mergeIndexBatches).toHaveBeenCalled();
const memoryIndexToFSIndex = jest.spyOn(SearchApi, 'memoryIndexToFSIndex');
SearchApi.memoryIndexToFSIndex().then(function () {
expect(memoryIndexToFSIndex).toHaveBeenCalled();
done();
});
});
it('should match messages length after batch indexing', function (done) {
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
SearchApi.searchQuery('it works', [], [], '', undefined, undefined, 25, 0, 0).then(function (res) {
expect(res.messages.length).toEqual(3);
expect(searchQuery).toHaveBeenCalled();
done();
});
it('should exist data folder after ram index to fs index', function () {
expect(fs.existsSync(dataFolderPath)).toBe(true);
});
});
@ -280,7 +274,6 @@ describe('Tests for Search', function() {
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
SearchApi.searchQuery('realtime working', ["71811853189212"], ["Au8O2xKHyX1LtE6zW019GX///rZYegAtdA=="], '', undefined, undefined, 25, 0, 0).then(function (res) {
expect(res.messages.length).toEqual(3);
expect(fs.existsSync(realTimeIndexPath)).toBe(true);
expect(searchQuery).toHaveBeenCalled();
done();
})
@ -309,8 +302,6 @@ describe('Tests for Search', function() {
SearchApi.searchQuery('isRealTimeIndexing', [], [], '', undefined, undefined, 25, 0, 0).then(function (res) {
expect(res.messages.length).toEqual(0);
expect(fs.existsSync(realTimeIndexPath)).toBe(true);
done();
});
}, 6000)
@ -378,7 +369,6 @@ describe('Tests for Search', function() {
it('should delete realtime index', function () {
const deleteRealTimeFolder = jest.spyOn(SearchApi, 'deleteRealTimeFolder');
SearchApi.deleteRealTimeFolder();
expect(fs.existsSync(realTimeIndexPath)).toBe(true);
expect(deleteRealTimeFolder).toHaveBeenCalled();
});
});
@ -425,13 +415,14 @@ describe('Tests for Search', function() {
});
});
it('should not get the latest timestamp', function (done) {
it('should be equal to 0000000000000', function (done) {
const getLatestMessageTimestamp = jest.spyOn(SearchApi, 'getLatestMessageTimestamp');
deleteIndexFolders(dataFolderPath);
SearchApi.getLatestMessageTimestamp().catch(function (err) {
expect(err).toEqual(new Error('Index folder does not exist.'));
libSymphonySearch.symSEClearMainRAMIndex();
libSymphonySearch.symSEClearRealtimeRAMIndex();
SearchApi.getLatestMessageTimestamp().then(function (res) {
expect(getLatestMessageTimestamp).toHaveBeenCalled();
expect(getLatestMessageTimestamp).toHaveBeenCalledTimes(3);
expect(res).toEqual('0000000000000');
done();
});
});
@ -479,26 +470,25 @@ describe('Tests for Search', function() {
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
SearchApi.searchQuery('works', [], [], '', '', '', 2, 0, 0).then(function (res) {
expect(res.messages.length).toBe(2);
expect(searchQuery).toHaveBeenCalledTimes(7);
expect(searchQuery).toHaveBeenCalledTimes(6);
expect(searchQuery).toHaveBeenCalled();
done();
});
});
it('should search fails index folder not fund', function (done) {
deleteIndexFolders(dataFolderPath);
setTimeout(function () {
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
SearchApi.searchQuery('it works', [], [], '', '', '', 25, 0, 0).catch(function (err) {
expect(err).toEqual(new Error('Index folder does not exist.'));
expect(searchQuery).toHaveBeenCalledTimes(8);
expect(searchQuery).toHaveBeenCalled();
SearchApi = undefined;
const { Search } = require('../js/search/search.js');
SearchApi = new Search(userId, key);
done();
})
}, 3000);
it('should search fails result cleared', function (done) {
libSymphonySearch.symSEClearMainRAMIndex();
libSymphonySearch.symSEClearRealtimeRAMIndex();
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
SearchApi.searchQuery('it works', [], [], '', '', '', 25, 0, 0).then(function (res) {
expect(res.messages.length).toBe(0);
expect(searchQuery).toHaveBeenCalledTimes(7);
expect(searchQuery).toHaveBeenCalled();
SearchApi = undefined;
const { Search } = require('../js/search/search.js');
SearchApi = new Search(userId, key);
done();
});
});
it('should search fails query is undefined', function (done) {
@ -531,5 +521,52 @@ describe('Tests for Search', function() {
done();
});
});
it('should index for testing quote', function (done) {
let messages = [{
messageId: "Jc+4K8RtPxHJfyuDQU9atX///qN3KHYXdA==",
threadId: "Au8O2xKHyX1LtE6zW019GX///rZYegAtdA==",
ingestionDate: currentDate.toString(),
senderId: "71811853189212",
chatType: "CHATROOM",
isPublic: "false",
sendingApp: "lc",
text: "quote search"
}, {
messageId: "Jc+4K8RtPxHJfyuDQU9atX///qN3KHYXdA==",
threadId: "Au8O2xKHyX1LtE6zW019GX///rZYegAtdA==",
ingestionDate: currentDate.toString(),
senderId: "71811853189212",
chatType: "CHATROOM",
isPublic: "false",
sendingApp: "lc",
text: "search"
}];
const indexBatch = jest.spyOn(SearchApi, 'indexBatch');
SearchApi.indexBatch(JSON.stringify(messages)).then(function () {
expect(indexBatch).toHaveBeenCalledWith(JSON.stringify(messages));
done();
});
});
it('should search without quote', function (done) {
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
SearchApi.searchQuery('search', [], [], undefined, '', '', 25, 0, 0).then(function (res) {
expect(res.messages.length).toEqual(2);
expect(searchQuery).toHaveBeenCalled();
expect(searchQuery).toHaveBeenCalledTimes(4);
done();
});
});
it('should quote search', function (done) {
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
SearchApi.searchQuery('\"quote search\"', [], [], undefined, '', '', 25, 0, 0).then(function (res) {
expect(res.messages.length).toEqual(1);
expect(searchQuery).toHaveBeenCalled();
expect(searchQuery).toHaveBeenCalledTimes(5);
done();
});
});
});
});

View File

@ -65,14 +65,14 @@ describe('Tests for Search Utils', function() {
it('should return error', function (done) {
const checkFreeSpace = jest.spyOn(SearchUtilsAPI, 'checkFreeSpace');
if (isMac) {
SearchUtilsAPI.path = undefined;
searchConfig.FOLDERS_CONSTANTS.USER_DATA_PATH = undefined;
SearchUtilsAPI.checkFreeSpace().catch(function (err) {
expect(err).toEqual(new Error("Please provide path"));
expect(checkFreeSpace).toHaveBeenCalled();
done();
});
} else {
SearchUtilsAPI.path = undefined;
searchConfig.FOLDERS_CONSTANTS.USER_DATA_PATH = undefined;
SearchUtilsAPI.checkFreeSpace().catch(function (err) {
expect(err).toBeTruthy();
expect(checkFreeSpace).toHaveBeenCalled();
@ -85,7 +85,7 @@ describe('Tests for Search Utils', function() {
const checkFreeSpace = jest.spyOn(SearchUtilsAPI, 'checkFreeSpace');
SearchUtilsAPI.path = './tp';
if (isWindowsOS) {
SearchUtilsAPI.path = 'A://test';
searchConfig.FOLDERS_CONSTANTS.USER_DATA_PATH = 'A://test';
searchConfig.LIBRARY_CONSTANTS.FREE_DISK_SPACE = path.join(__dirname, '..',
"node_modules/electron-utils/FreeDiskSpace/bin/Release/FreeDiskSpace.exe");
}

View File

@ -4,6 +4,8 @@ const { buildNumber } = require('../../package');
const electronVersion = require('../../package').devDependencies.electron;
const bluebird = require('bluebird');
const SEARCH_API_VERSION = '2.0.0';
let app = new Application({});
describe('Tests for getVersionInfo API', () => {
@ -56,14 +58,16 @@ describe('Tests for getVersionInfo API', () => {
'#api-version',
'#container-identifier',
'#container-ver',
'#build-number'
'#build-number',
'#search-api-ver'
]).mapSeries((string) => {
return app.client.getText(string)
}).then((values) => {
expect(values[ 0 ]).toBe('1.0.0');
expect(values[ 0 ]).toBe('2.0.0');
expect(values[ 1 ]).toBe('Electron');
expect(values[ 2 ]).toBe(electronVersion);
expect(values[ 3 ]).toBe(buildNumber);
expect(values[ 4 ]).toBe(SEARCH_API_VERSION);
done();
});
});