Skip to content

Commit 155dc50

Browse files
authored
Fixing headers not being sent (#161)
Wasn't copying them across properly for the response after the last refactor. Also bumped all testing deps as VS wasn't finding tests Fixes #160
1 parent 53ca312 commit 155dc50

8 files changed

Lines changed: 64 additions & 35 deletions

File tree

src/Teapot.Web.Tests/IntegrationTests/StatusCodeTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,24 @@ public async Task ResponseNoContent([Values] TestCase testCase)
8686
Assert.That(response.Content.Headers.ContentLength, Is.EqualTo(0));
8787
});
8888
}
89+
90+
[TestCaseSource(typeof(TestCases), nameof(TestCases.StatusCodesWithHeaders))]
91+
public async Task ResponseWithHeaders([Values] TestCase testCase)
92+
{
93+
string uri = $"/{testCase.Code}";
94+
using HttpRequestMessage httpRequest = new(httpMethod, uri);
95+
using HttpResponseMessage response = await _httpClient.SendAsync(httpRequest);
96+
Assert.That((int)response.StatusCode, Is.EqualTo(testCase.Code));
97+
string body = await response.Content.ReadAsStringAsync();
98+
Assert.Multiple(() =>
99+
{
100+
// Some headers as skipped as their info is represented elsewhere in the API, so we'll filter them out
101+
List<string> headersToSkip = ["Content-Type", "Content-Range"];
102+
foreach (KeyValuePair<string, string> header in testCase.TeapotStatusCodeMetadata.IncludeHeaders.Where(h => ! headersToSkip.Contains(h.Key)))
103+
{
104+
Assert.That(response.Headers.Contains(header.Key), Is.True);
105+
Assert.That(response.Headers.GetValues(header.Key).FirstOrDefault(), Is.EqualTo(header.Value));
106+
}
107+
});
108+
}
89109
}

src/Teapot.Web.Tests/Teapot.Web.Tests.csproj

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,20 @@
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
<IsPackable>false</IsPackable>
8+
<IsTestProject>true</IsTestProject>
89
</PropertyGroup>
910

1011
<ItemGroup>
11-
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0" />
12-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
12+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.2" />
13+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
1314
<PackageReference Include="Moq" Version="4.20.72" />
14-
<PackageReference Include="NUnit" Version="4.2.2" />
15-
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
16-
<PackageReference Include="NUnit.Analyzers" Version="4.4.0">
15+
<PackageReference Include="NUnit" Version="4.3.2" />
16+
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0" />
17+
<PackageReference Include="NUnit.Analyzers" Version="4.6.0">
1718
<PrivateAssets>all</PrivateAssets>
1819
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1920
</PackageReference>
20-
<PackageReference Include="coverlet.collector" Version="6.0.2">
21+
<PackageReference Include="coverlet.collector" Version="6.0.4">
2122
<PrivateAssets>all</PrivateAssets>
2223
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2324
</PackageReference>

src/Teapot.Web.Tests/TestCases.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ public class TestCases
3232
public static IEnumerable<TestCase> StatusCodesNoContent =>
3333
NoContentStatusCodes.Select(Map);
3434

35+
public static IEnumerable<TestCase> StatusCodesWithHeaders =>
36+
All
37+
.Where(x => x.Value.IncludeHeaders.Count != 0)
38+
.Select(Map);
39+
3540
private static TestCase Map(HttpStatusCode code)
3641
{
3742
int key = (int)code;

src/Teapot.Web.Tests/UnitTests/SleepTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public void Setup() {
2525
public void SleepReadFromQuery()
2626
{
2727
Mock<HttpRequest> request = HttpRequestHelper.GenerateMockRequest();
28-
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200, sleep: Sleep), null, request.Object, _statusCodes);
28+
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200, new(), sleep: Sleep), null, request.Object);
2929

3030
Assert.Multiple(() =>
3131
{
@@ -42,7 +42,7 @@ public void SleepReadFromHeader()
4242
Mock<HttpRequest> request = HttpRequestHelper.GenerateMockRequest();
4343
request.Object.Headers.Append(StatusExtensions.SLEEP_HEADER, Sleep.ToString());
4444

45-
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200), null, request.Object, _statusCodes);
45+
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200, new()), null, request.Object);
4646

4747
Assert.Multiple(() => {
4848
Assert.That(result, Is.InstanceOf<CustomHttpStatusCodeResult>());
@@ -57,7 +57,7 @@ public void SleepReadFromQSTakesPriorityHeader() {
5757
Mock<HttpRequest> request = HttpRequestHelper.GenerateMockRequest();
5858
request.Object.Headers.Append(StatusExtensions.SLEEP_HEADER, Sleep.ToString());
5959

60-
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200, sleep:Sleep * 2), null, request.Object, _statusCodes);
60+
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200, new(), sleep: Sleep * 2), null, request.Object);
6161

