@joystick.js/db-canary 0.0.0-canary.2209
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.build/getFilesToBuild.js +26 -0
- package/.build/getPlatformSafeFilePath.js +6 -0
- package/.build/getPlatformSafePath.js +6 -0
- package/.build/index.js +88 -0
- package/.build/isWindows.js +3 -0
- package/API_KEY +1 -0
- package/README.md +1821 -0
- package/data/data.mdb +0 -0
- package/data/lock.mdb +0 -0
- package/dist/client/database.js +1 -0
- package/dist/client/index.js +1 -0
- package/dist/server/cluster/index.js +1 -0
- package/dist/server/cluster/master.js +20 -0
- package/dist/server/cluster/worker.js +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/lib/api_key_manager.js +9 -0
- package/dist/server/lib/auth_manager.js +1 -0
- package/dist/server/lib/auto_index_manager.js +1 -0
- package/dist/server/lib/backup_manager.js +1 -0
- package/dist/server/lib/connection_manager.js +1 -0
- package/dist/server/lib/disk_utils.js +2 -0
- package/dist/server/lib/http_server.js +405 -0
- package/dist/server/lib/index_manager.js +1 -0
- package/dist/server/lib/load_settings.js +1 -0
- package/dist/server/lib/logger.js +1 -0
- package/dist/server/lib/op_types.js +1 -0
- package/dist/server/lib/operation_dispatcher.js +1 -0
- package/dist/server/lib/operations/admin.js +1 -0
- package/dist/server/lib/operations/bulk_write.js +1 -0
- package/dist/server/lib/operations/create_index.js +1 -0
- package/dist/server/lib/operations/delete_one.js +1 -0
- package/dist/server/lib/operations/drop_index.js +1 -0
- package/dist/server/lib/operations/find.js +1 -0
- package/dist/server/lib/operations/find_one.js +1 -0
- package/dist/server/lib/operations/get_indexes.js +1 -0
- package/dist/server/lib/operations/insert_one.js +1 -0
- package/dist/server/lib/operations/update_one.js +1 -0
- package/dist/server/lib/performance_monitor.js +1 -0
- package/dist/server/lib/query_engine.js +1 -0
- package/dist/server/lib/recovery_manager.js +1 -0
- package/dist/server/lib/replication_manager.js +1 -0
- package/dist/server/lib/safe_json_parse.js +1 -0
- package/dist/server/lib/send_response.js +1 -0
- package/dist/server/lib/tcp_protocol.js +1 -0
- package/dist/server/lib/write_forwarder.js +1 -0
- package/dist/server/lib/write_queue.js +1 -0
- package/increment_version.js +3 -0
- package/logs/.013e15b54597d05db4b4b53ecc37b10c92a72927-audit.json +20 -0
- package/logs/.02de550a67ea0f5961faa2dfd458a4d06f59ebd1-audit.json +20 -0
- package/logs/.03494ba24eb3c72214b4068a77d54b8993bee651-audit.json +20 -0
- package/logs/.06309ec60b339be1259a7993dd09c732f8907fbc-audit.json +20 -0
- package/logs/.0663a04dcfa17285661e5e1b8cfa51f41523b210-audit.json +20 -0
- package/logs/.0f06e6c4c9b824622729e13927587479e5060391-audit.json +20 -0
- package/logs/.16ccf58682ecb22b3e3ec63f0da1b7fe9be56528-audit.json +20 -0
- package/logs/.1fa1a5d02f496474b1ab473524c65c984146a9ad-audit.json +20 -0
- package/logs/.2223c0ae3bea6f0d62c62b1d319cc8634856abb7-audit.json +20 -0
- package/logs/.23dc79ffda3e083665e6f5993f59397adcbf4a46-audit.json +20 -0
- package/logs/.28104f49b03906b189eefd1cd462cb46c3c0af22-audit.json +20 -0
- package/logs/.29cdbf13808abe6a0ce70ee2f2efdd680ce3fd8e-audit.json +20 -0
- package/logs/.2a9889afd071f77f41f5170d08703a0afca866b7-audit.json +20 -0
- package/logs/.2acec3d1940a2bbed487528b703ee5948959a599-audit.json +20 -0
- package/logs/.2fb60ff326338c02bfedbcd0e936444e4a216750-audit.json +20 -0
- package/logs/.318fc7a19530d76a345f030f7cad00dda15300e7-audit.json +20 -0
- package/logs/.3cf27043e19085f908cedc7701e6d013463208ee-audit.json +25 -0
- package/logs/.3d90d785415817fc443402843b7c95f8371adc9b-audit.json +20 -0
- package/logs/.4074bca620375f72966fc52dfd439577727671e5-audit.json +20 -0
- package/logs/.40eecf018417ea80a70ea8ec7a3cc9406bc6334b-audit.json +20 -0
- package/logs/.50e974f1ef7c365fca6a1251b2e2c2252914cb5e-audit.json +20 -0
- package/logs/.52cb7d9e4223cf26ba36006ac26b949a97c7923c-audit.json +20 -0
- package/logs/.54befcdb84c15aad980705a31bcc9f555c3577ab-audit.json +20 -0
- package/logs/.57dfb70e22eddb84db2e3c0ceeefac5c0b9baffa-audit.json +20 -0
- package/logs/.5f0b24705a1eaad4eca4968f2d86f91b3f9be683-audit.json +20 -0
- package/logs/.61ba98fdda7db58576b382fee07904e5db1169d6-audit.json +20 -0
- package/logs/.6235017727ef6b199d569a99d6aa8c8e80a1b475-audit.json +20 -0
- package/logs/.63db16193699219489d218a1ddea5dde3750cae4-audit.json +20 -0
- package/logs/.64fb67dfe14149c9eef728d79bf30a54da809c60-audit.json +20 -0
- package/logs/.669137453368987c1f311b5345342527afb54e50-audit.json +20 -0
- package/logs/.7a71f8c89ea28ae266d356aeff6306e876a30fbb-audit.json +20 -0
- package/logs/.7afbaa90fe9dc3a7d682676f9bb79f9a1b1fd9a6-audit.json +20 -0
- package/logs/.7ca29e322cd05327035de850099e7610864f2347-audit.json +20 -0
- package/logs/.83335ab3347e449dae03455a110aaf7f120d4802-audit.json +20 -0
- package/logs/.8c2487b5fd445d2c8e5c483c80b9fa99bbf1ca58-audit.json +20 -0
- package/logs/.8c8b9dc386922c9f3b4c13251af7052aac1d24c0-audit.json +20 -0
- package/logs/.8d6155d94640c4863301ae0fee5e4e7372a21446-audit.json +20 -0
- package/logs/.944a3119a243deea7c8270d5d9e582bb1d0eaa10-audit.json +20 -0
- package/logs/.9816a845c30fb2909f3b26a23eeb3538ebcad5db-audit.json +20 -0
- package/logs/.9dc08784e38b865488177c26d4af5934555e0323-audit.json +20 -0
- package/logs/.9dd27d2e0e454ac0a37600206d1cac5493b0d7ee-audit.json +20 -0
- package/logs/.a3d486feeac7654c59b547de96600e8849a06d4f-audit.json +20 -0
- package/logs/.a5b811f4def22250f86cc18870d7c4573625df22-audit.json +20 -0
- package/logs/.a61648eb5f830e0b6f508ac35e4f8f629d2ad4c7-audit.json +20 -0
- package/logs/.a89016d507045771b4b5a65656944a9c0f1e528b-audit.json +20 -0
- package/logs/.a99bee160a1c590be959af46bacc02724803f691-audit.json +20 -0
- package/logs/.ada7906d6243fd7da802f03d86c4ae5dd9df6236-audit.json +20 -0
- package/logs/.b518339ee942143b6af983af167f5bbb6983b4de-audit.json +20 -0
- package/logs/.b51b124b166d53c9519017856ea610d61d65fabe-audit.json +20 -0
- package/logs/.b7a6aee19f58e55633d5e4a3709041c47dfff975-audit.json +20 -0
- package/logs/.bd7a8a6ba9c55d557a4867ab53f02e3ec2e1553d-audit.json +20 -0
- package/logs/.c1435dafe453b169d6392b25065f3cf4ab6fbb21-audit.json +20 -0
- package/logs/.c17e1ce043109f77dc2f0e2aa290a9d1ed842c03-audit.json +20 -0
- package/logs/.ca62637ce9540e5a38a2fbedb2115febb6ad308a-audit.json +15 -0
- package/logs/.ccee67b9c176967f8977071409a41f5cb5cd6ad4-audit.json +20 -0
- package/logs/.db24043417ea79a6f14cd947476399e53930b48d-audit.json +20 -0
- package/logs/.e0f12acccb57829f5f33712bb2e2607ecd808147-audit.json +20 -0
- package/logs/.e9b6cc33d0bbd2e644c4e2bf44d177f850016557-audit.json +20 -0
- package/logs/.f15291d434808e3bdca7963ccd2e73893be027e6-audit.json +20 -0
- package/logs/.f4bdf9e21ef84f8a3fae3ffb32bbc39275991351-audit.json +15 -0
- package/logs/.fbac3aefac1e81b4230df5aa50667cb90d51024f-audit.json +20 -0
- package/logs/.fcfd495c0a9169db243f4a4f21878ee02b76413c-audit.json +20 -0
- package/logs/admin-2025-09-12.log +580 -0
- package/logs/admin-2025-09-15.log +283 -0
- package/logs/admin-error-2025-09-12.log +22 -0
- package/logs/admin-error-2025-09-15.log +10 -0
- package/logs/api_key_manager-2025-09-12.log +658 -0
- package/logs/api_key_manager-2025-09-15.log +295 -0
- package/logs/api_key_manager-error-2025-09-12.log +0 -0
- package/logs/api_key_manager-error-2025-09-15.log +0 -0
- package/logs/auth_manager-2025-09-12.log +4432 -0
- package/logs/auth_manager-2025-09-15.log +2000 -0
- package/logs/auth_manager-error-2025-09-12.log +11 -0
- package/logs/auth_manager-error-2025-09-15.log +5 -0
- package/logs/auto_index_manager-2025-09-12.log +84 -0
- package/logs/auto_index_manager-2025-09-15.log +45 -0
- package/logs/auto_index_manager-error-2025-09-12.log +6 -0
- package/logs/auto_index_manager-error-2025-09-15.log +0 -0
- package/logs/backup_manager-2025-09-12.log +198 -0
- package/logs/backup_manager-2025-09-15.log +90 -0
- package/logs/backup_manager-error-2025-09-12.log +198 -0
- package/logs/backup_manager-error-2025-09-15.log +90 -0
- package/logs/bulk_write-2025-09-12.log +66 -0
- package/logs/bulk_write-2025-09-15.log +38 -0
- package/logs/bulk_write-error-2025-09-12.log +0 -0
- package/logs/bulk_write-error-2025-09-15.log +0 -0
- package/logs/connection_manager-2025-09-12.log +2412 -0
- package/logs/connection_manager-2025-09-15.log +1132 -0
- package/logs/connection_manager-error-2025-09-12.log +0 -0
- package/logs/connection_manager-error-2025-09-15.log +0 -0
- package/logs/create_index-2025-09-12.log +302 -0
- package/logs/create_index-2025-09-15.log +158 -0
- package/logs/create_index-error-2025-09-12.log +30 -0
- package/logs/create_index-error-2025-09-15.log +13 -0
- package/logs/delete_one-2025-09-12.log +73 -0
- package/logs/delete_one-2025-09-15.log +43 -0
- package/logs/delete_one-error-2025-09-12.log +0 -0
- package/logs/delete_one-error-2025-09-15.log +0 -0
- package/logs/disk_utils-2025-09-12.log +4954 -0
- package/logs/disk_utils-2025-09-15.log +2446 -0
- package/logs/disk_utils-error-2025-09-12.log +0 -0
- package/logs/disk_utils-error-2025-09-15.log +0 -0
- package/logs/drop_index-2025-09-12.log +41 -0
- package/logs/drop_index-2025-09-15.log +23 -0
- package/logs/drop_index-error-2025-09-12.log +11 -0
- package/logs/drop_index-error-2025-09-15.log +5 -0
- package/logs/find-2025-09-12.log +1050 -0
- package/logs/find-2025-09-15.log +592 -0
- package/logs/find-error-2025-09-12.log +1 -0
- package/logs/find-error-2025-09-15.log +0 -0
- package/logs/find_one-2025-09-12.log +425 -0
- package/logs/find_one-2025-09-15.log +264 -0
- package/logs/find_one-error-2025-09-12.log +5 -0
- package/logs/find_one-error-2025-09-15.log +0 -0
- package/logs/get_indexes-2025-09-12.log +84 -0
- package/logs/get_indexes-2025-09-15.log +56 -0
- package/logs/get_indexes-error-2025-09-12.log +6 -0
- package/logs/get_indexes-error-2025-09-15.log +0 -0
- package/logs/http_server-2025-09-12.log +2772 -0
- package/logs/http_server-2025-09-15.log +1276 -0
- package/logs/http_server-error-2025-09-12.log +212 -0
- package/logs/http_server-error-2025-09-15.log +44 -0
- package/logs/index_manager-2025-09-12.log +5031 -0
- package/logs/index_manager-2025-09-15.log +2909 -0
- package/logs/index_manager-error-2025-09-12.log +80 -0
- package/logs/index_manager-error-2025-09-15.log +38 -0
- package/logs/insert_one-2025-09-12.log +2181 -0
- package/logs/insert_one-2025-09-15.log +1293 -0
- package/logs/insert_one-error-2025-09-12.log +0 -0
- package/logs/insert_one-error-2025-09-15.log +0 -0
- package/logs/master-2025-09-12.log +1882 -0
- package/logs/master-2025-09-15.log +910 -0
- package/logs/master-error-2025-09-12.log +80 -0
- package/logs/master-error-2025-09-15.log +0 -0
- package/logs/operation_dispatcher-2025-09-12.log +751 -0
- package/logs/operation_dispatcher-2025-09-15.log +359 -0
- package/logs/operation_dispatcher-error-2025-09-12.log +33 -0
- package/logs/operation_dispatcher-error-2025-09-15.log +11 -0
- package/logs/performance_monitor-2025-09-12.log +14889 -0
- package/logs/performance_monitor-2025-09-15.log +6803 -0
- package/logs/performance_monitor-error-2025-09-12.log +0 -0
- package/logs/performance_monitor-error-2025-09-15.log +0 -0
- package/logs/query_engine-2025-09-12.log +5310 -0
- package/logs/query_engine-2025-09-15.log +2639 -0
- package/logs/query_engine-error-2025-09-12.log +0 -0
- package/logs/query_engine-error-2025-09-15.log +0 -0
- package/logs/recovery_manager-2025-09-12.log +462 -0
- package/logs/recovery_manager-2025-09-15.log +210 -0
- package/logs/recovery_manager-error-2025-09-12.log +22 -0
- package/logs/recovery_manager-error-2025-09-15.log +10 -0
- package/logs/replication-2025-09-12.log +1923 -0
- package/logs/replication-2025-09-15.log +917 -0
- package/logs/replication-error-2025-09-12.log +33 -0
- package/logs/replication-error-2025-09-15.log +15 -0
- package/logs/server-2025-09-12.log +2601 -0
- package/logs/server-2025-09-15.log +1191 -0
- package/logs/server-error-2025-09-12.log +0 -0
- package/logs/server-error-2025-09-15.log +0 -0
- package/logs/tcp_protocol-2025-09-12.log +22 -0
- package/logs/tcp_protocol-2025-09-15.log +10 -0
- package/logs/tcp_protocol-error-2025-09-12.log +22 -0
- package/logs/tcp_protocol-error-2025-09-15.log +10 -0
- package/logs/test-2025-09-12.log +0 -0
- package/logs/test-2025-09-15.log +0 -0
- package/logs/test-error-2025-09-12.log +0 -0
- package/logs/test-error-2025-09-15.log +0 -0
- package/logs/update_one-2025-09-12.log +173 -0
- package/logs/update_one-2025-09-15.log +118 -0
- package/logs/update_one-error-2025-09-12.log +0 -0
- package/logs/update_one-error-2025-09-15.log +0 -0
- package/logs/worker-2025-09-12.log +1457 -0
- package/logs/worker-2025-09-15.log +695 -0
- package/logs/worker-error-2025-09-12.log +0 -0
- package/logs/worker-error-2025-09-15.log +0 -0
- package/logs/write_forwarder-2025-09-12.log +1956 -0
- package/logs/write_forwarder-2025-09-15.log +932 -0
- package/logs/write_forwarder-error-2025-09-12.log +66 -0
- package/logs/write_forwarder-error-2025-09-15.log +30 -0
- package/logs/write_queue-2025-09-12.log +612 -0
- package/logs/write_queue-2025-09-15.log +301 -0
- package/logs/write_queue-error-2025-09-12.log +184 -0
- package/logs/write_queue-error-2025-09-15.log +83 -0
- package/package.json +48 -0
- package/prompts/01-core-infrastructure.md +56 -0
- package/prompts/02-secondary-indexing.md +65 -0
- package/prompts/03-write-serialization.md +63 -0
- package/prompts/04-enhanced-authentication.md +75 -0
- package/prompts/05-comprehensive-admin-operations.md +75 -0
- package/prompts/06-backup-and-restore-system.md +106 -0
- package/prompts/07-production-safety-features.md +107 -0
- package/prompts/08-tcp-client-library.md +121 -0
- package/prompts/09-api-method-chaining.md +134 -0
- package/prompts/10-automatic-index-creation.md +223 -0
- package/prompts/11-operation-naming-consistency.md +268 -0
- package/prompts/12-tcp-replication-system.md +333 -0
- package/prompts/13-master-read-write-operations.md +57 -0
- package/prompts/14-index-upsert-operations.md +68 -0
- package/prompts/15-client-api-return-types.md +81 -0
- package/prompts/16-server-setup-ui.md +97 -0
- package/prompts/17-emergency-password-change.md +108 -0
- package/prompts/18-joystick-framework-integration.md +116 -0
- package/prompts/19-api-key-authentication-system.md +137 -0
- package/prompts/20-configurable-server-port.md +105 -0
- package/prompts/21-multi-database-support.md +161 -0
- package/prompts/FULL_TEXT_SEARCH.md +293 -0
- package/prompts/PROMPTS.md +158 -0
- package/prompts/README.md +221 -0
- package/prompts/TYPESCRIPT_GENERATION.md +179 -0
- package/src/client/database.js +166 -0
- package/src/client/index.js +752 -0
- package/src/server/cluster/index.js +53 -0
- package/src/server/cluster/master.js +774 -0
- package/src/server/cluster/worker.js +537 -0
- package/src/server/index.js +540 -0
- package/src/server/lib/api_key_manager.js +473 -0
- package/src/server/lib/auth_manager.js +375 -0
- package/src/server/lib/auto_index_manager.js +681 -0
- package/src/server/lib/backup_manager.js +650 -0
- package/src/server/lib/connection_manager.js +218 -0
- package/src/server/lib/disk_utils.js +118 -0
- package/src/server/lib/http_server.js +1165 -0
- package/src/server/lib/index_manager.js +756 -0
- package/src/server/lib/load_settings.js +143 -0
- package/src/server/lib/logger.js +135 -0
- package/src/server/lib/op_types.js +29 -0
- package/src/server/lib/operation_dispatcher.js +268 -0
- package/src/server/lib/operations/admin.js +808 -0
- package/src/server/lib/operations/bulk_write.js +367 -0
- package/src/server/lib/operations/create_index.js +68 -0
- package/src/server/lib/operations/delete_one.js +114 -0
- package/src/server/lib/operations/drop_index.js +58 -0
- package/src/server/lib/operations/find.js +340 -0
- package/src/server/lib/operations/find_one.js +319 -0
- package/src/server/lib/operations/get_indexes.js +52 -0
- package/src/server/lib/operations/insert_one.js +113 -0
- package/src/server/lib/operations/update_one.js +225 -0
- package/src/server/lib/performance_monitor.js +313 -0
- package/src/server/lib/query_engine.js +243 -0
- package/src/server/lib/recovery_manager.js +388 -0
- package/src/server/lib/replication_manager.js +727 -0
- package/src/server/lib/safe_json_parse.js +21 -0
- package/src/server/lib/send_response.js +47 -0
- package/src/server/lib/tcp_protocol.js +130 -0
- package/src/server/lib/write_forwarder.js +636 -0
- package/src/server/lib/write_queue.js +335 -0
- package/test_data/data.mdb +0 -0
- package/test_data/lock.mdb +0 -0
- package/tests/client/index.test.js +1232 -0
- package/tests/server/cluster/cluster.test.js +248 -0
- package/tests/server/cluster/master_read_write_operations.test.js +577 -0
- package/tests/server/index.test.js +651 -0
- package/tests/server/integration/authentication_integration.test.js +294 -0
- package/tests/server/integration/auto_indexing_integration.test.js +268 -0
- package/tests/server/integration/backup_integration.test.js +513 -0
- package/tests/server/integration/indexing_integration.test.js +126 -0
- package/tests/server/integration/production_safety_integration.test.js +358 -0
- package/tests/server/integration/replication_integration.test.js +227 -0
- package/tests/server/integration/write_serialization_integration.test.js +246 -0
- package/tests/server/lib/api_key_manager.test.js +516 -0
- package/tests/server/lib/auth_manager.test.js +317 -0
- package/tests/server/lib/auto_index_manager.test.js +275 -0
- package/tests/server/lib/backup_manager.test.js +238 -0
- package/tests/server/lib/connection_manager.test.js +221 -0
- package/tests/server/lib/disk_utils.test.js +63 -0
- package/tests/server/lib/http_server.test.js +389 -0
- package/tests/server/lib/index_manager.test.js +301 -0
- package/tests/server/lib/load_settings.test.js +107 -0
- package/tests/server/lib/load_settings_port_config.test.js +243 -0
- package/tests/server/lib/logger.test.js +282 -0
- package/tests/server/lib/operations/admin.test.js +638 -0
- package/tests/server/lib/operations/bulk_write.test.js +128 -0
- package/tests/server/lib/operations/create_index.test.js +138 -0
- package/tests/server/lib/operations/delete_one.test.js +52 -0
- package/tests/server/lib/operations/drop_index.test.js +72 -0
- package/tests/server/lib/operations/find.test.js +93 -0
- package/tests/server/lib/operations/find_one.test.js +91 -0
- package/tests/server/lib/operations/get_indexes.test.js +87 -0
- package/tests/server/lib/operations/insert_one.test.js +42 -0
- package/tests/server/lib/operations/update_one.test.js +89 -0
- package/tests/server/lib/performance_monitor.test.js +185 -0
- package/tests/server/lib/query_engine.test.js +46 -0
- package/tests/server/lib/recovery_manager.test.js +414 -0
- package/tests/server/lib/replication_manager.test.js +202 -0
- package/tests/server/lib/safe_json_parse.test.js +45 -0
- package/tests/server/lib/send_response.test.js +155 -0
- package/tests/server/lib/tcp_protocol.test.js +169 -0
- package/tests/server/lib/write_forwarder.test.js +258 -0
- package/tests/server/lib/write_queue.test.js +255 -0
- package/tsconfig.json +30 -0
- package/types/client/index.d.ts +447 -0
- package/types/server/cluster/index.d.ts +28 -0
- package/types/server/cluster/master.d.ts +115 -0
- package/types/server/cluster/worker.d.ts +1 -0
- package/types/server/lib/auth_manager.d.ts +13 -0
- package/types/server/lib/backup_manager.d.ts +43 -0
- package/types/server/lib/connection_manager.d.ts +15 -0
- package/types/server/lib/disk_utils.d.ts +3 -0
- package/types/server/lib/index_manager.d.ts +24 -0
- package/types/server/lib/load_settings.d.ts +4 -0
- package/types/server/lib/logger.d.ts +44 -0
- package/types/server/lib/op_types.d.ts +6 -0
- package/types/server/lib/performance_monitor.d.ts +68 -0
- package/types/server/lib/query_engine.d.ts +10 -0
- package/types/server/lib/safe_json_parse.d.ts +7 -0
- package/types/server/lib/send_response.d.ts +3 -0
- package/types/server/lib/tcp_protocol.d.ts +12 -0
- package/types/server/lib/write_queue.d.ts +2 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import bcrypt from 'bcrypt';
|
|
3
|
+
import {
|
|
4
|
+
setup_authentication,
|
|
5
|
+
verify_password,
|
|
6
|
+
get_client_ip,
|
|
7
|
+
get_auth_stats,
|
|
8
|
+
initialize_auth_manager,
|
|
9
|
+
reset_auth_state
|
|
10
|
+
} from '../../../src/server/lib/auth_manager.js';
|
|
11
|
+
|
|
12
|
+
test.beforeEach(() => {
|
|
13
|
+
// Reset module state and clean up environment variables
|
|
14
|
+
reset_auth_state();
|
|
15
|
+
delete process.env.JOYSTICK_DB_SETTINGS;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test.afterEach(() => {
|
|
19
|
+
// Reset module state and clean up environment variables after each test
|
|
20
|
+
reset_auth_state();
|
|
21
|
+
delete process.env.JOYSTICK_DB_SETTINGS;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('setup_authentication creates authentication in environment variable with valid structure', (t) => {
|
|
25
|
+
const password = setup_authentication();
|
|
26
|
+
|
|
27
|
+
t.true(process.env.JOYSTICK_DB_SETTINGS !== undefined);
|
|
28
|
+
t.is(typeof password, 'string');
|
|
29
|
+
t.is(password.length, 32);
|
|
30
|
+
|
|
31
|
+
const settings_data = JSON.parse(process.env.JOYSTICK_DB_SETTINGS);
|
|
32
|
+
const auth_data = settings_data.authentication;
|
|
33
|
+
|
|
34
|
+
t.true(typeof auth_data.password_hash === 'string');
|
|
35
|
+
t.true(typeof auth_data.created_at === 'string');
|
|
36
|
+
t.true(typeof auth_data.last_updated === 'string');
|
|
37
|
+
t.true(typeof auth_data.failed_attempts === 'object');
|
|
38
|
+
t.true(typeof auth_data.rate_limits === 'object');
|
|
39
|
+
|
|
40
|
+
// Verify password hash is valid bcrypt hash
|
|
41
|
+
t.true(bcrypt.compareSync(password, auth_data.password_hash));
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('setup_authentication throws error when authentication already exists', (t) => {
|
|
45
|
+
setup_authentication();
|
|
46
|
+
|
|
47
|
+
const error = t.throws(() => {
|
|
48
|
+
setup_authentication();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
t.is(error.message, 'Authentication already configured. Update JOYSTICK_DB_SETTINGS environment variable to reconfigure.');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('setup_authentication generates unique passwords', (t) => {
|
|
55
|
+
const password1 = setup_authentication();
|
|
56
|
+
delete process.env.JOYSTICK_DB_SETTINGS;
|
|
57
|
+
reset_auth_state(); // Reset in-memory state after clearing environment variable
|
|
58
|
+
|
|
59
|
+
const password2 = setup_authentication();
|
|
60
|
+
|
|
61
|
+
t.not(password1, password2);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('verify_password returns true for correct password', async (t) => {
|
|
65
|
+
const password = setup_authentication();
|
|
66
|
+
const client_ip = '192.168.1.100';
|
|
67
|
+
|
|
68
|
+
const result = await verify_password(password, client_ip);
|
|
69
|
+
|
|
70
|
+
t.true(result);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('verify_password returns false for incorrect password', async (t) => {
|
|
74
|
+
setup_authentication();
|
|
75
|
+
const client_ip = '192.168.1.100';
|
|
76
|
+
|
|
77
|
+
const result = await verify_password('wrong_password', client_ip);
|
|
78
|
+
|
|
79
|
+
t.false(result);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('verify_password throws error when authentication not configured', async (t) => {
|
|
83
|
+
// Ensure no environment variable exists and use a fresh IP
|
|
84
|
+
delete process.env.JOYSTICK_DB_SETTINGS;
|
|
85
|
+
|
|
86
|
+
const client_ip = '192.168.1.200'; // Use completely fresh IP
|
|
87
|
+
|
|
88
|
+
const error = await t.throwsAsync(async () => {
|
|
89
|
+
await verify_password('any_password', client_ip);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
t.is(error.message, 'Authentication not configured. Run setup first.');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('verify_password implements timing attack protection', async (t) => {
|
|
96
|
+
const password = setup_authentication();
|
|
97
|
+
const client_ip = '192.168.1.100';
|
|
98
|
+
|
|
99
|
+
const start_time = Date.now();
|
|
100
|
+
await verify_password('wrong_password', client_ip);
|
|
101
|
+
const wrong_duration = Date.now() - start_time;
|
|
102
|
+
|
|
103
|
+
const start_time2 = Date.now();
|
|
104
|
+
await verify_password(password, client_ip);
|
|
105
|
+
const correct_duration = Date.now() - start_time2;
|
|
106
|
+
|
|
107
|
+
// Both should take at least 100ms due to timing protection
|
|
108
|
+
t.true(wrong_duration >= 100);
|
|
109
|
+
t.true(correct_duration >= 100);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('verify_password records failed attempts for non-whitelisted IPs', async (t) => {
|
|
113
|
+
setup_authentication();
|
|
114
|
+
const client_ip = '192.168.1.100';
|
|
115
|
+
|
|
116
|
+
await verify_password('wrong_password', client_ip);
|
|
117
|
+
|
|
118
|
+
const settings_data = JSON.parse(process.env.JOYSTICK_DB_SETTINGS);
|
|
119
|
+
const auth_data = settings_data.authentication;
|
|
120
|
+
t.true(Array.isArray(auth_data.failed_attempts[client_ip]));
|
|
121
|
+
t.is(auth_data.failed_attempts[client_ip].length, 1);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('verify_password records failed attempts for all IPs in test environment', async (t) => {
|
|
125
|
+
setup_authentication();
|
|
126
|
+
const test_ip = '127.0.0.1';
|
|
127
|
+
|
|
128
|
+
await verify_password('wrong_password', test_ip);
|
|
129
|
+
|
|
130
|
+
const settings_data = JSON.parse(process.env.JOYSTICK_DB_SETTINGS);
|
|
131
|
+
const auth_data = settings_data.authentication;
|
|
132
|
+
// In test environment, IP whitelisting is disabled, so failed attempts are recorded for all IPs
|
|
133
|
+
t.true(Array.isArray(auth_data.failed_attempts[test_ip]));
|
|
134
|
+
t.is(auth_data.failed_attempts[test_ip].length, 1);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('verify_password clears failed attempts on successful authentication', async (t) => {
|
|
138
|
+
const password = setup_authentication();
|
|
139
|
+
const client_ip = '192.168.1.101'; // Use different IP to avoid cross-test contamination
|
|
140
|
+
|
|
141
|
+
// Record a failed attempt
|
|
142
|
+
await verify_password('wrong_password', client_ip);
|
|
143
|
+
|
|
144
|
+
let settings_data = JSON.parse(process.env.JOYSTICK_DB_SETTINGS);
|
|
145
|
+
let auth_data = settings_data.authentication;
|
|
146
|
+
t.is(auth_data.failed_attempts[client_ip].length, 1);
|
|
147
|
+
|
|
148
|
+
// Successful authentication should clear failed attempts
|
|
149
|
+
await verify_password(password, client_ip);
|
|
150
|
+
|
|
151
|
+
settings_data = JSON.parse(process.env.JOYSTICK_DB_SETTINGS);
|
|
152
|
+
auth_data = settings_data.authentication;
|
|
153
|
+
t.is(auth_data.failed_attempts[client_ip], undefined);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('rate limiting blocks after maximum failed attempts', async (t) => {
|
|
157
|
+
setup_authentication();
|
|
158
|
+
const client_ip = '192.168.1.102'; // Use different IP to avoid cross-test contamination
|
|
159
|
+
|
|
160
|
+
// Make 5 failed attempts
|
|
161
|
+
for (let i = 0; i < 5; i++) {
|
|
162
|
+
await verify_password('wrong_password', client_ip);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 6th attempt should be rate limited
|
|
166
|
+
const error = await t.throwsAsync(async () => {
|
|
167
|
+
await verify_password('wrong_password', client_ip);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
t.is(error.message, 'Too many failed attempts. Please try again later.');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('rate limiting affects all IPs in test environment', async (t) => {
|
|
174
|
+
setup_authentication();
|
|
175
|
+
const test_ip = '192.168.1.200'; // Use different IP to avoid cross-test contamination
|
|
176
|
+
|
|
177
|
+
// Make 5 failed attempts to trigger rate limiting
|
|
178
|
+
for (let i = 0; i < 5; i++) {
|
|
179
|
+
const result = await verify_password('wrong_password', test_ip);
|
|
180
|
+
t.false(result);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 6th attempt should be rate limited (even for localhost in test environment)
|
|
184
|
+
const error = await t.throwsAsync(async () => {
|
|
185
|
+
await verify_password('wrong_password', test_ip);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
t.is(error.message, 'Too many failed attempts. Please try again later.');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test('get_client_ip extracts IP from socket', (t) => {
|
|
192
|
+
const mock_socket = {
|
|
193
|
+
remoteAddress: '192.168.1.100'
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const ip = get_client_ip(mock_socket);
|
|
197
|
+
|
|
198
|
+
t.is(ip, '192.168.1.100');
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test('get_client_ip returns localhost for socket without remoteAddress', (t) => {
|
|
202
|
+
const mock_socket = {};
|
|
203
|
+
|
|
204
|
+
const ip = get_client_ip(mock_socket);
|
|
205
|
+
|
|
206
|
+
t.is(ip, '127.0.0.1');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test('get_auth_stats returns correct structure when configured', (t) => {
|
|
210
|
+
setup_authentication();
|
|
211
|
+
|
|
212
|
+
const stats = get_auth_stats();
|
|
213
|
+
|
|
214
|
+
t.true(stats.configured);
|
|
215
|
+
t.is(typeof stats.failed_attempts_count, 'number');
|
|
216
|
+
t.is(typeof stats.rate_limited_ips, 'number');
|
|
217
|
+
t.is(typeof stats.created_at, 'string');
|
|
218
|
+
t.is(typeof stats.last_updated, 'string');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test('initialize_auth_manager loads existing authentication data', (t) => {
|
|
222
|
+
// Create auth file first
|
|
223
|
+
setup_authentication();
|
|
224
|
+
|
|
225
|
+
// Initialize should load the data without error
|
|
226
|
+
t.notThrows(() => {
|
|
227
|
+
initialize_auth_manager();
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test('initialize_auth_manager handles missing authentication file gracefully', (t) => {
|
|
232
|
+
// Should not throw when no auth file exists
|
|
233
|
+
t.notThrows(() => {
|
|
234
|
+
initialize_auth_manager();
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test('authentication data is stored in environment variable', (t) => {
|
|
239
|
+
setup_authentication();
|
|
240
|
+
|
|
241
|
+
// Verify environment variable exists and contains valid JSON
|
|
242
|
+
t.true(process.env.JOYSTICK_DB_SETTINGS !== undefined);
|
|
243
|
+
|
|
244
|
+
const settings_data = JSON.parse(process.env.JOYSTICK_DB_SETTINGS);
|
|
245
|
+
t.true(typeof settings_data.authentication === 'object');
|
|
246
|
+
t.true(typeof settings_data.authentication.password_hash === 'string');
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test('password generation creates 32-character hex string', (t) => {
|
|
250
|
+
const password = setup_authentication();
|
|
251
|
+
|
|
252
|
+
// Should be 32 characters long
|
|
253
|
+
t.is(password.length, 32);
|
|
254
|
+
|
|
255
|
+
// Should be valid hex string
|
|
256
|
+
t.true(/^[0-9a-f]{32}$/.test(password));
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test('bcrypt hashing works correctly', (t) => {
|
|
260
|
+
const password = setup_authentication();
|
|
261
|
+
const settings_data = JSON.parse(process.env.JOYSTICK_DB_SETTINGS);
|
|
262
|
+
const auth_data = settings_data.authentication;
|
|
263
|
+
|
|
264
|
+
// Should be able to verify the password with the stored hash
|
|
265
|
+
t.true(bcrypt.compareSync(password, auth_data.password_hash));
|
|
266
|
+
|
|
267
|
+
// Should not verify with wrong password
|
|
268
|
+
t.false(bcrypt.compareSync('wrong_password', auth_data.password_hash));
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test('authentication environment variable corruption is handled gracefully', (t) => {
|
|
272
|
+
// Create corrupted environment variable
|
|
273
|
+
process.env.JOYSTICK_DB_SETTINGS = 'invalid json content';
|
|
274
|
+
|
|
275
|
+
// initialize_auth_manager doesn't throw, it logs warnings and continues
|
|
276
|
+
// So we test that it doesn't throw and the environment variable remains corrupted
|
|
277
|
+
t.notThrows(() => {
|
|
278
|
+
initialize_auth_manager();
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// The corrupted environment variable should still exist
|
|
282
|
+
t.true(process.env.JOYSTICK_DB_SETTINGS !== undefined);
|
|
283
|
+
|
|
284
|
+
// And should still be corrupted
|
|
285
|
+
t.is(process.env.JOYSTICK_DB_SETTINGS, 'invalid json content');
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test('rate limiting implements exponential backoff', async (t) => {
|
|
289
|
+
setup_authentication();
|
|
290
|
+
const client_ip = '192.168.1.103'; // Use different IP to avoid cross-test contamination
|
|
291
|
+
|
|
292
|
+
// Make 5 failed attempts to trigger rate limiting
|
|
293
|
+
for (let i = 0; i < 5; i++) {
|
|
294
|
+
await verify_password('wrong_password', client_ip);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Make the 6th attempt that should trigger rate limiting
|
|
298
|
+
try {
|
|
299
|
+
await verify_password('wrong_password', client_ip);
|
|
300
|
+
t.fail('Should have thrown rate limiting error');
|
|
301
|
+
} catch (error) {
|
|
302
|
+
t.is(error.message, 'Too many failed attempts. Please try again later.');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Now check that rate limit info is stored
|
|
306
|
+
const settings_data = JSON.parse(process.env.JOYSTICK_DB_SETTINGS);
|
|
307
|
+
const auth_data = settings_data.authentication;
|
|
308
|
+
t.true(typeof auth_data.rate_limits[client_ip] === 'object');
|
|
309
|
+
t.true(typeof auth_data.rate_limits[client_ip].expires_at === 'number');
|
|
310
|
+
t.true(typeof auth_data.rate_limits[client_ip].attempts === 'number');
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test('whitelisted IPs behavior is tested through other tests', (t) => {
|
|
314
|
+
// This test verifies that whitelisted IP behavior is covered
|
|
315
|
+
// by the other tests (like rate limiting not affecting whitelisted IPs)
|
|
316
|
+
t.pass();
|
|
317
|
+
});
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import {
|
|
3
|
+
initialize_auto_index_database,
|
|
4
|
+
cleanup_auto_index_database,
|
|
5
|
+
record_query,
|
|
6
|
+
record_index_usage,
|
|
7
|
+
get_query_statistics,
|
|
8
|
+
get_auto_index_statistics,
|
|
9
|
+
force_index_evaluation,
|
|
10
|
+
remove_automatic_indexes,
|
|
11
|
+
is_auto_created_index
|
|
12
|
+
} from '../../../src/server/lib/auto_index_manager.js';
|
|
13
|
+
import { initialize_database, cleanup_database } from '../../../src/server/lib/query_engine.js';
|
|
14
|
+
import { initialize_index_database, create_index, get_indexes, cleanup_index_database } from '../../../src/server/lib/index_manager.js';
|
|
15
|
+
|
|
16
|
+
test.beforeEach(async (t) => {
|
|
17
|
+
initialize_database('./test_data');
|
|
18
|
+
initialize_index_database();
|
|
19
|
+
initialize_auto_index_database();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test.afterEach(async (t) => {
|
|
23
|
+
cleanup_auto_index_database();
|
|
24
|
+
cleanup_index_database();
|
|
25
|
+
await cleanup_database();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('should initialize auto index database', (t) => {
|
|
29
|
+
t.notThrows(() => {
|
|
30
|
+
initialize_auto_index_database();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should record query statistics', (t) => {
|
|
35
|
+
const collection = 'test_collection';
|
|
36
|
+
const filter = { name: 'John', age: 25 };
|
|
37
|
+
const execution_time = 50;
|
|
38
|
+
|
|
39
|
+
t.notThrows(() => {
|
|
40
|
+
record_query(collection, filter, execution_time, false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const stats = get_query_statistics(collection);
|
|
44
|
+
t.truthy(stats.name);
|
|
45
|
+
t.truthy(stats.age);
|
|
46
|
+
t.is(stats.name.query_count, 1);
|
|
47
|
+
t.is(stats.age.query_count, 1);
|
|
48
|
+
t.is(stats.name.total_time_ms, execution_time);
|
|
49
|
+
t.is(stats.age.total_time_ms, execution_time);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('should record multiple queries and aggregate statistics', (t) => {
|
|
53
|
+
const collection = 'test_collection';
|
|
54
|
+
const filter = { name: 'John' };
|
|
55
|
+
|
|
56
|
+
record_query(collection, filter, 30, false);
|
|
57
|
+
record_query(collection, filter, 50, false);
|
|
58
|
+
record_query(collection, filter, 70, false);
|
|
59
|
+
|
|
60
|
+
const stats = get_query_statistics(collection);
|
|
61
|
+
t.is(stats.name.query_count, 3);
|
|
62
|
+
t.is(stats.name.total_time_ms, 150);
|
|
63
|
+
t.is(stats.name.avg_time_ms, 50);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('should track slow queries', (t) => {
|
|
67
|
+
const collection = 'test_collection';
|
|
68
|
+
const filter = { name: 'John' };
|
|
69
|
+
|
|
70
|
+
record_query(collection, filter, 100, false);
|
|
71
|
+
record_query(collection, filter, 20, false);
|
|
72
|
+
record_query(collection, filter, 80, false);
|
|
73
|
+
|
|
74
|
+
const stats = get_query_statistics(collection);
|
|
75
|
+
t.is(stats.name.slow_query_count, 2);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('should record index usage', (t) => {
|
|
79
|
+
const collection = 'test_collection';
|
|
80
|
+
const field = 'name';
|
|
81
|
+
|
|
82
|
+
record_query(collection, { [field]: 'John' }, 30, true);
|
|
83
|
+
record_index_usage(collection, field);
|
|
84
|
+
|
|
85
|
+
const stats = get_query_statistics(collection);
|
|
86
|
+
t.is(stats[field].used_index_count, 1);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('should get query statistics for all collections', (t) => {
|
|
90
|
+
record_query('collection1', { name: 'John' }, 30, false);
|
|
91
|
+
record_query('collection2', { age: 25 }, 40, false);
|
|
92
|
+
|
|
93
|
+
const all_stats = get_query_statistics();
|
|
94
|
+
t.truthy(all_stats.collection1);
|
|
95
|
+
t.truthy(all_stats.collection2);
|
|
96
|
+
t.truthy(all_stats.collection1.name);
|
|
97
|
+
t.truthy(all_stats.collection2.age);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('should get empty statistics for non-existent collection', (t) => {
|
|
101
|
+
const stats = get_query_statistics('non_existent');
|
|
102
|
+
t.deepEqual(stats, {});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('should get auto index statistics', (t) => {
|
|
106
|
+
const stats = get_auto_index_statistics();
|
|
107
|
+
t.is(typeof stats, 'object');
|
|
108
|
+
t.is(stats.total_auto_indexes, 0);
|
|
109
|
+
t.is(typeof stats.collections, 'object');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('should force index evaluation', async (t) => {
|
|
113
|
+
const collection = 'test_collection';
|
|
114
|
+
const field = 'name';
|
|
115
|
+
|
|
116
|
+
for (let i = 0; i < 150; i++) {
|
|
117
|
+
record_query(collection, { [field]: `user${i}` }, 60, false);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const result = await force_index_evaluation(collection);
|
|
121
|
+
t.is(result.acknowledged, true);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('should force index evaluation for all collections', async (t) => {
|
|
125
|
+
record_query('collection1', { name: 'John' }, 60, false);
|
|
126
|
+
record_query('collection2', { age: 25 }, 70, false);
|
|
127
|
+
|
|
128
|
+
const result = await force_index_evaluation();
|
|
129
|
+
t.is(result.acknowledged, true);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('should remove automatic indexes', async (t) => {
|
|
133
|
+
const collection = 'test_collection';
|
|
134
|
+
const field = 'name';
|
|
135
|
+
|
|
136
|
+
await create_index('default', collection, field);
|
|
137
|
+
|
|
138
|
+
const result = await remove_automatic_indexes(collection, [field]);
|
|
139
|
+
t.is(result.acknowledged, true);
|
|
140
|
+
t.is(result.removed_count, 0);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test('should remove all automatic indexes from collection', async (t) => {
|
|
144
|
+
const collection = 'test_collection';
|
|
145
|
+
|
|
146
|
+
const result = await remove_automatic_indexes(collection);
|
|
147
|
+
t.is(result.acknowledged, true);
|
|
148
|
+
t.is(typeof result.removed_count, 'number');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('should identify auto-created indexes', (t) => {
|
|
152
|
+
const collection = 'test_collection';
|
|
153
|
+
const field = 'name';
|
|
154
|
+
|
|
155
|
+
const is_auto = is_auto_created_index(collection, field);
|
|
156
|
+
t.is(typeof is_auto, 'boolean');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('should handle excluded fields', (t) => {
|
|
160
|
+
const collection = 'test_collection';
|
|
161
|
+
const filter = { _id: '123', created_at: new Date(), name: 'John' };
|
|
162
|
+
|
|
163
|
+
record_query(collection, filter, 30, false);
|
|
164
|
+
|
|
165
|
+
const stats = get_query_statistics(collection);
|
|
166
|
+
t.falsy(stats._id);
|
|
167
|
+
t.falsy(stats.created_at);
|
|
168
|
+
t.truthy(stats.name);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test('should handle complex filter objects', (t) => {
|
|
172
|
+
const collection = 'test_collection';
|
|
173
|
+
const filter = {
|
|
174
|
+
name: { $regex: 'John' },
|
|
175
|
+
age: { $gt: 18, $lt: 65 },
|
|
176
|
+
status: { $in: ['active', 'pending'] }
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
record_query(collection, filter, 45, false);
|
|
180
|
+
|
|
181
|
+
const stats = get_query_statistics(collection);
|
|
182
|
+
t.truthy(stats.name);
|
|
183
|
+
t.truthy(stats.age);
|
|
184
|
+
t.truthy(stats.status);
|
|
185
|
+
t.is(stats.name.query_count, 1);
|
|
186
|
+
t.is(stats.age.query_count, 1);
|
|
187
|
+
t.is(stats.status.query_count, 1);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test('should handle null and undefined filters', (t) => {
|
|
191
|
+
const collection = 'test_collection';
|
|
192
|
+
|
|
193
|
+
t.notThrows(() => {
|
|
194
|
+
record_query(collection, null, 30, false);
|
|
195
|
+
record_query(collection, undefined, 30, false);
|
|
196
|
+
record_query(collection, {}, 30, false);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const stats = get_query_statistics(collection);
|
|
200
|
+
t.deepEqual(stats, {});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test('should handle invalid collection names', (t) => {
|
|
204
|
+
t.notThrows(() => {
|
|
205
|
+
record_query('', { name: 'John' }, 30, false);
|
|
206
|
+
record_query(null, { name: 'John' }, 30, false);
|
|
207
|
+
record_query(undefined, { name: 'John' }, 30, false);
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('should handle negative execution times', (t) => {
|
|
212
|
+
const collection = 'test_collection';
|
|
213
|
+
const filter = { name: 'John' };
|
|
214
|
+
|
|
215
|
+
t.notThrows(() => {
|
|
216
|
+
record_query(collection, filter, -10, false);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const stats = get_query_statistics(collection);
|
|
220
|
+
t.is(stats.name.total_time_ms, -10);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('should handle very large execution times', (t) => {
|
|
224
|
+
const collection = 'test_collection';
|
|
225
|
+
const filter = { name: 'John' };
|
|
226
|
+
|
|
227
|
+
t.notThrows(() => {
|
|
228
|
+
record_query(collection, filter, 999999, false);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const stats = get_query_statistics(collection);
|
|
232
|
+
t.is(stats.name.total_time_ms, 999999);
|
|
233
|
+
t.is(stats.name.slow_query_count, 1);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test('should update last_queried timestamp', (t) => {
|
|
237
|
+
const collection = 'test_collection';
|
|
238
|
+
const filter = { name: 'John' };
|
|
239
|
+
const before = new Date();
|
|
240
|
+
|
|
241
|
+
record_query(collection, filter, 30, false);
|
|
242
|
+
|
|
243
|
+
const stats = get_query_statistics(collection);
|
|
244
|
+
const after = new Date();
|
|
245
|
+
|
|
246
|
+
t.true(stats.name.last_queried >= before);
|
|
247
|
+
t.true(stats.name.last_queried <= after);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
test('should handle concurrent query recording', (t) => {
|
|
251
|
+
const collection = 'test_collection';
|
|
252
|
+
const filter = { name: 'John' };
|
|
253
|
+
|
|
254
|
+
for (let i = 0; i < 100; i++) {
|
|
255
|
+
record_query(collection, filter, 30 + i, false);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const stats = get_query_statistics(collection);
|
|
259
|
+
t.is(stats.name.query_count, 100);
|
|
260
|
+
t.is(stats.name.total_time_ms, 100 * 30 + (99 * 100) / 2);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test('should cleanup auto index database', (t) => {
|
|
264
|
+
const collection = 'test_collection';
|
|
265
|
+
const filter = { name: 'John' };
|
|
266
|
+
|
|
267
|
+
record_query(collection, filter, 30, false);
|
|
268
|
+
|
|
269
|
+
t.notThrows(() => {
|
|
270
|
+
cleanup_auto_index_database();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const stats = get_query_statistics(collection);
|
|
274
|
+
t.deepEqual(stats, {});
|
|
275
|
+
});
|