Skip to content
This repository was archived by the owner on Nov 8, 2024. It is now read-only.

Commit abcecd6

Browse files
committed
Merge branch 'release/0.8.0' into production
2 parents 1a0c18f + b63a868 commit abcecd6

File tree

161 files changed

+4846
-1473
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

161 files changed

+4846
-1473
lines changed

.appveyor.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ test:
1212
assemblies:
1313
except:
1414
- '**\CSF.Screenplay.Web.Tests.dll'
15+
- '**\CSF.Screenplay.JsonApis.Tests.dll'
1516
- '**\Ploeh.AutoFixture.NUnit3.dll'
1617
- '**\CSF.Screenplay.NUnit.dll'
1718
artifacts:

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ Screenshots/
1414
*.log
1515
*.orig
1616
.xsp4.pid
17+
Backup/
18+
UpgradeLog.htm

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ matrix:
3434
- env:
3535
- SAUCE_USERNAME="craigfowler_screenplay"
3636
- secure: "ZI+FDrm6aec9HNMS4bbkgUzpeqVwy11flgnqWpYIyG12GzKQmrdXqMoAwD1kimIRNvry4r/z33GhBPDQaHly8edFzlkG4H8ITCyE48qttrVG71j5yYsyk6RLPm28zhcuhmnlalssk9jCsp09YFJ3zRO3Ayj/vboxTkQFhTa8d6nwag+MpfiVZVRdouO3qcKL3lPeWaQECo9hpX8o5MrQDCWprqg7b0ZMgW0vi5bqIFAmKoE/hn+qgp7BUQeVc983D8KClqYBsoJ09crn5ifd3CeCoOzeyczyS/DPrRgOOT63VdllGEQGKQZ78RY1LoloqEbbRI5ibjq7vuc8Er73yzxSbBbnKhG6nHRdfdNwxn2IAtZw86tpNSaKO1u8lprFDLbdCbHu42J6qQx4R8HZcq12Myv1eRYvupQrFv3mDAHK+NWYwCMKvouof50RNnJiFn6zcisvNQXCgG8NWeDBWbszRIwgvmQLsNB/vHCzrHO1bAT4lEYNuFVoUstO8t1r0C7ZVM6Qruuj46J0ZESTo10hUoHCohutdJ0ZAmH4ZxmW57L+BO1eFarkM7hmEZX6fImn0fobNHhSaEy+dNpYa9OS6n4iE6N4teTw20rpZ/AjkLUvJXjMh/YPkQ7M4VvDLqUHh5MPqAbgq3tUEfgPTm+lNy9QibquFwBRsAb3HRU="
37-
- BROWSER_PLATFORM="macOS 10.12"
37+
- BROWSER_PLATFORM="OS X 10.11"
3838
- BROWSER_NAME="Safari"
39+
- BROWSER_VERSION="10.0"
3940

