Skip to content

Commit ec7850d

Browse files
authored
Merge pull request #2 from askazakov/base-implementation-and-gha-tests
Base implementation and gha for tests
2 parents f8df972 + e96289a commit ec7850d

File tree

11 files changed

+420
-8
lines changed

11 files changed

+420
-8
lines changed

.github/workflows/pr.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
on:
2+
push:
3+
branches:
4+
- "**"
5+
6+
jobs:
7+
test:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/setup-dotnet@v1
11+
- uses: actions/checkout@v2
12+
- run: dotnet build --configuration Release
13+
- name: unit tests
14+
run: |
15+
cd ${{ github.workspace }}/mongo-declarative-indexes.Tests
16+
dotnet test --configuration Release --no-build
17+

.github/workflows/publish.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ jobs:
1111
- uses: actions/checkout@v2
1212
with:
1313
ref: ${{ github.event.release.tag_name }}
14-
fetch-depth: 0
1514
- run: dotnet build --configuration Release
1615
- name: pack
1716
run: >
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using MongoDB.DeclarativeIndexes;
5+
using NSubstitute;
6+
using Xunit;
7+
using Index = MongoDB.DeclarativeIndexes.Index;
8+
9+
namespace mongo_declarative_indexes.Tests
10+
{
11+
public class IndexEnsurerShould
12+
{
13+
[Fact]
14+
public void Ensure_CreatesMissingIndexes()
15+
{
16+
var database = Substitute.For<IDatabase>();
17+
var ensurer = new IndexEnsurer(database);
18+
var expectedIndexes = new[] {new Index(keys: new Key("field", IndexType.Ascending))};
19+
ensurer.Ensure(new CollectionIndexes("testCollection", expectedIndexes));
20+
21+
database.Received().CreateManyIndexes("testCollection",
22+
Arg.Is<Index[]>(actualIndexes =>
23+
actualIndexes.SequenceEqual(expectedIndexes)));
24+
}
25+
26+
[Fact]
27+
public void Ensure_DropsExtraIndexes()
28+
{
29+
var database = Substitute.For<IDatabase>();
30+
var extraIndex = new Dictionary<string, object>
31+
{
32+
{"v", 2},
33+
{"key", new Dictionary<string, object> {{"field", 1}}},
34+
{"name", "field_1"},
35+
{"ns", "test.collections"}
36+
};
37+
database.ListCollectionNames().Returns(new[] {"collectionName"});
38+
database.ListIndexes("collectionName").Returns(new[] {extraIndex});
39+
40+
var ensurer = new IndexEnsurer(database);
41+
ensurer.Ensure(Array.Empty<CollectionIndexes>());
42+
43+
database.DidNotReceiveWithAnyArgs().CreateManyIndexes(default, default);
44+
database.Received().DropOneIndex("collectionName", "field_1");
45+
}
46+
47+
[Fact]
48+
public void Ensure_DoesNothingWithIdIndex()
49+
{
50+
var database = Substitute.For<IDatabase>();
51+
var idIndex = new Dictionary<string, object>
52+
{
53+
{"v", 2},
54+
{"key", new Dictionary<string, object> {{"_id", 1}}},
55+
{"name", "_id_"},
56+
{"ns", "test.collections"}
57+
};
58+
database.ListCollectionNames().Returns(new[] {"collectionName"});
59+
database.ListIndexes("collectionName").Returns(new[] {idIndex});
60+
61+
var ensurer = new IndexEnsurer(database);
62+
ensurer.Ensure(Array.Empty<CollectionIndexes>());
63+
64+
database.DidNotReceiveWithAnyArgs().CreateManyIndexes(default, default);
65+
database.DidNotReceiveWithAnyArgs().DropOneIndex(default, default);
66+
}
67+
68+
[Fact]
69+
public void Ensure_DropsExtraAndCreatesMissingIndexes()
70+
{
71+
var database = Substitute.For<IDatabase>();
72+
var extraIndex = new Dictionary<string, object>
73+
{
74+
{"v", 2},
75+
{"key", new Dictionary<string, object> {{"field", 1}}},
76+
{"name", "field_1"},
77+
{"ns", "test.collections"}
78+
};
79+
const string remainingFieldName = "remaining_field";
80+
var remainingDbIndex = new Dictionary<string, object>
81+
{
82+
{"v", 2},
83+
{"key", new Dictionary<string, object> {{remainingFieldName, 1}}},
84+
{"name", $"{remainingFieldName}_1"},
85+
{"ns", "test.collections"}
86+
};
87+
const string collectionName = "collectionName";
88+
database.ListCollectionNames().Returns(new[] {collectionName});
89+
database.ListIndexes(collectionName).Returns(new[] {extraIndex, remainingDbIndex});
90+
91+
var expectedCreatedIndexes = new[] {new Index(keys: new Key("yet_another_field", IndexType.Descending))};
92+
var ensurer = new IndexEnsurer(database);
93+
var remainingIndex = new Index(keys: new Key(remainingFieldName, IndexType.Ascending));
94+
ensurer.Ensure(new CollectionIndexes(collectionName,
95+
expectedCreatedIndexes.Append(remainingIndex).ToArray()));
96+
database.Received().DropOneIndex(collectionName, "field_1");
97+
database.Received().CreateManyIndexes(collectionName,
98+
Arg.Is<Index[]>(actualIndexes =>
99+
actualIndexes
100+
.SequenceEqual(expectedCreatedIndexes)));
101+
}
102+
}
103+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net5.0</TargetFramework>
5+
<RootNamespace>mongo_declarative_indexes.Tests</RootNamespace>
6+
7+
<IsPackable>false</IsPackable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
12+
<PackageReference Include="NSubstitute" Version="4.2.2" />
13+
<PackageReference Include="NSubstitute.Analyzers.CSharp" Version="1.0.14" />
14+
<PackageReference Include="xunit" Version="2.4.1" />
15+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
16+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
17+
<PrivateAssets>all</PrivateAssets>
18+
</PackageReference>
19+
<PackageReference Include="coverlet.collector" Version="1.3.0">
20+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
21+
<PrivateAssets>all</PrivateAssets>
22+
</PackageReference>
23+
</ItemGroup>
24+
25+
<ItemGroup>
26+
<ProjectReference Include="..\mongo-declarative-indexes\mongo-declarative-indexes.csproj" />
27+
</ItemGroup>
28+
29+
</Project>

mongo-declarative-indexes.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3+
#
34
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mongo-declarative-indexes", "mongo-declarative-indexes\mongo-declarative-indexes.csproj", "{4BAF5452-C015-4896-B132-F71398203255}"
45
EndProject
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mongo-declarative-indexes.Tests", "mongo-declarative-indexes.Tests\mongo-declarative-indexes.Tests.csproj", "{B4733E13-E55A-45B1-B592-032206E3BBF3}"
7+
EndProject
58
Global
69
GlobalSection(SolutionConfigurationPlatforms) = preSolution
710
Debug|Any CPU = Debug|Any CPU
@@ -12,5 +15,9 @@ Global
1215
{4BAF5452-C015-4896-B132-F71398203255}.Debug|Any CPU.Build.0 = Debug|Any CPU
1316
{4BAF5452-C015-4896-B132-F71398203255}.Release|Any CPU.ActiveCfg = Release|Any CPU
1417
{4BAF5452-C015-4896-B132-F71398203255}.Release|Any CPU.Build.0 = Release|Any CPU
18+
{B4733E13-E55A-45B1-B592-032206E3BBF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19+
{B4733E13-E55A-45B1-B592-032206E3BBF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
20+
{B4733E13-E55A-45B1-B592-032206E3BBF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
21+
{B4733E13-E55A-45B1-B592-032206E3BBF3}.Release|Any CPU.Build.0 = Release|Any CPU
1522
EndGlobalSection
1623
EndGlobal
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace MongoDB.DeclarativeIndexes
2+
{
3+
public class CollectionIndexes
4+
{
5+
public CollectionIndexes(string collectionName, params Index[] indexes)
6+
{
7+
CollectionName = collectionName;
8+
Indexes = indexes;
9+
}
10+
11+
public string CollectionName { get; }
12+
13+
public Index[] Indexes { get; }
14+
}
15+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System.Collections.Generic;
2+
3+
namespace MongoDB.DeclarativeIndexes
4+
{
5+
/*
6+
* Abstraction for eliminate dependency on MongoDB.Driver
7+
*/
8+
public interface IDatabase
9+
{
10+
void CreateManyIndexes(string collectionName, IEnumerable<Index> indexes);
11+
12+
IEnumerable<Dictionary<string, object>> ListIndexes(string collectionName);
13+
14+
IEnumerable<string> ListCollectionNames();
15+
16+
void DropOneIndex(string collectionName, string indexName);
17+
}
18+
}

mongo-declarative-indexes/Index.cs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using MongoDB.DeclarativeIndexes.helpers;
5+
6+
namespace MongoDB.DeclarativeIndexes
7+
{
8+
public class Index
9+
{
10+
public Index(bool unique = false, string name = null, params Key[] keys)
11+
{
12+
Keys = keys;
13+
Unique = unique;
14+
Name = name;
15+
}
16+
17+
public Key[] Keys { get; }
18+
public bool Unique { get; }
19+
public string Name { get; }
20+
21+
public static Index FromDb(Dictionary<string, object> dbDocument)
22+
{
23+
/*
24+
* {
25+
* "v": 2,
26+
* "key": {"field_name": "type"},
27+
* "name": "index_name",
28+
* "ns": "{namespace}
29+
* }
30+
*/
31+
var dbKeys = (IEnumerable<KeyValuePair<string, object>>) dbDocument["key"];
32+
return new Index(keys: dbKeys.Select(x => new Key(x.Key, IndexType.Ascending)).ToArray(),
33+
name: (string) dbDocument.GetValueOrDefault("name"));
34+
}
35+
36+
public Dictionary<string, object> ToDb()
37+
{
38+
return Keys.ToDictionary(k => k.Field, k => ConvertIndexTypeToDb(k.IndexType));
39+
}
40+
41+
private static object ConvertIndexTypeToDb(IndexType indexType)
42+
{
43+
// ReSharper disable once HeapView.BoxingAllocation
44+
return indexType switch
45+
{
46+
IndexType.Ascending => 1,
47+
IndexType.Descending => -1,
48+
// IndexType.Text => "text",
49+
_ => throw new ArgumentOutOfRangeException(nameof(indexType), indexType, null)
50+
};
51+
}
52+
}
53+
54+
public class Key
55+
{
56+
public Key(string field, IndexType indexType)
57+
{
58+
Field = field;
59+
IndexType = indexType;
60+
}
61+
62+
public string Field { get; }
63+
64+
public IndexType IndexType { get; }
65+
66+
protected bool Equals(Key other)
67+
{
68+
return Field == other.Field && IndexType == other.IndexType;
69+
}
70+
71+
public override bool Equals(object obj)
72+
{
73+
if (ReferenceEquals(null, obj)) return false;
74+
if (ReferenceEquals(this, obj)) return true;
75+
return obj.GetType() == GetType() && Equals((Key) obj);
76+
}
77+
78+
public override int GetHashCode()
79+
{
80+
unchecked
81+
{
82+
return ((Field != null ? Field.GetHashCode() : 0) * 397) ^ (int) IndexType;
83+
}
84+
}
85+
}
86+
87+
public enum IndexType
88+
{
89+
Ascending,
90+
Descending,
91+
// Text
92+
}
93+
}

0 commit comments

Comments
 (0)