Skip to content

Commit 386e946

Browse files
committed
Support login, capture cookies and enhance CustomHttpClient.
1 parent 2e5b2be commit 386e946

25 files changed

+676
-327
lines changed

.editorconfig

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,15 +398,18 @@ dotnet_diagnostic.CA1054.severity = none # CA1054: Uri parameters should not be
398398
dotdotnet_diagnostic.CA1056.severity = none # CA1056: Uri properties should not be strings
399399
dotnet_diagnostic.CA1304.severity = none # CA1304: Specify CultureInfo
400400
dotnet_diagnostic.CA1311.severity = none # CA1311: Specify a culture or use an invariant version
401+
dotnet_diagnostic.CA1515.severity = none #
401402

402403

403404
################ test projects ###################333
404405
[{OData2Poco.Tests/**.cs,OData2Poco.CommandLine.Test/**.cs}]
405406
dotnet_diagnostic.CA1707.severity = none # CA1707: Identifiers should not contain underscores
406407
dotnet_diagnostic.IDE0060.severity = none # IDE0060: Remove unused parameter
407-
dotnet_diagnostic.CA1852.severity = none #
408+
dotnet_diagnostic.CA1852.severity = none # CA1852: Make parameter ref read-only
408409
dotnet_diagnostic.CA1051.severity = none # CA1051: Do not declare visible instance fields
409410
dotnet_diagnostic.CA2000.severity = none # CA2000: Dispose objects before losing scope
410-
dotnet_diagnostic.CA1062.severity = none
411+
dotnet_diagnostic.CA1062.severity = none # CA1062: Validate arguments of public methods
412+
dotnet_diagnostic.CA1050.severity = none # CA1050: Declare types in namespaces
413+
411414

412415

Fake/Common/OdataService.cs

Lines changed: 100 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,136 @@
11
// Copyright (c) Mohamed Hassan & Contributors. All rights reserved. See License.md in the project root for license information.
22

3-
namespace OData2Poco.Fake.Common;
4-
3+
using System.Text;
4+
using OData2Poco;
55
using WireMock.RequestBuilders;
66
using WireMock.ResponseBuilders;
77
using WireMock.Server;
88

9-
public sealed class OdataService : IDisposable
9+
internal sealed class OdataService : IDisposable
1010
{
11-
private static readonly Lazy<OdataService> s_lazy = new(() => new OdataService());
12-
private readonly WireMockServer _mockServer;
11+
private static readonly Lazy<OdataService> s_instance = new(() =>
12+
new OdataService());
13+
internal static OdataService Instance => s_instance.Value;
14+
public static string BaseAddress => Instance._mockServer.Urls[0];
15+
internal static bool IsStarted => Instance._mockServer.IsStarted;
16+
public static string Trippin => Instance.TrippinUrl;
17+
public static string TrippinBasic => Instance.TrippinBasicUrl;
18+
public static string TrippinBearer => Instance.TrippinBearerUrl;
19+
public static string Northwind => Instance.NorthwindUrl;
20+
public static string Northwind4 => Instance.Northwind4Url;
21+
public static string Northwind3 => Instance.Northwind3Url;
22+
public static string Northwind2 => Instance.Northwind2Url;
23+
24+
internal readonly WireMockServer _mockServer;
25+
26+
#if TESTLIB
27+
private readonly int _port = 5678;
28+
#else
29+
private readonly int _port = 5679;
30+
#endif
1331
private bool _disposedValue;
1432

1533
private OdataService()
1634
{
17-
_mockServer = WireMockServer.Start();
18-
CreateGzipService("/trippin", TestSample.TripPin4Gzip);
19-
CreateService("/northwind", TestSample.NorthWindV4);
20-
CreateService("/v4/northwind", TestSample.NorthWindV4);
21-
CreateService("/v3/northwind", TestSample.NorthWindV3);
22-
CreateService("/v2/northwind", TestSample.NorthWindV2);
35+
var setting = new WireMock.Settings.WireMockServerSettings
36+
{
37+
Port = 0,
38+
StartAdminInterface = true,
39+
};
40+
_mockServer = WireMockServer.Start(setting);
41+
InitializeWireMockServer();
42+
}
43+
44+
public string TrippinUrl { get; private set; }
45+
46+
public string TrippinBasicUrl { get; private set; }
47+
public string TrippinBearerUrl { get; private set; }
48+
public string NorthwindUrl { get; private set; }
49+
public string Northwind4Url { get; private set; }
50+
public string Northwind3Url { get; private set; }
51+
public string Northwind2Url { get; private set; }
52+
53+
public void ShowWireMockServerInfo()
54+
{
55+
var isStarted = IsStarted;
56+
if (!isStarted)
57+
{
58+
throw new OData2PocoException("Failed to start OData service");
59+
}
60+
Console.WriteLine("OData service is started");
61+
Console.WriteLine($"OData service is running on {_mockServer.Urls[0]}");
62+
Console.WriteLine($"Trippin: {Trippin}");
63+
Console.WriteLine($"TrippinBasic: {TrippinBasic}");
64+
Console.WriteLine($"TrippinBearer: {TrippinBearer}");
65+
Console.WriteLine($"Northwind: {Northwind}");
66+
Console.WriteLine($"Northwind2: {Northwind2}");
67+
Console.WriteLine($"Northwind3: {Northwind3}");
68+
Console.WriteLine($"Northwind4: {Northwind4}");
69+
}
70+
private void InitializeWireMockServer()
71+
{
72+
TrippinUrl = CreateGzipService("/trippin", TestSample.TripPin4Gzip);
73+
NorthwindUrl = CreateService("/northwind", TestSample.NorthWindV4);
74+
Northwind4Url = CreateService("/v4/northwind", TestSample.NorthWindV4);
75+
Northwind3Url = CreateService("/v3/northwind", TestSample.NorthWindV3);
76+
Northwind2Url = CreateService("/v2/northwind", TestSample.NorthWindV2);
77+
TrippinBasicUrl = CreateServiceWithBasicAuth("/trippin/basic", TestSample.TripPin4);
78+
TrippinBearerUrl = CreateServiceWithBearerTokenAuth("/trippin/bearer", TestSample.TripPin4);
2379
}
2480

25-
private void CreateService(string url, string body)
81+
82+
private string CreateService(string path, string body)
2683
{
2784
_mockServer
28-
.Given(Request.Create().WithPath($"{url}/$metadata"))
85+
.Given(Request.Create().WithPath($"{path}/$metadata").UsingGet())
2986
.RespondWith(Response.Create()
3087
.WithStatusCode(200)
88+
.WithHeader("Content-Type", "application/xml")
3189
.WithBodyFromFile(body));
90+
return $"{_mockServer.Urls[0]}{path}";
3291
}
3392

34-
private void CreateGzipService(string url, string body)
93+
private string CreateGzipService(string path, string body)
3594
{
3695
_mockServer
37-
.Given(Request.Create().WithPath($"{url}/$metadata"))
96+
.Given(Request.Create().WithPath($"{path}/$metadata").UsingGet())
3897
.RespondWith(Response.Create()
3998
.WithStatusCode(200)
4099
.WithHeader("Content-Encoding", "gzip")
41100
.WithBodyFromFile(body));
101+
return $"{_mockServer.Urls[0]}{path}";
42102
}
43103

44-
public static string Trippin => $"{Instance._mockServer.Urls[0]}/trippin";
45-
46-
public static string Northwind => $"{Instance._mockServer.Urls[0]}/northwind";
47-
public static string Northwind4 => $"{Instance._mockServer.Urls[0]}/v4/northwind";
48-
public static string Northwind3 => $"{Instance._mockServer.Urls[0]}/v3/northwind";
49-
public static string Northwind2 => $"{Instance._mockServer.Urls[0]}/v2/northwind";
50-
internal static OdataService Instance => s_lazy.Value;
104+
private string CreateServiceWithBasicAuth(string path, string body, string user = "user", string password = "secret")
105+
{
106+
_mockServer
107+
.Given(Request.Create().WithPath($"{path}/$metadata").UsingGet()
108+
.WithHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes($"{user}:{password}"))))
109+
.RespondWith(Response.Create()
110+
.WithStatusCode(200)
111+
.WithHeader("Content-Type", "application/xml")
112+
.WithBodyFromFile(body));
113+
return $"{_mockServer.Urls[0]}{path}";
114+
}
51115

52-
internal static bool IsStarted => Instance._mockServer.IsStarted;
116+
private string CreateServiceWithBearerTokenAuth(string path,
117+
string body,
118+
string token = "secret_token")
119+
{
120+
_mockServer
121+
.Given(Request.Create().WithPath($"{path}/$metadata").UsingGet()
122+
.WithHeader("Authorization", $"Bearer {token}"))
123+
.RespondWith(Response.Create()
124+
.WithStatusCode(200)
125+
.WithHeader("Content-Type", "application/xml")
126+
.WithBodyFromFile(body));
127+
return $"{_mockServer.Urls[0]}{path}";
128+
}
53129

54130
public void Dispose()
55131
{
56132
Dispose(true);
133+
GC.SuppressFinalize(this);
57134
}
58135

59136
private void Dispose(bool disposing)

Fake/CommonTestData.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace OData2Poco.Fake;
44

55
using System.Reflection;
6-
using Common;
76

87
internal static class TestSample
98
{

OData2Poco.Cli/Options.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ public static IEnumerable<Example> Examples
9595
"Sets the SSL/TSL protocols. Allowed values: tls, tls11, tls12,tls13. Multiple values separated by comma are allowed,e.g, tls11,tls12.")]
9696
public SecurityProtocolType TlsProtocol { get; set; }
9797

98+
[Option('H', "login", HelpText = "Login Url as a separate basic authentication")]
99+
public string LoginUrl { get; set; }
100+
98101
//-----------pocoSetting-----------------
99102

100103
[Option('f', "filename", HelpText = "filename to save generated c# code.")]

OData2Poco.Cli/StartUp.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ public static async Task RunAsync(string[] args)
9191
RetCode = (int)ExitCodes.HandledException;
9292
Logger.Error("Error in executing o2pgen");
9393
#if DEBUG
94-
Logger.Error($"{ex.FullExceptionMessage(true)}");
94+
Console.WriteLine("-------------------------- Exception Message for DEBUG ------------------");
95+
// Logger.Error($"{ex.FullExceptionMessage(true)}");
96+
Logger.Error($"{ex.GetExceptionDetails()}");
97+
Console.WriteLine("---------------------------------------------");
9598
#else
9699
Logger.Error($"{ex.FullExceptionMessage()}");
97100
FileSystem.WriteAllText("error.txt", $"{ex.FullExceptionMessage(true)}");

OData2Poco.CommandLine.Test/IntegearationTest.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ namespace OData2Poco.CommandLine.Test;
77
using System.Runtime.InteropServices;
88
using System.Text;
99
using CliWrap;
10-
using Fake.Common;
1110

1211
public class IntegrationTest
1312
{

OData2Poco.CommandLine.Test/OData2Poco.CommandLine.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
<ItemGroup Label="mocks">
1919
<Compile Include="..\Fake\Common\ODataService.cs" Link="HttpMock\ODataService.cs" />
20+
<Compile Include="..\OData2Poco.Tests\OdataServiceSetup.cs" Link="OdataServiceSetup.cs" />
2021
</ItemGroup>
2122

2223

OData2Poco.CommandLine.Test/OptionManagerTest.cs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace OData2Poco.CommandLine.Test;
44

5+
using System.Net;
56
using Http;
67

78
public class OptionManagerTest
@@ -74,28 +75,39 @@ public void Option_with_password_should_be_serialized_deserialized_correctly_tes
7475
}
7576

7677
[Test]
77-
[TestCase(AuthenticationType.Basic, "Basic dXNlcjE6c2VjcmV0")]
78-
[TestCase(AuthenticationType.Token, "Bearer secret")]
79-
public async Task Option_with_auth_method_should_success_test(
80-
AuthenticationType auth, string expected)
78+
[TestCase(AuthenticationType.Basic)]
79+
[TestCase(AuthenticationType.Token)]
80+
public async Task Option_with_auth_method_should_success_test(AuthenticationType auth)
8181
{
82-
//test flow option->optionManager->CustomHttpClient
8382
//Arrange
8483
var options = new Options
8584
{
86-
ServiceUrl = "http://localhost",
87-
UserName = "user1",
88-
Password = "secret",
85+
ServiceUrl = auth == AuthenticationType.Basic
86+
? OdataService.TrippinBasic : OdataService.TrippinBearer,
8987
Authenticate = auth,
9088
};
89+
if (auth == AuthenticationType.Basic)
90+
{
91+
options.UserName = "user";
92+
options.Password = "secret";
93+
}
94+
else
95+
{
96+
options.Password = "secret_token";
97+
}
9198
//Act
9299
var (cs, _) = new OptionManager(options);
93-
var dh = new AuthHandler();
94-
var client = cs.ToCustomHttpClient(dh);
95-
await client.GetAsync("http://localhost2").ConfigureAwait(false);
100+
Console.WriteLine(cs.ToJson());
101+
var client = await CustomHttpClient.CreateAsync(cs).ConfigureAwait(false);
102+
Console.WriteLine(options.ServiceUrl);
103+
var response = await client.ReadMetaDataAsync()
104+
.ConfigureAwait(false);
105+
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
96106
//Assert
97-
dh.AuthHeader.Should().NotBeNull();
98-
dh.AuthHeader?.ToString().Should().BeEquivalentTo(expected);
107+
Assert.That(cs.Authenticate, Is.EqualTo(options.Authenticate));
108+
Assert.That( cs.ServiceUrl, Is.EqualTo(options.ServiceUrl));
109+
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
110+
Assert.That(content, Does.Contain("Edm"));
99111
}
100112

101113
[Test]

OData2Poco.CommandLine.Test/ProgramTests.cs

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22

33
namespace OData2Poco.CommandLine.Test;
44

5-
using Fake.Common;
6-
using FluentAssertions.Equivalency;
5+
using System.Threading.Tasks;
76
using TestUtility;
8-
using WireMock.ResponseBuilders;
97

108
[TestFixture]
119
public partial class ProgramTests : BaseTest
@@ -386,6 +384,32 @@ public async Task Url_test()
386384
Assert.That(output, Does.Contain("public partial class Trip")); //-v
387385
}
388386

387+
[Test]
388+
public async Task Url_test_basic_with_valid_user_password()
389+
{
390+
//Arrange
391+
var url = OdataService.TrippinBasic;
392+
var a = $"-r {url} -v -o basic -u user -p secret";
393+
//Act
394+
var (exitCode, output) = await RunCommand(a).ConfigureAwait(false);
395+
//Assert
396+
exitCode.Should().Be(0);
397+
Assert.That(output, Does.Contain("public partial class Trip")); //-v
398+
}
399+
400+
[Test]
401+
public async Task Url_test_bearer_valid_token()
402+
{
403+
//Arrange
404+
var url = OdataService.TrippinBearer;
405+
var a = $"-r {url} -v -o token -p secret_token";
406+
//Act
407+
var (exitCode, output) = await RunCommand(a).ConfigureAwait(false);
408+
//Assert
409+
exitCode.Should().Be(0);
410+
Assert.That(output, Does.Contain("public partial class Trip")); //-v
411+
}
412+
389413
[Test]
390414
[Category("code_header")]
391415
[TestCaseSource(typeof(TestSample), nameof(TestSample.FileCases))]
@@ -847,7 +871,7 @@ public City (string countryRegion, string name, string region)
847871
}
848872

849873
[Test]
850-
public void Track_metadata_change_on_server_test()
874+
public async Task Track_metadata_change_on_server_test()
851875
{
852876
//This test is not running in the CI/CD pipeline. it acts as a manual test
853877
//Arrange
@@ -856,11 +880,24 @@ public void Track_metadata_change_on_server_test()
856880
Assert.Ignore("live test");
857881

858882
var url = Environment.GetEnvironmentVariable("DEMO_URL", EnvironmentVariableTarget.User);
859-
var a = $"-r {url} -f {TestSample.DemoCs} -v ";
883+
var a = $"-r {url} -f test.cs -v ";
860884
//Act
861885
//Assert
862-
var ex = Assert.ThrowsAsync<MetaDataNotUpdatedException>(
863-
async () => await RunCommand(a).ConfigureAwait(false));
864-
Assert.That(ex.Message, Does.Contain("The metadata has not been modified and No code generation is done."));
886+
if (File.Exists("test.cs"))
887+
{
888+
//expect 304
889+
var ex = Assert.ThrowsAsync<MetaDataNotUpdatedException>(
890+
async () => await RunCommand(a).ConfigureAwait(false));
891+
Assert.That(ex.Message, Does.Contain("The metadata has not been modified and No code generation is done."));
892+
}
893+
else
894+
{
895+
//expect 200
896+
var (exitCode, output) = await RunCommand(a).ConfigureAwait(false);
897+
Assert.That(exitCode, Is.EqualTo(0));
898+
Assert.That(output, Does.Contain("class"));
899+
}
865900
}
901+
902+
866903
}

OData2Poco.Tests/CustomHttpClientProxyTest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ public async Task Proxy_with_valid_credentials_should_succeed()
3030
Proxy = _proxy,
3131
ProxyUser = "user:password"
3232
};
33-
using var customClient = new CustomHttpClient(cs);
34-
var metaData = await customClient.ReadMetaDataAsync().ConfigureAwait(false);
33+
using var customClient = await CustomHttpClient.CreateAsync(cs).ConfigureAwait(false);
34+
var metaData = await customClient.ReadMetaDataAsStringAsync().ConfigureAwait(false);
3535
Assert.That(metaData, Does.StartWith("""<?xml version="1.0" encoding="UTF-8"?>"""));
3636
}
3737

@@ -46,7 +46,7 @@ public void Proxy_with_Invalid_credentials_should_fail()
4646
Proxy = _proxy,
4747
ProxyUser = "user:invalid_password"
4848
};
49-
using var customClient = new CustomHttpClient(cs);
49+
using var customClient = CustomHttpClient.CreateAsync(cs).GetAwaiter().GetResult();
5050
const string Msg = "Response status code does not indicate success: 407";
5151
Assert.That(
5252
customClient.ReadMetaDataAsync,

0 commit comments

Comments
 (0)