@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,294 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
import net from 'net';
|
|
4
|
+
import { create_server } from '../../../src/server/index.js';
|
|
5
|
+
import { encode_message, create_message_parser } from '../../../src/server/lib/tcp_protocol.js';
|
|
6
|
+
import { initialize_database, cleanup_database } from '../../../src/server/lib/query_engine.js';
|
|
7
|
+
import { setup_authentication, reset_auth_state } from '../../../src/server/lib/auth_manager.js';
|
|
8
|
+
|
|
9
|
+
// Dynamic port allocation
|
|
10
|
+
let current_port = 3000;
|
|
11
|
+
const get_next_port = () => {
|
|
12
|
+
return ++current_port;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
let server;
|
|
16
|
+
let port;
|
|
17
|
+
|
|
18
|
+
test.beforeEach(async () => {
|
|
19
|
+
// Reset auth state and clean up environment variables
|
|
20
|
+
reset_auth_state();
|
|
21
|
+
delete process.env.JOYSTICK_DB_SETTINGS;
|
|
22
|
+
|
|
23
|
+
// Initialize database for testing
|
|
24
|
+
initialize_database();
|
|
25
|
+
|
|
26
|
+
// Create server with dynamic port
|
|
27
|
+
const test_port = get_next_port();
|
|
28
|
+
server = await create_server();
|
|
29
|
+
|
|
30
|
+
// Start server on specific port
|
|
31
|
+
await new Promise((resolve) => {
|
|
32
|
+
server.listen(test_port, () => {
|
|
33
|
+
port = test_port;
|
|
34
|
+
setTimeout(resolve, 100);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test.afterEach(async () => {
|
|
40
|
+
if (server) {
|
|
41
|
+
await server.cleanup();
|
|
42
|
+
server.close();
|
|
43
|
+
server = null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Clean up database
|
|
47
|
+
try {
|
|
48
|
+
await cleanup_database(true); // Remove test database directory
|
|
49
|
+
} catch (error) {
|
|
50
|
+
// Ignore cleanup errors
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Clean up environment variables
|
|
54
|
+
reset_auth_state();
|
|
55
|
+
delete process.env.JOYSTICK_DB_SETTINGS;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const create_client = () => {
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
const client = net.createConnection(port, 'localhost');
|
|
61
|
+
const parser = create_message_parser();
|
|
62
|
+
|
|
63
|
+
client.on('connect', () => {
|
|
64
|
+
resolve({
|
|
65
|
+
client,
|
|
66
|
+
send: (data) => {
|
|
67
|
+
const encoded = encode_message(data);
|
|
68
|
+
client.write(encoded);
|
|
69
|
+
},
|
|
70
|
+
receive: () => {
|
|
71
|
+
return new Promise((resolve) => {
|
|
72
|
+
const handler = (data) => {
|
|
73
|
+
try {
|
|
74
|
+
const messages = parser.parse_messages(data);
|
|
75
|
+
for (const message of messages) {
|
|
76
|
+
client.off('data', handler);
|
|
77
|
+
resolve(message);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
// Continue listening
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
client.on('data', handler);
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
close: () => {
|
|
88
|
+
client.end();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
client.on('error', reject);
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
test('integration - setup command creates authentication and returns password', async (t) => {
|
|
98
|
+
const { client, send, receive, close } = await create_client();
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
send({ op: 'setup' });
|
|
102
|
+
const response = await receive();
|
|
103
|
+
|
|
104
|
+
t.true(response.ok === 1 || response.ok === true);
|
|
105
|
+
t.is(typeof response.password, 'string');
|
|
106
|
+
t.is(response.password.length, 32);
|
|
107
|
+
t.true(response.message.includes('Authentication setup completed'));
|
|
108
|
+
|
|
109
|
+
// Verify environment variable was created
|
|
110
|
+
t.true(process.env.JOYSTICK_DB_SETTINGS !== undefined);
|
|
111
|
+
|
|
112
|
+
const settings_data = JSON.parse(process.env.JOYSTICK_DB_SETTINGS);
|
|
113
|
+
t.true(typeof settings_data.authentication.password_hash === 'string');
|
|
114
|
+
t.true(typeof settings_data.authentication.created_at === 'string');
|
|
115
|
+
} finally {
|
|
116
|
+
close();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('integration - authentication succeeds with correct password', async (t) => {
|
|
121
|
+
// Setup authentication first
|
|
122
|
+
const password = setup_authentication();
|
|
123
|
+
|
|
124
|
+
const { client, send, receive, close } = await create_client();
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
send({ op: 'authentication', data: { password } });
|
|
128
|
+
const response = await receive();
|
|
129
|
+
|
|
130
|
+
t.is(response.ok, 1);
|
|
131
|
+
t.is(response.version, '1.0.0');
|
|
132
|
+
t.is(response.message, 'Authentication successful');
|
|
133
|
+
} finally {
|
|
134
|
+
close();
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('integration - authentication fails with incorrect password', async (t) => {
|
|
139
|
+
// Setup authentication first
|
|
140
|
+
setup_authentication();
|
|
141
|
+
|
|
142
|
+
const { client, send, receive, close } = await create_client();
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
send({ op: 'authentication', data: { password: 'wrong_password' } });
|
|
146
|
+
const response = await receive();
|
|
147
|
+
|
|
148
|
+
t.true(response.ok === 0 || response.ok === false);
|
|
149
|
+
t.is(response.error, 'Authentication failed');
|
|
150
|
+
} finally {
|
|
151
|
+
close();
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('integration - database operations require authentication', async (t) => {
|
|
156
|
+
// Setup authentication first
|
|
157
|
+
setup_authentication();
|
|
158
|
+
|
|
159
|
+
const { client, send, receive, close } = await create_client();
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
// Try to perform find operation without authentication
|
|
163
|
+
send({ op: 'find', data: { collection: 'users', filter: {} } });
|
|
164
|
+
const response = await receive();
|
|
165
|
+
|
|
166
|
+
t.true(response.ok === 0 || response.ok === false);
|
|
167
|
+
t.is(response.error, 'Authentication required');
|
|
168
|
+
} finally {
|
|
169
|
+
close();
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('integration - database operations work after authentication', async (t) => {
|
|
174
|
+
// Setup authentication first
|
|
175
|
+
const password = setup_authentication();
|
|
176
|
+
|
|
177
|
+
const { client, send, receive, close } = await create_client();
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
// First authenticate
|
|
181
|
+
send({ op: 'authentication', data: { password } });
|
|
182
|
+
const auth_response = await receive();
|
|
183
|
+
t.is(auth_response.ok, 1);
|
|
184
|
+
t.is(auth_response.version, '1.0.0');
|
|
185
|
+
|
|
186
|
+
// Now try a database operation
|
|
187
|
+
send({ op: 'ping' });
|
|
188
|
+
const ping_response = await receive();
|
|
189
|
+
t.is(ping_response.ok, 1);
|
|
190
|
+
} finally {
|
|
191
|
+
close();
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test('integration - admin operation includes authentication stats', async (t) => {
|
|
196
|
+
// Setup authentication first
|
|
197
|
+
const password = setup_authentication();
|
|
198
|
+
|
|
199
|
+
const { client, send, receive, close } = await create_client();
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
// First authenticate
|
|
203
|
+
send({ op: 'authentication', data: { password } });
|
|
204
|
+
const auth_response = await receive();
|
|
205
|
+
t.is(auth_response.ok, 1);
|
|
206
|
+
t.is(auth_response.version, '1.0.0');
|
|
207
|
+
|
|
208
|
+
// Now try admin operation
|
|
209
|
+
send({ op: 'admin' });
|
|
210
|
+
const admin_response = await receive();
|
|
211
|
+
|
|
212
|
+
// This should be the admin response
|
|
213
|
+
t.true(typeof admin_response.authentication === 'object');
|
|
214
|
+
t.is(admin_response.authentication.authenticated_clients, 1);
|
|
215
|
+
t.true(admin_response.authentication.configured);
|
|
216
|
+
t.is(typeof admin_response.authentication.created_at, 'string');
|
|
217
|
+
t.true(typeof admin_response.server === 'object');
|
|
218
|
+
t.true(typeof admin_response.database === 'object');
|
|
219
|
+
} finally {
|
|
220
|
+
close();
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test('integration - rate limiting blocks multiple failed attempts', async (t) => {
|
|
225
|
+
// Setup authentication first
|
|
226
|
+
setup_authentication();
|
|
227
|
+
|
|
228
|
+
// Make 5 failed attempts
|
|
229
|
+
for (let i = 0; i < 5; i++) {
|
|
230
|
+
const { client, send, receive, close } = await create_client();
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
send({ op: 'authentication', data: { password: 'wrong_password' } });
|
|
234
|
+
const response = await receive();
|
|
235
|
+
|
|
236
|
+
t.true(response.ok === 0 || response.ok === false);
|
|
237
|
+
t.is(response.error, 'Authentication failed');
|
|
238
|
+
} finally {
|
|
239
|
+
close();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Small delay between attempts
|
|
243
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// 6th attempt should be rate limited
|
|
247
|
+
const { client, send, receive, close } = await create_client();
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
send({ op: 'authentication', data: { password: 'wrong_password' } });
|
|
251
|
+
const response = await receive();
|
|
252
|
+
|
|
253
|
+
t.true(response.ok === 0 || response.ok === false);
|
|
254
|
+
t.true(response.error.includes('Too many failed attempts'));
|
|
255
|
+
} finally {
|
|
256
|
+
close();
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test('integration - setup fails when authentication already configured', async (t) => {
|
|
261
|
+
// Setup authentication first
|
|
262
|
+
setup_authentication();
|
|
263
|
+
|
|
264
|
+
const { client, send, receive, close } = await create_client();
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
// Try to setup again
|
|
268
|
+
send({ op: 'setup' });
|
|
269
|
+
const response = await receive();
|
|
270
|
+
|
|
271
|
+
t.true(response.ok === 0 || response.ok === false);
|
|
272
|
+
t.true(response.error.includes('Authentication already configured'));
|
|
273
|
+
} finally {
|
|
274
|
+
close();
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
test('integration - protocol versioning returns correct version', async (t) => {
|
|
279
|
+
// Setup authentication first
|
|
280
|
+
const password = setup_authentication();
|
|
281
|
+
|
|
282
|
+
const { client, send, receive, close } = await create_client();
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
send({ op: 'authentication', data: { password } });
|
|
286
|
+
const response = await receive();
|
|
287
|
+
|
|
288
|
+
t.is(response.ok, 1);
|
|
289
|
+
t.is(response.version, '1.0.0');
|
|
290
|
+
t.is(response.message, 'Authentication successful');
|
|
291
|
+
} finally {
|
|
292
|
+
close();
|
|
293
|
+
}
|
|
294
|
+
});
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { initialize_database, cleanup_database } from '../../../src/server/lib/query_engine.js';
|
|
3
|
+
import { initialize_index_database, get_indexes, cleanup_index_database } from '../../../src/server/lib/index_manager.js';
|
|
4
|
+
import { initialize_auto_index_database, cleanup_auto_index_database } from '../../../src/server/lib/auto_index_manager.js';
|
|
5
|
+
import find from '../../../src/server/lib/operations/find.js';
|
|
6
|
+
import find_one from '../../../src/server/lib/operations/find_one.js';
|
|
7
|
+
import insert_one from '../../../src/server/lib/operations/insert_one.js';
|
|
8
|
+
import admin from '../../../src/server/lib/operations/admin.js';
|
|
9
|
+
|
|
10
|
+
test.beforeEach(async (t) => {
|
|
11
|
+
initialize_database('./test_data');
|
|
12
|
+
initialize_index_database();
|
|
13
|
+
initialize_auto_index_database();
|
|
14
|
+
|
|
15
|
+
const test_documents = [
|
|
16
|
+
{ name: 'Alice', age: 25, department: 'Engineering', salary: 75000 },
|
|
17
|
+
{ name: 'Bob', age: 30, department: 'Marketing', salary: 65000 },
|
|
18
|
+
{ name: 'Charlie', age: 35, department: 'Engineering', salary: 85000 },
|
|
19
|
+
{ name: 'Diana', age: 28, department: 'Sales', salary: 70000 },
|
|
20
|
+
{ name: 'Eve', age: 32, department: 'Engineering', salary: 80000 }
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
for (const doc of test_documents) {
|
|
24
|
+
await insert_one('default', 'employees', doc);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test.afterEach(async (t) => {
|
|
29
|
+
cleanup_auto_index_database();
|
|
30
|
+
cleanup_index_database();
|
|
31
|
+
await cleanup_database();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should record query statistics during find operations', async (t) => {
|
|
35
|
+
await find('default', 'employees', { name: 'Alice' });
|
|
36
|
+
await find('default', 'employees', { age: 25 });
|
|
37
|
+
await find('default', 'employees', { department: 'Engineering' });
|
|
38
|
+
|
|
39
|
+
const stats = await admin('get_query_stats', { collection: 'employees' });
|
|
40
|
+
|
|
41
|
+
t.truthy(stats.name);
|
|
42
|
+
t.truthy(stats.age);
|
|
43
|
+
t.truthy(stats.department);
|
|
44
|
+
t.is(stats.name.query_count, 1);
|
|
45
|
+
t.is(stats.age.query_count, 1);
|
|
46
|
+
t.is(stats.department.query_count, 1);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('should record query statistics during find_one operations', async (t) => {
|
|
50
|
+
await find_one('default', 'employees', { name: 'Bob' });
|
|
51
|
+
await find_one('default', 'employees', { age: 30 });
|
|
52
|
+
|
|
53
|
+
const stats = await admin('get_query_stats', { collection: 'employees' });
|
|
54
|
+
|
|
55
|
+
t.truthy(stats.name);
|
|
56
|
+
t.truthy(stats.age);
|
|
57
|
+
t.is(stats.name.query_count, 1);
|
|
58
|
+
t.is(stats.age.query_count, 1);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('should track execution times for queries', async (t) => {
|
|
62
|
+
await find('default', 'employees', { name: 'Alice' });
|
|
63
|
+
await find('default', 'employees', { name: 'Bob' });
|
|
64
|
+
await find('default', 'employees', { name: 'Charlie' });
|
|
65
|
+
|
|
66
|
+
const stats = await admin('get_query_stats', { collection: 'employees' });
|
|
67
|
+
|
|
68
|
+
t.is(stats.name.query_count, 3);
|
|
69
|
+
t.true(stats.name.total_time_ms >= 0);
|
|
70
|
+
t.true(stats.name.avg_time_ms >= 0);
|
|
71
|
+
t.is(stats.name.avg_time_ms, stats.name.total_time_ms / 3);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('should get auto index statistics', async (t) => {
|
|
75
|
+
const stats = await admin('get_auto_index_stats');
|
|
76
|
+
|
|
77
|
+
t.is(typeof stats, 'object');
|
|
78
|
+
t.is(stats.total_auto_indexes, 0);
|
|
79
|
+
t.is(typeof stats.collections, 'object');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('should force index evaluation', async (t) => {
|
|
83
|
+
for (let i = 0; i < 50; i++) {
|
|
84
|
+
await find('default', 'employees', { name: `User${i}` });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const result = await admin('evaluate_auto_indexes', { collection: 'employees' });
|
|
88
|
+
t.is(result.acknowledged, true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('should force index evaluation for all collections', async (t) => {
|
|
92
|
+
await find('default', 'employees', { name: 'Alice' });
|
|
93
|
+
await find('default', 'products', { category: 'Electronics' });
|
|
94
|
+
|
|
95
|
+
const result = await admin('evaluate_auto_indexes');
|
|
96
|
+
t.is(result.acknowledged, true);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('should remove automatic indexes', async (t) => {
|
|
100
|
+
const result = await admin('remove_auto_indexes', {
|
|
101
|
+
collection: 'employees',
|
|
102
|
+
field_names: ['name']
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
t.is(result.acknowledged, true);
|
|
106
|
+
t.is(typeof result.removed_count, 'number');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('should remove all automatic indexes from collection', async (t) => {
|
|
110
|
+
const result = await admin('remove_auto_indexes', { collection: 'employees' });
|
|
111
|
+
|
|
112
|
+
t.is(result.acknowledged, true);
|
|
113
|
+
t.is(typeof result.removed_count, 'number');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('should handle complex query filters', async (t) => {
|
|
117
|
+
await find('default', 'employees', {
|
|
118
|
+
age: { $gte: 25, $lte: 35 },
|
|
119
|
+
department: { $in: ['Engineering', 'Marketing'] },
|
|
120
|
+
salary: { $gt: 70000 }
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const stats = await admin('get_query_stats', { collection: 'employees' });
|
|
124
|
+
|
|
125
|
+
t.truthy(stats.age);
|
|
126
|
+
t.truthy(stats.department);
|
|
127
|
+
t.truthy(stats.salary);
|
|
128
|
+
t.is(stats.age.query_count, 1);
|
|
129
|
+
t.is(stats.department.query_count, 1);
|
|
130
|
+
t.is(stats.salary.query_count, 1);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('should track index usage when indexes exist', async (t) => {
|
|
134
|
+
await admin('create_index', { collection: 'employees', field: 'name' });
|
|
135
|
+
|
|
136
|
+
await find('default', 'employees', { name: 'Alice' });
|
|
137
|
+
await find('default', 'employees', { name: 'Bob' });
|
|
138
|
+
|
|
139
|
+
const stats = await admin('get_query_stats', { collection: 'employees' });
|
|
140
|
+
|
|
141
|
+
t.is(stats.name.query_count, 2);
|
|
142
|
+
t.is(stats.name.used_index_count, 2);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('should differentiate between indexed and non-indexed queries', async (t) => {
|
|
146
|
+
await admin('create_index', { collection: 'employees', field: 'name' });
|
|
147
|
+
|
|
148
|
+
await find('default', 'employees', { name: 'Alice' });
|
|
149
|
+
await find('default', 'employees', { age: 25 });
|
|
150
|
+
|
|
151
|
+
const stats = await admin('get_query_stats', { collection: 'employees' });
|
|
152
|
+
|
|
153
|
+
t.is(stats.name.used_index_count, 1);
|
|
154
|
+
t.is(stats.age.used_index_count, 0);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('should handle queries with projection and sorting', async (t) => {
|
|
158
|
+
await find('default', 'employees', { department: 'Engineering' }, {
|
|
159
|
+
projection: { name: 1, salary: 1 },
|
|
160
|
+
sort: { salary: -1 },
|
|
161
|
+
limit: 2
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const stats = await admin('get_query_stats', { collection: 'employees' });
|
|
165
|
+
|
|
166
|
+
t.truthy(stats.department);
|
|
167
|
+
t.is(stats.department.query_count, 1);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test('should handle find_one with projection', async (t) => {
|
|
171
|
+
await find_one('default', 'employees', { name: 'Alice' }, {
|
|
172
|
+
projection: { age: 1, department: 1 }
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const stats = await admin('get_query_stats', { collection: 'employees' });
|
|
176
|
+
|
|
177
|
+
t.truthy(stats.name);
|
|
178
|
+
t.is(stats.name.query_count, 1);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test('should accumulate statistics across multiple operations', async (t) => {
|
|
182
|
+
await find('default', 'employees', { name: 'Alice' });
|
|
183
|
+
await find_one('default', 'employees', { name: 'Bob' });
|
|
184
|
+
await find('default', 'employees', { name: 'Charlie' });
|
|
185
|
+
|
|
186
|
+
const stats = await admin('get_query_stats', { collection: 'employees' });
|
|
187
|
+
|
|
188
|
+
t.is(stats.name.query_count, 3);
|
|
189
|
+
t.true(stats.name.total_time_ms > 0);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test('should handle empty result sets', async (t) => {
|
|
193
|
+
await find('default', 'employees', { name: 'NonExistent' });
|
|
194
|
+
await find_one('default', 'employees', { age: 999 });
|
|
195
|
+
|
|
196
|
+
const stats = await admin('get_query_stats', { collection: 'employees' });
|
|
197
|
+
|
|
198
|
+
t.truthy(stats.name);
|
|
199
|
+
t.truthy(stats.age);
|
|
200
|
+
t.is(stats.name.query_count, 1);
|
|
201
|
+
t.is(stats.age.query_count, 1);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test('should handle queries on non-existent collections', async (t) => {
|
|
205
|
+
await find('default', 'non_existent_collection', { field: 'value' });
|
|
206
|
+
|
|
207
|
+
const stats = await admin('get_query_stats', { collection: 'non_existent_collection' });
|
|
208
|
+
|
|
209
|
+
t.truthy(stats.field);
|
|
210
|
+
t.is(stats.field.query_count, 1);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test('should track slow queries correctly', async (t) => {
|
|
214
|
+
for (let i = 0; i < 10; i++) {
|
|
215
|
+
await find('default', 'employees', { department: 'Engineering' });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const stats = await admin('get_query_stats', { collection: 'employees' });
|
|
219
|
+
|
|
220
|
+
t.is(stats.department.query_count, 10);
|
|
221
|
+
t.true(stats.department.slow_query_count >= 0);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test('should get statistics for specific collection only', async (t) => {
|
|
225
|
+
await find('default', 'employees', { name: 'Alice' });
|
|
226
|
+
await find('default', 'products', { category: 'Electronics' });
|
|
227
|
+
|
|
228
|
+
const employee_stats = await admin('get_query_stats', { collection: 'employees' });
|
|
229
|
+
const product_stats = await admin('get_query_stats', { collection: 'products' });
|
|
230
|
+
|
|
231
|
+
t.truthy(employee_stats.name);
|
|
232
|
+
t.falsy(employee_stats.category);
|
|
233
|
+
t.truthy(product_stats.category);
|
|
234
|
+
t.falsy(product_stats.name);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
test('should get statistics for all collections', async (t) => {
|
|
238
|
+
await find('default', 'employees', { name: 'Alice' });
|
|
239
|
+
await find('default', 'products', { category: 'Electronics' });
|
|
240
|
+
|
|
241
|
+
const all_stats = await admin('get_query_stats');
|
|
242
|
+
|
|
243
|
+
t.truthy(all_stats.employees);
|
|
244
|
+
t.truthy(all_stats.products);
|
|
245
|
+
t.truthy(all_stats.employees.name);
|
|
246
|
+
t.truthy(all_stats.products.category);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test('should handle admin operations without errors', async (t) => {
|
|
250
|
+
await t.notThrowsAsync(async () => {
|
|
251
|
+
await admin('get_auto_index_stats');
|
|
252
|
+
await admin('get_query_stats');
|
|
253
|
+
await admin('evaluate_auto_indexes');
|
|
254
|
+
await admin('remove_auto_indexes', { collection: 'test' });
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test('should maintain statistics persistence across operations', async (t) => {
|
|
259
|
+
await find('default', 'employees', { name: 'Alice' });
|
|
260
|
+
|
|
261
|
+
let stats = await admin('get_query_stats', { collection: 'employees' });
|
|
262
|
+
t.is(stats.name.query_count, 1);
|
|
263
|
+
|
|
264
|
+
await find('default', 'employees', { name: 'Bob' });
|
|
265
|
+
|
|
266
|
+
stats = await admin('get_query_stats', { collection: 'employees' });
|
|
267
|
+
t.is(stats.name.query_count, 2);
|
|
268
|
+
});
|