6262
Assert.Multiple(() => {
6363
Assert.That(result, Is.InstanceOf<CustomHttpStatusCodeResult>());
@@ -73,7 +73,7 @@ public void BadSleepHeaderIgnored()
7373
Mock<HttpRequest> request = HttpRequestHelper.GenerateMockRequest();
7474
request.Object.Headers.Append(StatusExtensions.SLEEP_HEADER, "invalid");
7575

76-
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200), null, request.Object, _statusCodes);
76+
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200, new()), null, request.Object);
7777

7878
Assert.Multiple(() =>
7979
{

src/Teapot.Web.Tests/UnitTests/SuppressBodyTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public void Setup()
2828
public void SuppressBodyReadFromQuery(bool? suppressBody)
2929
{
3030
Mock<HttpRequest> request = HttpRequestHelper.GenerateMockRequest();
31-
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200, suppressBody:suppressBody), null, request.Object, _statusCodes);
31+
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200, new(), suppressBody: suppressBody), null, request.Object);
3232

3333
Assert.Multiple(() =>
3434
{
@@ -48,7 +48,7 @@ public void SuppressBodyReadFromHeader(string? suppressBody)
4848
Mock<HttpRequest> request = HttpRequestHelper.GenerateMockRequest();
4949
request.Object.Headers.Append(StatusExtensions.SUPPRESS_BODY_HEADER, suppressBody);
5050

51-
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200), null, request.Object, _statusCodes);
51+
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200, new()), null, request.Object);
5252

5353
Assert.Multiple(() =>
5454
{
@@ -76,7 +76,7 @@ public void SuppressBodyReadFromQSTakesPriorityHeader(string? headerValue, bool?
7676
Mock<HttpRequest> request = HttpRequestHelper.GenerateMockRequest();
7777
request.Object.Headers.Append(StatusExtensions.SUPPRESS_BODY_HEADER, headerValue);
7878

79-
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200, suppressBody: queryStringValue), null, request.Object, _statusCodes);
79+
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200, new(), suppressBody: queryStringValue), null, request.Object);
8080

8181
Assert.Multiple(() =>
8282
{
@@ -98,7 +98,7 @@ public void BadSuppressBodyHeaderIgnored()
9898
Mock<HttpRequest> request = HttpRequestHelper.GenerateMockRequest();
9999
request.Object.Headers.Append(StatusExtensions.SUPPRESS_BODY_HEADER, "invalid");
100100

101-
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200),null, request.Object, _statusCodes);
101+
IResult result = StatusExtensions.CommonHandleStatusRequestAsync(new ResponseOptions(200, new()), null, request.Object);
102102

103103
Assert.Multiple(() =>
104104
{

src/Teapot.Web/Models/TeapotStatusCodeMetadataCollection.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public TeapotStatusCodeMetadataCollection(
115115
Description = "Moved Permanently",
116116
IncludeHeaders = new Dictionary<string, string>
117117
{
118-
{"Location", "https://httpstat.us"},
118+
{"Location", "https://httpstat.us/"},
119119
{"Retry-After", "5"}
120120
}
121121
});
@@ -124,15 +124,15 @@ public TeapotStatusCodeMetadataCollection(
124124
Description = "Found",
125125
IncludeHeaders = new Dictionary<string, string>
126126
{
127-
{"Location", "https://httpstat.us"}
127+
{"Location", "https://httpstat.us/"}
128128
}
129129
});
130130
Add(303, new TeapotStatusCodeMetadata
131131
{
132132
Description = "See Other",
133133
IncludeHeaders = new Dictionary<string, string>
134134
{
135-
{"Location", "https://httpstat.us"}
135+
{"Location", "https://httpstat.us/"}
136136
}
137137
});
138138
Add(304, new TeapotStatusCodeMetadata
@@ -145,7 +145,7 @@ public TeapotStatusCodeMetadataCollection(
145145
Description = "Use Proxy",
146146
IncludeHeaders = new Dictionary<string, string>
147147
{
148-
{"Location", "https://httpstat.us"}
148+
{"Location", "https://httpstat.us/"}
149149
}
150150
});
151151
Add(306, new TeapotStatusCodeMetadata
@@ -157,15 +157,15 @@ public TeapotStatusCodeMetadataCollection(
157157
Description = "Temporary Redirect",
158158
IncludeHeaders = new Dictionary<string, string>
159159
{
160-
{"Location", "https://httpstat.us"}
160+
{"Location", "https://httpstat.us/"}
161161
}
162162
});
163163
Add(308, new TeapotStatusCodeMetadata
164164
{
165165
Description = "Permanent Redirect",
166166
IncludeHeaders = new Dictionary<string, string>
167167
{
168-
{"Location", "https://httpstat.us"}
168+
{"Location", "https://httpstat.us/"}
169169
}
170170
});
171171

