diff --git a/demo/index.html b/demo/index.html index 1ab9cd7c..9307a5e7 100644 --- a/demo/index.html +++ b/demo/index.html @@ -92,12 +92,14 @@ Container Identifier Container Version Build Number + Search Api Version + @@ -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; }); }); diff --git a/demo/search.html b/demo/search.html index 4b6eda04..0c966bd8 100644 --- a/demo/search.html +++ b/demo/search.html @@ -79,13 +79,7 @@
- - - -
-
-
- +

@@ -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 @@ }); - \ No newline at end of file + diff --git a/js/preload/preloadMain.js b/js/preload/preloadMain.js index a4af0835..b95c8994 100644 --- a/js/preload/preloadMain.js +++ b/js/preload/preloadMain.js @@ -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(); -} \ No newline at end of file +} diff --git a/js/search/search.js b/js/search/search.js index be7f7d8c..de04e28e 100644 --- a/js/search/search.js +++ b/js/search/search.js @@ -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} - */ -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 diff --git a/js/search/searchConfig.js b/js/search/searchConfig.js index a390771b..311e8d2a 100644 --- a/js/search/searchConfig.js +++ b/js/search/searchConfig.js @@ -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, diff --git a/js/search/searchLibrary.js b/js/search/searchLibrary.js index 8d6da093..52ff6b82 100644 --- a/js/search/searchLibrary.js +++ b/js/search/searchLibrary.js @@ -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, }; \ No newline at end of file diff --git a/js/search/searchUtils.js b/js/search/searchUtils.js index 00f9d2a8..38b52e6f 100644 --- a/js/search/searchUtils.js +++ b/js/search/searchUtils.js @@ -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; diff --git a/tests/Search.test.js b/tests/Search.test.js index d66fd90d..69c2b446 100644 --- a/tests/Search.test.js +++ b/tests/Search.test.js @@ -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(); + }); + }); }); }); diff --git a/tests/SearchUtils.test.js b/tests/SearchUtils.test.js index 0e16b021..1e8d42a7 100644 --- a/tests/SearchUtils.test.js +++ b/tests/SearchUtils.test.js @@ -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"); } diff --git a/tests/spectron/getVersionInfo.spectron.js b/tests/spectron/getVersionInfo.spectron.js index 40e8c075..8d80c3a6 100644 --- a/tests/spectron/getVersionInfo.spectron.js +++ b/tests/spectron/getVersionInfo.spectron.js @@ -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(); }); });