Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/Delete_build_and_test_on_main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Delete build main

on:
push:
branches:
branches:
- master
paths:
- 'Frends.MongoDB.Delete/**'
Expand Down
18 changes: 18 additions & 0 deletions .github/workflows/Index_build_and_test_on_main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Index build main

on:
push:
branches:
- master
paths:
- 'Frends.MongoDB.Index/**'
workflow_dispatch:

jobs:
build:
uses: FrendsPlatform/FrendsTasks/.github/workflows/linux_build_main.yml@main
with:
workdir: Frends.MongoDB.Index
prebuild_command: docker-compose -f ./Frends.MongoDB.Index.Tests/Files/docker-compose.yml up -d
secrets:
badge_service_api_key: ${{ secrets.BADGE_SERVICE_API_KEY }}
19 changes: 19 additions & 0 deletions .github/workflows/Index_build_and_test_on_push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Index build test

on:
push:
branches-ignore:
- master
paths:
- 'Frends.MongoDB.Index/**'
workflow_dispatch:

jobs:
build:
uses: FrendsPlatform/FrendsTasks/.github/workflows/linux_build_test.yml@main
with:
workdir: Frends.MongoDB.Index
prebuild_command: docker-compose -f ./Frends.MongoDB.Index.Tests/Files/docker-compose.yml up -d
secrets:
badge_service_api_key: ${{ secrets.BADGE_SERVICE_API_KEY }}
test_feed_api_key: ${{ secrets.TASKS_TEST_FEED_API_KEY }}
12 changes: 12 additions & 0 deletions .github/workflows/Index_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Index release

on:
workflow_dispatch:

jobs:
build:
uses: FrendsPlatform/FrendsTasks/.github/workflows/release.yml@main
with:
workdir: Frends.MongoDB.Index
secrets:
feed_api_key: ${{ secrets.TASKS_FEED_API_KEY }}
2 changes: 1 addition & 1 deletion .github/workflows/Insert_build_and_test_on_main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Insert build main

on:
push:
branches:
branches:
- master
paths:
- 'Frends.MongoDB.Insert/**'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/Query_build_and_test_on_main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Query build main

on:
push:
branches:
branches:
- master
paths:
- 'Frends.MongoDB.Query/**'
Expand Down
12 changes: 12 additions & 0 deletions Frends.MongoDB.Delete/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## [2.0.0] - 2025-03-12
### Added
- Adds caching for the MongoClient connection to improve performance.

### Updated
- Updated MongoDB.Driver to version 3.2.1