src/Teapot.Web/ResponseOptions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ namespace Teapot.Web;
77
public record class ResponseOptions
88
{
99
public ResponseOptions(int statusCode,
10+
TeapotStatusCodeMetadata metadata,
1011
int? sleep = null,
1112
int? sleepAfterHeaders = null,
1213
bool? abortBeforeHeaders = null,
1314
bool? abortAfterHeaders = null,
1415
bool? abortDuringBody = null,
1516
bool? suppressBody = null,
1617
bool? dribbleBody = null,
17-
TeapotStatusCodeMetadata? metadata = null,
1818
Dictionary<string, StringValues>? customHeaders = null)
1919
{
2020
StatusCode = statusCode;
@@ -25,8 +25,8 @@ public ResponseOptions(int statusCode,
2525
AbortDuringBody = abortDuringBody;
2626
SuppressBody = suppressBody;
2727
DribbleBody = dribbleBody;
28-
CustomHeaders = customHeaders ?? new Dictionary<string, StringValues>();
29-
Metadata = metadata ?? new();
28+
CustomHeaders = customHeaders ?? [];
29+
Metadata = metadata;
3030
}
3131

3232
public int StatusCode { get; set; }

src/Teapot.Web/StatusExtensions.cs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,24 +52,23 @@ internal static IResult HandleStatusRequestAsync(
5252
[FromServices] TeapotStatusCodeMetadataCollection statusCodes
5353
)
5454
{
55-
ResponseOptions options = new(status)
55+
TeapotStatusCodeMetadata statusData = statusCodes.TryGetValue(status, out TeapotStatusCodeMetadata? value) ?
56+
value :
57+
new TeapotStatusCodeMetadata { Description = $"{status} Unknown Code" };
58+
59+
ResponseOptions options = new(status, statusData)
5660
{
5761
Sleep = sleep,
5862
SuppressBody = suppressBody
5963
};
60-
return CommonHandleStatusRequestAsync(options, wildcard, req, statusCodes);
64+
return CommonHandleStatusRequestAsync(options, wildcard, req);
6165
}
6266

6367
internal static IResult CommonHandleStatusRequestAsync(
6468
ResponseOptions options,
6569
string? wildcard,
66-
HttpRequest req,
67-
TeapotStatusCodeMetadataCollection statusCodes
68-
)
70+
HttpRequest req)
6971
{
70-
TeapotStatusCodeMetadata statusData = statusCodes.TryGetValue(options.StatusCode, out TeapotStatusCodeMetadata? value) ?
71-
value :
72-
new TeapotStatusCodeMetadata { Description = $"{options.StatusCode} Unknown Code" };
7372
options.Sleep ??= ParseHeaderInt(req, SLEEP_HEADER);
7473
options.SleepAfterHeaders ??= ParseHeaderInt(req, SLEEP_AFTER_HEADERS);
7574
options.SuppressBody ??= ParseHeaderBool(req, SUPPRESS_BODY_HEADER);
@@ -78,8 +77,7 @@ TeapotStatusCodeMetadataCollection statusCodes
7877
options.AbortBeforeHeaders ??= ParseHeaderBool(req, ABORT_BEFORE_HEADERS);
7978
options.AbortDuringBody ??= ParseHeaderBool(req, ABORT_DURING_BODY);
8079

81-
82-
Dictionary<string, StringValues> customResponseHeaders = req.Headers
80+
options.CustomHeaders = req.Headers
8381
.Where(header => header.Key.StartsWith(CUSTOM_RESPONSE_HEADER_PREFIX, StringComparison.InvariantCultureIgnoreCase))
8482
.ToDictionary(
8583
header => header.Key.Replace(CUSTOM_RESPONSE_HEADER_PREFIX, string.Empty, StringComparison.InvariantCultureIgnoreCase),
@@ -98,8 +96,13 @@ internal static IResult HandleRandomRequest(
9896
{
9997
try
10098
{
101-
var options = new ResponseOptions(GetRandomStatus(range));
102-
return CommonHandleStatusRequestAsync(options, wildcard, req, statusCodes);
99+
var status = GetRandomStatus(range);
100+
TeapotStatusCodeMetadata statusData = statusCodes.TryGetValue(status, out TeapotStatusCodeMetadata? value) ?
101+
value :
102+
new TeapotStatusCodeMetadata { Description = $"{status} Unknown Code" };
103+
104+
ResponseOptions options = new(status, statusData);
105+
return CommonHandleStatusRequestAsync(options, wildcard, req);
103106
}
104107
catch
105108
{

0 commit comments

Comments
 (0)