Skip to content

Commit 63e08d5

Browse files
authored
Merge pull request #41 from catcherwong/feat/moretest
test: add more tests and add Codecov
2 parents 0529c92 + 60f8680 commit 63e08d5

12 files changed

Lines changed: 361 additions & 8 deletions

File tree

.github/workflows/build.yml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,22 @@ jobs:
5151
5252
- name: Run tests on net6.0
5353
run: |
54-
dotnet test --framework=net6.0 src/Dtmcli.Tests/Dtmcli.Tests.csproj
54+
dotnet test --framework=net6.0 src/Dtmcli.Tests/Dtmcli.Tests.csproj --collect:"XPlat Code Coverage"
55+
56+
- name: Prepare Codecov
57+
run: |
58+
mkdir ${{ github.workspace }}/coverage/
59+
60+
cp ${{ github.workspace }}/src/Dtmcli.Tests/TestResults/*/coverage.cobertura.xml ${{ github.workspace }}/coverage/
61+
62+
ls ${{ github.workspace }}/coverage/
63+
64+
- name: Upload coverage to Codecov
65+
if: ${{ matrix.os == 'ubuntu-latest' }}
66+
uses: codecov/codecov-action@v2
67+
with:
68+
token: ${{ secrets.CODECOV_TOKEN }}
69+
fail_ci_if_error: true
70+
files: ${{ github.workspace }}/coverage/coverage.cobertura.xml
71+
name: codecov-umbrella
72+
verbose: true

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*.xap
77
*.user
88
/TestResults
9+
TestResults/
910
*.suo
1011
*.cache
1112
*.docstates

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ English | [简体中文](./README-cn.md)
66

77
It has supported distributed transaction patterns of Saga pattern, TCC pattern and 2-phase message pattern.
88

9-
![Build_And_Test](https://github.com/dtm-labs/dtmcli-csharp/actions/workflows/build.yml/badge.svg)
9+
![Build_And_Test](https://github.com/dtm-labs/dtmcli-csharp/actions/workflows/build.yml/badge.svg) [![codecov](https://codecov.io/gh/dtm-labs/dtmcli-csharp/branch/main/graph/badge.svg?token=Y2BOSQ5QKO)](https://codecov.io/gh/dtm-labs/dtmcli-csharp)
1010

1111
![](https://img.shields.io/nuget/v/Dtmcli.svg) ![](https://img.shields.io/nuget/vpre/Dtmcli.svg) ![](https://img.shields.io/nuget/dt/Dtmcli) ![](https://img.shields.io/github/license/dtm-labs/dtmcli-csharp)
1212

src/Dtmcli.Tests/DtmClientTests.cs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
using Xunit;
2+
using System.Net;
3+
using Moq;
4+
using System.Net.Http;
5+
using System.Threading.Tasks;
6+
using System.Threading;
7+
8+
namespace Dtmcli.Tests
9+
{
10+
public class DtmClientTests
11+
{
12+
[Fact]
13+
public async void GenGid_Should_Succeed()
14+
{
15+
var factory = new Mock<IHttpClientFactory>();
16+
var options = Microsoft.Extensions.Options.Options.Create(new DtmCommon.DtmOptions { DtmUrl = "http://localhost:8080" });
17+
var mockHttpMessageHandler = new ClientMockHttpMessageHandler(HttpStatusCode.OK, "{\"dtm_result\":\"SUCCESS\",\"gid\":\"123\"}");
18+
factory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(new HttpClient(mockHttpMessageHandler));
19+
20+
var client = new DtmClient(factory.Object, options);
21+
22+
var res = await client.GenGid(new CancellationToken());
23+
24+
Assert.Equal("123", res);
25+
}
26+
27+
[Fact]
28+
public async void GenGid_Should_Throw_Failure_Exception()
29+
{
30+
var factory = new Mock<IHttpClientFactory>();
31+
var options = Microsoft.Extensions.Options.Options.Create(new DtmCommon.DtmOptions { DtmUrl = "http://localhost:8080" });
32+
var mockHttpMessageHandler = new ClientMockHttpMessageHandler(HttpStatusCode.BadGateway, "");
33+
factory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(new HttpClient(mockHttpMessageHandler));
34+
35+
var client = new DtmClient(factory.Object, options);
36+
37+
await Assert.ThrowsAsync<DtmCommon.DtmException>( async()=> await client.GenGid(new CancellationToken()));
38+
}
39+
40+
[Fact]
41+
public async void TransRegisterBranch_Should_Succeed()
42+
{
43+
var factory = new Mock<IHttpClientFactory>();
44+
var options = Microsoft.Extensions.Options.Options.Create(new DtmCommon.DtmOptions { DtmUrl = "http://localhost:8080" });
45+
var mockHttpMessageHandler = new ClientMockHttpMessageHandler(HttpStatusCode.OK, "");
46+
factory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(new HttpClient(mockHttpMessageHandler));
47+
48+
var client = new DtmClient(factory.Object, options);
49+
50+
var tb = new DtmCommon.TransBase() { Gid = "123", TransType = "tcc" };
51+
52+
await client.TransRegisterBranch(tb, null, "OP", new CancellationToken());
53+
}
54+
55+
[Fact]
56+
public async void TransRegisterBranch_With_Added_Should_Succeed()
57+
{
58+
var factory = new Mock<IHttpClientFactory>();
59+
var options = Microsoft.Extensions.Options.Options.Create(new DtmCommon.DtmOptions { DtmUrl = "http://localhost:8080" });
60+
var mockHttpMessageHandler = new ClientMockHttpMessageHandler(HttpStatusCode.OK, "");
61+
factory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(new HttpClient(mockHttpMessageHandler));
62+
63+
var client = new DtmClient(factory.Object, options);
64+
65+
var tb = new DtmCommon.TransBase() { Gid = "123", TransType = "tcc" };
66+
var added = new System.Collections.Generic.Dictionary<string, string>() { { "a", "b" } };
67+
68+
await client.TransRegisterBranch(tb, added, "OP", new CancellationToken());
69+
}
70+
71+
[Fact]
72+
public async void TransRequestBranch_Should_Succeed()
73+
{
74+
var factory = new Mock<IHttpClientFactory>();
75+
var options = Microsoft.Extensions.Options.Options.Create(new DtmCommon.DtmOptions { DtmUrl = "http://localhost:8080" });
76+
var mockHttpMessageHandler = new ClientMockHttpMessageHandler(HttpStatusCode.OK, "");
77+
factory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(new HttpClient(mockHttpMessageHandler));
78+
79+
var client = new DtmClient(factory.Object, options);
80+
81+
var tb = new DtmCommon.TransBase()
82+
{
83+
Gid = "123",
84+
TransType = "tcc",
85+
};
86+
87+
await client.TransRequestBranch(tb, HttpMethod.Post, new { }, "00", "try", "http://www.baidu.com?a=1", new CancellationToken());
88+
}
89+
90+
[Fact]
91+
public async void TransRequestBranch_With_BranchHeaders_Should_Succeed()
92+
{
93+
var factory = new Mock<IHttpClientFactory>();
94+
var options = Microsoft.Extensions.Options.Options.Create(new DtmCommon.DtmOptions { DtmUrl = "http://localhost:8080" });
95+
var mockHttpMessageHandler = new ClientMockHttpMessageHandler(HttpStatusCode.OK, "");
96+
factory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(new HttpClient(mockHttpMessageHandler));
97+
98+
var client = new DtmClient(factory.Object, options);
99+
100+
var tb = new DtmCommon.TransBase()
101+
{
102+
Gid = "123",
103+
TransType = "tcc",
104+
BranchHeaders = new System.Collections.Generic.Dictionary<string, string> { { "a", "b" } }
105+
};
106+
107+
await client.TransRequestBranch(tb, HttpMethod.Post, new { }, "00", "try", "http://www.baidu.com", new CancellationToken());
108+
}
109+
110+
#if NET5_0_OR_GREATER
111+
[Fact]
112+
public void TransBaseFromQuery_Should_Succeed()
113+
{
114+
var factory = new Mock<IHttpClientFactory>();
115+
var options = Microsoft.Extensions.Options.Options.Create(new DtmCommon.DtmOptions { DtmUrl = "http://localhost:8080" });
116+
var mockHttpMessageHandler = new ClientMockHttpMessageHandler(HttpStatusCode.OK, "");
117+
factory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(new HttpClient(mockHttpMessageHandler));
118+
119+
var client = new DtmClient(factory.Object, options);
120+
121+
var dict = new System.Collections.Generic.Dictionary<string, Microsoft.Extensions.Primitives.StringValues>()
122+
{
123+
{ "branch_id","11" },
124+
{ "gid","1111" },
125+
{ "op","try" },
126+
{ "trans_type","tcc" },
127+
};
128+
129+
var qs = new Microsoft.AspNetCore.Http.QueryCollection(dict);
130+
131+
var tb = client.TransBaseFromQuery(qs);
132+
133+
Assert.Equal(dict["op"], tb.Op);
134+
Assert.Equal(dict["gid"], tb.Gid);
135+
Assert.Equal(dict["trans_type"], tb.TransType);
136+
Assert.Equal(dict["branch_id"], tb.BranchIDGen.BranchID);
137+
}
138+
#endif
139+
}
140+
141+
internal class ClientMockHttpMessageHandler : DelegatingHandler
142+
{
143+
private readonly HttpStatusCode _code;
144+
private readonly string _msg;
145+
public ClientMockHttpMessageHandler(HttpStatusCode code, string msg)
146+
{
147+
this._code = code;
148+
this._msg = msg;
149+
}
150+
151+
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
152+
{
153+
var content = new StringContent(_msg);
154+
var resp = new HttpResponseMessage(_code);
155+
resp.Content = content;
156+
157+
return Task.FromResult(resp);
158+
}
159+
}
160+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using Moq;
2+
using Xunit;
3+
4+
namespace Dtmcli.Tests
5+
{
6+
public class DtmTransFactoryTest
7+
{
8+
[Fact]
9+
public void NewMsg_Should_Succeed()
10+
{
11+
var dtmClient = new Mock<IDtmClient>();
12+
var bbFactory = new Mock<IBranchBarrierFactory>();
13+
14+
var tFactory = new DtmTransFactory(dtmClient.Object, bbFactory.Object);
15+
16+
var gid = "TestMsgNormal";
17+
18+
var msg = tFactory.NewMsg(gid);
19+
20+
Assert.NotNull(msg);
21+
}
22+
23+
[Fact]
24+
public void NewSaga_Should_Succeed()
25+
{
26+
var dtmClient = new Mock<IDtmClient>();
27+
var bbFactory = new Mock<IBranchBarrierFactory>();
28+
29+
var tFactory = new DtmTransFactory(dtmClient.Object, bbFactory.Object);
30+
31+
var gid = "TestSagaNormal";
32+
33+
var saga = tFactory.NewSaga(gid);
34+
35+
Assert.NotNull(saga);
36+
}
37+
}
38+
}

src/Dtmcli.Tests/MsgTests.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,28 @@ public async void Submit_Should_Succeed()
5252
{
5353
{ "bh1", "123" },
5454
{ "bh2", "456" },
55-
});
55+
})
56+
.SetPassthroughHeaders(new List<string> { "bh1" });
5657

5758
await msg.Prepare(busi + "/query");
5859
await msg.Submit();
5960

6061
Assert.True(true);
6162
}
6263

64+
[Fact]
65+
public async void DoAndSubmit_Should_Throw_Exception_When_BB_InValid()
66+
{
67+
var dtmClient = new Mock<IDtmClient>();
68+
var bbFactory = new Mock<IBranchBarrierFactory>();
69+
70+
bbFactory.Setup(x => x.CreateBranchBarrier(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), null))
71+
.Returns(new BranchBarrier("", "", "", "", null, null));
72+
73+
var msg = new Msg(dtmClient.Object, bbFactory.Object, "123");
74+
await Assert.ThrowsAnyAsync<DtmException>(async () => await msg.DoAndSubmit("", x => Task.CompletedTask));
75+
}
76+
6377
[Fact]
6478
public async void DoAndSubmitDB_Should_Throw_Exception_When_Transbase_InValid()
6579
{
@@ -197,6 +211,7 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
197211
Assert.Contains("bh2", transBase.BranchHeaders.Keys);
198212
Assert.Equal(2, transBase.Payloads.Count);
199213
Assert.Equal(2, transBase.Steps.Count);
214+
Assert.Contains("bh1", transBase.PassthroughHeaders);
200215

201216
var content = new StringContent("{\"dtm_result\":\"SUCCESS\"}");
202217

src/Dtmcli.Tests/SagaTests.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,12 @@ public async void Submit_Should_Succeed()
4444
{
4545
{ "bh1", "123" },
4646
{ "bh2", "456" },
47-
});
47+
})
48+
.SetPassthroughHeaders(new List<string> { "bh1" });
4849

4950
await sage.Submit();
51+
52+
Assert.NotNull(sage.GetTransBase());
5053
}
5154

5255
[Fact]
@@ -121,6 +124,7 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
121124
Assert.Contains("bh2", transBase.BranchHeaders.Keys);
122125
Assert.Equal(4, transBase.Payloads.Count);
123126
Assert.Equal(4, transBase.Steps.Count);
127+
Assert.Contains("bh1", transBase.PassthroughHeaders);
124128

125129
var content = new StringContent("{\"dtm_result\":\"SUCCESS\"}");
126130

src/Dtmcli.Tests/ServiceCollectionExtensionsTests.cs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public void AddDtmcli_With_Action_Should_Succeed()
1818
services.AddDtmcli(x =>
1919
{
2020
x.DtmUrl = dtmUrl;
21+
x.DtmTimeout = 8000;
22+
x.BranchTimeout = 8000;
2123
});
2224

2325
var provider = services.BuildServiceProvider();
@@ -39,13 +41,15 @@ public void AddDtmcli_Without_Action_Should_Throw_Exception()
3941
}
4042

4143
[Fact]
42-
public void AddDtmcli_With_IConfiguration_Should_Succeed()
44+
public async void AddDtmcli_With_IConfiguration_Should_Succeed()
4345
{
4446
var dtmUrl = "http://localhost:36789";
4547

4648
var dict = new Dictionary<string, string>
4749
{
4850
{ "dtm:DtmUrl", dtmUrl },
51+
{ "dtm:DtmTimeout", "1000" },
52+
{ "dtm:BranchTimeout", "8000" },
4953
};
5054

5155
var config = new ConfigurationBuilder().AddInMemoryCollection(dict).Build();
@@ -61,6 +65,32 @@ public void AddDtmcli_With_IConfiguration_Should_Succeed()
6165

6266
var dtmClient = provider.GetRequiredService<IDtmClient>();
6367
Assert.NotNull(dtmClient);
68+
69+
// for real test
70+
await Assert.ThrowsAnyAsync<System.Exception>(async () => await dtmClient.GenGid(default));
71+
await dtmClient.TransRequestBranch(new TransBase(), System.Net.Http.HttpMethod.Get, null, "", "", "https://www.baidu.com", default);
72+
}
73+
74+
[Fact]
75+
public void AddDtmcli_With_IConfiguration_And_Empty_Option_Should_Succeed()
76+
{
77+
var dtmUrl = "http://localhost:36789";
78+
79+
var dict = new Dictionary<string, string>
80+
{
81+
{ "dtmx:DtmUrl", dtmUrl },
82+
};
83+
84+
var config = new ConfigurationBuilder().AddInMemoryCollection(dict).Build();
85+
86+
var services = new ServiceCollection();
87+
services.AddDtmcli(config, "dtm");
88+
89+
var provider = services.BuildServiceProvider();
90+
91+
var dtmOptionsAccs = provider.GetService<IOptions<DtmOptions>>();
92+
var dtmOptions = dtmOptionsAccs.Value;
93+
Assert.NotEqual(dtmUrl, dtmOptions.DtmUrl);
6494
}
6595
}
6696
}

0 commit comments

Comments
 (0)