@@ -6,7 +6,7 @@ const P = require('../../../util/promise');
66const fs_utils = require ( '../../../util/fs_utils' ) ;
77const NamespaceFS = require ( '../../../sdk/namespace_fs' ) ;
88const buffer_utils = require ( '../../../util/buffer_utils' ) ;
9- const { TMP_PATH } = require ( '../../system_tests/test_utils' ) ;
9+ const { TMP_PATH , TEST_TIMEOUT } = require ( '../../system_tests/test_utils' ) ;
1010const { crypto_random_string } = require ( '../../../util/string_utils' ) ;
1111const endpoint_stats_collector = require ( '../../../sdk/endpoint_stats_collector' ) ;
1212
@@ -27,18 +27,20 @@ function make_dummy_object_sdk(nsfs_config, uid, gid) {
2727}
2828
2929const DUMMY_OBJECT_SDK = make_dummy_object_sdk ( true ) ;
30+
31+ const tmp_fs_path = path . join ( TMP_PATH , 'test_nsfs_concurrency' ) ;
32+
33+ const nsfs = new NamespaceFS ( {
34+ bucket_path : tmp_fs_path ,
35+ bucket_id : '1' ,
36+ namespace_resource_id : undefined ,
37+ access_mode : undefined ,
38+ versioning : 'DISABLED' ,
39+ force_md5_etag : false ,
40+ stats : endpoint_stats_collector . instance ( ) ,
41+ } ) ;
42+
3043describe ( 'test nsfs concurrency' , ( ) => {
31- const tmp_fs_path = path . join ( TMP_PATH , 'test_nsfs_concurrency' ) ;
32-
33- const nsfs = new NamespaceFS ( {
34- bucket_path : tmp_fs_path ,
35- bucket_id : '1' ,
36- namespace_resource_id : undefined ,
37- access_mode : undefined ,
38- versioning : 'DISABLED' ,
39- force_md5_etag : false ,
40- stats : endpoint_stats_collector . instance ( ) ,
41- } ) ;
4244
4345 beforeEach ( async ( ) => {
4446 await fs_utils . create_fresh_path ( tmp_fs_path ) ;
@@ -68,5 +70,101 @@ describe('test nsfs concurrency', () => {
6870 }
6971 await P . delay ( 5000 ) ;
7072 expect ( res_etags ) . toHaveLength ( 15 ) ;
71- } , 6000 ) ;
73+ } , TEST_TIMEOUT ) ;
74+
75+ test_list_and_delete ( {
76+ test_name : 'list objects and delete an object during it - random deletion' ,
77+ bucket_name : 'bucket1' ,
78+ num_of_objects_to_upload : 5 ,
79+ expected_num_of_object_in_list : 4 ,
80+ key_to_delete : `my-key-${ random_integer ( 1 , 5 ) } ` ,
81+ iterations : 5 ,
82+ } ) ;
83+
84+ test_list_and_delete ( {
85+ test_name : 'list objects and delete an object during it - delete the last object' ,
86+ bucket_name : 'bucket2' ,
87+ num_of_objects_to_upload : 1000 ,
88+ expected_num_of_object_in_list : 999 ,
89+ key_to_delete : `my-key-1000` ,
90+ iterations : 1
91+ } ) ;
7292} ) ;
93+
94+ /**
95+ * @param {{
96+ * test_name: string,
97+ * bucket_name: string,
98+ * num_of_objects_to_upload: number,
99+ * expected_num_of_object_in_list: number,
100+ * key_to_delete?: string,
101+ * iterations?: number,
102+ * }} params
103+ */
104+ function test_list_and_delete ( {
105+ test_name,
106+ bucket_name,
107+ num_of_objects_to_upload,
108+ expected_num_of_object_in_list,
109+ key_to_delete,
110+ iterations = 1
111+ } ) {
112+
113+ it ( test_name , async ( ) => {
114+ await _upload_objects ( bucket_name , num_of_objects_to_upload ) ;
115+ if ( key_to_delete === undefined ) {
116+ key_to_delete = `my-key-${ random_integer ( 1 , expected_num_of_object_in_list ) } ` ;
117+ console . log ( 'test_list_and_delete: key_to_delete' , key_to_delete ) ;
118+ }
119+
120+ console . log ( `test_list_and_delete: ${ test_name } ${ bucket_name } num_of_objects_to_upload: ${ num_of_objects_to_upload } ,
121+ expected_num_of_object_in_list ${ expected_num_of_object_in_list } key_to_delete ${ key_to_delete } ` ) ;
122+
123+ for ( let i = 0 ; i < iterations ; ++ i ) {
124+ nsfs . list_objects ( { bucket : bucket_name } , DUMMY_OBJECT_SDK )
125+ . catch ( err => {
126+ console . log ( 'error during list_objects' , err ) ;
127+ throw err ;
128+ } ) . then ( res => {
129+ console . log ( 'list was successful' ) ;
130+ } ) ;
131+ nsfs . delete_object ( { bucket : bucket_name , key : key_to_delete } , DUMMY_OBJECT_SDK )
132+ . catch ( err => {
133+ console . log ( 'delete_object got an error' , err ) ;
134+ throw err ;
135+ } ) . then ( res => {
136+ console . log ( 'delete_object during list objects was successful' ) ;
137+ } ) ;
138+ await P . delay ( 5000 ) ;
139+ // up to this point if it was successful, the race between the delete object and list object went fine.
140+ }
141+ } , TEST_TIMEOUT ) ;
142+ }
143+
144+ /**
145+ * _upload_objects uploads number_of_versions of objects in bucket
146+ * note: this function is not concurrent, it's a helper function for preparing a bucket with a couple of objects
147+ * @param {string } bucket
148+ * @param {number } number_of_objects
149+ */
150+ async function _upload_objects ( bucket , number_of_objects ) {
151+ const keys_names = [ ] ;
152+ for ( let i = 0 ; i < number_of_objects ; i ++ ) {
153+ const key_name = `my-key-${ i + 1 } ` ;
154+ const random_data = Buffer . from ( String ( crypto_random_string ( 7 ) ) ) ;
155+ const body = buffer_utils . buffer_to_read_stream ( random_data ) ;
156+ await nsfs . upload_object ( { bucket : bucket , key : key_name , source_stream : body } , DUMMY_OBJECT_SDK ) ;
157+ keys_names . push ( key_name ) ;
158+ }
159+ return keys_names ;
160+ }
161+
162+ /**
163+ * randomInteger between min (included) and max (included)
164+ * // copied from: https://stackoverflow.com/questions/4959975/generate-random-number-between-two-numbers-in-javascript
165+ * @param {number } min
166+ * @param {number } max
167+ */
168+ function random_integer ( min , max ) {
169+ return Math . floor ( Math . random ( ) * ( max - min + 1 ) ) + min ;
170+ }
0 commit comments