diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3047e8676d0..61448a90377 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,559 @@ -## Contributing to the driver +# Contributing to the MongoDB C# Driver -### Bugfixes +## Overview -- Before starting to write code, look for existing [tickets](https://jira.mongodb.org/browse/CSHARP#selectedTab=com.atlassian.jira.plugin.system.project%3Asummary-panel) or create one for your specific issue. That way you avoid working on something that might not be of interest or that has been addressed already in a different branch. -- Fork the [repo](https://github.com/mongodb/mongo-csharp-driver). -- Ensure your core.autocrlf settings are set to true. -- Follow the general coding style of the rest of the project. -- Write tests and make sure they pass. -- Your final commit should have the JIRA issue number as the first part of the commit message. [see here](https://github.com/mongodb/mongo-csharp-driver/commit/40e69fe1cf45b0ed9d68a551b0222a140fa26ba2) -- Submit a pull request from github. +This repo contains the code and tests for the official MongoDB driver for .NET/C#. + +## Find or create a tracking issue + +Any bug fix should have an issue tracking it in the [Jira issue tracker for the MongoDB C# Driver](https://jira.mongodb.org/projects/CSHARP/issues/). First, check for any existing issue, and if found, make sure to read any discussion and look at any existing pull requests. If there is no existing issue covering your case, then create one and wait for feedback from the team for any guidance. This avoids you doing work that might not be accepted. + +> Note: An issue is not required for a simple typo PR. + +## Building and testing the code + +It is important to ensure that any change works correctly and does not regress existing behaviors before submitting a pull request. To do this, you will need to build the code and run the tests on your local machine. This is straightforward, but does require some one-time set up. + +### Install the .NET SDKs + +The C# driver is multi-targetted so that it works across multiple .NET versions. However, building and testing requires .NET 10 (latest) and .NET 8 (LTS). Install the SDK from [Microsoft .NET home](https://dotnet.microsoft.com/download). You may wish to install other .NET runtime versions for testing. + +### Install git + +Ensure that git is installed on your system. It may already be installed as part of your IDE or other development tools, such as [Homebrew](https://brew.sh/) on MacOS. Alternately, it can be downloaded from directly from [git](https://git-scm.com/downloads). + +### Install and run MongoDB locally + +> Note: These instructions have been tested on MacOS. There is no reason that this should not work on Linux and Windows too, but that has not been tested. + +#### Running MongoDB in Docker + +Most tests can run against a local instance of MongoDB running in Docker. A Docker compose file called [docker-compose.yml](docker-compose.yml) is provided to start this server for you. There is also a shell script called [start-mongodb.sh](start-mongodb.sh) that will start the container and wait for it to be ready. This script executes the following commands: + +Stop any existing containers: + +```bash +docker compose down 2>/dev/null || true +``` + +Start MongoDB: + +```bash +docker compose up -d +``` + +The connection string for this local MongoDB instance is, `mongodb://localhost:56665/?replicaSet=rs0&directConnection=true`. Set the environment variable `MONGODB_URI` to this value before running the tests. Adjust the docker compose file if you need to change the port. + +#### Running Atlas in Docker + +The [Atlas Local CLI](https://www.mongodb.com/docs/atlas/cli/current/atlas-cli-deploy-local/) is a great way to work with MongoDB locally. Unfortunately, it is not suitable for general driver testing because it does not support `--setParameter enableTestCommands=1` when starting the mongod server. + +However, non-Atlas MongoDB cannot currently execute all the search and vector tests targetted at Atlas Search. Therefore, these tests do not run by default. To enable them, set the following environment variables: + +- `ATLAS_SEARCH_TESTS_ENABLED` = 1 +- `ATLAS_SEARCH_INDEX_HELPERS_TESTS_ENABLED` = 1 +- `ATLAS_SEARCH_URI` to the connection string for your Atlas Local instance + +#### Encryption tests + +Additional libraries are needed to run the encryption tests. Download the "Crypt Shared" `tgz` or `zip` archive for your platform from [MongoDB Enterprise Downloads](https://www.mongodb.com/try/download/enterprise-advanced/releases). + +Extract the archive to a location of your choice. For example: + +```zsh +tar -xvzf mongo_crypt_shared_v1-macos-arm64-enterprise-8.0.11.tgz -C mongo_crypt_shared_v1-macos-arm64-enterprise-8.0.11 +``` + +Finally, set environment variables to point to the extracted archive: + +- `CRYPT_SHARED_LIB_PATH` points to the crypt shared library itself--that is, the `.dll`, `.so`, or `.dylib` file. +- `MONGODB_BINARIES` points to the folder containing the server binaries. + +### Fork and clone the GitHub repo + +You will make your changes in your own copy of the GitHub repo. To do this, go to the [MongoDB C# Driver repo](https://github.com/mongodb/mongo-csharp-driver) and choose "Fork" at the top right. See [Fork a repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) for more information on creating an using forks. + +You now have your own copy (fork) of the code in GitHub, so you can use `git clone` to work with that copy on your local machine. For example: + +```bash +clone https://github.com/your-github-name/mongo-csharp-driver +``` + +### Build the code and run tests + +The .NET solution "CSharpDriver.sln" can be used to work with the code in your favorite IDE. Alternately, the code can be built from the command line with: + +```zsh +dotnet build +``` + +And tests can be run with: + +```zsh +dotnet test +``` + +#### Notes on running tests locally + +The tests are run against multiple targets by default. This means: + +- The .NET Framework target cannot be used on Mac or Linux systems. +- Targets before .NET 6 cannot be used on ARM64 systems. + +To run tests only against a single target, use the `--framework` option. For example: + +```zsh +dotnet test --framework net10 +``` + +## Submit a PR + +Once the changes have been made and all tests are passing, create a branch with these changes and push to your GitHub fork. If your branch contains multiple commits, then please [squash these into a single commit](https://stackoverflow.com/questions/5189560/how-do-i-squash-my-last-n-commits-together) before submitting a PR. Also, you may need to rebase your PR on top of recent upstream changes to the official repo. Use the "Sync fork" button on your GitHub fork page to do this. + +![Syncing your fork with upstream changes](syncfork.png) + +> Note: Your final commit should have the JIRA issue number as the first part of the commit message. + +Use the "Compare and pull request" button on the [official provider repo](https://github.com/mongodb/mongo-csharp-driver) to create a pull request, pulling changes from your fork. + +Make sure to explain what you did and why in the pull request description. + +# Appendix + +## MongoDB C# Driver - Environment Variables Usage Summary + +This document provides a comprehensive summary of all environment variables used across the MongoDB C# Driver codebase, including their purpose, location, and usage context. + +--- + +## 1. Connection & URI Configuration + +### `MONGODB_URI` +**Primary MongoDB connection string** +- **Used in:** + - `tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs:258` + - `tests/SmokeTests/MongoDB.Driver.SmokeTests.Sdk/InfrastructureUtilities.cs:28` + - `tests/MongoDB.Driver.Examples/InfrastructureUtilities.cs:22` + - `tests/FaasTests/LambdaTests/MongoDB.Driver.LambdaTest/LambdaFunction.cs:51` + - `benchmarks/MongoDB.Driver.Benchmarks/BenchmarkHelper.cs:83` + - `tests/AstrolabeWorkloadExecutor/Program.cs:106` (SET) + - `tests/MongoDB.Driver.Tests/Specifications/UnifiedTestSpecRunner.cs:147` (SET) +- **Purpose:** Main connection string for tests and examples +- **Fallback:** Falls back to `MONGO_URI` or default `mongodb://localhost` + +### `MONGO_URI` +**Alternative MongoDB connection string** +- **Used in:** + - `tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs:259` + - `tests/SmokeTests/MongoDB.Driver.SmokeTests.Sdk/InfrastructureUtilities.cs:29` + - `tests/MongoDB.Driver.Examples/InfrastructureUtilities.cs:23` +- **Purpose:** Fallback for `MONGODB_URI` +- **Default:** `mongodb://localhost` + +### `MONGODB_URI_WITH_MULTIPLE_MONGOSES` +**Connection string with multiple mongos servers** +- **Used in:** + - `tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs:264` + - `tests/MongoDB.Driver.Tests/Specifications/UnifiedTestSpecRunner.cs:148` (SET) + - `tests/MongoDB.Driver.Tests/Core/LoadBalancingIntegrationTests.cs:741` (SET) +- **Purpose:** Testing load balancing and sharded cluster scenarios +- **Default:** `mongodb://localhost,localhost:27018` + +### `ATLAS_SEARCH_URI` +**Atlas Search connection string** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Search/AtlasSearchTestsUtils.cs:28` +- **Purpose:** Connection string for Atlas Search integration tests +- **Required:** For Atlas Search tests only + +--- + +## 2. Authentication - AWS + +### `AWS_ACCESS_KEY_ID` +**AWS access key for authentication** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Communication/Security/AwsAuthenticationTests.cs:114` + - `tests/MongoDB.Driver.Examples/Aws/AwsAuthenticationExamples.cs:72, 117` + - `tests/MongoDB.Driver.Examples/Aws/AwsLambdaExamples.cs:59` +- **Purpose:** AWS authentication credential + +### `AWS_SECRET_ACCESS_KEY` +**AWS secret access key** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Communication/Security/AwsAuthenticationTests.cs:114` + - `tests/MongoDB.Driver.Examples/Aws/AwsAuthenticationExamples.cs:73, 118` + - `tests/MongoDB.Driver.Examples/Aws/AwsLambdaExamples.cs:60` +- **Purpose:** AWS authentication credential + +### `AWS_SESSION_TOKEN` +**AWS session token for temporary credentials** +- **Used in:** + - `tests/MongoDB.Driver.Examples/Aws/AwsAuthenticationExamples.cs:74, 119` + - `tests/MongoDB.Driver.Examples/Aws/AwsLambdaExamples.cs:61` +- **Purpose:** Temporary AWS session credential + +### `AWS_PROFILE` +**AWS credential profile name** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Communication/Security/AwsAuthenticationTests.cs:144` +- **Purpose:** Selects AWS credential profile +- **Default:** `default` + +### `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` +**ECS container credentials endpoint** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Communication/Security/AwsAuthenticationTests.cs:64, 128` +- **Purpose:** ECS container credential resolution + +### `AWS_CONTAINER_CREDENTIALS_FULL_URI` +**Full URI for container credentials** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Communication/Security/AwsAuthenticationTests.cs:64, 128` +- **Purpose:** Alternative ECS container credential endpoint + +### `AWS_WEB_IDENTITY_TOKEN_FILE` +**Path to web identity token file** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Communication/Security/AwsAuthenticationTests.cs:84` +- **Purpose:** Web identity federation for AWS + +### `AWS_ECS_ENABLED` +**Indicates ECS environment** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Communication/Security/AwsAuthenticationTests.cs:63` +- **Purpose:** Detect ECS execution environment + +--- + +## 3. FaaS & Serverless Environment Detection + +### `AWS_EXECUTION_ENV` +**AWS Lambda execution environment** +- **Used in:** + - `src/MongoDB.Driver/Core/Servers/ServerMonitor.cs:272` + - `src/MongoDB.Driver/Core/Connections/ClientDocumentHelper.cs:147` +- **Purpose:** Detect AWS Lambda environment (checks if starts with `AWS_Lambda_`) +- **Effect:** Adjusts heartbeat frequency, modifies client metadata + +### `AWS_LAMBDA_RUNTIME_API` +**AWS Lambda runtime API endpoint** +- **Used in:** + - `src/MongoDB.Driver/Core/Servers/ServerMonitor.cs:273` + - `src/MongoDB.Driver/Core/Connections/ClientDocumentHelper.cs:148` +- **Purpose:** Detect AWS Lambda environment +- **Effect:** Sets `faas.name` to "aws.lambda" in client metadata + +### `AWS_REGION` +**AWS region** +- **Used in:** + - `src/MongoDB.Driver/Core/Connections/ClientDocumentHelper.cs:177` +- **Purpose:** Populate `faas.region` in client metadata for Lambda + +### `FUNCTIONS_WORKER_RUNTIME` +**Azure Functions runtime** +- **Used in:** + - `src/MongoDB.Driver/Core/Servers/ServerMonitor.cs:274` + - `src/MongoDB.Driver/Core/Connections/ClientDocumentHelper.cs:152` +- **Purpose:** Detect Azure Functions environment +- **Effect:** Sets `faas.name` to "azure.func" in client metadata + +### `K_SERVICE` +**Google Cloud Run service name** +- **Used in:** + - `src/MongoDB.Driver/Core/Servers/ServerMonitor.cs:275` + - `src/MongoDB.Driver/Core/Connections/ClientDocumentHelper.cs:158` +- **Purpose:** Detect Google Cloud Run/Functions environment +- **Effect:** Sets `faas.name` to "gcp.func" in client metadata + +### `FUNCTION_NAME` +**Generic function name** +- **Used in:** + - `src/MongoDB.Driver/Core/Servers/ServerMonitor.cs:276` + - `src/MongoDB.Driver/Core/Connections/ClientDocumentHelper.cs:158` +- **Purpose:** Detect Google Cloud Functions environment + +### `VERCEL` +**Vercel environment indicator** +- **Used in:** + - `src/MongoDB.Driver/Core/Servers/ServerMonitor.cs:277` + - `src/MongoDB.Driver/Core/Connections/ClientDocumentHelper.cs:164` +- **Purpose:** Detect Vercel serverless environment +- **Effect:** Sets `faas.name` to "vercel" in client metadata + +--- + +## 4. Authentication - X.509 Certificates + +### `MONGO_X509_CLIENT_CERTIFICATE_PATH` +**Path to X.509 client certificate** +- **Used in:** + - `tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs:145` + - `tests/MongoDB.Driver.Tests/AuthenticationTests.cs:302` + - `tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/EncryptionTestHelper.cs:282` +- **Purpose:** Client certificate for X.509 authentication + +### `MONGO_X509_CLIENT_CERTIFICATE_PASSWORD` +**Password for X.509 certificate** +- **Used in:** + - `tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs:150` + - `tests/MongoDB.Driver.Tests/AuthenticationTests.cs:303` + - `tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/EncryptionTestHelper.cs:283` +- **Purpose:** Unlock password-protected certificate files + +--- + +## 5. Authentication - GSSAPI/Kerberos + +### `AUTH_GSSAPI` +**GSSAPI/Kerberos authentication configuration** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Communication/Security/GssapiAuthenticationTests.cs:83, 95` + - `tests/MongoDB.Driver.Tests/Authentication/Libgssapi/GssapiSecurityCredentialTests.cs:35` +- **Purpose:** Enable and configure Kerberos authentication tests +- **Required:** Throws exception if not set when needed + +### `AUTH_HOST` +**Authentication host for Kerberos** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Communication/Security/GssapiAuthenticationTests.cs:90` +- **Purpose:** Kerberos authentication endpoint + +--- + +## 6. Authentication - OIDC + +### `OIDC_ENV` +**OIDC environment type** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Specifications/auth/OidcAuthenticationProseTests.cs:54, 604` + - `tests/MongoDB.Driver.Tests/UnifiedTestOperations/UnifiedEntityMap.cs:548` +- **Purpose:** Controls OIDC test environment +- **Values:** `test`, `azure`, `gcp`, `k8s` + +### `OIDC_TOKEN_DIR` +**Directory containing OIDC tokens** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Specifications/auth/OidcAuthenticationProseTests.cs:53, 559` + - `src/MongoDB.Driver/Authentication/Oidc/OidcCallbackAdapterFactory.cs:65` (as `OIDC_TOKEN_FILE`) +- **Purpose:** Path to OIDC token files for testing + +### `TOKEN_RESOURCE` +**OIDC token resource identifier** +- **Used in:** + - `tests/MongoDB.Driver.Tests/Specifications/auth/OidcAuthenticationProseTests.cs:617` + - `tests/MongoDB.Driver.Tests/UnifiedTestOperations/UnifiedEntityMap.cs:554` +- **Purpose:** OIDC token resource parameter + +--- + +## 7. Client-Side Field Level Encryption (CSFLE) + +### `CRYPT_SHARED_LIB_PATH` +**Path to crypt_shared library** +- **Used in:** + - `tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs:255` + - `tests/MongoDB.Driver.Tests/Encryption/AutoEncryptionTests.cs:129` +- **Purpose:** Path to MongoDB crypt_shared dynamic library + +### `LIBMONGOCRYPT_PATH` +**Path to libmongocrypt library** +- **Used in:** + - `src/MongoDB.Driver.Encryption/LibraryLoader.cs:31` +- **Purpose:** Path to libmongocrypt library for encryption + +### AWS KMS Credentials (FLE) + +#### `FLE_AWS_KEY` +- **Used in:** `EncryptionTestHelper.cs:45, 52` +- **Purpose:** AWS access key for FLE KMS + +#### `FLE_AWS_SECRET` +- **Used in:** `EncryptionTestHelper.cs:46, 53` +- **Purpose:** AWS secret key for FLE KMS + +#### `FLE_AWS_KEY2` / `FLE_AWS_SECRET2` +- **Used in:** `EncryptionTestHelper.cs:59, 60` +- **Purpose:** Secondary AWS credentials for FLE tests + +### Azure KMS Credentials (FLE) + +#### `FLE_AZURE_TENANTID` +- **Used in:** `EncryptionTestHelper.cs:84, 92` +- **Purpose:** Azure tenant ID for FLE + +#### `FLE_AZURE_CLIENTID` +- **Used in:** `EncryptionTestHelper.cs:85, 93` +- **Purpose:** Azure client ID for FLE + +#### `FLE_AZURE_CLIENTSECRET` +- **Used in:** `EncryptionTestHelper.cs:86, 94` +- **Purpose:** Azure client secret for FLE + +### GCP KMS Credentials (FLE) + +#### `FLE_GCP_EMAIL` +- **Used in:** `EncryptionTestHelper.cs:100, 107` +- **Purpose:** GCP service account email for FLE + +#### `FLE_GCP_PRIVATEKEY` +- **Used in:** `EncryptionTestHelper.cs:101, 108` +- **Purpose:** GCP private key for FLE + +### FLE Test Controls + +#### `CSFLE_AWS_TEMPORARY_CREDS_ENABLED` +- **Used in:** `EncryptionTestHelper.cs:125` +- **Purpose:** Enable AWS temporary credentials for FLE tests + +#### `CSFLE_AWS_TEMP_ACCESS_KEY_ID` +- **Used in:** `EncryptionTestHelper.cs:131, 139` +- **Purpose:** Temporary AWS access key for FLE + +#### `CSFLE_AWS_TEMP_SECRET_ACCESS_KEY` +- **Used in:** `EncryptionTestHelper.cs:132, 140` +- **Purpose:** Temporary AWS secret key for FLE + +#### `CSFLE_AWS_TEMP_SESSION_TOKEN` +- **Used in:** `EncryptionTestHelper.cs:133` +- **Purpose:** Temporary AWS session token for FLE + +#### `CSFLE_AZURE_KMS_TESTS_ENABLED` +- **Used in:** `ClientEncryptionProseTests.cs:2028` +- **Purpose:** Enable Azure KMS integration tests + +#### `CSFLE_GCP_KMS_TESTS_ENABLED` +- **Used in:** `ClientEncryptionProseTests.cs:2053` +- **Purpose:** Enable GCP KMS integration tests + +### `MONGODB_BINARIES` +**Path to MongoDB binaries directory** +- **Used in:** + - `EncryptionTestHelper.cs:35` +- **Purpose:** Path to mongocryptd and other MongoDB binaries +- **Default:** Empty string + +### `FLE_MONGOCRYPTD_PORT` +**Port for mongocryptd process** +- **Used in:** + - `EncryptionTestHelper.cs:174` +- **Purpose:** Custom port for mongocryptd service + +--- + +## 8. GCP Integration + +### `GCE_METADATA_HOST` +**Google Compute Engine metadata host** +- **Used in:** + - `src/MongoDB.Driver/Authentication/External/GcpAuthenticationCredentialsProvider.cs:64` + - `tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs:2078` +- **Purpose:** Custom GCE metadata server endpoint +- **Default:** `metadata.google.internal` + +### `AZURE_IMDS_MOCK_ENDPOINT` +**Azure IMDS mock endpoint** +- **Used in:** + - `ClientEncryptionProseTests.cs:2167` +- **Purpose:** Mock Azure Instance Metadata Service endpoint for testing +- **Required:** For Azure IMDS tests + +--- + +## 9. Testing & Configuration + +### `MONGO_LOGGING` +**Enable MongoDB driver logging** +- **Used in:** + - `tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs:171` +- **Purpose:** Enable test logging output + +### `MONGO_SERVER_SELECTION_TIMEOUT_MS` +**Server selection timeout** +- **Used in:** + - `tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs:448` + - `tests/MongoDB.Driver.TestHelpers/DriverTestConfiguration.cs:181` +- **Purpose:** Override default server selection timeout for tests + +### `MONGODB_API_VERSION` +**MongoDB Server API version** +- **Used in:** + - `tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs:281` +- **Purpose:** Specify Server API version for tests + +### `SKIPTESTSTHATREQUIRESERVER` +**Skip server-dependent tests** +- **Used in:** + - `tests/MongoDB.Driver.TestHelpers/Core/XunitExtensions/RequireServer.cs:31` +- **Purpose:** Skip integration tests when no server available + +### `DRIVER_PACKAGE_VERSION` +**Expected driver package version** +- **Used in:** + - `tests/SmokeTests/MongoDB.Driver.SmokeTests.Sdk/ValidatePackagesVersionTests.cs:31` +- **Purpose:** Validate NuGet package versions in smoke tests + +--- + +## 10. Astrolabe Workload Executor + +### `RESULTS_DIR` +**Output directory for Astrolabe results** +- **Used in:** + - `tests/AstrolabeWorkloadExecutor/Program.cs:44` +- **Purpose:** Directory to write test results +- **Default:** Empty string + +### `ASYNC` +**Run workload asynchronously** +- **Used in:** + - `tests/AstrolabeWorkloadExecutor/Program.cs:54` +- **Purpose:** Control sync vs async execution +- **Required:** Must be set to `true` or `false` + +--- + +## 11. OCSP Testing + +### Custom OCSP test variables +- **Used in:** + - `tests/MongoDB.Driver.Tests/OcspIntegrationTests.cs:116` +- **Purpose:** Control OCSP certificate validation tests +- **Variable name:** Dynamically determined per test + +--- + +## Summary Statistics + +- **Total unique environment variables:** ~60+ +- **Production code usage:** 14 variables (FaaS detection, GCP auth, library paths) +- **Test-only usage:** ~46 variables +- **Categories:** + - Connection/URI: 4 + - AWS Authentication: 8 + - FaaS Detection: 7 + - X.509 Certificates: 2 + - GSSAPI/Kerberos: 2 + - OIDC: 3 + - Client-Side Encryption: 20+ + - GCP/Azure: 3 + - Testing Configuration: 5 + - Astrolabe: 2 + - Other: 4+ + +--- + +## Production vs Test Usage + +### Production Code (src/) +These variables affect production driver behavior: +- FaaS detection: `AWS_EXECUTION_ENV`, `AWS_LAMBDA_RUNTIME_API`, `FUNCTIONS_WORKER_RUNTIME`, `K_SERVICE`, `FUNCTION_NAME`, `VERCEL`, `AWS_REGION` +- GCP authentication: `GCE_METADATA_HOST` +- Library loading: `LIBMONGOCRYPT_PATH` + +### Test Code (tests/) +All other variables are used exclusively in test code for: +- Test configuration +- Integration test credentials +- Test environment selection +- Mock/stub configuration diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000000..bcbca2a1302 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,35 @@ +services: + mongodb: + image: mongo:8 + container_name: mongodb-test + command: > + mongod + --replSet rs0 + --bind_ip_all + --setParameter enableTestCommands=1 + ports: + - "56665:27017" + volumes: + - mongodb_data:/data/db + healthcheck: + test: | + mongosh --quiet --eval " + try { + rs.status(); + print('Replica set initialized'); + } catch(e) { + print('Initializing replica set...'); + rs.initiate({ + _id: 'rs0', + members: [{ _id: 0, host: 'localhost:27017' }] + }); + } + " + interval: 5s + timeout: 10s + retries: 10 + start_period: 10s + +volumes: + mongodb_data: + driver: local diff --git a/src/MongoDB.Driver/Encryption/AutoEncryptionProviderRegistry.cs b/src/MongoDB.Driver/Encryption/AutoEncryptionProviderRegistry.cs index c87c7a53383..e4d089ffedf 100644 --- a/src/MongoDB.Driver/Encryption/AutoEncryptionProviderRegistry.cs +++ b/src/MongoDB.Driver/Encryption/AutoEncryptionProviderRegistry.cs @@ -28,10 +28,16 @@ internal sealed class AutoEncryptionProviderRegistry : IAutoEncryptionProviderRe public void Register(Func factory) { + if(ReferenceEquals(factory, _autoCryptClientControllerFactory)) + { + return; + } + if (_autoCryptClientControllerFactory != null) { throw new MongoConfigurationException("AutoEncryption Provider already registered."); } + _autoCryptClientControllerFactory = factory; } diff --git a/start-mongodb.sh b/start-mongodb.sh new file mode 100755 index 00000000000..227fd165cd7 --- /dev/null +++ b/start-mongodb.sh @@ -0,0 +1,102 @@ +#!/bin/bash + +# MongoDB Test Environment Startup Script +# Starts MongoDB with single-node replica set and test commands enabled + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored messages +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if Docker is installed +if ! command -v docker &> /dev/null; then + print_error "Docker is not installed. Please install Docker first." + exit 1 +fi + +# Check if Docker Compose is available +if ! docker compose version &> /dev/null; then + print_error "Docker Compose is not available. Please install Docker Compose." + exit 1 +fi + +# Check if docker-compose.yml exists +if [ ! -f "docker-compose.yml" ]; then + print_error "docker-compose.yml not found in current directory." + exit 1 +fi + +print_info "Starting MongoDB with test commands enabled..." + +# Stop any existing containers +docker compose down 2>/dev/null || true + +# Start MongoDB +docker compose up -d + +print_info "Waiting for MongoDB to be ready..." + +# Wait for container to be healthy +max_attempts=30 +attempt=0 +while [ $attempt -lt $max_attempts ]; do + if docker compose ps | grep -q "healthy"; then + print_success "MongoDB is ready!" + break + fi + + attempt=$((attempt + 1)) + if [ $attempt -eq $max_attempts ]; then + print_error "MongoDB failed to start within expected time." + print_info "Showing container logs:" + docker compose logs + exit 1 + fi + + echo -n "." + sleep 2 +done + +echo "" + +# Display connection information +print_success "MongoDB is running with the following configuration:" +echo "" +echo " • Single-node replica set: rs0" +echo " • Test commands: ENABLED" +echo " • Port: 56665" +echo "" +echo "Connection String:" +echo " mongodb://localhost:56665/?replicaSet=rs0&directConnection=true" +echo "" +echo "C# Driver Connection String:" +echo ' var connectionString = "mongodb://localhost:56665/?replicaSet=rs0&directConnection=true";' +echo ' var client = new MongoClient(connectionString);' +echo "" +print_info "To stop MongoDB, run:" +echo " docker compose down" +echo "" +print_info "To view logs, run:" +echo " docker compose logs -f" +echo "" diff --git a/tests/AtlasConnectivity.Tests/ConnectivityTests.cs b/tests/AtlasConnectivity.Tests/ConnectivityTests.cs index d778f83249c..b07e5fa66e7 100644 --- a/tests/AtlasConnectivity.Tests/ConnectivityTests.cs +++ b/tests/AtlasConnectivity.Tests/ConnectivityTests.cs @@ -18,6 +18,7 @@ using MongoDB.Bson; using MongoDB.Driver; using MongoDB.Driver.Core.TestHelpers.Logging; +using MongoDB.TestHelpers.XunitExtensions; using Xunit; using Xunit.Abstractions; @@ -46,6 +47,8 @@ public ConnectivityTests(ITestOutputHelper testOutputHelper) [InlineData("ATLAS_SRV_TLS12")] public void Connection_to_Atlas_should_work(string environmentVariableName) { + RequireEnvironment.Check().EnvironmentVariable(environmentVariableName); + var connectionString = Environment.GetEnvironmentVariable(environmentVariableName); connectionString.Should().NotBeNull(); diff --git a/tests/AtlasConnectivity.Tests/Properties/AssemblyInfo.cs b/tests/AtlasConnectivity.Tests/Properties/AssemblyInfo.cs index fe231fb3732..c348f94ab99 100644 --- a/tests/AtlasConnectivity.Tests/Properties/AssemblyInfo.cs +++ b/tests/AtlasConnectivity.Tests/Properties/AssemblyInfo.cs @@ -14,5 +14,9 @@ */ using System.Runtime.InteropServices; +using MongoDB.TestHelpers.XunitExtensions; +using Xunit; [assembly: ComVisible(false)] + +[assembly: TestFramework(XunitExtensionsConstants.TimeoutEnforcingXunitFramework, XunitExtensionsConstants.TimeoutEnforcingFrameworkAssembly)] diff --git a/tests/MongoDB.Driver.Examples/CausalConsistencyExamples.cs b/tests/MongoDB.Driver.Examples/CausalConsistencyExamples.cs index a2c1e5a069b..73988e79780 100644 --- a/tests/MongoDB.Driver.Examples/CausalConsistencyExamples.cs +++ b/tests/MongoDB.Driver.Examples/CausalConsistencyExamples.cs @@ -120,9 +120,10 @@ public void Causal_Consistency_Example_3() DropCollection(CreateClient(), "myDatabase", "myCollection"); // Start Tunable Consistency Controls Example - var connectionString = "mongodb://localhost/?readPreference=secondaryPreferred"; + var clientSettings = MongoClientSettings.FromConnectionString(CoreTestConfiguration.ConnectionString.ToString()); + clientSettings.ReadPreference = ReadPreference.SecondaryPreferred; - var client = new MongoClient(connectionString); + var client = new MongoClient(clientSettings); var database = client.GetDatabase("myDatabase"); var collection = database.GetCollection("myCollection"); @@ -147,11 +148,7 @@ public void Causal_Consistency_Example_3() result.Should().Be("{ name: 'John' }"); } - private IMongoClient CreateClient() - { - var connectionString = CoreTestConfiguration.ConnectionString.ToString(); - return new MongoClient(connectionString); - } + private IMongoClient CreateClient() => new MongoClient(CoreTestConfiguration.ConnectionString.ToString()); private void DropCollection(IMongoClient client, string databaseName, string collectionName) { diff --git a/tests/MongoDB.Driver.Examples/ChangeStreamExamples.cs b/tests/MongoDB.Driver.Examples/ChangeStreamExamples.cs index 730dfe80d1f..e076d1abddc 100644 --- a/tests/MongoDB.Driver.Examples/ChangeStreamExamples.cs +++ b/tests/MongoDB.Driver.Examples/ChangeStreamExamples.cs @@ -16,7 +16,6 @@ using System; using System.Linq; using System.Threading; -using System.Threading.Tasks; using FluentAssertions; using MongoDB.Bson; using MongoDB.Driver.Core.TestHelpers.XunitExtensions; @@ -37,12 +36,13 @@ public void ChangeStreamExample1() var inventory = database.GetCollection("inventory"); var document = new BsonDocument("x", 1); - new Thread(() => + var thread = new Thread(() => { Thread.Sleep(TimeSpan.FromMilliseconds(100)); inventory.InsertOne(document); - }) - .Start(); + }); + + thread.Start(); // Start Changestream Example 1 var cursor = inventory.Watch(); @@ -52,6 +52,9 @@ public void ChangeStreamExample1() // End Changestream Example 1 next.FullDocument.Should().Be(document); + + // Make sure worker thread is finished before we let the next test run. + thread.Join(); } [Fact] @@ -64,14 +67,15 @@ public void ChangeStreamExample2() var document = new BsonDocument("x", 1); inventory.InsertOne(document); - new Thread(() => + var thread = new Thread(() => { Thread.Sleep(TimeSpan.FromMilliseconds(100)); var filter = new BsonDocument("_id", document["_id"]); var update = "{ $set : { x : 2 } }"; inventory.UpdateOne(filter, update); - }) - .Start(); + }); + + thread.Start(); // Start Changestream Example 2 var options = new ChangeStreamOptions { FullDocument = ChangeStreamFullDocumentOption.UpdateLookup }; @@ -83,6 +87,9 @@ public void ChangeStreamExample2() var expectedFullDocument = document.Set("x", 2); next.FullDocument.Should().Be(expectedFullDocument); + + // Make sure worker thread is finished before we let the next test run. + thread.Join(); } [Fact] @@ -101,15 +108,19 @@ public void ChangeStreamExample3() IChangeStreamCursor> previousCursor; { - new Thread(() => + var thread = new Thread(() => { Thread.Sleep(TimeSpan.FromMilliseconds(100)); inventory.InsertMany(documents); - }) - .Start(); + }); + + thread.Start(); previousCursor = inventory.Watch(new ChangeStreamOptions { BatchSize = 1 }); while (previousCursor.MoveNext() && previousCursor.Current.Count() == 0) { } // keep calling MoveNext until we've read the first batch + + // Make sure worker thread is finished before we let the next test run. + thread.Join(); } { @@ -135,22 +146,24 @@ public void ChangestreamExample4() var database = client.GetDatabase("ChangeStreamExamples"); database.DropCollection("inventory"); - using var cancelationTokenSource = new CancellationTokenSource(); - try + var stopEvent = new ManualResetEventSlim(false); + var document = new BsonDocument("username", "alice"); + + var thread = new Thread(() => { - var document = new BsonDocument("username", "alice"); + var inventoryCollection = database.GetCollection("inventory"); - Task.Run(() => + while (!stopEvent.IsSet) { - var inventoryCollection = database.GetCollection("inventory"); + Thread.Sleep(TimeSpan.FromMilliseconds(100)); + document["_id"] = ObjectId.GenerateNewId(); + inventoryCollection.InsertOne(document); + } + }); - while (!cancelationTokenSource.IsCancellationRequested) - { - Thread.Sleep(TimeSpan.FromMilliseconds(100)); - document["_id"] = ObjectId.GenerateNewId(); - inventoryCollection.InsertOne(document); - } - }, cancelationTokenSource.Token); + try + { + thread.Start(); // Start Changestream Example 4 var pipeline = new EmptyPipelineDefinition>() @@ -170,7 +183,12 @@ public void ChangestreamExample4() } finally { - cancelationTokenSource.Cancel(); + stopEvent.Set(); + + // Make sure the worker thread is finished before we let the next test run. + // Especially important for this test case since the thread continually inserts documents. + thread.Join(); + stopEvent.Dispose(); } } } diff --git a/tests/MongoDB.Driver.Examples/ClientEncryptionExamples.cs b/tests/MongoDB.Driver.Examples/ClientEncryptionExamples.cs index a2c7a54051f..6b42a971eb3 100644 --- a/tests/MongoDB.Driver.Examples/ClientEncryptionExamples.cs +++ b/tests/MongoDB.Driver.Examples/ClientEncryptionExamples.cs @@ -56,10 +56,8 @@ public void ClientSideEncryptionSimpleTour() var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault"); var autoEncryptionOptions = new AutoEncryptionOptions(keyVaultNamespace, kmsProviders); - var mongoClientSettings = new MongoClientSettings - { - AutoEncryptionOptions = autoEncryptionOptions - }; + var mongoClientSettings = MongoClientSettings.FromConnectionString(InfrastructureUtilities.MongoUri); + mongoClientSettings.AutoEncryptionOptions = autoEncryptionOptions; var client = new MongoClient(mongoClientSettings); var database = client.GetDatabase("test"); @@ -87,7 +85,7 @@ public void ClientSideEncryptionAutoEncryptionSettingsTour() kmsProviders.Add("local", localKey); var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault"); - var keyVaultMongoClient = new MongoClient(); + var keyVaultMongoClient = new MongoClient(InfrastructureUtilities.MongoUri); var clientEncryptionSettings = new ClientEncryptionOptions( keyVaultMongoClient, keyVaultNamespace, @@ -124,10 +122,9 @@ public void ClientSideEncryptionAutoEncryptionSettingsTour() { { collectionNamespace.ToString(), BsonDocument.Parse(schemaMap) } }); - var clientSettings = new MongoClientSettings - { - AutoEncryptionOptions = autoEncryptionSettings - }; + + var clientSettings = MongoClientSettings.FromConnectionString(InfrastructureUtilities.MongoUri); + clientSettings.AutoEncryptionOptions = autoEncryptionSettings; var client = new MongoClient(clientSettings); var database = client.GetDatabase("test"); diff --git a/tests/MongoDB.Driver.Examples/ClientSideEncryption2Examples.cs b/tests/MongoDB.Driver.Examples/ClientSideEncryption2Examples.cs index 2524e5cb378..a9077a5f11f 100644 --- a/tests/MongoDB.Driver.Examples/ClientSideEncryption2Examples.cs +++ b/tests/MongoDB.Driver.Examples/ClientSideEncryption2Examples.cs @@ -37,7 +37,7 @@ public class ClientSideEncryption2Examples [Fact] public void FLE2AutomaticEncryption() { - RequireServer.Check().Supports(Feature.Csfle2).ClusterTypes(ClusterType.ReplicaSet, ClusterType.Sharded, ClusterType.LoadBalanced); + RequireServer.Check().Supports(Feature.Csfle2); var unencryptedClient = DriverTestConfiguration.Client; @@ -52,7 +52,7 @@ public void FLE2AutomaticEncryption() }; kmsProviders.Add("local", localKey); - var keyVaultClient = new MongoClient(); + var keyVaultClient = new MongoClient(InfrastructureUtilities.MongoUri); // Create two data keys. var clientEncryptionOptions = new ClientEncryptionOptions(keyVaultClient, KeyVaultNamespace, kmsProviders); @@ -92,7 +92,9 @@ public void FLE2AutomaticEncryption() }; var autoEncryptionOptions = new AutoEncryptionOptions(KeyVaultNamespace, kmsProviders, encryptedFieldsMap: encryptedFieldsMap); - var encryptedClient = new MongoClient(new MongoClientSettings { AutoEncryptionOptions = autoEncryptionOptions }); + var mongoClientSettings = MongoClientSettings.FromConnectionString(InfrastructureUtilities.MongoUri); + mongoClientSettings.AutoEncryptionOptions = autoEncryptionOptions; + var encryptedClient = new MongoClient(mongoClientSettings); // Create an FLE 2 collection. var database = encryptedClient.GetDatabase(CollectionNamespace.DatabaseNamespace.DatabaseName); diff --git a/tests/MongoDB.Driver.Examples/DocumentationExamples.cs b/tests/MongoDB.Driver.Examples/DocumentationExamples.cs index 5903574dcd0..e549b0ad08b 100644 --- a/tests/MongoDB.Driver.Examples/DocumentationExamples.cs +++ b/tests/MongoDB.Driver.Examples/DocumentationExamples.cs @@ -987,7 +987,7 @@ public void Example_50() // End Example 50 Render(filter).Should().Be("{ status: \"A\" }"); - Render(projection).Should().Be("{ item: 1, status: 1, instock: { $slice: -1 } }"); + Render(projection).Should().Be("{ item: 1, status: 1, instock: { $slice: [ '$instock', -1 ] } }"); } [Fact] diff --git a/tests/MongoDB.Driver.Examples/ExplicitEncryptionExamples.cs b/tests/MongoDB.Driver.Examples/ExplicitEncryptionExamples.cs index 3676919afae..fdbda2ae1ef 100644 --- a/tests/MongoDB.Driver.Examples/ExplicitEncryptionExamples.cs +++ b/tests/MongoDB.Driver.Examples/ExplicitEncryptionExamples.cs @@ -54,7 +54,8 @@ public void ClientSideExplicitEncryptionAndDecryptionTour() kmsProviders.Add("local", localKey); var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault"); - var keyVaultClient = new MongoClient("mongodb://localhost"); + var clientSettings = MongoClientSettings.FromConnectionString(InfrastructureUtilities.MongoUri); + var keyVaultClient = new MongoClient(clientSettings); var keyVaultDatabase = keyVaultClient.GetDatabase(keyVaultNamespace.DatabaseNamespace.DatabaseName); keyVaultDatabase.DropCollection(keyVaultNamespace.CollectionName); @@ -109,14 +110,15 @@ public void ClientSideExplicitEncryptionAndAutoDecryptionTour() keyVaultNamespace, kmsProviders, bypassAutoEncryption: true); - var clientSettings = MongoClientSettings.FromConnectionString("mongodb://localhost"); + var clientSettings = MongoClientSettings.FromConnectionString(InfrastructureUtilities.MongoUri); clientSettings.AutoEncryptionOptions = autoEncryptionOptions; var mongoClient = new MongoClient(clientSettings); var database = mongoClient.GetDatabase(collectionNamespace.DatabaseNamespace.DatabaseName); database.DropCollection(collectionNamespace.CollectionName); var collection = database.GetCollection(collectionNamespace.CollectionName); - var keyVaultClient = new MongoClient("mongodb://localhost"); + var keyVaultClientSettings = MongoClientSettings.FromConnectionString(InfrastructureUtilities.MongoUri); + var keyVaultClient = new MongoClient(keyVaultClientSettings); var keyVaultDatabase = keyVaultClient.GetDatabase(keyVaultNamespace.DatabaseNamespace.DatabaseName); keyVaultDatabase.DropCollection(keyVaultNamespace.CollectionName); diff --git a/tests/MongoDB.Driver.Examples/InfrastructureUtilities.cs b/tests/MongoDB.Driver.Examples/InfrastructureUtilities.cs new file mode 100644 index 00000000000..7373b22e91e --- /dev/null +++ b/tests/MongoDB.Driver.Examples/InfrastructureUtilities.cs @@ -0,0 +1,25 @@ +/* Copyright 2017-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; + +namespace MongoDB.Driver.Examples; + +internal static class InfrastructureUtilities +{ + public static readonly string MongoUri = Environment.GetEnvironmentVariable("MONGODB_URI") ?? + Environment.GetEnvironmentVariable("MONGO_URI") ?? + "mongodb://localhost"; +} diff --git a/tests/MongoDB.Driver.Examples/StableApiExamples.cs b/tests/MongoDB.Driver.Examples/StableApiExamples.cs index 8d636aa63e0..51e5e99ffb3 100644 --- a/tests/MongoDB.Driver.Examples/StableApiExamples.cs +++ b/tests/MongoDB.Driver.Examples/StableApiExamples.cs @@ -26,7 +26,7 @@ public class StableApiExamples public void ConfigureServerApi() { // Start Stable API Example 1 - var connectionString = "mongodb://localhost"; + var connectionString = InfrastructureUtilities.MongoUri; var serverApi = new ServerApi(ServerApiVersion.V1); var mongoClientSettings = MongoClientSettings.FromConnectionString(connectionString); mongoClientSettings.ServerApi = serverApi; @@ -38,7 +38,7 @@ public void ConfigureServerApi() public void ConfigureServerApiStrict() { // Start Stable API Example 2 - var connectionString = "mongodb://localhost"; + var connectionString = InfrastructureUtilities.MongoUri; var serverApi = new ServerApi(ServerApiVersion.V1, strict: true); var mongoClientSettings = MongoClientSettings.FromConnectionString(connectionString); mongoClientSettings.ServerApi = serverApi; @@ -50,7 +50,7 @@ public void ConfigureServerApiStrict() public void ConfigureServerApiNonStrict() { // Start Stable API Example 3 - var connectionString = "mongodb://localhost"; + var connectionString = InfrastructureUtilities.MongoUri; var serverApi = new ServerApi(ServerApiVersion.V1, strict: false); var mongoClientSettings = MongoClientSettings.FromConnectionString(connectionString); mongoClientSettings.ServerApi = serverApi; @@ -62,7 +62,7 @@ public void ConfigureServerApiNonStrict() public void ConfigureServerApiDeprecationErrors() { // Start Stable API Example 4 - var connectionString = "mongodb://localhost"; + var connectionString = InfrastructureUtilities.MongoUri; var serverApi = new ServerApi(ServerApiVersion.V1, deprecationErrors: true); var mongoClientSettings = MongoClientSettings.FromConnectionString(connectionString); mongoClientSettings.ServerApi = serverApi; @@ -73,7 +73,7 @@ public void ConfigureServerApiDeprecationErrors() [Fact] public void StableAPI_Strict_Migration_Example() { - var connectionString = "mongodb://localhost"; + var connectionString = InfrastructureUtilities.MongoUri; var serverApi = new ServerApi(ServerApiVersion.V1, strict: true); var mongoClientSettings = MongoClientSettings.FromConnectionString(connectionString); mongoClientSettings.ServerApi = serverApi; diff --git a/tests/MongoDB.Driver.Examples/TransactionExamplesForDocs/WithTransactionExample1.cs b/tests/MongoDB.Driver.Examples/TransactionExamplesForDocs/WithTransactionExample1.cs index 66da76dc1a0..f61f80a232b 100644 --- a/tests/MongoDB.Driver.Examples/TransactionExamplesForDocs/WithTransactionExample1.cs +++ b/tests/MongoDB.Driver.Examples/TransactionExamplesForDocs/WithTransactionExample1.cs @@ -16,7 +16,6 @@ using System.Threading; using FluentAssertions; using MongoDB.Bson; -using MongoDB.Driver.Core.Clusters; using MongoDB.Driver.Core.Misc; using MongoDB.Driver.Core.TestHelpers.XunitExtensions; using Xunit; @@ -29,7 +28,7 @@ public class WithTransactionExample1 [Fact] public void Example1() { - RequireServer.Check().ClusterTypes(ClusterType.ReplicaSet, ClusterType.Sharded).Supports(Feature.Transactions); + RequireServer.Check().Supports(Feature.Transactions); var connectionString = CoreTestConfiguration.ConnectionString.ToString(); DropCollections( diff --git a/tests/MongoDB.Driver.TestHelpers/Core/XunitExtensions/RequireServer.cs b/tests/MongoDB.Driver.TestHelpers/Core/XunitExtensions/RequireServer.cs index 81a77237554..17c2222daa2 100644 --- a/tests/MongoDB.Driver.TestHelpers/Core/XunitExtensions/RequireServer.cs +++ b/tests/MongoDB.Driver.TestHelpers/Core/XunitExtensions/RequireServer.cs @@ -171,9 +171,10 @@ public RequireServer Supports(params Feature[] features) } public RequireServer SupportsCausalConsistency() - { - return ClusterTypes(Clusters.ClusterType.Sharded, Clusters.ClusterType.ReplicaSet).SupportsSessions(); - } + => CoreTestConfiguration.Cluster.Description.Type == Clusters.ClusterType.Standalone + && CoreTestConfiguration.ConnectionString.DirectConnection + ? this + : ClusterTypes(Clusters.ClusterType.Sharded, Clusters.ClusterType.ReplicaSet).SupportsSessions(); public RequireServer SupportsSessions() { @@ -337,7 +338,8 @@ private bool IsRequirementSatisfied(BsonElement requirement) case "topology": var actualClusterType = CoreTestConfiguration.Cluster.Description.Type; var runOnClusterTypes = requirement.Value.AsBsonArray.Select(topology => MapTopologyToClusterType(topology.AsString)).ToList(); - return runOnClusterTypes.Contains(actualClusterType); + return runOnClusterTypes.Contains(actualClusterType) + && !CoreTestConfiguration.ConnectionString.DirectConnection; case "csfle": return IsCsfleRequirementSatisfied(requirement); default: diff --git a/tests/MongoDB.Driver.Tests/Encryption/AutoEncryptionTests.cs b/tests/MongoDB.Driver.Tests/Encryption/AutoEncryptionTests.cs index 3a3c3cbf6a6..0e6fab081c4 100644 --- a/tests/MongoDB.Driver.Tests/Encryption/AutoEncryptionTests.cs +++ b/tests/MongoDB.Driver.Tests/Encryption/AutoEncryptionTests.cs @@ -53,6 +53,11 @@ public void CryptClient_should_be_initialized([Values(false, true)] bool withAut { RequireServer.Check().Supports(Feature.ClientSideEncryption); + if (withAutoEncryption) + { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); + } + using (var client = GetClient(withAutoEncryption)) { var libMongoCryptController = client.LibMongoCryptController; @@ -74,9 +79,14 @@ public async Task Mongocryptd_should_be_initialized_when_auto_encryption([Values { RequireServer.Check().Supports(Feature.ClientSideEncryption); + if (withAutoEncryption) + { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); + } + using (var client = GetClient( - withAutoEncryption, - new Dictionary { { "cryptSharedLibPath", "non_existing_path_to_use_mongocryptd" } })) + withAutoEncryption, + new Dictionary { { "cryptSharedLibPath", "non_existing_path_to_use_mongocryptd" } })) { if (withAutoEncryption) { @@ -124,6 +134,7 @@ public async Task Mongocryptd_should_be_initialized_when_auto_encryption([Values [Fact] public void Shared_library_should_be_loaded_when_CRYPT_SHARED_LIB_PATH_is_set() { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); RequireServer.Check().Supports(Feature.ClientSideEncryption); RequireEnvironment.Check().EnvironmentVariable("CRYPT_SHARED_LIB_PATH", isDefined: true, allowEmpty: false); Ensure.That(File.Exists(Environment.GetEnvironmentVariable("CRYPT_SHARED_LIB_PATH")), "CRYPT_SHARED_LIB_PATH should exist."); @@ -161,7 +172,7 @@ private MongoClient GetClient(bool withAutoEncryption = false, Dictionary> GetKmsProviders() => EncryptionTestHelper.GetKmsProviders(filter: "local"); + private IReadOnlyDictionary> GetKmsProviders() => EncryptionTestHelper.GetKmsProviders("local"); } internal static class LibMongoCryptControllerBaseReflector diff --git a/tests/MongoDB.Driver.Tests/Encryption/ClientEncryptionTests.cs b/tests/MongoDB.Driver.Tests/Encryption/ClientEncryptionTests.cs index 01ed41022a4..59fb5eba21a 100644 --- a/tests/MongoDB.Driver.Tests/Encryption/ClientEncryptionTests.cs +++ b/tests/MongoDB.Driver.Tests/Encryption/ClientEncryptionTests.cs @@ -49,6 +49,7 @@ public class ClientEncryptionTests [Fact] public async Task AddAlternateKeyName_should_correctly_handle_input_arguments() { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); RequireServer.Check().Supports(Feature.ClientSideEncryption); var guid = new Guid(); @@ -63,6 +64,7 @@ public async Task AddAlternateKeyName_should_correctly_handle_input_arguments() [Fact] public async Task CreateDataKey_should_correctly_handle_input_arguments() { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); RequireServer.Check().Supports(Feature.ClientSideEncryption); using (var subject = CreateSubject()) @@ -78,6 +80,8 @@ public async Task CreateDataKey_should_correctly_handle_input_arguments() [Fact] public async Task CreateEncryptedCollection_should_handle_input_arguments() { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); + const string kmsProvider = "local"; const string collectionName = "collName"; var createCollectionOptions = new CreateCollectionOptions(); @@ -119,6 +123,8 @@ public async Task CreateEncryptedCollection_should_handle_input_arguments() [Fact] public async Task CreateEncryptedCollection_should_handle_generated_key_when_second_key_failed() { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); + const string kmsProvider = "local"; const string collectionName = "collName"; const string encryptedFieldsStr = "{ fields : [{ keyId : null }, { keyId : null }] }"; @@ -210,6 +216,8 @@ datakeys have already been created by the helper. [InlineData("{ fields : [{ keyId : 3 }, { keyId : null }] }", "{ fields: [{ keyId : 3 }, { keyId : '#binary_generated#' }] }")] public async Task CreateEncryptedCollection_should_handle_various_encryptedFields(string encryptedFieldsStr, string expectedResult) { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); + const string kmsProvider = "local"; const string collectionName = "collName"; var serverId = new ServerId(__clusterId, __endPoint); @@ -287,6 +295,7 @@ public bool Equals(BsonDocument x, BsonDocument y) => [Fact] public void CryptClient_should_be_initialized() { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); RequireServer.Check().Supports(Feature.ClientSideEncryption); using (var subject = CreateSubject()) @@ -299,6 +308,7 @@ public void CryptClient_should_be_initialized() [Fact] public async Task Decrypt_should_correctly_handle_input_arguments() { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); RequireServer.Check().Supports(Feature.ClientSideEncryption); using (var subject = CreateSubject()) @@ -311,6 +321,7 @@ public async Task Decrypt_should_correctly_handle_input_arguments() [Fact] public async Task Encrypt_should_correctly_handle_input_arguments() { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); RequireServer.Check().Supports(Feature.ClientSideEncryption); using (var subject = CreateSubject()) @@ -327,6 +338,7 @@ public async Task Encrypt_should_correctly_handle_input_arguments() [ParameterAttributeData] public async Task Encryption_should_use_correct_binarySubType([Values(false, true)] bool async) { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); RequireServer.Check().Supports(Feature.ClientSideEncryption); using (var subject = CreateSubject()) @@ -347,6 +359,7 @@ public async Task Encryption_should_use_correct_binarySubType([Values(false, tru [Fact] public async Task GetKeyByAlternateKeyName_should_correctly_handle_input_arguments() { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); RequireServer.Check().Supports(Feature.ClientSideEncryption); using (var subject = CreateSubject()) @@ -359,6 +372,7 @@ public async Task GetKeyByAlternateKeyName_should_correctly_handle_input_argumen [Fact] public async Task RemoveAlternateKeyName_should_correctly_handle_input_arguments() { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); RequireServer.Check().Supports(Feature.ClientSideEncryption); var guid = new Guid(); @@ -373,6 +387,7 @@ public async Task RemoveAlternateKeyName_should_correctly_handle_input_arguments [Fact] public async Task RewrapManyDataKey_should_correctly_handle_input_arguments() { + RequireEnvironment.Check().EnvironmentVariable("FLE_AWS_KEY"); RequireServer.Check().Supports(Feature.ClientSideEncryption); using (var subject = CreateSubject()) @@ -391,7 +406,7 @@ private ClientEncryption CreateSubject(IMongoClient client = null) var clientEncryptionOptions = new ClientEncryptionOptions( client ?? DriverTestConfiguration.Client, __keyVaultCollectionNamespace, - kmsProviders: EncryptionTestHelper.GetKmsProviders(filter: "local")); + kmsProviders: EncryptionTestHelper.GetKmsProviders("local")); return new ClientEncryption(clientEncryptionOptions); } diff --git a/tests/MongoDB.Driver.Tests/MongoClientSettingsTests.cs b/tests/MongoDB.Driver.Tests/MongoClientSettingsTests.cs index 48bf2608fcb..90ac7dde6a9 100644 --- a/tests/MongoDB.Driver.Tests/MongoClientSettingsTests.cs +++ b/tests/MongoDB.Driver.Tests/MongoClientSettingsTests.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Net.Sockets; using System.Security.Authentication; using System.Text; @@ -726,6 +727,8 @@ public void TestFromUrlWithMongoDBX509_without_username() [ParameterAttributeData] public void TestFromUrlWithMongoDBAWS_should_parse_credentials_correctly([Values(false, true)] bool escapeToken) { + RequireEnvironment.Check().HostReachable(new DnsEndPoint("awssessiontokentest.example.net", 53)); + const string authMechanism = "MONGODB-AWS"; const string username = "AKIAIOSFODNN7EXAMPLE"; const string password = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY"; diff --git a/tests/MongoDB.Driver.Tests/MongoUrlTests.cs b/tests/MongoDB.Driver.Tests/MongoUrlTests.cs index 96a23b8240b..250cec9cec9 100644 --- a/tests/MongoDB.Driver.Tests/MongoUrlTests.cs +++ b/tests/MongoDB.Driver.Tests/MongoUrlTests.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Net; using System.Threading.Tasks; using FluentAssertions; using MongoDB.Driver.Core.Compression; @@ -66,6 +67,8 @@ public void constructor_with_string_should_set_isResolved_to_expected_value(stri [InlineData("mongodb+srv://test2.test.build.10gen.cc")] public void constructor_with_resolved_connection_string_should_initialize_resolved_instance(string url) { + RequireEnvironment.Check().HostReachable(new DnsEndPoint("test2.test.build.10gen.cc", 53)); + var connectionString = new ConnectionString(url); var resolvedConnectionString = connectionString.Resolve(); var builder = new MongoUrlBuilder(resolvedConnectionString); @@ -126,6 +129,8 @@ public void Resolve_with_resolveHosts_should_return_expected_result(string url, [InlineData("mongodb+srv://test1.test.build.10gen.cc/?srvMaxHosts=2", true, 2, true)] public void Resolve_with_srvMaxHosts_should_return_expected_result(string url, bool resolveHosts, int expectedSrvMaxHosts, bool async) { + RequireEnvironment.Check().HostReachable(new DnsEndPoint("test1.test.build.10gen.cc", 53)); + var subject = new MongoUrl(url); MongoUrl result; diff --git a/tests/MongoDB.Driver.Tests/ReadPreferenceOnStandaloneTests.cs b/tests/MongoDB.Driver.Tests/ReadPreferenceOnStandaloneTests.cs index fb507d13c37..130d0f15450 100644 --- a/tests/MongoDB.Driver.Tests/ReadPreferenceOnStandaloneTests.cs +++ b/tests/MongoDB.Driver.Tests/ReadPreferenceOnStandaloneTests.cs @@ -62,7 +62,9 @@ public void ReadPreference_should_not_be_sent_to_standalone_server( var clusterType = client.Cluster.Description.Type; - var expectedContainsReadPreference = clusterType != ClusterType.Standalone; + var expectedContainsReadPreference = clusterType != ClusterType.Standalone + || DriverTestConfiguration.GetClientSettings().DirectConnection; + var readPreferenceFieldName = sentCommand.Command.Contains("$readPreference") ? "$readPreference" : "readPreference"; diff --git a/tests/MongoDB.Driver.Tests/Search/AtlasSearchTests.cs b/tests/MongoDB.Driver.Tests/Search/AtlasSearchTests.cs index e4df3e98fe6..e2e6f8846c1 100644 --- a/tests/MongoDB.Driver.Tests/Search/AtlasSearchTests.cs +++ b/tests/MongoDB.Driver.Tests/Search/AtlasSearchTests.cs @@ -286,11 +286,13 @@ public AtlasSearchTests(ITestOutputHelper testOutputHelper) : base(testOutputHel _mongoClient = AtlasSearchTestsUtils.CreateAtlasSearchMongoClient(); } - protected override void DisposeInternal() => _mongoClient.Dispose(); + protected override void DisposeInternal() => _mongoClient?.Dispose(); [Fact] public void Autocomplete() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle(Builders.Search.Autocomplete(x => x.Title, "Declaration of Ind")); result.Title.Should().Be("Declaration of Independence"); @@ -299,6 +301,8 @@ public void Autocomplete() [Fact] public void Compound() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + const int score = 42; var searchDefinition = Builders.Search.Compound(Builders.SearchScore.Constant(score)) .Must(Builders.Search.Text(x => x.Body, "life"), Builders.Search.Text(x => x.Body, "liberty")) @@ -318,6 +322,8 @@ public void Compound() [Fact] public void Count_total() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var results = GetTestCollection().Aggregate() .Search( Builders.Search.Phrase(x => x.Body, "life, liberty, and the pursuit of happiness"), @@ -334,6 +340,8 @@ public void Count_total() [Fact] public void EmbeddedDocument() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var builderHistoricalDocument = Builders.Search; var builderComments = Builders.Search; @@ -354,6 +362,8 @@ public void EmbeddedDocument() [Fact] public void EqualsGuid() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var testGuid = Guid.Parse("b52af144-bc97-454f-a578-418a64fa95bf"); var result = GetExtraTestsCollection().Aggregate() @@ -366,6 +376,8 @@ public void EqualsGuid() [Fact] public void EqualsNull() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = GetExtraTestsCollection().Aggregate() .Search(Builders.Search.Equals(c => c.TestString, null)) .Single(); @@ -376,6 +388,8 @@ public void EqualsNull() [Fact] public void EqualsArrayField() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var results = GetMoviesCollection().Aggregate() .Search(Builders.Search.Equals(p => p.Genres, "family")) .Limit(3) @@ -395,6 +409,8 @@ public void EqualsArrayField() [Fact] public void EqualsStringField() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var results = GetMoviesCollection().Aggregate() .Search(Builders.Search.Equals(p => p.Title, "a corner in wheat")) .ToList(); @@ -405,6 +421,8 @@ public void EqualsStringField() [Fact] public void Exists() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle( Builders.Search.Compound().Must( Builders.Search.Text(x => x.Body, "life, liberty, and the pursuit of happiness"), @@ -416,6 +434,8 @@ public void Exists() [Fact] public void Filter() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle( Builders.Search.Compound().Filter( Builders.Search.Phrase(x => x.Body, "life, liberty"), @@ -435,6 +455,8 @@ public void Filter() [InlineData("relevance")] public void FunctionScore(string functionScoreType) { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var scoreFunction = functionScoreType switch { "add" => Builders.SearchScoreFunction.Add(Constant(1), Constant(2)), @@ -462,6 +484,8 @@ SearchScoreFunction Constant(double value) => [Fact] public void GeoShape() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var results = GeoSearch( GeoBuilders.Search.GeoShape( x => x.Address.Location, @@ -478,6 +502,8 @@ public void GeoShape() [InlineData("polygon")] public void GeoWithin(string geometryType) { + AtlasSearchTestsUtils.RequireAtlasSearch(); + GeoWithinArea geoArea = geometryType switch { "box" => __testBox, @@ -495,6 +521,8 @@ public void GeoWithin(string geometryType) [Fact] public void In() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var results = GetMoviesCollection() .Aggregate() .Search( @@ -511,6 +539,7 @@ public void In() [Fact] public void InGuid() { + AtlasSearchTestsUtils.RequireAtlasSearch(); var testGuids = new[] { Guid.Parse("b52af144-bc97-454f-a578-418a64fa95bf"), Guid.Parse("84da5d44-bc97-454f-a578-418a64fa937a") @@ -528,6 +557,8 @@ public void InGuid() [Fact] public void MoreLikeThis() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var likeThisDocument = new HistoricalDocument { Title = "Declaration of Independence", @@ -541,6 +572,8 @@ public void MoreLikeThis() [Fact] public void Must() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle( Builders.Search.Compound().Must( Builders.Search.Phrase(x => x.Body, "life, liberty"), @@ -552,6 +585,8 @@ public void Must() [Fact] public void MustNot() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle( Builders.Search.Compound().MustNot( Builders.Search.Phrase(x => x.Body, "life, liberty")), @@ -562,6 +597,8 @@ public void MustNot() [Fact] public void Near() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var results = GetGeoTestCollection().Aggregate() .Search(GeoBuilders.Search.Near(x => x.Address.Location, __testCircle.Center, 1000)) .Limit(1) @@ -573,6 +610,8 @@ public void Near() [Fact] public void Phrase() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + // This test case exercises the indexName and returnStoredSource arguments. The // remaining test cases omit them. var results = GetTestCollection().Aggregate() @@ -618,6 +657,8 @@ public void Phrase() [Fact] public void PhraseMultiPath() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle( Builders.Search.Phrase( Builders.SearchPath.Multi(x => x.Title, x => x.Body), @@ -629,6 +670,8 @@ public void PhraseMultiPath() [Fact] public void PhraseAnalyzerPath() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle( Builders.Search.Phrase( Builders.SearchPath.Analyzer(x => x.Body, "english"), @@ -640,6 +683,8 @@ public void PhraseAnalyzerPath() [Fact] public void PhraseSynonym() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = GetMoviesCollection().Aggregate() .Search( @@ -660,6 +705,8 @@ public void PhraseSynonym() [Fact] public void PhraseWildcardPath() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle( Builders.Search.Phrase( Builders.SearchPath.Wildcard("b*"), @@ -671,6 +718,8 @@ public void PhraseWildcardPath() [Fact] public void QueryString() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle(Builders.Search.QueryString(x => x.Body, "life, liberty, and the pursuit of happiness")); result.Title.Should().Be("Declaration of Independence"); @@ -679,6 +728,8 @@ public void QueryString() [Fact] public void Range() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var results = GeoSearch( GeoBuilders.Search.Compound().Must( GeoBuilders.Search.Range(x => x.Bedrooms, SearchRangeV2Builder.Gt(2).Lt(4)), @@ -690,6 +741,8 @@ public void Range() [Fact] public void RangeString() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var results = GetMoviesCollection().Aggregate() .Search(Builders.Search.Range(p => p.Title, SearchRangeV2Builder.Gt("city").Lt("country"))) .Limit(5) @@ -706,6 +759,8 @@ public void RangeString() [Fact] public void RankFusion() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + const int limit = 5; var vector = new[] { -0.00028408386, -0.030921403, 0.0017461961, -0.007926553, -0.008247016, 0.029273309, 0.0027844305, 0.0088290805, 0.0020862792, 0.001850837, 0.0004868257, 0.004914855, 0.030529, -0.033118863, 0.022419326, 0.0031359587, 0.030842923, -0.016101629, 0.018940013, -0.006186897, -0.008390897, 0.007514529, 0.008175075, -0.012380334, 0.007200606, 0.0015352791, 0.0071482854, -0.011484345, 0.007194066, -0.006736262, 0.0009049808, -0.01856069, 0.008959882, -0.02718049, -0.030031955, -0.012609236, -0.011432025, -0.000060597744, 0.0390834, -0.00019783681, 0.0071025053, 0.01747504, -0.015918506, -0.0062261373, -0.0049966057, 0.008534778, 0.009247645, -0.007959253, -0.04015597, 0.013838767, 0.013969569, 0.010934981, -0.0040025166, 0.0022285255, -0.0067820423, -0.008194695, -0.0096335085, 0.006209787, 0.010261354, -0.006445229, -0.0066839415, -0.0025702436, -0.0028007806, 0.0009164259, -0.012151431, -0.00014674259, 0.011314304, -0.019737901, 0.0068997634, 0.007331407, 0.036336575, -0.0021680298, 0.0024606977, -0.0007745884, 0.00985587, -0.0049573653, -0.022066163, -0.0065040896, -0.010745319, -0.008802921, 0.00021173444, -0.028880905, -0.021098234, 0.03481928, 0.03822011, 0.003809585, -0.011693628, 0.012726957, -0.012197211, 0.0019865432, -0.0028776263, -0.008436677, -0.0021631247, 0.0118375085, -0.0044962913, 0.002622564, -0.011360084, 0.00865904, -0.009659668, -0.027677534, -0.019397818, 0.0040875375, 0.011386245, -0.0011322479, 0.003714754, 0.005578671, 0.025218472, 0.012112191, 0.014623574, -0.002947932, 0.0041954485, 0.009456927, 0.018142127, -0.055878274, -0.014335811, -0.03162773, 0.0075733894, 0.015840026, 0.005258208, -0.015879266, 0.033354305, -0.004542072, -0.006638161, -0.0075930096, -0.011366624, 0.019332416, -0.019515539, -0.022445485, 0.005876244, -0.016559431, 0.018220607, -0.0039894367, 0.031209165, -0.0049737156, -0.020195706, 0.0175012, -0.024669107, 0.0014339081, -0.005912214, -0.015800785, 0.0117197875, 0.008161995, -0.00982971, -0.0023348015, -0.008292796, 0.035420965, -0.00040343995, 0.0022628608, 0.00032904677, -0.009273805, 0.01975098, -0.013420203, 0.016650993, -0.009143004, 0.024865309, 0.0035185523, 0.007305247, 0.024132822, -0.012635396, -0.0118375085, -0.00873098, 0.011706707, 0.0009687464, -0.012295313, 0.0057160123, 0.03508088, 0.003142499, 0.00035152823, 0.009476547, -0.028410021, -0.009908191, -0.0033109053, -0.009188784, 0.0148720965, -0.031183006, 0.022066163, 0.014021888, 0.022144644, -0.0108565, -0.008155455, -0.009005663, 0.025231551, 0.018966174, 0.009156084, -0.017017236, -0.017893605, -0.021320596, -0.008103134, 0.015840026, -0.013420203, 0.0027533653, 0.0054249796, -0.009339206, 0.0120271705, -0.6701207, -0.029901154, -0.012995099, -0.008050814, -0.005356309, 0.016977996, 0.021202875, -0.008207776, -0.006464849, 0.0027942406, -0.004453781, 0.027154328, -0.0054249796, -0.015905425, 0.0003684915, -0.011432025, 0.023544217, -0.024289783, 0.0054053594, -0.020313427, -0.03398215, 0.030031955, 0.020993592, -0.0015753369, -0.01965942, 0.0072725466, 0.02515307, -0.0078022913, -0.0094438465, 0.015683064, -0.022288524, 0.028880905, -0.0020388637, 0.009620428, 0.056296837, -0.02825306, -0.0049508256, 0.030319719, -0.020561948, 0.02189612, -0.009594268, -0.014885177, -0.004842914, -0.0040940777, 0.0069651636, -0.0061836266, 0.013564085, -0.0030018876, 0.023504976, 0.007946173, 0.00439492, 0.030895242, -0.007109045, -0.002619294, -0.0028759914, 0.008711359, 0.030215077, -0.013551004, 0.012406494, -0.010562196, -0.010503336, -0.0016023146, 0.005088167, 0.0026634394, -0.0011150802, 0.04154246, 0.015447621, 0.0417779, 0.016781794, -0.03377287, 0.037696905, 0.014466613, -0.0071417456, 0.017775884, -0.010137093, 0.0028972465, 0.024315942, -0.011026541, -0.008103134, -0.004470131, -0.0019244127, -0.0027975107, -0.025859397, -0.0050293063, 0.02404126, -0.012275693, -0.010719159, 0.01203371, 0.0030002524, 0.005892594, -0.008632879, 0.027154328, -0.0020241486, 0.000026620088, 0.007913472, -0.0123345535, 0.007821912, 0.0049508256, 0.0072463863, -0.039449643, 0.017592762, -0.034583837, 0.0058173835, -0.0136164045, 0.0045191813, -0.0022432406, -0.0027599053, 0.004872345, 0.061633524, -0.020287266, -0.008672119, 0.0023658667, 0.014440453, -0.004061377, -0.011785188, -0.02391046, 0.0074360482, 0.009411146, 0.030999884, -0.022602446, -0.0059449147, 0.016755633, 0.008417057, -0.014675895, 0.024760667, 0.015643824, -0.025950957, -0.01975098, -0.034688476, 0.013256702, -0.015853105, -0.004542072, 0.0031147036, -0.0036428133, 0.016167028, -0.0038815255, 0.013838767, -0.0061705466, 0.01963326, 0.0041006175, -0.008436677, 0.013276322, 0.011327384, -0.01757968, 0.00070837024, -0.029377948, -0.0011714882, -0.007501449, -0.04912893, 0.026591884, 0.017736642, -0.009371906, -0.015604583, 0.00028060944, 0.009581188, 0.00657276, -0.024826068, -0.006252297, -0.0038651754, -0.016729474, 0.01858685, 0.0048265643, -0.011628226, 0.011360084, -0.0044014603, -0.017736642, 0.016023146, 0.033171184, -0.008338576, -0.024211302, -0.009025283, -0.035525605, -0.02287713, 0.029037867, -0.002849831, -0.010627598, -0.0019881781, -0.022602446, -0.015316821, 0.008227396, -0.0026863297, 0.011700167, -0.00043777528, -0.001362785, 0.03604881, -0.0003721703, 0.00057225523, 0.017867444, -0.009757769, 0.037749227, -0.021516798, 0.027991457, 0.012864298, -0.011248903, -0.0052778283, 0.013498683, 0.008528238, 0.021137474, 0.008515158, 0.031339966, -0.001971828, -0.009947431, 0.028462341, -0.005150297, 0.020575028, -0.009522327, 0.0011649482, -0.028907064, 0.03508088, 0.003377941, 0.004287009, -0.024865309, 0.02064043, -0.0020192435, 0.006477929, 0.014911337, -0.005856624, 0.0015025787, -0.01629783, -0.0022285255, 0.019070815, -0.012426114, -0.01739656, -0.0031245137, -0.015539182, 0.02084971, 0.0005252486, 0.026539564, 0.006029935, -0.042222627, 0.013152061, 0.008031194, -0.015146779, 0.009221485, 0.022759408, -0.023060251, -0.0026634394, -0.015094458, 0.023295693, -0.014518933, 0.014924417, 0.026448002, 0.04350448, -0.010405235, -0.012184132, 0.014793616, 0.004015597, 0.00004401767, -0.019031575, 0.023714257, -0.017592762, 0.016873354, -0.012511135, 0.020391908, 0.0036297333, 0.012262613, 0.009430766, 0.0035545225, 0.022497807, 0.036336575, 0.0074229683, -0.013269782, 0.020221865, 0.021438317, 0.017972086, -0.013328643, 0.016821034, 0.009169164, 0.005117597, 0.024564466, -0.008037734, -0.01408729, -0.008070434, -0.00977085, 0.023884298, -0.0017412909, 0.006203247, -0.004578042, 0.013799527, -0.008279716, -0.013904167, -0.034296073, 0.020234946, 0.0153299, -0.011006921, -0.012753117, -0.015382221, 0.0047317334, -0.03144461, 0.013655645, -0.025715515, 0.012870838, -0.015055218, -0.011275063, 0.0025244632, -0.0068997634, 0.037696905, -0.005261478, 0.034296073, -0.021987682, 0.0059710746, 0.012746577, -0.02843618, -0.01739656, 0.011870209, -0.004018867, -0.024525225, -0.004571502, 0.0066774013, 0.005133947, -0.0029708222, -0.007534149, -0.0174358, 0.011190043, 0.0009000758, -0.012896998, -0.008541319, 0.013511764, 0.023884298, 0.009156084, -0.007095965, -0.032909583, -0.02733745, -0.002501573, 0.11887213, 0.017605841, 0.018390648, 0.013969569, 0.013577164, -0.004463591, -0.019358577, -0.018024405, 0.014100369, -0.0023462465, 0.005761793, -0.02281173, 0.002182745, 0.0037376443, 0.01747504, 0.00044840286, -0.022026923, -0.016101629, 0.013825687, -0.011772108, 0.0066970214, 0.0108892, -0.0031915493, 0.01631091, -0.021909202, -0.024172062, 0.008619799, 0.012569996, -0.008207776, -0.015042138, -0.015486862, -0.010542576, 0.0008943532, 0.021307515, -0.0015557167, 0.009476547, -0.00005768537, 0.011791728, 0.036388893, -0.0036657036, 0.023871219, 0.024747588, 0.0113404635, -0.037592266, 0.014819776, -0.005568861, 0.013825687, 0.017134957, 0.001968558, -0.021556038, 0.056453798, 0.0017069556, -0.009404606, 0.009842791, 0.02172608, -0.0067493417, 0.014728215, 0.00878984, -0.018286008, 0.01642863, 0.006304618, -0.023151813, 0.009731609, -0.0062457575, 0.011464725, -0.01866533, -0.009496167, 0.007403348, -0.011020001, 0.0038717154, 0.00972507, -0.031758532, -0.010228653, -0.015996987, 0.008384357, 0.0018998875, 0.020234946, -0.02733745, 0.018652251, 0.011229283, -0.0021189793, -0.014466613, -0.018246768, -0.014074209, -0.0106537575, 0.02817458, 0.013642565, 0.007749971, -0.006690481, 0.0053955493, 0.013851847, 0.009306505, 0.0070044044, -0.0015965921, -0.0022481456, -0.025767837, -0.0016824304, 0.02733745, -0.002951202, 0.018299088, 0.021320596, -0.028593142, 0.0017134957, -0.015552263, 0.036179613, -0.010954601, -0.014453532, -0.005362849, -0.025754755, 0.0014151054, -0.0055982913, -0.013551004, 0.0053922795, -0.009417687, 0.0050947065, 0.0112685235, 0.01861301, 0.025924798, 0.00058533537, -0.017723562, -0.008855241, -0.0075603095, 0.027075848, 0.016598672, -0.0017331159, -0.004211799, 0.01522526, -0.026644204, 0.018848453, 0.0065073594, -0.0028253058, -0.0076060896, 0.012550375, 0.0034008313, -0.030790603, 0.002516288, -0.021268275, 0.0025244632, -0.005313799, -0.0014077479, 0.0015107539, -0.009640048, -0.008253556, -0.023387255, -0.024368264, -0.027049689, -0.00092950603, 0.00087718555, 0.00011823202, 0.017723562, -0.0239497, -0.009947431, -0.00163992, 0.0102024935, -0.031078365, -0.04379224, -0.011870209, 0.0063569383, 0.0218438, 0.015905425, 0.034243755, -0.008430137, 0.03497624, 0.019463219, 0.0010153443, 0.00015430454, -0.0060626357, 0.013799527, -0.06629005, 0.036755137, 0.018756893, 0.011170423, 0.032569498, -0.008443218, 0.026107918, 0.010594897, -0.008933722, -0.014610494, -0.023622697, -0.011641307, 0.0030721931, -0.011229283, -0.00072063284, 0.012393414, -0.014597414, -0.015015977, 0.071522094, 0.017775884, -0.029220987, -0.0095157875, 0.023243373, -0.028985545, -0.0049704458, -0.0065073594, -0.006661051, -0.014963658, 0.020967431, -0.00006550279, -0.0013088295, 0.01975098, 0.009430766, 0.0014952212, 0.01962018, -0.009718529, 0.009267265, 0.039737403, 0.022013841, -0.0054347897, 0.010091312, -0.02718049, -0.023792738, -0.022746328, -0.026487242, -0.03573489, -0.017723562, 0.0049867956, -0.005673502, 0.009659668, -0.016821034, -0.0390834, 0.009509247, 0.014545093, 0.04007749, 0.0084497575, 0.02817458, 0.0099408915, -0.013472524, -0.016114708, 0.028148418, 0.015683064, -0.0009205134, 0.0010096218, 0.01844297, -0.001850837, -0.020823551, -0.01089574, 0.012341093, -0.04996606, -0.014335811, 0.015604583, -0.009156084, -0.00436876, -0.008855241, -0.016860275, 0.0019244127, 0.014100369, -0.02504843, 0.010424855, 0.001983273, -0.030921403, -0.047925558, -0.011942149, -0.014558174, 0.0027811604, 0.010509877, -0.0136164045, 0.0014894987, 0.0009164259, 0.0106995385, 0.014597414, 0.020483468, 0.004143128, -0.0028759914, -0.0067035616, 0.007769591, -0.020470388, -0.00028776264, -0.00763879, 0.0091364635, 0.027023528, 0.00545441, 0.01083688, -0.004649983, 0.01625859, -0.007213686, 0.0111508025, -0.001973463, -0.01090882, -0.015866185, -0.0050391164, 0.011418945, 0.015434542, -0.020692749, -0.013152061, -0.022223124, 0.0023609616, -0.01858685, -0.012641936, 0.019031575, -0.014532013, -0.0054871105, -0.0094438465, 0.005022766, 0.0053824694, 0.017252678, 0.0034923921, -0.0151991, 0.017710483, -0.04245807, 0.008881401, 0.0034825818, 0.0064942795, -0.015748464, -0.0071352054, 0.011301223, -0.0069324635, 0.01408729, -0.038743313, -0.019293176, -0.014702055, -0.009208404, 0.00432952, -0.021477558, -0.010640678, 0.010012832, 0.015094458, 0.009280345, -0.02077123, -0.02494379, 0.012635396, 0.0021238844, -0.011752488, 0.028619302, -0.024773747, 0.007965793, 0.008848701, 0.013969569, 0.006860523, -0.034191433, -0.00011067008, -0.008175075, 0.017815124, 0.0091364635, -0.012962399, -0.019855622, -0.013387503, -0.022367004, 0.021385996, 0.013943408, -0.021542957, 0.010019372, 0.027703693, 0.0058500837, -0.0016202999, 0.0306598, -0.0012123636, 0.006111686, -0.023217212, -0.028540822, -0.014034969, -0.0067820423, 0.030738281, 0.003590493, -0.004908315, -0.032988064, -0.0035316325, -0.041804064, 0.0141134495, -0.022000762, 0.0136164045, 0.030764442, -0.0040057865, 0.0040548374, 0.021242116, 0.010065152, -0.0031310536, -0.029848834, -0.0050587365, -0.0028563712, -0.0018328518, -0.003597033, 0.014793616, -0.019554779, -0.0020143385, 0.029874993, -0.0034302615, -0.006455039, 0.014728215, -0.034479197, -0.009731609, -0.010725698, 0.015591503, 0.0067951223, 0.0044308905, 0.009509247, -0.012301853, 0.0017707213, -0.00058697036, 0.010097853, -0.012386873, -0.0082600955, 0.0023969319, -0.0043033594, 0.028854745, -0.0066839415, -0.006742802, -0.00549365, -0.021137474, 0.017331159, -0.011392784, -0.0044308905, 0.01747504, 0.0050521963, -0.03413911, -0.028828584, 0.0075799297, 0.014832856, -0.014571253, 0.0045191813, -0.0038847956, 0.02172608, -0.008462838, 0.018809212, -0.016611753, 0.009156084, -0.02393662, 0.0037180241, -0.03563025, 0.0262518, 0.010032452, -0.01523834, -0.0015123888, 0.0066774013, -0.0015393667, -0.024054341, -0.025506234, -0.010477176, -0.0048559946, -0.0070305644, -0.010869579, -0.017252678, -0.029953474, 0.0061738165, -0.024420584, -0.04258887, 0.00983625, 0.21576966, -0.004787324, 0.0048592645, 0.012046791, -0.014924417, 0.024669107, 0.036493536, 0.016951835, -0.0010063518, -0.0034596918, -0.009299966, 0.008299336, -0.014832856, 0.0019113325, -0.0090645235, -0.018926933, -0.037435304, -0.0015508117, -0.016768714, -0.018756893, 0.021869961, -0.00439492, -0.003606843, -0.010280974, 0.015983906, -0.0073771877, -0.0032471397, 0.0007529244, 0.0005877879, -0.0003386525, -0.006314428, -0.031026045, -0.0051045166, -0.016533272, -0.013577164, -0.004048297, 0.0063536684, 0.005035846, -0.0060887956, 0.015643824, 0.02494379, 0.015042138, -0.015787704, 0.002517923, -0.015316821, 0.0149898175, -0.008364737, -0.01752736, 0.010254814, 0.006435419, -0.024185142, -0.01083688, 0.016624833, 0.051718794, -0.0037572645, -0.00067485246, 0.010575277, 0.022353925, 0.007429508, 0.004564962, -0.005689852, 0.019044654, 0.006186897, 0.019842543, -0.024381343, 0.018992335, -0.048788846, 0.005163377, 0.023034092, -0.021699918, -0.006723182, -0.036022652, -0.012138351, -0.01204025, -0.0103921555, -0.0348716, 0.018024405, 0.008959882, 0.013158601, -0.007043645, 0.00870482, 0.0023282613, 0.008024653, 0.004247769, -0.017252678, -0.020470388, 0.033406626, 0.0104640955, -0.011660927, 0.0021663948, 0.0018230417, -0.02943027, 0.0013913978, -0.0047480837, 0.013184761, 0.032386377, -0.0060855257, -0.001146963, -0.006978244, -0.0086852, -0.018338328, -0.036205772, 0.0196071, -0.01417885, -0.021608358, 0.0071679056, -0.0008632879, 0.012256073, 0.039449643, -0.030712122, -0.0015181114, -0.0136164045, 0.0074360482, -0.010326754, 0.022523966, 0.015395301, -0.011713248, -0.02067967, 0.0015311915, -0.018979253, -0.007318327, -0.038560193, -0.01304088, -0.008914102, -0.010692998, -0.028017618, 0.003175199, 0.020143384, 0.04052221, -0.014034969, 0.028200738, -0.03612729, -0.012936238, -0.0063536684, 0.008358196, 0.00763225, 0.005778143, -0.006886683, 0.010241734, 0.011347004, 0.021215955, 0.01746196, 0.00326022, -0.010287514, 0.016873354, -0.011490885, 0.012144892, 0.0038488253, -0.0055230805, 0.001145328, -0.015552263, -0.024747588, 0.004551882, -0.0039796266, 0.03709522, -0.021032833, -0.020418067, -0.016127788, -0.0037899648, 0.00014061129, -0.016716393, 0.013027799, 0.0050489265, -0.018142127, -0.011732868, 0.01852145, -0.16721626, 0.024682187, 0.008887942, 0.002089549, 0.041908704, -0.002836751, 0.01644171, -0.009646588, -0.008044274, 0.002403472, 0.004103888, -0.00068098377, -0.0370429, -0.0032520448, -0.005133947, 0.007063265, -0.010712618, 0.008606719, 0.019437058, 0.0027811604, 0.0071352054, -0.0064910096, 0.0055525107, 0.007763051, 0.011046161, 0.012968939, 0.009384986, -0.016624833, -0.010228653, -0.014963658, -0.009463467, -0.0031375939, 0.011674007, 0.0144927725, 0.024224382, 0.0009205134, -0.013269782, -0.017605841, -0.0122887725, 0.012779277, 0.005261478, 0.014244251, 0.013263241, -0.004829834, 0.014702055, 0.04805636, 0.003606843, 0.0020143385, -0.0008780031, -0.012347633, 0.006304618, -0.029744193, 0.008135835, 0.00035193696, 0.023871219, 0.022353925, 0.010006292, -0.012831598, 0.014754375, -0.03272646, -0.009201865, 0.0013251797, 0.009522327, -0.014675895, -0.025571635, -0.015879266, -0.004022137, 0.0018819022, -0.02956107, 0.019737901, -0.036781296, -0.013348263, 0.02623872, -0.017893605, 0.006177087, -0.0050718165, -0.014715135, 0.006958624, -0.010071692, -0.0097054485, -0.038455553, 0.03361591, 0.003809585, -0.008436677, 0.014061129, 0.0005665327, -0.0033109053, -0.014675895, -0.013721046, -0.030947564, -0.0021124394, -0.016088547, -0.011922529, -0.03152309, 0.020575028, 0.029325629, -0.0003155579, 0.0038913356, 0.012491515, -0.011883289, -0.009404606, 0.018037485, -0.021477558, 0.020431148, 0.030764442, 0.02510075, 0.021987682, 0.0077761314, 0.042981274, -0.0045322618, -0.0073902677, 0.008574018, -0.002056849, 0.027625212, -0.0017592761, 0.019214695, 0.010019372, -0.020012584, 0.04146398, -0.019201616, 0.03897876, 0.0049671754, -0.02935179, 0.021072073, -0.021490637, -0.010287514, -0.106419854, -0.0026716145, -0.019018494, 0.013171681, -0.0020094335, 0.010640678, -0.0046401727, 0.012321473, -0.0073771877, 0.008390897, -0.0058533535, -0.0218438, 0.019123135, -0.013930327, 0.035342485, 0.000036966667, -0.015460702, 0.0045682318, -0.023191053, 0.015813865, -0.010542576, 0.005549241, 0.0137341255, -0.013407123, 0.012962399, -0.0041202377, -0.032255575, 0.0044374308, 0.007534149, 0.00766495, -0.01194869, -0.015604583, 0.01836449, -0.020182624, 0.0030934485, -0.001960383, -0.030110436, 0.0072725466, 0.034400716, -0.033668227, 0.009175704, 0.009620428, 0.0027942406, -0.017932845, 0.006458309, 0.0027746204, -0.008384357, 0.012419574, -0.0028988817, -0.027546732, -0.030738281, 0.00016186648, -0.029848834, 0.007939633, 0.017344238, 0.0048690746, 0.0046532527, 0.008927182, 0.028017618, 0.005791223, -0.0019947183, -0.01314552, 0.002277576, 0.00044431532, -0.0069847843, -0.0079527125, -0.014976737, 0.011732868, 0.00035398075, -0.0018017865, 0.010137093, 0.021359837, -0.008220855, 0.008632879, -0.037775386, 0.020195706, -0.013995728, 0.0012401589, 0.013799527, -0.017815124, -0.007920013, -0.021346755, 0.009993211, -0.01633707, 0.006873603, 0.004810214, 0.0032896502, -0.00025383607, -0.010163253, -0.012275693, 0.0037605346, -0.008999122, -0.011817888, -0.03623193, -0.021242116, 0.015826944, 0.0061607365, -0.0064975494, -0.0067951223, -0.012393414, -0.013551004, 0.008626339, -0.06644701, 0.024656026, 0.0024590625, -0.00020263967, -0.002517923, -0.012798897, 0.016925676, -0.0026814246, -0.004296819, -0.005748713, -0.0056931223, 0.02725897, 0.0030967183, -0.002411647, -0.006736262, -0.019463219, -0.00075496815, -0.008488998, 0.016572513, 0.011360084, 0.009489627, 0.012504594, 0.001317822, 0.007926553, -0.0066185407, -0.0020862792, -0.0036885939, 0.021569118, -0.0022138103, 0.0018606471, -0.009646588, -0.023491895, -0.010732238, 0.0017592761, 0.0011714882, 0.008273176, -0.001744561, 0.0064942795, 0.01635015, 0.06372634, -0.02731129, -0.014571253, 0.010294055, -0.011052702, -0.019267017, 0.0031441338, 0.008593638, 0.007893852, 0.03495008, -0.019175455, 0.016703313, 0.037644584, -0.00975123, 0.00041938134, -0.00976431, -0.0039730864, 0.018181367, -0.00050440215, 0.014767455, -0.0042379587, 0.02524463, -0.0049966057, 0.009280345, 0.014924417, -0.0012115461, -0.029874993, -0.0132370815, -0.010006292, 0.0035152822, -0.016206268, -0.004914855, -0.023675017, -0.0016619927, 0.005330149, -0.004453781, 0.0003075872, -0.0053857393, -0.0017069556, -0.008384357, 0.021516798, -0.006232677, 0.0031097985, -0.042039506, 0.00438184, 0.024917629, 0.001138788, 0.006853983, 0.015696144, -0.013348263, 0.016114708, -0.010791099, 0.017867444, -0.0035185523, 0.022445485, -0.014270411, 0.014963658, -0.040705334, -0.007279087, 0.01627167, 0.012373794, 0.0070567247, 0.0008632879, 0.0070567247, -0.011588986, -0.011772108, 0.0046140123, -0.032229416, -0.043059755, -0.011013461, 0.004780784, 0.023635777, -0.016546352, -0.013034339, 0.011445105, -0.005814113, 0.00977085, -0.0045061014, -0.002202365, -0.017200358, 0.014675895, 0.007501449, 0.00761917, 0.014021888, 0.0014012079, 0.002275941, 0.015630743, 0.010405235, -0.004264119, -0.009424226, -0.02506151, -0.0010733873, 0.0074949088, -0.01963326, 0.00031433164, -0.018063646, -0.017383479, 0.0000909988, 0.018050566, -0.027102008, 0.028645463, -0.008332036, 0.0029528372, 0.014702055, -0.027154328, 0.021909202, 0.0034466116, 0.03897876, -0.0031228787, -0.015015977, 0.0062915375, -0.035604086, 0.02185688, 0.008613259, -0.008194695, 0.030188916, -0.0010096218, 0.0070174844, 0.0066970214, 0.004607472, 0.022000762, 0.012655016, 0.0087179, -0.007279087, -0.016860275, 0.000018994277, 0.0010177968, 0.01618011, -0.012046791, -0.035473283, 0.013361342, -0.0067035616, -0.013577164, 0.012825058, -0.007965793, -0.021699918, 0.011588986, -0.007161366, -0.0050652763, -0.00540863, -0.019123135, 0.026304122, -0.0042150686, -0.022393165, -0.013943408, 0.00078439846, -0.005801033, -0.00087555056, -0.027232809 }; @@ -737,6 +792,8 @@ public void RankFusion() [Fact] public void SearchSequenceToken() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + const int limitVal = 10; var titles = new[] { @@ -809,6 +866,8 @@ public void SearchSequenceToken() [Fact] public void Search_count_lowerBound() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var results = GetTestCollection().Aggregate() .Search( Builders.Search.Phrase(x => x.Body, "life, liberty, and the pursuit of happiness"), @@ -826,6 +885,8 @@ public void Search_count_lowerBound() [Fact] public void SearchMeta_count() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = GetTestCollection().Aggregate() .SearchMeta( Builders.Search.Phrase(x => x.Body, "life, liberty, and the pursuit of happiness"), @@ -841,6 +902,8 @@ public void SearchMeta_count() [Fact] public void SearchMeta_facet() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = GetTestCollection().Aggregate() .SearchMeta(Builders.Search.Facet( Builders.Search.Phrase(x => x.Body, "life, liberty, and the pursuit of happiness"), @@ -867,6 +930,8 @@ public void SearchMeta_facet() [Fact] public void Should() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle( Builders.Search.Compound().Should( Builders.Search.Phrase(x => x.Body, "life, liberty"), @@ -878,6 +943,8 @@ public void Should() [Fact] public void Sort() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle( Builders.Search.Text(x => x.Body, "liberty"), Builders.Projection.Include(x => x.Title), @@ -889,6 +956,8 @@ public void Sort() [Fact] public void Sort_MetaSearchScore() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var results = GetMoviesCollection().Aggregate() .Search( Builders.Search.QueryString(x => x.Title, "dance"), @@ -909,6 +978,8 @@ public void Sort_MetaSearchScore() [InlineData("subtract")] public void Span(string spanType) { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var spanDefinition = spanType switch { "first" => Builders.SearchSpan.First(Term("happiness"), 250), @@ -927,6 +998,8 @@ public void Span(string spanType) [Fact] public void Text() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle(Builders.Search.Text(x => x.Body, "life, liberty, and the pursuit of happiness")); result.Title.Should().Be("Declaration of Independence"); @@ -935,6 +1008,8 @@ public void Text() [Fact] public void TextMatchCriteria() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = GetMoviesCollection().Aggregate() .Search( @@ -957,6 +1032,8 @@ public void TextMatchCriteria() [InlineData("boat", "transportSynonyms", "And the Ship Sails On")] public void Synonyms(string query, string synonym, string expected) { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var sortDefinition = Builders.Sort.Ascending(x => x.Title); var result = GetMoviesCollection().Aggregate() @@ -972,6 +1049,8 @@ public void Synonyms(string query, string synonym, string expected) [Fact] public void SynonymsMappings() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var automobileAndAttireSearchResults = SearchMultipleSynonymMapping( Builders.Search.Text(x => x.Title, "automobile", "transportSynonyms"), Builders.Search.Text(x => x.Title, "attire", "attireSynonyms")); @@ -1000,6 +1079,8 @@ public void SynonymsMappings() [Fact] public void VectorSearch() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var expectedTitles = new[] { "Willy Wonka & the Chocolate Factory", @@ -1022,6 +1103,8 @@ public void VectorSearch() [Fact] public void VectorSearch_Limit() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var expectedTitles = new[] { "Willy Wonka & the Chocolate Factory", @@ -1043,6 +1126,8 @@ public void VectorSearch_Limit() [Fact] public void VectorSearch_Filter() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var expectedTitles = new[] { "Time Bandits", @@ -1071,6 +1156,8 @@ public void VectorSearch_Filter() [Fact] public void VectorSearch_Exact() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var expectedTitles = new[] { "Willy Wonka & the Chocolate Factory", @@ -1098,6 +1185,8 @@ public void VectorSearch_Exact() [Fact] public void VectorSearch_ProjectAndScore() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var expectedTitles = new[] { "Time Bandits", @@ -1130,6 +1219,8 @@ public void VectorSearch_ProjectAndScore() [Fact] public void VectorSearch_ProjectAndCount() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var expectedTitles = new[] { "Time Bandits", @@ -1161,6 +1252,8 @@ public void VectorSearch_ProjectAndCount() [Fact] public void Wildcard() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var result = SearchSingle(Builders.Search.Wildcard(x => x.Body, "tranquil*", true)); result.Title.Should().Be("US Constitution"); diff --git a/tests/MongoDB.Driver.Tests/Search/AtlasSearchTestsUtils.cs b/tests/MongoDB.Driver.Tests/Search/AtlasSearchTestsUtils.cs index b09b0b9762a..a77b5fb8330 100644 --- a/tests/MongoDB.Driver.Tests/Search/AtlasSearchTestsUtils.cs +++ b/tests/MongoDB.Driver.Tests/Search/AtlasSearchTestsUtils.cs @@ -21,9 +21,16 @@ namespace MongoDB.Driver.Tests.Search; public static class AtlasSearchTestsUtils { + public static void RequireAtlasSearch() + => RequireEnvironment.Check().EnvironmentVariable("ATLAS_SEARCH_TESTS_ENABLED"); + public static IMongoClient CreateAtlasSearchMongoClient() { - RequireEnvironment.Check().EnvironmentVariable("ATLAS_SEARCH_TESTS_ENABLED"); + var testsEnabled = Environment.GetEnvironmentVariable("ATLAS_SEARCH_TESTS_ENABLED"); + if (string.IsNullOrWhiteSpace(testsEnabled) || testsEnabled == "0") + { + return null; + } var atlasSearchUri = Environment.GetEnvironmentVariable("ATLAS_SEARCH_URI"); Ensure.IsNotNullOrEmpty(atlasSearchUri, nameof(atlasSearchUri)); diff --git a/tests/MongoDB.Driver.Tests/Search/AutoEmbedVectorSearchTests.cs b/tests/MongoDB.Driver.Tests/Search/AutoEmbedVectorSearchTests.cs index 2174571fca3..d1269f1dd46 100644 --- a/tests/MongoDB.Driver.Tests/Search/AutoEmbedVectorSearchTests.cs +++ b/tests/MongoDB.Driver.Tests/Search/AutoEmbedVectorSearchTests.cs @@ -40,24 +40,93 @@ public class AutoEmbedVectorSearchTests : LoggableTestClass public AutoEmbedVectorSearchTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { - SkipTests(); + if (SkipTestsBool()) + { + return; + } _mongoClient = AtlasSearchTestsUtils.CreateAtlasSearchMongoClient(); + if (_mongoClient == null) + { + return; + } _collection = _mongoClient.GetDatabase("dotnet-test").GetCollection(GetRandomName()); _autoEmbedIndexName = GetRandomName(); _collection.InsertMany([ - new Movie { Title = "Tigers on the Moon", Plot = "Tigers escape from a moonbase and run amok in the lunar dust.", Runtime = 60, Year = 1986 }, - new Movie { Title = "Red Dawn", Plot = "A group of teenagers form a guerrilla army to fight off an invading force.", Runtime = 114, Year = 1984 }, - new Movie { Title = "Sands of Iwo Jima", Plot = "A tough sergeant leads his platoon of recruits through the battle of Iwo Jima.", Runtime = 100, Year = 1949 }, - new Movie { Title = "White Tiger", Plot = "A Russian tank commander searches for a mysterious German tank during WWII.", Runtime = 104, Year = 2012 }, - new Movie { Title = "P-51 Dragon Fighter", Plot = "Allied pilots in North Africa must fight off a swarm of Nazi dragons.", Runtime = 85, Year = 2014 }, - new Movie { Title = "When Trumpets Fade", Plot = "A soldier's struggle for survival during the Battle of Hurtgen Forest.", Runtime = 95, Year = 1998 }, - new Movie { Title = "The Great Escape", Plot = "Allied prisoners of war plan a massive escape from a German camp.", Runtime = 172, Year = 1963 }, - new Movie { Title = "Saving Private Ryan", Plot = "Soldiers go behind enemy lines to rescue a paratrooper whose brothers have been killed.", Runtime = 169, Year = 1998 }, - new Movie { Title = "Dunkirk", Plot = "Allied soldiers from Belgium, the British Empire, and France are surrounded by the German Army.", Runtime = 106, Year = 2017 }, - new Movie { Title = "Fury", Plot = "A battle-hardened sergeant and his tank crew fight their way across Germany.", Runtime = 134, Year = 2014 } + new Movie + { + Title = "Tigers on the Moon", + Plot = "Tigers escape from a moonbase and run amok in the lunar dust.", + Runtime = 60, + Year = 1986 + }, + new Movie + { + Title = "Red Dawn", + Plot = "A group of teenagers form a guerrilla army to fight off an invading force.", + Runtime = 114, + Year = 1984 + }, + new Movie + { + Title = "Sands of Iwo Jima", + Plot = "A tough sergeant leads his platoon of recruits through the battle of Iwo Jima.", + Runtime = 100, + Year = 1949 + }, + new Movie + { + Title = "White Tiger", + Plot = "A Russian tank commander searches for a mysterious German tank during WWII.", + Runtime = 104, + Year = 2012 + }, + new Movie + { + Title = "P-51 Dragon Fighter", + Plot = "Allied pilots in North Africa must fight off a swarm of Nazi dragons.", + Runtime = 85, + Year = 2014 + }, + new Movie + { + Title = "When Trumpets Fade", + Plot = "A soldier's struggle for survival during the Battle of Hurtgen Forest.", + Runtime = 95, + Year = 1998 + }, + new Movie + { + Title = "The Great Escape", + Plot = "Allied prisoners of war plan a massive escape from a German camp.", + Runtime = 172, + Year = 1963 + }, + new Movie + { + Title = "Saving Private Ryan", + Plot = + "Soldiers go behind enemy lines to rescue a paratrooper whose brothers have been killed.", + Runtime = 169, + Year = 1998 + }, + new Movie + { + Title = "Dunkirk", + Plot = + "Allied soldiers from Belgium, the British Empire, and France are surrounded by the German Army.", + Runtime = 106, + Year = 2017 + }, + new Movie + { + Title = "Fury", + Plot = "A battle-hardened sergeant and his tank crew fight their way across Germany.", + Runtime = 134, + Year = 2014 + } ]); _collection.SearchIndexes.CreateOne(new CreateAutoEmbeddingVectorSearchIndexModel( @@ -83,6 +152,7 @@ public AutoEmbedVectorSearchTests(ITestOutputHelper testOutputHelper) : base(tes } private void SkipTests() => throw new SkipException("Test skipped because of CSHARP-5840."); + private bool SkipTestsBool() => true; private bool TryGetIndex( IMongoCollection collection, string indexName, out BsonDocument indexDefinition) @@ -95,13 +165,15 @@ private bool TryGetIndex( protected override void DisposeInternal() { - _collection.Database.DropCollection(_collection.CollectionNamespace.CollectionName); - _mongoClient.Dispose(); + _collection?.Database.DropCollection(_collection?.CollectionNamespace.CollectionName); + _mongoClient?.Dispose(); } [Fact(Timeout = Timeout)] public async Task VectorSearchAutoEmbed() { + SkipTests(); + var expectedTitles = new[] { "Tigers on the Moon", "Dunkirk", "P-51 Dragon Fighter", "Red Dawn", "Fury" @@ -132,6 +204,8 @@ public async Task VectorSearchAutoEmbed() [Fact(Timeout = Timeout)] public async Task VectorSearchAutoEmbed_Filters() { + SkipTests(); + var expectedTitles = new[] { "Dunkirk", "P-51 Dragon Fighter", "White Tiger", "When Trumpets Fade" @@ -169,6 +243,8 @@ public async Task VectorSearchAutoEmbed_Filters() [Fact(Timeout = Timeout)] public async Task VectorSearchAutoEmbed_Exact() { + SkipTests(); + var expectedTitles = new[] { "Tigers on the Moon", "Dunkirk", "P-51 Dragon Fighter", "Red Dawn", "Fury" diff --git a/tests/MongoDB.Driver.Tests/Search/VectorSearchTests.cs b/tests/MongoDB.Driver.Tests/Search/VectorSearchTests.cs index 8e164b36cc3..7ccb64e36b1 100644 --- a/tests/MongoDB.Driver.Tests/Search/VectorSearchTests.cs +++ b/tests/MongoDB.Driver.Tests/Search/VectorSearchTests.cs @@ -38,13 +38,21 @@ public VectorSearchTests(ITestOutputHelper testOutputHelper) : base(testOutputHe _mongoClient = AtlasSearchTestsUtils.CreateAtlasSearchMongoClient(); } - protected override void DisposeInternal() => _mongoClient.Dispose(); + protected override void DisposeInternal() => _mongoClient?.Dispose(); - [Theory] - [MemberData(nameof(BinaryVectorSearchTestData))] - public void BinaryVectorSearch(BinaryVector binaryVector, string fieldName) + [Fact] + public void BinaryVectorSearch_Int8() + => BinaryVectorSearch(new BinaryVectorInt8(new sbyte[] { 0, 1, 2, 3, 4 }), "int8Vector"); + + [Fact] + public void BinaryVectorSearch_Float32() + => BinaryVectorSearch(new BinaryVectorFloat32(new float[] { 0.0001f, 1.12345f, 2.23456f, 3.34567f, 4.45678f }), "float32Vector"); + + private void BinaryVectorSearch(BinaryVector binaryVector, string fieldName) where T : struct { + AtlasSearchTestsUtils.RequireAtlasSearch(); + const int Limit = 5; var collection = _mongoClient.GetDatabase("csharpExtraTests").GetCollection("binaryVectorTests"); @@ -62,15 +70,11 @@ public void BinaryVectorSearch(BinaryVector binaryVector, string fieldName result[0].Score.Should().Be(1); } - public static IEnumerable BinaryVectorSearchTestData => - [ - [new BinaryVectorInt8(new sbyte[] { 0, 1, 2, 3, 4 }), "int8Vector"], - [new BinaryVectorFloat32(new float[] { 0.0001f, 1.12345f, 2.23456f, 3.34567f, 4.45678f }), "float32Vector"], - ]; - [Fact] public void VectorSearch() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var expectedTitles = new[] { "Willy Wonka & the Chocolate Factory", @@ -103,6 +107,8 @@ public void VectorSearch() [Fact] public void VectorSearchExact() { + AtlasSearchTestsUtils.RequireAtlasSearch(); + var expectedTitles = new[] { "Red Dawn", @@ -135,6 +141,7 @@ public void VectorSearchExact() [Fact] public void VectorSearch_on_embedded_documents() { + AtlasSearchTestsUtils.RequireAtlasSearch(); SkipTests(); var nestedVectorCollection = diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/EncryptionTestHelper.cs b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/EncryptionTestHelper.cs index 38b4d94549b..e3d2e8d8be9 100644 --- a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/EncryptionTestHelper.cs +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/EncryptionTestHelper.cs @@ -15,6 +15,7 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -25,124 +26,96 @@ using MongoDB.Driver.Core.Misc; using MongoDB.Driver.Encryption; using MongoDB.Driver.TestHelpers; +using MongoDB.TestHelpers.XunitExtensions; namespace MongoDB.Driver.Tests.Specifications.client_side_encryption { public static class EncryptionTestHelper { - private static readonly Lazy>> __kmsProviders = new Lazy>>(ConfigureDefaultKmsProviders, isThreadSafe: true); + private static readonly ConcurrentDictionary> __kmsProviders = new(); private const string KmsProviderFilterDelimiter = ";"; private static readonly string __defaultMongocryptdPath = Environment.GetEnvironmentVariable("MONGODB_BINARIES") ?? ""; - private static readonly Lazy<(bool IsValid, SemanticVersion Version)> __defaultCsfleSetupState = new Lazy<(bool IsValid, SemanticVersion Version)>(IsDefaultCsfleSetupValid, isThreadSafe: true); + private static readonly Lazy<(bool IsValid, SemanticVersion Version)> __defaultCsfleSetupState = new(IsDefaultCsfleSetupValid, isThreadSafe: true); - private static IReadOnlyDictionary> ConfigureDefaultKmsProviders() + private static IReadOnlyDictionary CreateKmsProvider(string name) { - var kmsProviders = new Dictionary> + return name switch { + "aws" => new Dictionary { - "aws", new Dictionary - { - { "accessKeyId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AWS_KEY") }, - { "secretAccessKey", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AWS_SECRET") } - } + { "accessKeyId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AWS_KEY") }, + { "secretAccessKey", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AWS_SECRET") } }, + "aws:name1" => new Dictionary { - "aws:name1", new Dictionary - { - { "accessKeyId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AWS_KEY") }, - { "secretAccessKey", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AWS_SECRET") } - } + { "accessKeyId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AWS_KEY") }, + { "secretAccessKey", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AWS_SECRET") } }, + "aws:name2" => new Dictionary { - "aws:name2", new Dictionary - { - { "accessKeyId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AWS_KEY2") }, - { "secretAccessKey", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AWS_SECRET2") } - } + { "accessKeyId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AWS_KEY2") }, + { "secretAccessKey", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AWS_SECRET2") } }, + "local" => new Dictionary { - "local", new Dictionary - { - { "key", new BsonBinaryData(Convert.FromBase64String(LocalMasterKey)).Bytes } - } + { "key", new BsonBinaryData(Convert.FromBase64String(LocalMasterKey)).Bytes } }, + "local:name1" => new Dictionary { - "local:name1", new Dictionary - { - { "key", new BsonBinaryData(Convert.FromBase64String(LocalMasterKey)).Bytes } - } + { "key", new BsonBinaryData(Convert.FromBase64String(LocalMasterKey)).Bytes } }, + "local:name2" => new Dictionary { - "local:name2", new Dictionary - { - { "key", new BsonBinaryData(Convert.FromBase64String(LocalMasterKey)).Bytes } - } + { "key", new BsonBinaryData(Convert.FromBase64String(LocalMasterKey)).Bytes } }, + "azure" => new Dictionary { - "azure", new Dictionary - { - { "tenantId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AZURE_TENANTID") }, - { "clientId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AZURE_CLIENTID") }, - { "clientSecret", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AZURE_CLIENTSECRET") } - } + { "tenantId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AZURE_TENANTID") }, + { "clientId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AZURE_CLIENTID") }, + { "clientSecret", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AZURE_CLIENTSECRET") } }, + "azure:name1" => new Dictionary { - "azure:name1", new Dictionary - { - { "tenantId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AZURE_TENANTID") }, - { "clientId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AZURE_CLIENTID") }, - { "clientSecret", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AZURE_CLIENTSECRET") } - } + { "tenantId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AZURE_TENANTID") }, + { "clientId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AZURE_CLIENTID") }, + { "clientSecret", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_AZURE_CLIENTSECRET") } }, + "gcp" => new Dictionary { - "gcp", new Dictionary - { - { "email", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_GCP_EMAIL") }, - { "privateKey", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_GCP_PRIVATEKEY") } - } + { "email", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_GCP_EMAIL") }, + { "privateKey", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_GCP_PRIVATEKEY") } }, + "gcp:name1" => new Dictionary { - "gcp:name1", new Dictionary - { - { "email", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_GCP_EMAIL") }, - { "privateKey", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_GCP_PRIVATEKEY") } - } + { "email", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_GCP_EMAIL") }, + { "privateKey", GetEnvironmentVariableOrDefaultOrThrowIfNothing("FLE_GCP_PRIVATEKEY") } }, + "kmip" => new Dictionary { { "endpoint", "localhost:5698" } }, + "kmip:name1" => new Dictionary { { "endpoint", "localhost:5698" } }, + "awsTemporary" => new Dictionary { - "kmip", new Dictionary { - { "endpoint", "localhost:5698" } - } + "accessKeyId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("CSFLE_AWS_TEMP_ACCESS_KEY_ID") + }, + { + "secretAccessKey", + GetEnvironmentVariableOrDefaultOrThrowIfNothing("CSFLE_AWS_TEMP_SECRET_ACCESS_KEY") + }, + { "sessionToken", GetEnvironmentVariableOrDefaultOrThrowIfNothing("CSFLE_AWS_TEMP_SESSION_TOKEN") } }, + "awsTemporaryNoSessionToken" => new Dictionary { - "kmip:name1", new Dictionary { - { "endpoint", "localhost:5698" } + "accessKeyId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("CSFLE_AWS_TEMP_ACCESS_KEY_ID") + }, + { + "secretAccessKey", + GetEnvironmentVariableOrDefaultOrThrowIfNothing("CSFLE_AWS_TEMP_SECRET_ACCESS_KEY") } - } + }, + _ => throw new ArgumentException($"Unsupported KMS provider: {name}.", nameof(name)) }; - if (Environment.GetEnvironmentVariable("CSFLE_AWS_TEMPORARY_CREDS_ENABLED") != null) - { - kmsProviders.Add( - "awsTemporary", - new Dictionary - { - { "accessKeyId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("CSFLE_AWS_TEMP_ACCESS_KEY_ID") }, - { "secretAccessKey", GetEnvironmentVariableOrDefaultOrThrowIfNothing("CSFLE_AWS_TEMP_SECRET_ACCESS_KEY") }, - { "sessionToken", GetEnvironmentVariableOrDefaultOrThrowIfNothing("CSFLE_AWS_TEMP_SESSION_TOKEN") } - }); - kmsProviders.Add( - "awsTemporaryNoSessionToken", - new Dictionary - { - { "accessKeyId", GetEnvironmentVariableOrDefaultOrThrowIfNothing("CSFLE_AWS_TEMP_ACCESS_KEY_ID") }, - { "secretAccessKey", GetEnvironmentVariableOrDefaultOrThrowIfNothing("CSFLE_AWS_TEMP_SECRET_ACCESS_KEY") } - }); - } - - return kmsProviders; - string GetEnvironmentVariableOrDefaultOrThrowIfNothing(string variableName, string defaultValue = null) => Environment.GetEnvironmentVariable(variableName) ?? defaultValue ?? @@ -289,18 +262,16 @@ public static SslSettings CreateTlsOptionsIfAllowed( return null; } - public static IReadOnlyDictionary> GetKmsProviders(string filter = null) => - __kmsProviders - .Value - .Where(kms => filter == null || filter.Split(new[] { KmsProviderFilterDelimiter }, StringSplitOptions.None).Contains(kms.Key)) - .ToDictionary( - k => k.Key, - v => (IReadOnlyDictionary)v.Value.ToDictionary(ik => ik.Key, iv => iv.Value)); // ensure that inner dictionary is a new instance + public static IReadOnlyDictionary> GetKmsProviders(string names) + => names.Split([KmsProviderFilterDelimiter], StringSplitOptions.None).Distinct().ToDictionary( + n => n, + n => (IReadOnlyDictionary)__kmsProviders + .GetOrAdd(n, CreateKmsProvider) + .ToDictionary(k => k.Key, v => v.Value)); // ensure that inner dictionary is a new instance public static IReadOnlyDictionary> ParseKmsProviders(BsonDocument kmsProviders, bool legacy = false) { var providers = new Dictionary>(); - var kmsProvidersFromEnvs = GetKmsProviders(); foreach (var kmsProvider in kmsProviders.Elements) { var kmsOptions = new Dictionary(); @@ -333,7 +304,8 @@ public static IReadOnlyDictionary> P if (legacy) { kmsProviderDocument.ElementCount.Should().Be(0); - kmsOptions = (Dictionary)kmsProvidersFromEnvs[kmsProvider.Name]; + RequireEnvironment.Check().RequireKmsProviders(kmsProvider.Name); + kmsOptions = (Dictionary)GetKmsProviders(kmsProvider.Name); } else { @@ -364,7 +336,12 @@ public static IReadOnlyDictionary> P return providers; bool IsPlaceholder(BsonValue value) => value.IsBsonDocument && value.AsBsonDocument.Contains("$$placeholder"); - string GetFromEnvVariables(string kmsProvider, string key) => kmsProvidersFromEnvs[kmsProvider][key].ToString(); + string GetFromEnvVariables(string kmsProvider, string key) + { + RequireEnvironment.Check().RequireKmsProviders(kmsProvider); + + return GetKmsProviders(kmsProvider)[key].ToString(); + } } // private methods @@ -379,7 +356,7 @@ private static (bool IsValid, SemanticVersion MongocryptdVersion) IsDefaultCsfle var dummyNamespace = CollectionNamespace.FromFullName("db.dummy"); var autoEncryptionOptions = new AutoEncryptionOptions( dummyNamespace, - kmsProviders: GetKmsProviders(filter: "local"), + kmsProviders: GetKmsProviders("local"), extraOptions: new Dictionary() { { "cryptSharedLibPath", cryptSharedLibPath } }); var mongoClientSettings = new MongoClientSettings diff --git a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs index 5b5143b8872..14be2871f4d 100644 --- a/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs +++ b/tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/prose-tests/ClientEncryptionProseTests.cs @@ -703,6 +703,8 @@ public void CreateDataKeyAndDoubleEncryptionTest( RequireEnvironment.Check().EnvironmentVariable("KMS_MOCK_SERVERS_ENABLED", isDefined: true); } + RequireEnvironment.Check().RequireKmsProviders(kmsProvider); + using (var client = ConfigureClient()) using (var clientEncrypted = ConfigureClientEncrypted(BsonDocument.Parse(SchemaMap), kmsProviderFilter: kmsProvider)) using (var clientEncryption = ConfigureClientEncryption(clientEncrypted, kmsProviderFilter: kmsProvider)) @@ -795,6 +797,8 @@ public void CustomEndpointTest( RequireEnvironment.Check().EnvironmentVariable("KMS_MOCK_SERVERS_ENABLED", isDefined: true); } + RequireEnvironment.Check().RequireKmsProviders(kmsType); + using (var client = ConfigureClient()) using (var clientEncryption = ConfigureClientEncryption(client, ValidKmsEndpointConfigurator, kmsProviderFilter: kmsType)) using (var clientEncryptionInvalid = ConfigureClientEncryption(client, InvalidKmsEndpointConfigurator, kmsProviderFilter: kmsType)) @@ -2467,6 +2471,8 @@ public void RewrapTest( RequireEnvironment.Check().EnvironmentVariable("KMS_MOCK_SERVERS_ENABLED", isDefined: true); } + RequireEnvironment.Check().RequireKmsProviders(kmsProviderFilter); + const string value = "test"; using (var client1 = ConfigureClient(clearCollections: true)) @@ -3054,6 +3060,7 @@ public void UnsupportedPlatformsTests( [Values("gcp")] string kmsProvider, // the rest kms providers are supported on all supported TFs [Values(false, true)] bool async) { + RequireEnvironment.Check().EnvironmentVariable("FLE_GCP_EMAIL"); RequireServer.Check().Supports(Feature.ClientSideEncryption); using (var clientEncrypted = ConfigureClientEncrypted(kmsProviderFilter: kmsProvider)) @@ -3193,7 +3200,7 @@ private MongoClientSettings ConfigureClientEncryptedSettings( bool? retryReads = null, CollectionNamespace keyVaultCollectionNamespace = null) { - var kmsProviders = EncryptionTestHelper.GetKmsProviders(filter: kmsProviderFilter); + var kmsProviders = EncryptionTestHelper.GetKmsProviders(kmsProviderFilter); var tlsOptions = EncryptionTestHelper.CreateTlsOptionsIfAllowed( kmsProviders, // only kmip currently requires tls configuration for ClientEncrypted @@ -3232,7 +3239,7 @@ private ClientEncryption ConfigureClientEncryption( if (kmsDocument == null) { kmsProviders = EncryptionTestHelper - .GetKmsProviders(filter: kmsProviderFilter) + .GetKmsProviders(kmsProviderFilter) .Select(k => { if (kmsProviderConfigurator != null) diff --git a/tests/MongoDB.Driver.Tests/Specifications/initial-dns-seedlist-discovery/InitialDnsSeedlistDiscoveryTestRunner.cs b/tests/MongoDB.Driver.Tests/Specifications/initial-dns-seedlist-discovery/InitialDnsSeedlistDiscoveryTestRunner.cs index 1240f8ec908..c0f2c20dcff 100644 --- a/tests/MongoDB.Driver.Tests/Specifications/initial-dns-seedlist-discovery/InitialDnsSeedlistDiscoveryTestRunner.cs +++ b/tests/MongoDB.Driver.Tests/Specifications/initial-dns-seedlist-discovery/InitialDnsSeedlistDiscoveryTestRunner.cs @@ -39,6 +39,8 @@ public class InitialDnsSeedlistDiscoveryTestRunner [ClassData(typeof(TestCaseFactory))] public void RunTestDefinition(TestCase testCase) { + RequireEnvironment.Check().HostReachable(new DnsEndPoint("test2.test.build.10gen.cc", 53)); + ConnectionString connectionString = null; Exception resolveException = Record.Exception(() => connectionString = new ConnectionString((string)testCase.Definition["uri"]).Resolve()); Assert(connectionString, resolveException, testCase.Definition); @@ -48,6 +50,8 @@ public void RunTestDefinition(TestCase testCase) [ClassData(typeof(TestCaseFactory))] public async Task RunTestDefinitionAsync(TestCase testCase) { + RequireEnvironment.Check().HostReachable(new DnsEndPoint("test2.test.build.10gen.cc", 53)); + ConnectionString connectionString = null; Exception resolveException = await Record.ExceptionAsync(async () => connectionString = await new ConnectionString((string)testCase.Definition["uri"]).ResolveAsync()); Assert(connectionString, resolveException, testCase.Definition); diff --git a/tests/MongoDB.TestHelpers/XunitExtensions/RequireEnvironment.cs b/tests/MongoDB.TestHelpers/XunitExtensions/RequireEnvironment.cs index ac6692867b4..0e6dbbe5b06 100644 --- a/tests/MongoDB.TestHelpers/XunitExtensions/RequireEnvironment.cs +++ b/tests/MongoDB.TestHelpers/XunitExtensions/RequireEnvironment.cs @@ -65,6 +65,54 @@ public RequireEnvironment ProcessStarted(string processName) throw new SkipException($"Test skipped because an OS process {processName} has not been detected."); } + public RequireEnvironment RequireKmsProviders(string names) + { + foreach (var name in names.Split([";"], StringSplitOptions.None)) + { + switch (name) + { + case "aws": + case "aws:name1": + EnvironmentVariable("FLE_AWS_KEY"); + EnvironmentVariable("FLE_AWS_SECRET"); + break; + case "aws:name2": + EnvironmentVariable("FLE_AWS_KEY2"); + EnvironmentVariable("FLE_AWS_SECRET2"); + break; + case "azure": + case "azure:name1": + EnvironmentVariable("FLE_AZURE_TENANTID"); + EnvironmentVariable("FLE_AZURE_CLIENTID"); + EnvironmentVariable("FLE_AZURE_CLIENTSECRET"); + break; + case "gcp": + case "gcp:name1": + EnvironmentVariable("FLE_GCP_EMAIL"); + EnvironmentVariable("FLE_GCP_PRIVATEKEY"); + break; + case "awsTemporary": + EnvironmentVariable("CSFLE_AWS_TEMP_SESSION_TOKEN"); + goto case "awsTemporaryNoSessionToken"; + case "awsTemporaryNoSessionToken": + EnvironmentVariable("CSFLE_AWS_TEMP_ACCESS_KEY_ID"); + EnvironmentVariable("CSFLE_AWS_TEMP_SECRET_ACCESS_KEY"); + break; + case "local": + case "local:name1": + case "local:name2": + case "kmip": + case "kmip:name1": + break; + default: + throw new NotImplementedException($"KMS provider {name} is not not known."); + } + } + + return this; + } + + public RequireEnvironment HostReachable(DnsEndPoint endPoint) { if (IsReachable()) diff --git a/tests/SmokeTests/MongoDB.Driver.SmokeTests.Sdk/LibmongocryptTests.cs b/tests/SmokeTests/MongoDB.Driver.SmokeTests.Sdk/LibmongocryptTests.cs index 037b9e3b2b8..6c461bc6a7e 100644 --- a/tests/SmokeTests/MongoDB.Driver.SmokeTests.Sdk/LibmongocryptTests.cs +++ b/tests/SmokeTests/MongoDB.Driver.SmokeTests.Sdk/LibmongocryptTests.cs @@ -59,7 +59,7 @@ public void Explicit_encryption_with_libmongocrypt_package_works() kmsProviders.Add("local", localKey); var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault"); - var keyVaultMongoClient = new MongoClient(); + var keyVaultMongoClient = new MongoClient(InfrastructureUtilities.MongoUri); var clientEncryptionSettings = new ClientEncryptionOptions( keyVaultMongoClient, keyVaultNamespace,