Skip to content

Commit f974707

Browse files
authored
Merge pull request #50 from dacharyc/csharp-test-suite-poc
C# test suite PoC
2 parents 1fe29cc + 1c77041 commit f974707

File tree

12 files changed

+393
-0
lines changed

12 files changed

+393
-0
lines changed

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,12 @@ node_modules
2828

2929
# Mongosh temporary files
3030
temp
31+
32+
# C# Debug files
33+
Debug/
34+
35+
# NuGet generated artifact files
36+
obj/
37+
38+
# User-specific settings files from JetBrains Rider and ReSharper
39+
*.DotSettings.user
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// :replace-start: {
2+
// "terms": {
3+
// "_order": "order",
4+
// "_aggDb": "aggDb"
5+
// }
6+
// }
7+
8+
namespace Examples.Aggregation;
9+
10+
using MongoDB.Driver;
11+
using MongoDB.Bson;
12+
13+
public class GroupTotal
14+
{
15+
private IMongoDatabase? _aggDB;
16+
private IMongoCollection<Order>? _orders;
17+
18+
public void LoadSampleData()
19+
{
20+
var uri = DotNetEnv.Env.GetString("CONNECTION_STRING", "Env variable not found. Verify you have a .env file with a valid connection string.");
21+
// :snippet-start: connection-string
22+
// :uncomment-start:
23+
//var uri = "mongodb+srv://mongodb-example:27017";
24+
// :uncomment-end:
25+
// :snippet-end:
26+
var client = new MongoClient(uri);
27+
_aggDB = client.GetDatabase("agg_tutorials_db");
28+
// :snippet-start: add-sample-data
29+
_orders = _aggDB.GetCollection<Order>("orders");
30+
_orders.DeleteMany(Builders<Order>.Filter.Empty);
31+
32+
_orders.InsertMany(new List<Order>
33+
{
34+
new Order
35+
{
36+
CustomerId = "[email protected]",
37+
OrderDate = DateTime.Parse("2020-05-30T08:35:52Z"),
38+
Value = 231
39+
},
40+
new Order
41+
{
42+
CustomerId = "[email protected]",
43+
OrderDate = DateTime.Parse("2020-01-13T09:32:07Z"),
44+
Value = 99
45+
},
46+
new Order
47+
{
48+
CustomerId = "[email protected]",
49+
OrderDate = DateTime.Parse("2020-01-01T08:25:37Z"),
50+
Value = 63
51+
},
52+
new Order
53+
{
54+
CustomerId = "[email protected]",
55+
OrderDate = DateTime.Parse("2019-05-28T19:13:32Z"),
56+
Value = 2
57+
},
58+
new Order
59+
{
60+
CustomerId = "[email protected]",
61+
OrderDate = DateTime.Parse("2020-11-23T22:56:53Z"),
62+
Value = 187
63+
},
64+
new Order
65+
{
66+
CustomerId = "[email protected]",
67+
OrderDate = DateTime.Parse("2020-08-18T23:04:48Z"),
68+
Value = 4
69+
},
70+
new Order
71+
{
72+
CustomerId = "[email protected]",
73+
OrderDate = DateTime.Parse("2020-12-26T08:55:46Z"),
74+
Value = 4
75+
},
76+
new Order
77+
{
78+
CustomerId = "[email protected]",
79+
OrderDate = DateTime.Parse("2021-02-28T07:49:32Z"),
80+
Value = 1024
81+
},
82+
new Order
83+
{
84+
CustomerId = "[email protected]",
85+
OrderDate = DateTime.Parse("2020-10-03T13:49:44Z"),
86+
Value = 102
87+
}
88+
});
89+
// :snippet-end:
90+
}
91+
92+
public List<BsonDocument> PerformAggregation()
93+
{
94+
if (_aggDB == null || _orders == null)
95+
{
96+
throw new InvalidOperationException("You must call LoadSampleData before performing aggregation.");
97+
}
98+
99+
// :snippet-start: match
100+
var results = _orders.Aggregate()
101+
.Match(o => o.OrderDate >= DateTime.Parse("2020-01-01T00:00:00Z") && o.OrderDate < DateTime.Parse("2021-01-01T00:00:00Z"))
102+
// :snippet-end:
103+
// :snippet-start: sort-order-date
104+
.SortBy(o => o.OrderDate)
105+
// :snippet-end:
106+
// :snippet-start: group
107+
.Group(
108+
o => o.CustomerId,
109+
g => new
110+
{
111+
CustomerId = g.Key,
112+
FirstPurchaseDate = g.First().OrderDate,
113+
TotalValue = g.Sum(i => i.Value),
114+
TotalOrders = g.Count(),
115+
Orders = g.Select(i => new { i.OrderDate, i.Value }).ToList()
116+
}
117+
)
118+
// :snippet-end:
119+
// :snippet-start: sort-first-order
120+
.SortBy(c => c.FirstPurchaseDate)
121+
.As<BsonDocument>();
122+
// :snippet-end:
123+
124+
foreach (var result in results.ToList())
125+
{
126+
Console.WriteLine(result);
127+
}
128+
129+
return results.ToList();
130+
}
131+
}
132+
// :replace-end:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{ "CustomerId" : "[email protected]", "FirstPurchaseDate" : { "$date" : "2020-01-01T08:25:37Z" }, "TotalValue" : 63, "TotalOrders" : 1, "Orders" : [{ "OrderDate" : { "$date" : "2020-01-01T08:25:37Z" }, "Value" : 63 }] }
2+
{ "CustomerId" : "[email protected]", "FirstPurchaseDate" : { "$date" : "2020-01-13T09:32:07Z" }, "TotalValue" : 436, "TotalOrders" : 4, "Orders" : [{ "OrderDate" : { "$date" : "2020-01-13T09:32:07Z" }, "Value" : 99 }, { "OrderDate" : { "$date" : "2020-05-30T08:35:52Z" }, "Value" : 231 }, { "OrderDate" : { "$date" : "2020-10-03T13:49:44Z" }, "Value" : 102 }, { "OrderDate" : { "$date" : "2020-12-26T08:55:46Z" }, "Value" : 4 }] }
3+
{ "CustomerId" : "[email protected]", "FirstPurchaseDate" : { "$date" : "2020-08-18T23:04:48Z" }, "TotalValue" : 191, "TotalOrders" : 2, "Orders" : [{ "OrderDate" : { "$date" : "2020-08-18T23:04:48Z" }, "Value" : 4 }, { "OrderDate" : { "$date" : "2020-11-23T22:56:53Z" }, "Value" : 187 }] }
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using MongoDB.Bson;
2+
using MongoDB.Bson.Serialization.Attributes;
3+
4+
namespace Examples.Aggregation;
5+
6+
// :snippet-start: class-declaration
7+
public class Order
8+
{
9+
[BsonId]
10+
public ObjectId Id { get; set; }
11+
public string CustomerId { get; set; }
12+
public DateTime OrderDate { get; set; }
13+
public int Value { get; set; }
14+
}
15+
// :snippet-end:
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net9.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="DotNetEnv" Version="3.1.1" />
12+
<PackageReference Include="MongoDB.Driver" Version="3.4.0" />
13+
</ItemGroup>
14+
15+
</Project>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Console.WriteLine("This project is not intended to be run as a console application. Run the tests using the 'Tests' solution.");
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# C# Driver Code Example Test PoC
2+
3+
This is a PoC to explore testing C# Driver code examples for MongoDB documentation.
4+
5+
The structure of this C# project is as follows:
6+
7+
- `driver.sln`: This solution contains the following projects:
8+
- `Examples`: This project contains example code and output to validate.
9+
- `Tests`: This project contains the test infrastructure to actually run
10+
the tests by invoking the example code.
11+
12+
## To run the tests locally
13+
14+
### Create a MongoDB Docker Deployment
15+
16+
To run these tests locally, you need a MongoDB Docker deployment. Make sure Docker is
17+
running, and then:
18+
19+
1. Pull the MongoDB image from Docker Hub:
20+
21+
```shell
22+
docker pull mongo
23+
```
24+
2. Run the container:
25+
26+
```shell
27+
docker run --name mongodb-test -d -p 27017:27017 mongo
28+
```
29+
30+
3. Verify the container is running:
31+
32+
```shell
33+
docker ps
34+
```
35+
36+
The output resembles:
37+
38+
```text
39+
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
40+
ef70cce38f26 mongo "/usr/local/bin/runn…" 29 hours ago Up 29 hours (healthy) 127.0.0.1:63201->27017/tcp mongodb-test
41+
```
42+
43+
You may note the actual port is different than `27017`, if something else is already running on
44+
`27017` on your machine. Note the port next to the IP address for running the tests. Alternately, you can get just
45+
the port info for your container using the following command:
46+
47+
```shell
48+
docker port mongodb-test
49+
```
50+
51+
The output resembles:
52+
53+
```text
54+
27017/tcp -> 0.0.0.0:27017
55+
27017/tcp -> [::]:27017
56+
```
57+
58+
### Create a .env file
59+
60+
Create a file named `.env` at the root of the `/driver` directory.
61+
Add the following values to your .env file, similar to the following example:
62+
63+
```
64+
CONNECTION_STRING="mongodb://localhost:27017"
65+
SOLUTION_ROOT="/Users/dachary.carey/workspace/docs-code-examples/usage-examples/csharp/driver/"
66+
```
67+
68+
- `CONNECTION_STRING`: replace the port with the port where your local deployment is running.
69+
- `SOLUTION_ROOT`: insert the path to the `driver` directory on your filesystem.
70+
71+
### Install the dependencies
72+
73+
This test suite requires you to have `.NET` v9.0 installed. If you
74+
do not yet have .NET installed, refer to
75+
[the .NET installation page](https://learn.microsoft.com/en-us/dotnet/core/install/macos)
76+
for details.
77+
78+
From the root of each project directory, run the following command to install
79+
dependencies:
80+
81+
```
82+
dotnet restore
83+
```
84+
85+
### Run the tests
86+
87+
You can run tests from the command line or through your IDE.
88+
89+
#### Run All Tests from the command line
90+
91+
From the `/drivers` directory, run:
92+
93+
```
94+
dotnet test
95+
```
96+
97+
#### Run Individual Tests from the command line
98+
99+
You can run a single test within a given test suite (file).
100+
101+
From the `/drivers` directory, run:
102+
103+
```
104+
dotnet test --filter "FullyQualifiedName=YourNamespace.YourTestClass.YourTestMethod"
105+
```
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using Examples.Aggregation;
2+
3+
namespace Tests;
4+
5+
public class GroupTotalTest
6+
{
7+
private GroupTotal _example;
8+
[SetUp]
9+
public void Setup()
10+
{
11+
_example = new GroupTotal();
12+
_example.LoadSampleData();
13+
}
14+
15+
[Test]
16+
public void TestOutputMatchesDocs()
17+
{
18+
var results = _example.PerformAggregation();
19+
20+
var solutionRoot = DotNetEnv.Env.GetString("SOLUTION_ROOT", "Env variable not found. Verify you have a .env file with a valid connection string.");
21+
var outputLocation = "Examples/Aggregation/GroupTotalOutput.txt";
22+
var fullPath = Path.Combine(solutionRoot, outputLocation);
23+
var fileData = TestUtils.ReadBsonDocumentsFromFile(fullPath);
24+
25+
Assert.That(results.Count, Is.EqualTo(fileData.Length), $"Result count {results.Count} does not match output example length {fileData.Length}.");
26+
for (var i = 0; i < fileData.Length; i++)
27+
{
28+
Assert.That(fileData[i], Is.EqualTo(results[i]), $"Mismatch at index {i}: expected {fileData[i]}, got {results[i]}.");
29+
}
30+
}
31+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace Tests;
2+
3+
using DotNetEnv;
4+
5+
[SetUpFixture]
6+
public class TestSuiteSetup
7+
{
8+
[OneTimeSetUp]
9+
public void GlobalSetup()
10+
{
11+
Env.TraversePath().Load();
12+
}
13+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using MongoDB.Bson;
2+
3+
public static class TestUtils
4+
{
5+
public static BsonDocument[] ReadBsonDocumentsFromFile(string filePath)
6+
{
7+
var bsonDocuments = new List<BsonDocument>();
8+
9+
foreach (var line in File.ReadLines(filePath))
10+
{
11+
if (!string.IsNullOrWhiteSpace(line))
12+
{
13+
var bsonDoc = BsonDocument.Parse(line);
14+
bsonDocuments.Add(bsonDoc);
15+
}
16+
}
17+
18+
return bsonDocuments.ToArray();
19+
}
20+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<LangVersion>latest</LangVersion>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<IsPackable>false</IsPackable>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="coverlet.collector" Version="6.0.2"/>
13+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
14+
<PackageReference Include="NUnit" Version="4.2.2"/>
15+
<PackageReference Include="NUnit.Analyzers" Version="4.3.0"/>
16+
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<Using Include="NUnit.Framework"/>
21+
</ItemGroup>
22+
23+
<ItemGroup>
24+
<ProjectReference Include="..\Examples\Examples.csproj" />
25+
</ItemGroup>
26+
27+
</Project>

0 commit comments

Comments
 (0)