### Breaking changes
- The MongoDB driver drops support for MongoDB Server v3.6 and earlier.
- The MongoDB driver drops support for .NET Core 2.x and .NET Framework 4.6.
- Read more about MongoDB driver 3.0 breaking changes [here](https://mongodb.github.io/mongo-csharp-driver/3.0/reference/breaking_changes/)

## [1.0.1] - 2023-11-22
### Fixed
- Fixed dll error when importing the Task to Frends by adding local dll reference to the project file.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: '3'
services:
mongo:
image: mongo:3
image: mongo:7
environment:
- AUTH=yes
- MONGO_INITDB_ROOT_USERNAME=admin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,15 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.8.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.8.2" />
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.22.0" />
<PackageReference Include="MongoDB.Driver.Core" Version="2.22.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Frends.MongoDB.Delete\Frends.MongoDB.Delete.csproj" />
Expand Down
103 changes: 56 additions & 47 deletions Frends.MongoDB.Delete/Frends.MongoDB.Delete.Tests/UnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,23 @@ namespace Frends.MongoDB.Delete.Tests;
[TestClass]
public class UnitTests
{
/// <summary>
/// Run command 'docker-compose up -d' in \Frends.MongoDB.Delete.Tests\Files\
/// </summary>

private static readonly Connection _connection = new()
{
ConnectionString = "mongodb://admin:Salakala@localhost:27017/?authSource=admin",
Database = "testdb",
CollectionName = "testcoll",
};

private readonly string _doc1 = "{ \"foo\":\"bar\", \"bar\": \"foo\" }";
private readonly string _doc2 = "{ \"foo\":\"bar\", \"bar\": \"foo\" }";
private readonly string _doc3 = "{ \"qwe\":\"rty\", \"asd\": \"fgh\" }";

/// <summary>
/// Run command 'docker-compose up -d' in \Frends.MongoDB.Delete.Tests\Files\
/// </summary>

private static readonly Connection _connection = new()
{
ConnectionString = "mongodb://admin:Salakala@localhost:27017/?authSource=admin",
Database = "testdb",
CollectionName = "testcoll",
};

private readonly List<string> _documents = new()
{
"{ 'foo':'bar', 'bar': 'foo' }",
"{ 'foo':'bar', 'bar': 'foo' }",
"{ 'qwe':'rty', 'asd': 'fgh' }"
};

[TestInitialize]
public void StartUp()
Expand Down Expand Up @@ -184,38 +186,45 @@ public void Test_InvalidConnectionString()
Assert.IsTrue(ex.Result.Message.StartsWith("Delete error: System.Exception: DeleteOperation error: MongoDB.Driver.MongoAuthenticationException: Unable to authenticate using sasl protocol mechanism SCRAM-SHA-1."));
}

private void InsertTestData()
{
try
{
var collection = GetMongoCollection(_connection.ConnectionString, _connection.Database, _connection.CollectionName);

var doc1 = BsonDocument.Parse(_doc1);
var doc2 = BsonDocument.Parse(_doc2);
var doc3 = BsonDocument.Parse(_doc3);

collection.InsertOne(doc1);
collection.InsertOne(doc2);
collection.InsertOne(doc3);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
private static void DeleteTestData()
{
var collection = GetMongoCollection(_connection.ConnectionString, _connection.Database, _connection.CollectionName);

var filter1 = "{'bar':'foo'}";
var filter2 = "{'qwe':'rty'}";
var filter3 = "{'asd':'fgh'}";
collection.DeleteMany(filter1);
collection.DeleteMany(filter2);
collection.DeleteMany(filter3);
}

private static IMongoCollection<BsonDocument> GetMongoCollection(string connectionString, string database, string collectionName)
private void InsertTestData()
{
try
{
var collection = GetMongoCollection(_connection.ConnectionString, _connection.Database, _connection.CollectionName);

foreach (var doc in _documents)
{
collection.InsertOne(BsonDocument.Parse(doc));
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}

private static void DeleteTestData()
{
var collection = GetMongoCollection(_connection.ConnectionString, _connection.Database, _connection.CollectionName);

List<string> filters = new()
{
"{'bar':'foo'}",
"{'qwe':'rty'}",
"{'asd':'fgh'}",
"{foo:'update'}",
"{'foobar':'upsert_create'}",
"{'array':'arr'}"
};

foreach (var filter in filters)
{
collection.DeleteMany(filter);
}
}


private static IMongoCollection<BsonDocument> GetMongoCollection(string connectionString, string database, string collectionName)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Update method signature in GetMongoCollection

This method should be updated to match the signature changes in the main Delete.cs file, which now includes collection name in the GetMongoDatabase method call.

-private static IMongoCollection<BsonDocument> GetMongoCollection(string connectionString, string database, string collectionName)
+private static IMongoCollection<BsonDocument> GetMongoCollection(string connectionString, string database, string collectionName)
 {
-    var dataBase = GetMongoDatabase(connectionString, database);
+    var dataBase = GetMongoDatabase(connectionString, database, collectionName);
     var collection = dataBase.GetCollection<BsonDocument>(collectionName);
     return collection;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private static IMongoCollection<BsonDocument> GetMongoCollection(string connectionString, string database, string collectionName)
private static IMongoCollection<BsonDocument> GetMongoCollection(string connectionString, string database, string collectionName)
{
var dataBase = GetMongoDatabase(connectionString, database, collectionName);
var collection = dataBase.GetCollection<BsonDocument>(collectionName);
return collection;
}

{
var dataBase = GetMongoDatabase(connectionString, database);
var collection = dataBase.GetCollection<BsonDocument>(collectionName);
Expand Down
98 changes: 62 additions & 36 deletions Frends.MongoDB.Delete/Frends.MongoDB.Delete/Delete.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
using MongoDB.Driver;
using System.IO;
using System.Threading.Tasks;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Caching;
using System.Linq;

namespace Frends.MongoDB.Delete;

Expand All @@ -14,15 +17,18 @@ namespace Frends.MongoDB.Delete;
/// </summary>
public class MongoDB
{
/// <summary>
/// MongoDB delete operation.
/// [Documentation](https://tasks.frends.com/tasks/frends-tasks/Frends.MongoDB.Delete)
/// </summary>
/// <param name="input">Input parameters.</param>
/// <param name="connection">Connection parameters.</param>
/// <param name="cancellationToken">Token generated by Frends to stop this task.</param>
/// <returns>Object { bool Success, long Count }</returns>
public static async Task<Result> Delete([PropertyTab] Input input, [PropertyTab] Connection connection, CancellationToken cancellationToken)
internal static readonly ObjectCache ClientCache = MemoryCache.Default;
private static readonly CacheItemPolicy _cachePolicy = new() { SlidingExpiration = TimeSpan.FromHours(1) };

/// <summary>
/// MongoDB delete operation.
/// [Documentation](https://tasks.frends.com/tasks/frends-tasks/Frends.MongoDB.Delete)
/// </summary>
/// <param name="input">Input parameters.</param>
/// <param name="connection">Connection parameters.</param>
/// <param name="cancellationToken">Token generated by Frends to stop this task.</param>
/// <returns>Object { bool Success, long Count }</returns>
public static async Task<Result> Delete([PropertyTab] Input input, [PropertyTab] Connection connection, CancellationToken cancellationToken)
{
var collection = GetMongoCollection(connection.ConnectionString, connection.Database, connection.CollectionName);

Expand All @@ -41,7 +47,10 @@ public static async Task<Result> Delete([PropertyTab] Input input, [PropertyTab]
}

case InputType.Filter:
return new Result(true, await DeleteOperation(input, BsonDocument.Parse(input.Filter), collection, cancellationToken));
if (string.IsNullOrWhiteSpace(input.Filter))
throw new ArgumentException("Filter string missing.");

return new Result(true, await DeleteOperation(input, BsonDocument.Parse(input.Filter), collection, cancellationToken));

case InputType.Filters:
long count = 0;
Expand Down Expand Up @@ -80,31 +89,48 @@ private static async Task<long> DeleteOperation(Input input, BsonDocument filter
}
}

private static IMongoCollection<BsonDocument> GetMongoCollection(string connectionString, string database, string collectionName)
{
try
{
var dataBase = GetMongoDatabase(connectionString, database);
var collection = dataBase.GetCollection<BsonDocument>(collectionName);
return collection;
}
catch (Exception ex)
{
throw new Exception($"GetMongoCollection error: {ex}");
}
}
private static IMongoCollection<BsonDocument> GetMongoCollection(string connectionString, string database, string collectionName)
{
try
{
var dataBase = GetMongoDatabase(connectionString, database, collectionName);
var collection = dataBase.GetCollection<BsonDocument>(collectionName);
return collection;
}
catch (Exception ex)
{
throw new Exception($"GetMongoCollection error: {ex}");
}
}

private static IMongoDatabase GetMongoDatabase(string connectionString, string database)
{
try
{
var mongoClient = new MongoClient(connectionString);
var dataBase = mongoClient.GetDatabase(database);
return dataBase;
}
catch (Exception ex)
{
throw new Exception($"GetMongoDatabase error: {ex}");
}
}
private static IMongoDatabase GetMongoDatabase(string connectionString, string database, string collectionName)
{
var cacheKey = GetMongoDbCacheKey(connectionString, database, collectionName);

if (ClientCache.Get(cacheKey) is IMongoDatabase mongoDatabase)
{
return mongoDatabase;
}

try
{
var mongoClient = new MongoClient(connectionString);
var dataBase = mongoClient.GetDatabase(database);

ClientCache.Add(cacheKey, dataBase, _cachePolicy);

return dataBase;
}
catch (Exception ex)
{
throw new Exception($"GetMongoDatabase error: {ex}");
}
}


[ExcludeFromCodeCoverage]
private static string GetMongoDbCacheKey(string connectionString, string database, string collectionName)
{
return $"{connectionString.GetHashCode()}:{database}:{collectionName}";
}
Comment on lines +92 to +135
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

❓ Verification inconclusive

Consider unit tests for caching behavior

While the caching implementation looks good, ensure that unit tests verify the caching behavior works as expected - particularly that connections are reused when expected and that expired cache entries are properly recreated.


🏁 Script executed:

#!/bin/bash
# Check if there are tests covering the caching functionality
rg -A 5 "ClientCache" --glob "*.Tests.cs"

Length of output: 190


Here’s a new shell script to re-verify whether any test files (using a more relaxed filename filter) reference caching (i.e. the ClientCache usage):

Please run this script and share its output so we can further validate whether caching behavior is covered by unit tests.


🏁 Script executed:

#!/bin/bash
# Searching for caching test references using a relaxed glob pattern.
rg -A 5 "ClientCache" --glob "*test*.cs"

Length of output: 311


Action: Add unit tests to verify caching behavior

While the caching implementation itself appears solid, my investigation did not uncover any tests verifying that the caching works as intended. Please confirm manually if tests exist elsewhere; otherwise, ensure that unit tests are added covering the following scenarios:

  • Connection reuse: Verify that multiple calls with the same connection parameters yield a reused instance from the cache.
  • Cache expiration: Test that expired cache entries lead to a correct re-creation of the database connection.

}
Loading