├── .gitignore ├── README.md ├── buildlocal.sh ├── src └── StatlerWaldorfCorp.TeamService │ ├── Controllers │ ├── MembersController.cs │ └── TeamsController.cs │ ├── Models │ ├── Member.cs │ └── Team.cs │ ├── Persistence │ ├── ITeamRepository.cs │ └── MemoryTeamRepository.cs │ ├── Program.cs │ ├── Startup.cs │ ├── StatlerWaldorfCorp.TeamService.csproj │ └── docker_entrypoint.sh ├── test ├── StatlerWaldorfCorp.TeamService.Tests.Integration │ ├── SimpleIntegrationTests.cs │ └── StatlerWaldorfCorp.TeamService.Tests.Integration.csproj └── StatlerWaldorfCorp.TeamService.Tests │ ├── .gitignore │ ├── MembersControllerTest.cs │ ├── StatlerWaldorfCorp.TeamService.Tests.csproj │ ├── TeamsControllerTest.cs │ └── TestMemoryTeamRepository.cs └── wercker.yml /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # Wercker temp 11 | .wercker/ 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | build/ 24 | bld/ 25 | [Bb]in/ 26 | [Oo]bj/ 27 | 28 | # Visual Studio 2015 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | # NUNIT 38 | *.VisualState.xml 39 | TestResult.xml 40 | 41 | # Build Results of an ATL Project 42 | [Dd]ebugPS/ 43 | [Rr]eleasePS/ 44 | dlldata.c 45 | 46 | # DNX 47 | project.lock.json 48 | artifacts/ 49 | 50 | *_i.c 51 | *_p.c 52 | *_i.h 53 | *.ilk 54 | *.meta 55 | *.obj 56 | *.pch 57 | *.pdb 58 | *.pgc 59 | *.pgd 60 | *.rsp 61 | *.sbr 62 | *.tlb 63 | *.tli 64 | *.tlh 65 | *.tmp 66 | *.tmp_proj 67 | *.log 68 | *.vspscc 69 | *.vssscc 70 | .builds 71 | *.pidb 72 | *.svclog 73 | *.scc 74 | 75 | # Chutzpah Test files 76 | _Chutzpah* 77 | 78 | # Visual C++ cache files 79 | ipch/ 80 | *.aps 81 | *.ncb 82 | *.opendb 83 | *.opensdf 84 | *.sdf 85 | *.cachefile 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | *.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | 158 | # Microsoft Azure Build Output 159 | csx/ 160 | *.build.csdef 161 | 162 | # Microsoft Azure Emulator 163 | ecf/ 164 | rcf/ 165 | 166 | # Microsoft Azure ApplicationInsights config file 167 | ApplicationInsights.config 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | ~$* 182 | *~ 183 | *.dbmdl 184 | *.dbproj.schemaview 185 | *.pfx 186 | *.publishsettings 187 | node_modules/ 188 | orleans.codegen.cs 189 | 190 | # RIA/Silverlight projects 191 | Generated_Code/ 192 | 193 | # Backup & report files from converting an old project file 194 | # to a newer Visual Studio version. Backup files are not needed, 195 | # because we have git ;-) 196 | _UpgradeReport_Files/ 197 | Backup*/ 198 | UpgradeLog*.XML 199 | UpgradeLog*.htm 200 | 201 | # SQL Server files 202 | *.mdf 203 | *.ldf 204 | 205 | # Business Intelligence projects 206 | *.rdl.data 207 | *.bim.layout 208 | *.bim_*.settings 209 | 210 | # Microsoft Fakes 211 | FakesAssemblies/ 212 | 213 | # GhostDoc plugin setting file 214 | *.GhostDoc.xml 215 | 216 | # Node.js Tools for Visual Studio 217 | .ntvs_analysis.dat 218 | 219 | # Visual Studio 6 build log 220 | *.plg 221 | 222 | # Visual Studio 6 workspace options file 223 | *.opt 224 | 225 | # Visual Studio LightSwitch build output 226 | **/*.HTMLClient/GeneratedArtifacts 227 | **/*.DesktopClient/GeneratedArtifacts 228 | **/*.DesktopClient/ModelManifest.xml 229 | **/*.Server/GeneratedArtifacts 230 | **/*.Server/ModelManifest.xml 231 | _Pvt_Extensions 232 | 233 | # Paket dependency manager 234 | .paket/paket.exe 235 | 236 | # FAKE - F# Make 237 | .fake/ 238 | .vscode/ 239 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![wercker status](https://app.wercker.com/status/98cdd1f2575eae0ae490e5032d95a2df/s/master "wercker status")](https://app.wercker.com/project/byKey/98cdd1f2575eae0ae490e5032d95a2df) 2 | 3 | # Team Service 4 | The first microservice sample from the **Building Microservices with ASP.NET Core** book. -------------------------------------------------------------------------------- /buildlocal.sh: -------------------------------------------------------------------------------- 1 | rm -rf _builds _steps _projects _cache _temp 2 | wercker build --git-domain github.com --git-owner microservices-aspnetcore --git-repository teamservice 3 | rm -rf _builds _steps _projects _cache _temp -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.TeamService/Controllers/MembersController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.AspNetCore.Mvc; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using StatlerWaldorfCorp.TeamService.Models; 8 | using System.Threading.Tasks; 9 | using StatlerWaldorfCorp.TeamService.Persistence; 10 | 11 | namespace StatlerWaldorfCorp.TeamService 12 | { 13 | [Route("/teams/{teamId}/[controller]")] 14 | public class MembersController : Controller 15 | { 16 | ITeamRepository repository; 17 | 18 | public MembersController(ITeamRepository repo) 19 | { 20 | repository = repo; 21 | } 22 | 23 | [HttpGet] 24 | public virtual IActionResult GetMembers(Guid teamID) 25 | { 26 | Team team = repository.Get(teamID); 27 | 28 | if(team == null) { 29 | return this.NotFound(); 30 | } else { 31 | return this.Ok(team.Members); 32 | } 33 | } 34 | 35 | 36 | [HttpGet] 37 | [Route("/teams/{teamId}/[controller]/{memberId}")] 38 | public virtual IActionResult GetMember(Guid teamID, Guid memberId) 39 | { 40 | Team team = repository.Get(teamID); 41 | 42 | if(team == null) { 43 | return this.NotFound(); 44 | } else { 45 | var q = team.Members.Where(m => m.ID == memberId); 46 | 47 | if(q.Count() < 1) { 48 | return this.NotFound(); 49 | } else { 50 | return this.Ok(q.First()); 51 | } 52 | } 53 | } 54 | 55 | [HttpPut] 56 | [Route("/teams/{teamId}/[controller]/{memberId}")] 57 | public virtual IActionResult UpdateMember([FromBody]Member updatedMember, Guid teamID, Guid memberId) 58 | { 59 | Team team = repository.Get(teamID); 60 | 61 | if(team == null) { 62 | return this.NotFound(); 63 | } else { 64 | var q = team.Members.Where(m => m.ID == memberId); 65 | 66 | if(q.Count() < 1) { 67 | return this.NotFound(); 68 | } else { 69 | team.Members.Remove(q.First()); 70 | team.Members.Add(updatedMember); 71 | return this.Ok(); 72 | } 73 | } 74 | } 75 | 76 | [HttpPost] 77 | public virtual IActionResult CreateMember([FromBody]Member newMember, Guid teamID) 78 | { 79 | Team team = repository.Get(teamID); 80 | 81 | if(team == null) { 82 | return this.NotFound(); 83 | } else { 84 | team.Members.Add(newMember); 85 | var teamMember = new {TeamID = team.ID, MemberID = newMember.ID}; 86 | return this.Created($"/teams/{teamMember.TeamID}/[controller]/{teamMember.MemberID}", teamMember); 87 | } 88 | } 89 | 90 | [HttpGet] 91 | [Route("/members/{memberId}/team")] 92 | public IActionResult GetTeamForMember(Guid memberId) 93 | { 94 | var teamId = GetTeamIdForMember(memberId); 95 | if (teamId != Guid.Empty) { 96 | return this.Ok(new { 97 | TeamID = teamId 98 | }); 99 | } else { 100 | return this.NotFound(); 101 | } 102 | } 103 | 104 | private Guid GetTeamIdForMember(Guid memberId) 105 | { 106 | foreach (var team in repository.List()) { 107 | var member = team.Members.FirstOrDefault( m => m.ID == memberId); 108 | if (member != null) { 109 | return team.ID; 110 | } 111 | } 112 | return Guid.Empty; 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.TeamService/Controllers/TeamsController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.AspNetCore.Mvc; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using StatlerWaldorfCorp.TeamService.Models; 8 | using System.Threading.Tasks; 9 | using StatlerWaldorfCorp.TeamService.Persistence; 10 | 11 | namespace StatlerWaldorfCorp.TeamService 12 | { 13 | [Route("[controller]")] 14 | public class TeamsController : Controller 15 | { 16 | ITeamRepository repository; 17 | 18 | public TeamsController(ITeamRepository repo) 19 | { 20 | repository = repo; 21 | } 22 | 23 | [HttpGet] 24 | public virtual IActionResult GetAllTeams() 25 | { 26 | return this.Ok(repository.List()); 27 | } 28 | 29 | [HttpGet("{id}")] 30 | public IActionResult GetTeam(Guid id) 31 | { 32 | Team team = repository.Get(id); 33 | 34 | if (team != null) // I HATE NULLS, MUST FIXERATE THIS. 35 | { 36 | return this.Ok(team); 37 | } else { 38 | return this.NotFound(); 39 | } 40 | } 41 | 42 | [HttpPost] 43 | public virtual IActionResult CreateTeam([FromBody]Team newTeam) 44 | { 45 | repository.Add(newTeam); 46 | 47 | //TODO: add test that asserts result is a 201 pointing to URL of the created team. 48 | //TODO: teams need IDs 49 | //TODO: return created at route to point to team details 50 | return this.Created($"/teams/{newTeam.ID}", newTeam); 51 | } 52 | 53 | [HttpPut("{id}")] 54 | public virtual IActionResult UpdateTeam([FromBody]Team team, Guid id) 55 | { 56 | team.ID = id; 57 | 58 | if(repository.Update(team) == null) { 59 | return this.NotFound(); 60 | } else { 61 | return this.Ok(team); 62 | } 63 | } 64 | 65 | [HttpDelete("{id}")] 66 | public virtual IActionResult DeleteTeam(Guid id) 67 | { 68 | Team team = repository.Delete(id); 69 | 70 | if (team == null) { 71 | return this.NotFound(); 72 | } else { 73 | return this.Ok(team.ID); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.TeamService/Models/Member.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace StatlerWaldorfCorp.TeamService.Models 4 | { 5 | public class Member { 6 | public Guid ID { get; set; } 7 | public string FirstName { get; set; } 8 | public string LastName { get; set; } 9 | 10 | public Member() { 11 | } 12 | 13 | public Member(Guid id) : this() { 14 | this.ID = id; 15 | } 16 | 17 | public Member(string firstName, string lastName, Guid id) : this(id) { 18 | this.FirstName = firstName; 19 | this.LastName = lastName; 20 | } 21 | 22 | public override string ToString() { 23 | return this.LastName; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.TeamService/Models/Team.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace StatlerWaldorfCorp.TeamService.Models 5 | { 6 | public class Team { 7 | 8 | public string Name { get; set; } 9 | public Guid ID { get; set; } 10 | public ICollection Members { get; set; } 11 | 12 | public Team() 13 | { 14 | this.Members = new List(); 15 | } 16 | 17 | public Team(string name) : this() 18 | { 19 | this.Name = name; 20 | } 21 | 22 | public Team(string name, Guid id) : this(name) 23 | { 24 | this.ID = id; 25 | } 26 | 27 | public override string ToString() { 28 | return this.Name; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.TeamService/Persistence/ITeamRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using StatlerWaldorfCorp.TeamService.Models; 4 | 5 | namespace StatlerWaldorfCorp.TeamService.Persistence 6 | { 7 | public interface ITeamRepository { 8 | IEnumerable List(); 9 | Team Get(Guid id); 10 | Team Add(Team team); 11 | Team Update(Team team); 12 | Team Delete(Guid id); 13 | } 14 | } -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.TeamService/Persistence/MemoryTeamRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using StatlerWaldorfCorp.TeamService; 5 | using StatlerWaldorfCorp.TeamService.Models; 6 | 7 | namespace StatlerWaldorfCorp.TeamService.Persistence 8 | { 9 | public class MemoryTeamRepository : ITeamRepository { 10 | protected static ICollection teams; 11 | 12 | public MemoryTeamRepository() { 13 | if(teams == null) { 14 | teams = new List(); 15 | } 16 | } 17 | 18 | public MemoryTeamRepository(ICollection teams) { 19 | MemoryTeamRepository.teams = teams; 20 | } 21 | 22 | public IEnumerable List() { 23 | return teams; 24 | } 25 | 26 | public Team Get(Guid id) { 27 | return teams.FirstOrDefault(t => t.ID == id); 28 | } 29 | 30 | public Team Update(Team t) 31 | { 32 | Team team = this.Delete(t.ID); 33 | 34 | if(team != null) { 35 | team = this.Add(t); 36 | } 37 | 38 | return team; 39 | } 40 | 41 | public Team Add(Team team) 42 | { 43 | teams.Add(team); 44 | return team; 45 | } 46 | 47 | public Team Delete(Guid id) { 48 | var q = teams.Where(t => t.ID == id); 49 | Team team = null; 50 | 51 | if (q.Count() > 0) { 52 | team = q.First(); 53 | teams.Remove(team); 54 | } 55 | 56 | return team; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.TeamService/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.Extensions.Configuration; 5 | 6 | namespace StatlerWaldorfCorp.TeamService 7 | { 8 | public class Program 9 | { 10 | public static void Main(string[] args) 11 | { 12 | var config = new ConfigurationBuilder() 13 | .AddCommandLine(args) 14 | .Build(); 15 | 16 | var host = new WebHostBuilder() 17 | .UseKestrel() 18 | .UseStartup() 19 | .UseConfiguration(config) 20 | .Build(); 21 | 22 | host.Run(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.TeamService/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Logging; 4 | using Microsoft.AspNetCore.Http; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using StatlerWaldorfCorp.TeamService.Models; 8 | using StatlerWaldorfCorp.TeamService.Persistence; 9 | 10 | namespace StatlerWaldorfCorp.TeamService { 11 | public class Startup 12 | { 13 | public Startup(IHostingEnvironment env) 14 | { 15 | } 16 | 17 | public IConfigurationRoot Configuration { get; } 18 | 19 | public void ConfigureServices(IServiceCollection services) 20 | { 21 | services.AddMvc(); 22 | services.AddScoped(); 23 | } 24 | 25 | public void Configure(IApplicationBuilder app) 26 | { 27 | app.UseMvc(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.TeamService/StatlerWaldorfCorp.TeamService.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp1.1 5 | StatlerWaldorfCorp.TeamService 6 | Exe 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.TeamService/docker_entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd /pipeline/source/app/publish 3 | dotnet StatlerWaldorfCorp.TeamService.dll --server.urls=http://0.0.0.0:${PORT-"8080"} 4 | -------------------------------------------------------------------------------- /test/StatlerWaldorfCorp.TeamService.Tests.Integration/SimpleIntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | using System.Collections.Generic; 3 | using StatlerWaldorfCorp.TeamService.Models; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.TestHost; 8 | using System; 9 | using System.Net.Http; 10 | using System.Linq; 11 | using Newtonsoft.Json; 12 | using System.Text; 13 | 14 | namespace StatlerWaldorfCorp.TeamService.Tests.Integration 15 | { 16 | public class SimpleIntegrationTests 17 | { 18 | private readonly TestServer testServer; 19 | private readonly HttpClient testClient; 20 | 21 | private readonly Team teamZombie; 22 | 23 | public SimpleIntegrationTests() 24 | { 25 | testServer = new TestServer(new WebHostBuilder() 26 | .UseStartup()); 27 | testClient = testServer.CreateClient(); 28 | 29 | teamZombie = new Team() { 30 | ID = Guid.NewGuid(), 31 | Name = "Zombie" 32 | }; 33 | } 34 | 35 | [Fact] 36 | public async void TestTeamPostAndGet() 37 | { 38 | StringContent stringContent = new StringContent( 39 | JsonConvert.SerializeObject(teamZombie), 40 | UnicodeEncoding.UTF8, 41 | "application/json"); 42 | 43 | // Act 44 | HttpResponseMessage postResponse = await testClient.PostAsync( 45 | "/teams", 46 | stringContent); 47 | postResponse.EnsureSuccessStatusCode(); 48 | 49 | var getResponse = await testClient.GetAsync("/teams"); 50 | getResponse.EnsureSuccessStatusCode(); 51 | 52 | string raw = await getResponse.Content.ReadAsStringAsync(); 53 | List teams = JsonConvert.DeserializeObject>(raw); 54 | Assert.Equal(1, teams.Count()); 55 | Assert.Equal("Zombie", teams[0].Name); 56 | Assert.Equal(teamZombie.ID, teams[0].ID); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /test/StatlerWaldorfCorp.TeamService.Tests.Integration/StatlerWaldorfCorp.TeamService.Tests.Integration.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp1.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/StatlerWaldorfCorp.TeamService.Tests/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | 84 | # Visual Studio profiler 85 | *.psess 86 | *.vsp 87 | *.vspx 88 | *.sap 89 | 90 | # TFS 2012 Local Workspace 91 | $tf/ 92 | 93 | # Guidance Automation Toolkit 94 | *.gpState 95 | 96 | # ReSharper is a .NET coding add-in 97 | _ReSharper*/ 98 | *.[Rr]e[Ss]harper 99 | *.DotSettings.user 100 | 101 | # JustCode is a .NET coding add-in 102 | .JustCode 103 | 104 | # TeamCity is a build add-in 105 | _TeamCity* 106 | 107 | # DotCover is a Code Coverage Tool 108 | *.dotCover 109 | 110 | # NCrunch 111 | _NCrunch_* 112 | .*crunch*.local.xml 113 | nCrunchTemp_* 114 | 115 | # MightyMoose 116 | *.mm.* 117 | AutoTest.Net/ 118 | 119 | # Web workbench (sass) 120 | .sass-cache/ 121 | 122 | # Installshield output folder 123 | [Ee]xpress/ 124 | 125 | # DocProject is a documentation generator add-in 126 | DocProject/buildhelp/ 127 | DocProject/Help/*.HxT 128 | DocProject/Help/*.HxC 129 | DocProject/Help/*.hhc 130 | DocProject/Help/*.hhk 131 | DocProject/Help/*.hhp 132 | DocProject/Help/Html2 133 | DocProject/Help/html 134 | 135 | # Click-Once directory 136 | publish/ 137 | 138 | # Publish Web Output 139 | *.[Pp]ublish.xml 140 | *.azurePubxml 141 | # TODO: Comment the next line if you want to checkin your web deploy settings 142 | # but database connection strings (with potential passwords) will be unencrypted 143 | *.pubxml 144 | *.publishproj 145 | 146 | # NuGet Packages 147 | *.nupkg 148 | # The packages folder can be ignored because of Package Restore 149 | **/packages/* 150 | # except build/, which is used as an MSBuild target. 151 | !**/packages/build/ 152 | # Uncomment if necessary however generally it will be regenerated when needed 153 | #!**/packages/repositories.config 154 | 155 | # Microsoft Azure Build Output 156 | csx/ 157 | *.build.csdef 158 | 159 | # Microsoft Azure Emulator 160 | ecf/ 161 | rcf/ 162 | 163 | # Microsoft Azure ApplicationInsights config file 164 | ApplicationInsights.config 165 | 166 | # Windows Store app package directory 167 | AppPackages/ 168 | BundleArtifacts/ 169 | 170 | # Visual Studio cache files 171 | # files ending in .cache can be ignored 172 | *.[Cc]ache 173 | # but keep track of directories ending in .cache 174 | !*.[Cc]ache/ 175 | 176 | # Others 177 | ClientBin/ 178 | ~$* 179 | *~ 180 | *.dbmdl 181 | *.dbproj.schemaview 182 | *.pfx 183 | *.publishsettings 184 | node_modules/ 185 | orleans.codegen.cs 186 | 187 | # RIA/Silverlight projects 188 | Generated_Code/ 189 | 190 | # Backup & report files from converting an old project file 191 | # to a newer Visual Studio version. Backup files are not needed, 192 | # because we have git ;-) 193 | _UpgradeReport_Files/ 194 | Backup*/ 195 | UpgradeLog*.XML 196 | UpgradeLog*.htm 197 | 198 | # SQL Server files 199 | *.mdf 200 | *.ldf 201 | 202 | # Business Intelligence projects 203 | *.rdl.data 204 | *.bim.layout 205 | *.bim_*.settings 206 | 207 | # Microsoft Fakes 208 | FakesAssemblies/ 209 | 210 | # GhostDoc plugin setting file 211 | *.GhostDoc.xml 212 | 213 | # Node.js Tools for Visual Studio 214 | .ntvs_analysis.dat 215 | 216 | # Visual Studio 6 build log 217 | *.plg 218 | 219 | # Visual Studio 6 workspace options file 220 | *.opt 221 | 222 | # Visual Studio LightSwitch build output 223 | **/*.HTMLClient/GeneratedArtifacts 224 | **/*.DesktopClient/GeneratedArtifacts 225 | **/*.DesktopClient/ModelManifest.xml 226 | **/*.Server/GeneratedArtifacts 227 | **/*.Server/ModelManifest.xml 228 | _Pvt_Extensions 229 | 230 | # Paket dependency manager 231 | .paket/paket.exe 232 | 233 | # FAKE - F# Make 234 | .fake/ 235 | -------------------------------------------------------------------------------- /test/StatlerWaldorfCorp.TeamService.Tests/MembersControllerTest.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | using System.Collections.Generic; 3 | using StatlerWaldorfCorp.TeamService.Models; 4 | using Microsoft.AspNetCore.Mvc; 5 | using System; 6 | using System.Linq; 7 | using StatlerWaldorfCorp.TeamService.Persistence; 8 | 9 | [assembly:CollectionBehavior(MaxParallelThreads = 1)] 10 | 11 | namespace StatlerWaldorfCorp.TeamService 12 | { 13 | public class MembersControllerTest 14 | { 15 | [Fact] 16 | public void CreateMemberAddsTeamToList() 17 | { 18 | ITeamRepository repository = new TestMemoryTeamRepository(); 19 | MembersController controller = new MembersController(repository); 20 | 21 | Guid teamId = Guid.NewGuid(); 22 | Team team = new Team("TestController", teamId); 23 | repository.Add(team); 24 | 25 | Guid newMemberId = Guid.NewGuid(); 26 | Member newMember = new Member(newMemberId); 27 | controller.CreateMember(newMember, teamId); 28 | 29 | team = repository.Get(teamId); 30 | Assert.True(team.Members.Contains(newMember)); 31 | } 32 | 33 | [Fact] 34 | public void CreateMembertoNonexistantTeamReturnsNotFound() 35 | { 36 | ITeamRepository repository = new TestMemoryTeamRepository(); 37 | MembersController controller = new MembersController(repository); 38 | 39 | Guid teamId = Guid.NewGuid(); 40 | 41 | Guid newMemberId = Guid.NewGuid(); 42 | Member newMember = new Member(newMemberId); 43 | var result = controller.CreateMember(newMember, teamId); 44 | 45 | Assert.True(result is NotFoundResult); 46 | } 47 | 48 | [Fact] 49 | public void GetExistingMemberReturnsMember() 50 | { 51 | ITeamRepository repository = new TestMemoryTeamRepository(); 52 | MembersController controller = new MembersController(repository); 53 | 54 | Guid teamId = Guid.NewGuid(); 55 | Team team = new Team("TestTeam", teamId); 56 | var debugTeam = repository.Add(team); 57 | 58 | Guid memberId = Guid.NewGuid(); 59 | Member newMember = new Member(memberId); 60 | newMember.FirstName = "Jim"; 61 | newMember.LastName = "Smith"; 62 | controller.CreateMember(newMember, teamId); 63 | 64 | Member member = (Member)(controller.GetMember(teamId, memberId) as ObjectResult).Value; 65 | Assert.Equal(member.ID, newMember.ID); 66 | } 67 | 68 | [Fact] 69 | public void GetMembersReturnsMembers() 70 | { 71 | ITeamRepository repository = new TestMemoryTeamRepository(); 72 | MembersController controller = new MembersController(repository); 73 | 74 | Guid teamId = Guid.NewGuid(); 75 | Team team = new Team("TestTeam", teamId); 76 | var debugTeam = repository.Add(team); 77 | 78 | Guid firstMemberId = Guid.NewGuid(); 79 | Member newMember = new Member(firstMemberId); 80 | newMember.FirstName = "Jim"; 81 | newMember.LastName = "Smith"; 82 | controller.CreateMember(newMember, teamId); 83 | 84 | Guid secondMemberId = Guid.NewGuid(); 85 | newMember = new Member(secondMemberId); 86 | newMember.FirstName = "John"; 87 | newMember.LastName = "Doe"; 88 | controller.CreateMember(newMember, teamId); 89 | 90 | ICollection members = (ICollection)(controller.GetMembers(teamId) as ObjectResult).Value; 91 | Assert.Equal(2, members.Count()); 92 | Assert.NotNull(members.Where(m => m.ID == firstMemberId).First().ID); 93 | Assert.NotNull(members.Where(m => m.ID == secondMemberId).First().ID); 94 | } 95 | 96 | [Fact] 97 | public void GetMembersForNewTeamIsEmpty() 98 | { 99 | ITeamRepository repository = new TestMemoryTeamRepository(); 100 | MembersController controller = new MembersController(repository); 101 | 102 | Guid teamId = Guid.NewGuid(); 103 | Team team = new Team("TestTeam", teamId); 104 | var debugTeam = repository.Add(team); 105 | 106 | ICollection members = (ICollection)(controller.GetMembers(teamId) as ObjectResult).Value; 107 | Assert.Empty(members); 108 | } 109 | 110 | [Fact] 111 | public void GetMembersForNonExistantTeamReturnNotFound() 112 | { 113 | ITeamRepository repository = new TestMemoryTeamRepository(); 114 | MembersController controller = new MembersController(repository); 115 | 116 | var result = controller.GetMembers(Guid.NewGuid()); 117 | Assert.True(result is NotFoundResult); 118 | } 119 | 120 | [Fact] 121 | public void GetNonExistantTeamReturnsNotFound() 122 | { 123 | ITeamRepository repository = new TestMemoryTeamRepository(); 124 | MembersController controller = new MembersController(repository); 125 | 126 | var result = controller.GetMember(Guid.NewGuid(), Guid.NewGuid()); 127 | Assert.True(result is NotFoundResult); 128 | } 129 | 130 | [Fact] 131 | public void GetNonExistantMemberReturnsNotFound() 132 | { 133 | ITeamRepository repository = new TestMemoryTeamRepository(); 134 | MembersController controller = new MembersController(repository); 135 | 136 | Guid teamId = Guid.NewGuid(); 137 | Team team = new Team("TestTeam", teamId); 138 | var debugTeam = repository.Add(team); 139 | 140 | var result = controller.GetMember(teamId, Guid.NewGuid()); 141 | Assert.True(result is NotFoundResult); 142 | } 143 | 144 | [Fact] 145 | public void UpdateMemberOverwrites() 146 | { 147 | ITeamRepository repository = new TestMemoryTeamRepository(); 148 | MembersController controller = new MembersController(repository); 149 | 150 | Guid teamId = Guid.NewGuid(); 151 | Team team = new Team("TestTeam", teamId); 152 | var debugTeam = repository.Add(team); 153 | 154 | Guid memberId = Guid.NewGuid(); 155 | Member newMember = new Member(memberId); 156 | newMember.FirstName = "Jim"; 157 | newMember.LastName = "Smith"; 158 | controller.CreateMember(newMember, teamId); 159 | 160 | team = repository.Get(teamId); 161 | 162 | Member updatedMember = new Member(memberId); 163 | updatedMember.FirstName = "Bob"; 164 | updatedMember.LastName = "Jones"; 165 | controller.UpdateMember(updatedMember, teamId, memberId); 166 | 167 | team = repository.Get(teamId); 168 | Member testMember = team.Members.Where(m => m.ID == memberId).First(); 169 | 170 | Assert.Equal(testMember.FirstName, "Bob"); 171 | Assert.Equal(testMember.LastName, "Jones"); 172 | } 173 | 174 | [Fact] 175 | public void UpdateMembertoNonexistantMemberReturnsNoMatch() 176 | { 177 | ITeamRepository repository = new TestMemoryTeamRepository(); 178 | MembersController controller = new MembersController(repository); 179 | 180 | Guid teamId = Guid.NewGuid(); 181 | Team team = new Team("TestController", teamId); 182 | repository.Add(team); 183 | 184 | Guid memberId = Guid.NewGuid(); 185 | Member newMember = new Member(memberId); 186 | newMember.FirstName = "Jim"; 187 | controller.CreateMember(newMember, teamId); 188 | 189 | Guid nonMatchedGuid = Guid.NewGuid(); 190 | Member updatedMember = new Member(nonMatchedGuid); 191 | updatedMember.FirstName = "Bob"; 192 | var result = controller.UpdateMember(updatedMember, teamId, nonMatchedGuid); 193 | 194 | Assert.True(result is NotFoundResult); 195 | } 196 | } 197 | } -------------------------------------------------------------------------------- /test/StatlerWaldorfCorp.TeamService.Tests/StatlerWaldorfCorp.TeamService.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp1.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /test/StatlerWaldorfCorp.TeamService.Tests/TeamsControllerTest.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | using System.Collections.Generic; 3 | using StatlerWaldorfCorp.TeamService.Models; 4 | using Microsoft.AspNetCore.Mvc; 5 | using System; 6 | using System.Linq; 7 | 8 | namespace StatlerWaldorfCorp.TeamService 9 | { 10 | public class TeamsControllerTest 11 | { 12 | [Fact] 13 | public void QueryTeamListReturnsCorrectTeams() 14 | { 15 | TeamsController controller = new TeamsController(new TestMemoryTeamRepository()); 16 | var rawTeams = (IEnumerable)(controller.GetAllTeams() as ObjectResult).Value; 17 | List teams = new List(rawTeams); 18 | Assert.Equal(teams.Count, 2); 19 | Assert.Equal(teams[0].Name, "one"); 20 | Assert.Equal(teams[1].Name, "two"); 21 | } 22 | 23 | [Fact] 24 | public void GetTeamRetrievesTeam() 25 | { 26 | TeamsController controller = new TeamsController(new TestMemoryTeamRepository()); 27 | 28 | string sampleName = "sample"; 29 | Guid id = Guid.NewGuid(); 30 | Team sampleTeam = new Team(sampleName, id); 31 | controller.CreateTeam(sampleTeam); 32 | 33 | Team retrievedTeam = (Team)(controller.GetTeam(id) as ObjectResult).Value; 34 | Assert.Equal(retrievedTeam.Name, sampleName); 35 | Assert.Equal(retrievedTeam.ID, id); 36 | } 37 | 38 | [Fact] 39 | public void GetNonExistentTeamReturnsNotFound() 40 | { 41 | TeamsController controller = new TeamsController(new TestMemoryTeamRepository()); 42 | 43 | Guid id = Guid.NewGuid(); 44 | var result = controller.GetTeam(id); 45 | Assert.True(result is NotFoundResult); 46 | } 47 | 48 | [Fact] 49 | public void CreateTeamAddsTeamToList() 50 | { 51 | TeamsController controller = new TeamsController(new TestMemoryTeamRepository()); 52 | var teams = (IEnumerable)(controller.GetAllTeams() as ObjectResult).Value; 53 | List original = new List(teams); 54 | 55 | Team t = new Team("sample"); 56 | var result = controller.CreateTeam(t); 57 | //TODO: also assert that the destination URL of the new team reflects the team's GUID 58 | Assert.Equal((result as ObjectResult).StatusCode, 201); 59 | 60 | var actionResult = controller.GetAllTeams() as ObjectResult; 61 | var newTeamsRaw = (IEnumerable)(controller.GetAllTeams() as ObjectResult).Value; 62 | List newTeams = new List(newTeamsRaw); 63 | Assert.Equal(newTeams.Count, original.Count+1); 64 | var sampleTeam = newTeams.FirstOrDefault( target => target.Name == "sample"); 65 | Assert.NotNull(sampleTeam); 66 | } 67 | 68 | [Fact] 69 | public void UpdateTeamModifiesTeamToList() 70 | { 71 | TeamsController controller = new TeamsController(new TestMemoryTeamRepository()); 72 | var teams = (IEnumerable)(controller.GetAllTeams() as ObjectResult).Value; 73 | List original = new List(teams); 74 | 75 | Guid id = Guid.NewGuid(); 76 | Team t = new Team("sample", id); 77 | var result = controller.CreateTeam(t); 78 | 79 | Team newTeam = new Team("sample2", id); 80 | controller.UpdateTeam(newTeam, id); 81 | 82 | var newTeamsRaw = (IEnumerable)(controller.GetAllTeams() as ObjectResult).Value; 83 | List newTeams = new List(newTeamsRaw); 84 | var sampleTeam = newTeams.FirstOrDefault( target => target.Name == "sample"); 85 | Assert.Null(sampleTeam); 86 | 87 | Team retrievedTeam = (Team)(controller.GetTeam(id) as ObjectResult).Value; 88 | Assert.Equal(retrievedTeam.Name, "sample2"); 89 | } 90 | 91 | [Fact] 92 | public void UpdateNonExistentTeamReturnsNotFound() 93 | { 94 | TeamsController controller = new TeamsController(new TestMemoryTeamRepository()); 95 | var teams = (IEnumerable)(controller.GetAllTeams() as ObjectResult).Value; 96 | List original = new List(teams); 97 | 98 | Team someTeam = new Team("Some Team", Guid.NewGuid()); 99 | controller.CreateTeam(someTeam); 100 | 101 | Guid newTeamId = Guid.NewGuid(); 102 | Team newTeam = new Team("New Team", newTeamId); 103 | var result = controller.UpdateTeam(newTeam, newTeamId); 104 | 105 | Assert.True(result is NotFoundResult); 106 | } 107 | 108 | [Fact] 109 | public void DeleteTeamRemovesFromList() 110 | { 111 | TeamsController controller = new TeamsController(new TestMemoryTeamRepository()); 112 | var teams = (IEnumerable)(controller.GetAllTeams() as ObjectResult).Value; 113 | int ct = teams.Count(); 114 | 115 | string sampleName = "sample"; 116 | Guid id = Guid.NewGuid(); 117 | Team sampleTeam = new Team(sampleName, id); 118 | controller.CreateTeam(sampleTeam); 119 | 120 | teams = (IEnumerable)(controller.GetAllTeams() as ObjectResult).Value; 121 | sampleTeam = teams.FirstOrDefault(target => target.Name == sampleName); 122 | Assert.NotNull(sampleTeam); 123 | 124 | controller.DeleteTeam(id); 125 | 126 | teams = (IEnumerable)(controller.GetAllTeams() as ObjectResult).Value; 127 | sampleTeam = teams.FirstOrDefault(target => target.Name == sampleName); 128 | Assert.Null(sampleTeam); 129 | } 130 | 131 | [Fact] 132 | public void DeleteNonExistentTeamReturnsNotFound() 133 | { 134 | TeamsController controller = new TeamsController(new TestMemoryTeamRepository()); 135 | Guid id = Guid.NewGuid(); 136 | 137 | var result = controller.DeleteTeam(id); 138 | Assert.True(result is NotFoundResult); 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /test/StatlerWaldorfCorp.TeamService.Tests/TestMemoryTeamRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using StatlerWaldorfCorp.TeamService.Persistence; 3 | 4 | namespace StatlerWaldorfCorp.TeamService.Models 5 | { 6 | public class TestMemoryTeamRepository : MemoryTeamRepository { 7 | public TestMemoryTeamRepository() : base(CreateInitialFake()) { 8 | 9 | } 10 | 11 | private static ICollection CreateInitialFake() 12 | { 13 | var teams = new List(); 14 | teams.Add(new Team("one")); 15 | teams.Add(new Team("two")); 16 | 17 | return teams; 18 | } 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /wercker.yml: -------------------------------------------------------------------------------- 1 | box: microsoft/dotnet:1.1.1-sdk 2 | no-response-timeout: 10 3 | build: 4 | steps: 5 | - script: 6 | name: restore 7 | cwd: src/StatlerWaldorfCorp.TeamService 8 | code: | 9 | dotnet restore 10 | - script: 11 | name: build 12 | cwd: src/StatlerWaldorfCorp.TeamService 13 | code: | 14 | dotnet build 15 | - script: 16 | name: publish 17 | cwd: src/StatlerWaldorfCorp.TeamService 18 | code: | 19 | dotnet publish -o publish 20 | - script: 21 | name: test-restore 22 | cwd: test/StatlerWaldorfCorp.TeamService.Tests 23 | code: | 24 | dotnet restore 25 | - script: 26 | name: test-build 27 | cwd: test/StatlerWaldorfCorp.TeamService.Tests 28 | code: | 29 | dotnet build 30 | - script: 31 | name: test-run 32 | cwd: test/StatlerWaldorfCorp.TeamService.Tests 33 | code: | 34 | dotnet test 35 | - script: 36 | name: integration-test-restore 37 | cwd: test/StatlerWaldorfCorp.TeamService.Tests.Integration 38 | code: | 39 | dotnet restore 40 | - script: 41 | name: integration-test-build 42 | cwd: test/StatlerWaldorfCorp.TeamService.Tests.Integration 43 | code: | 44 | dotnet build 45 | - script: 46 | name: integration-test-run 47 | cwd: test/StatlerWaldorfCorp.TeamService.Tests.Integration 48 | code: | 49 | dotnet test 50 | - script: 51 | name: copy binary 52 | cwd: src/StatlerWaldorfCorp.TeamService 53 | code: | 54 | cp -r . $WERCKER_OUTPUT_DIR/app 55 | deploy: 56 | steps: 57 | - internal/docker-push: 58 | cwd: $WERCKER_OUTPUT_DIR/app 59 | username: $USERNAME 60 | password: $PASSWORD 61 | repository: dotnetcoreservices/teamservice 62 | registry: https://registry.hub.docker.com 63 | entrypoint: "/pipeline/source/app/docker_entrypoint.sh" --------------------------------------------------------------------------------