4041
install: Tools/Travis.install.sh
4142

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
using System;
2+
using System.IO;
3+
using System.Net.Http;
4+
using System.Threading.Tasks;
5+
using CSF.Screenplay.Abilities;
6+
using Newtonsoft.Json;
7+
8+
namespace CSF.Screenplay.JsonApis.Abilities
9+
{
10+
public class ConsumeJsonWebServices : Ability
11+
{
12+
#region fields
13+
14+
static readonly TimeSpan SystemDefaultTimeout = new TimeSpan(0, 0, 30);
15+
16+
readonly TimeSpan defaultTimeout;
17+
readonly HttpClient httpClient;
18+
readonly JsonSerializer serializer;
19+
20+
#endregion
21+
22+
#region public API
23+
24+
public virtual void Execute(IProvidesInvocationDetails invocationDetails)
25+
{
26+
GetResponse(invocationDetails);
27+
}
28+
29+
public virtual T GetResult<T>(IProvidesInvocationDetails invocationDetails)
30+
{
31+
var response = GetResponse(invocationDetails);
32+
return ConvertResponse<T>(response);
33+
}
34+
35+
#endregion
36+
37+
#region private methods
38+
39+
HttpResponseMessage GetResponse(IProvidesInvocationDetails invocationDetails)
40+
{
41+
if(invocationDetails == null)
42+
throw new ArgumentNullException(nameof(invocationDetails));
43+
44+
var requestMessage = invocationDetails.GetRequestMessage();
45+
var timeout = GetTimeout(invocationDetails);
46+
47+
var response = httpClient.SendAsync(requestMessage);
48+
49+
var waitSuccess = response.Wait(timeout);
50+
if(!waitSuccess)
51+
throw new TimeoutException($"Timeout waiting for a response from a JSON API. Waited for {timeout.ToString("g")}");
52+
53+
AssertThatResultIsSuccess(response.Result, timeout);
54+
55+
return response.Result;
56+
}
57+
58+
void AssertThatResultIsSuccess(HttpResponseMessage result, TimeSpan timeout)
59+
{
60+
try
61+
{
62+
result.EnsureSuccessStatusCode();
63+
}
64+
catch(HttpRequestException ex)
65+
{
66+
var response = GetResultString(result, timeout);
67+
throw new JsonApiException($@"The API request failed: HTTP {result.StatusCode.ToString()}
68+
{response}", ex);
69+
}
70+
}
71+
72+
string GetResultString(HttpResponseMessage result, TimeSpan timeout)
73+
{
74+
Task<string> contentTask = null;
75+
76+
try
77+
{
78+
contentTask = result.Content.ReadAsStringAsync();
79+
}
80+
catch(Exception ex)
81+
{
82+
throw new JsonApiException($"The API request failed with no content: HTTP {result.StatusCode.ToString()}", ex);
83+
}
84+
85+
contentTask.Wait(timeout);
86+
return contentTask.Result;
87+
}
88+
89+
protected virtual T ConvertResponse<T>(HttpResponseMessage response)
90+
{
91+
using(var buffer = new MemoryStream())
92+
{
93+
var copyTask = response.Content.CopyToAsync(buffer);
94+
copyTask.Wait(TimeSpan.FromSeconds(5));
95+
96+
buffer.Position = 0;
97+
98+
using(var reader = new StreamReader(buffer))
99+
{
100+
return (T) serializer.Deserialize(reader, typeof(T));
101+
}
102+
}
103+
}
104+
105+
TimeSpan GetTimeout(IProvidesInvocationDetails invocationDetails)
106+
=> invocationDetails.GetTimeout().GetValueOrDefault(defaultTimeout);
107+
108+
#endregion
109+
110+
#region boilerplate Ability overrides
111+
112+
protected override string GetReport(Actors.INamed actor)
113+
=> $"{actor.Name} can consume JSON web services.";
114+
115+
protected override void Dispose(bool disposing)
116+
{
117+
base.Dispose(disposing);
118+
119+
if(disposing)
120+
httpClient.Dispose();
121+
}
122+
123+
#endregion
124+
125+
#region constructor
126+
127+
public ConsumeJsonWebServices(string baseUriString, TimeSpan? defaultTimeout = null)
128+
: this(new Uri(baseUriString, UriKind.Absolute), defaultTimeout) {}
129+
130+
public ConsumeJsonWebServices(Uri baseUri = null, TimeSpan? defaultTimeout = null)
131+
{
132+
httpClient = new HttpClient { BaseAddress = baseUri };
133+
this.defaultTimeout = defaultTimeout.GetValueOrDefault(SystemDefaultTimeout);
134+
serializer = JsonSerializer.CreateDefault();
135+
}
136+
137+
#endregion
138+
}
139+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using CSF.Screenplay.Actors;
3+
using CSF.Screenplay.JsonApis.Abilities;
4+
using CSF.Screenplay.Performables;
5+
6+
namespace CSF.Screenplay.JsonApis.Actions
7+
{
8+
public class ExecuteApi : Performable
9+
{
10+
readonly IProvidesInvocationDetails service;
11+
12+
protected override string GetReport(INamed actor)
13+
=> $"{actor.Name} executes {service.ToString()}";
14+
15+
protected override void PerformAs(IPerformer actor)
16+
{
17+
if(actor == null)
18+
throw new ArgumentNullException(nameof(actor));
19+
20+
var ability = actor.GetAbility<ConsumeJsonWebServices>();
21+
ability.Execute(service);
22+
}
23+
24+
public ExecuteApi(IProvidesInvocationDetails service)
25+
{
26+
if(service == null)
27+
throw new ArgumentNullException(nameof(service));
28+
29+
this.service = service;
30+
}
31+
}
32+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using CSF.Screenplay.Actors;
3+
using CSF.Screenplay.JsonApis.Abilities;
4+
using CSF.Screenplay.Performables;
5+
6+
namespace CSF.Screenplay.JsonApis.Actions
7+
{
8+
public class GetApiResult<T> : Question<T>
9+
{
10+
readonly IProvidesInvocationDetails service;
11+
12+
protected override string GetReport(INamed actor)
13+
=> $"{actor.Name} gets the result of {service.ToString()}";
14+
15+
protected override T PerformAs(IPerformer actor)
16+
{
17+
if(actor == null)
18+
throw new ArgumentNullException(nameof(actor));
19+
20+
var ability = actor.GetAbility<ConsumeJsonWebServices>();
21+
return ability.GetResult<T>(service);
22+
}
23+
24+
public GetApiResult(IProvidesInvocationDetails service)
25+
{
26+
if(service == null)
27+
throw new ArgumentNullException(nameof(service));
28+
29+
this.service = service;
30+
}
31+
}
32+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using CSF.Screenplay.JsonApis.Actions;
3+
4+
namespace CSF.Screenplay.JsonApis.Builders
5+
{
6+
public static class Execute
7+
{
8+
public static ExecuteApi AJsonApi(JsonServiceDescription invocationDetails)
9+
=> new ExecuteApi(invocationDetails);
10+
11+
public static GetApiResult<TResult> AJsonApiAndGetTheResult<TResult>(JsonServiceDescription<TResult> invocationDetails)
12+
=> new GetApiResult<TResult>(invocationDetails);
13+
}
14+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6+
<ProjectGuid>{9AA1246E-B5BC-499E-B0D9-EFA5F62F2E2C}</ProjectGuid>
7+
<OutputType>Library</OutputType>
8+
<RootNamespace>CSF.Screenplay.JsonApis</RootNamespace>
9+
<AssemblyName>CSF.Screenplay.JsonApis</AssemblyName>
10+
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
11+
<ReleaseVersion>0.8.0-alpha</ReleaseVersion>
12+
</PropertyGroup>
13+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
14+
<DebugSymbols>true</DebugSymbols>
15+
<DebugType>full</DebugType>
16+
<Optimize>false</Optimize>
17+
<OutputPath>bin\Debug</OutputPath>
18+
<DefineConstants>DEBUG;</DefineConstants>
19+
<ErrorReport>prompt</ErrorReport>
20+
<WarningLevel>4</WarningLevel>
21+
<ConsolePause>false</ConsolePause>
22+
</PropertyGroup>
23+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
24+
<Optimize>true</Optimize>
25+
<OutputPath>bin\Release</OutputPath>
26+
<ErrorReport>prompt</ErrorReport>
27+
<WarningLevel>4</WarningLevel>
28+
<ConsolePause>false</ConsolePause>
29+
</PropertyGroup>
30+
<ItemGroup>
31+
<Reference Include="System" />
32+
<Reference Include="System.Net.Http" />
33+
<Reference Include="Newtonsoft.Json">
34+
<HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
35+
</Reference>
36+
</ItemGroup>
37+
<ItemGroup>
38+
<Compile Include="Properties\AssemblyInfo.cs" />
39+
<Compile Include="IProvidesInvocationDetails.cs" />
40+
<Compile Include="Abilities\ConsumeJsonWebServices.cs" />
41+
<Compile Include="JsonApiException.cs" />
42+
<Compile Include="JsonServiceDescription.cs" />
43+
<Compile Include="Actions\ExecuteApi.cs" />
44+
<Compile Include="Actions\GetApiResult.cs" />
45+
<Compile Include="Builders\Execute.cs" />
46+
<Compile Include="JsonServiceDescription`1.cs" />
47+
</ItemGroup>
48+
<ItemGroup>
49+
<Folder Include="Abilities\" />
50+
<Folder Include="Actions\" />
51+
<Folder Include="Builders\" />
52+
</ItemGroup>
53+
<ItemGroup>
54+
<ProjectReference Include="..\CSF.Screenplay\CSF.Screenplay.csproj">
55+
<Project>{46E6DEAA-E6D5-4EE6-A552-17376BEA80DC}</Project>
56+
<Name>CSF.Screenplay</Name>
57+
</ProjectReference>
58+
</ItemGroup>
59+
<ItemGroup>
60+
<None Include="packages.config" />
61+
<None Include="CSF.Screenplay.JsonApis.nuspec" />
62+
</ItemGroup>
63+
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
64+
</Project>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<package>
3+
<metadata>
4+
<id>CSF.Screenplay.JsonApis</id>
5+
<version>0.8.0-alpha</version>
6+
<title>CSF.Screenplay.JsonApis</title>
7+
<authors>CSF Software Ltd</authors>
8+
<licenseUrl>https://opensource.org/licenses/MIT</licenseUrl>
9+
<projectUrl>https://github.com/csf-dev/CSF.Screenplay</projectUrl>
10+
<requireLicenseAcceptance>false</requireLicenseAcceptance>
11+
<description>Screenplay Abilities and Actions for making use of JSON HTTP web APIs in Screenplay</description>
12+
<copyright>Copyright 2018</copyright>
13+
<dependencies>
14+
<dependency id="Newtonsoft.Json" version="[10.0.3,11.0.0)" />
15+
<dependency id="CSF.Screenplay" version="0.8.0-alpha" />
16+
</dependencies>
17+
</metadata>
18+
<files>
19+
<file src="bin/Release/CSF.Screenplay.JsonApis.dll" target="lib/net45" />
20+
<!--
21+
TODO: #117 - When this project is documented fully, uncomment this
22+
<file src="bin/Release/CSF.Screenplay.JsonApis.xml" target="lib/net45" />
23+
-->
24+
</files>
25+
</package>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
using System.Net.Http;
3+
4+
namespace CSF.Screenplay.JsonApis
5+
{
6+
public interface IProvidesInvocationDetails
7+
{
8+
HttpRequestMessage GetRequestMessage();
9+
10+
TimeSpan? GetTimeout();
11+
}
12+
}

0 commit comments

Comments
 (0)