├── .gitignore ├── README.md ├── buildlocal.sh ├── docker_entrypoint.sh ├── src └── StatlerWaldorfCorp.LocationService │ ├── Controllers │ └── LocationRecordController.cs │ ├── Migrations │ ├── 20160917140258_Initial.Designer.cs │ ├── 20160917140258_Initial.cs │ └── LocationDbContextModelSnapshot.cs │ ├── Models │ ├── ILocationRecordRepository.cs │ └── LocationRecord.cs │ ├── Persistence │ ├── InMemoryLocationRecordRepository.cs │ ├── LocationDbContext.cs │ └── LocationRecordRepository.cs │ ├── Program.cs │ ├── Startup.cs │ ├── StatlerWaldorfCorp.LocationService.csproj │ ├── appsettings.json │ └── nuget.config ├── test ├── StatlerWaldorfCorp.LocationService.Integration │ ├── PostgresIntegrationTest.cs │ ├── StatlerWaldorfCorp.LocationService.Integration.csproj │ └── appsettings.json └── StatlerWaldorfCorp.LocationService.Tests │ ├── LocationRecordControllerTest.cs │ └── StatlerWaldorfCorp.LocationService.Tests.csproj └── wercker.yml /.gitignore: -------------------------------------------------------------------------------- 1 | project.lock.json 2 | *~ 3 | \#* 4 | bin 5 | obj 6 | .vscode/ 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![wercker status](https://app.wercker.com/status/6e2e4539d366f796b4df865883bae4da/m/master "wercker status")](https://app.wercker.com/project/byKey/6e2e4539d366f796b4df865883bae4da) 2 | 3 | # Location Service 4 | Service to keep a historical record of team member locations. 5 | 6 | This branch of the project requires two environment variables to function properly: 7 | 8 | * TRANSIENT (boolean) 9 | * POSTGRES_CSTR (postgres connection string) 10 | 11 | -------------------------------------------------------------------------------- /buildlocal.sh: -------------------------------------------------------------------------------- 1 | rm -rf _builds _steps _projects _cache _temp 2 | wercker build --git-domain github.com --git-owner microservices-aspnetcore --git-repository locationservice 3 | rm -rf _builds _steps _projects _cache _temp -------------------------------------------------------------------------------- /docker_entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd /pipeline/source/app/publish 3 | echo "starting" 4 | # mkdir /pipeline/source/app/publish/tmp 5 | # export TEMP=/pipeline/source/app/publish/tmp 6 | export TMPDIR=/pipeline/source/app/publish/tmp 7 | dotnet StatlerWaldorfCorp.LocationService.dll --server.urls=http://0.0.0.0:${PORT-"8080"} 8 | -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/Controllers/LocationRecordController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Mvc; 3 | using StatlerWaldorfCorp.LocationService.Models; 4 | 5 | namespace StatlerWaldorfCorp.LocationService.Controllers { 6 | 7 | [Route("locations/{memberId}")] 8 | public class LocationRecordController : Controller { 9 | 10 | private ILocationRecordRepository locationRepository; 11 | 12 | public LocationRecordController(ILocationRecordRepository repository) { 13 | this.locationRepository = repository; 14 | } 15 | 16 | [HttpPost] 17 | public IActionResult AddLocation(Guid memberId, [FromBody]LocationRecord locationRecord) { 18 | locationRepository.Add(locationRecord); 19 | return this.Created($"/locations/{memberId}/{locationRecord.ID}", locationRecord); 20 | } 21 | 22 | [HttpGet] 23 | public IActionResult GetLocationsForMember(Guid memberId) { 24 | return this.Ok(locationRepository.AllForMember(memberId)); 25 | } 26 | 27 | [HttpGet("latest")] 28 | public IActionResult GetLatestForMember(Guid memberId) { 29 | return this.Ok(locationRepository.GetLatestForMember(memberId)); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/Migrations/20160917140258_Initial.Designer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using StatlerWaldorfCorp.LocationService.Persistence; 7 | 8 | namespace StatlerWaldorfCorp.LocationService.Migrations 9 | { 10 | [DbContext(typeof(LocationDbContext))] 11 | [Migration("20160917140258_Initial")] 12 | partial class Initial 13 | { 14 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 15 | { 16 | modelBuilder 17 | .HasAnnotation("Npgsql:PostgresExtension:.uuid-ossp", "'uuid-ossp', '', ''") 18 | .HasAnnotation("ProductVersion", "1.0.0-rtm-21431"); 19 | 20 | modelBuilder.Entity("StatlerWaldorfCorp.LocationService.Models.LocationRecord", b => 21 | { 22 | b.Property("ID") 23 | .ValueGeneratedOnAdd(); 24 | 25 | b.Property("Altitude"); 26 | 27 | b.Property("Latitude"); 28 | 29 | b.Property("Longitude"); 30 | 31 | b.Property("MemberID"); 32 | 33 | b.Property("Timestamp"); 34 | 35 | b.HasKey("ID"); 36 | 37 | b.ToTable("LocationRecords"); 38 | }); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/Migrations/20160917140258_Initial.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Npgsql.EntityFrameworkCore.PostgreSQL; 4 | using Microsoft.EntityFrameworkCore.Migrations; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | 7 | namespace StatlerWaldorfCorp.LocationService.Migrations 8 | { 9 | public partial class Initial : Migration 10 | { 11 | protected override void Up(MigrationBuilder migrationBuilder) 12 | { 13 | migrationBuilder.EnsurePostgresExtension("uuid-ossp"); 14 | 15 | migrationBuilder.CreateTable( 16 | name: "LocationRecords", 17 | columns: table => new 18 | { 19 | ID = table.Column(nullable: false) 20 | .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), 21 | //.Annotation("Npgsql:ValueGeneratedOnAdd", true), 22 | Altitude = table.Column(nullable: false), 23 | Latitude = table.Column(nullable: false), 24 | Longitude = table.Column(nullable: false), 25 | MemberID = table.Column(nullable: false), 26 | Timestamp = table.Column(nullable: false) 27 | }, 28 | constraints: table => 29 | { 30 | table.PrimaryKey("PK_LocationRecords", x => x.ID); 31 | }); 32 | } 33 | 34 | protected override void Down(MigrationBuilder migrationBuilder) 35 | { 36 | migrationBuilder.DropTable( 37 | name: "LocationRecords"); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/Migrations/LocationDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using StatlerWaldorfCorp.LocationService.Persistence; 7 | 8 | namespace StatlerWaldorfCorp.LocationService.Migrations 9 | { 10 | [DbContext(typeof(LocationDbContext))] 11 | partial class LocationDbContextModelSnapshot : ModelSnapshot 12 | { 13 | protected override void BuildModel(ModelBuilder modelBuilder) 14 | { 15 | modelBuilder 16 | .HasAnnotation("Npgsql:PostgresExtension:.uuid-ossp", "'uuid-ossp', '', ''") 17 | .HasAnnotation("ProductVersion", "1.0.0-rtm-21431"); 18 | 19 | modelBuilder.Entity("StatlerWaldorfCorp.LocationService.Models.LocationRecord", b => 20 | { 21 | b.Property("ID") 22 | .ValueGeneratedOnAdd(); 23 | 24 | b.Property("Altitude"); 25 | 26 | b.Property("Latitude"); 27 | 28 | b.Property("Longitude"); 29 | 30 | b.Property("MemberID"); 31 | 32 | b.Property("Timestamp"); 33 | 34 | b.HasKey("ID"); 35 | 36 | b.ToTable("LocationRecords"); 37 | }); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/Models/ILocationRecordRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace StatlerWaldorfCorp.LocationService.Models { 5 | 6 | public interface ILocationRecordRepository { 7 | LocationRecord Add(LocationRecord locationRecord); 8 | LocationRecord Update(LocationRecord locationRecord); 9 | LocationRecord Get(Guid memberId, Guid recordId); 10 | LocationRecord Delete(Guid memberId, Guid recordId); 11 | 12 | LocationRecord GetLatestForMember(Guid memberId); 13 | 14 | ICollection AllForMember(Guid memberId); 15 | } 16 | } -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/Models/LocationRecord.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace StatlerWaldorfCorp.LocationService.Models { 5 | 6 | public class LocationRecord { 7 | public Guid ID { get; set; } 8 | public float Latitude { get; set; } 9 | public float Longitude { get; set; } 10 | public float Altitude { get; set; } 11 | public long Timestamp { get; set; } 12 | public Guid MemberID { get; set; } 13 | } 14 | 15 | public class LocationRecordComparer : Comparer 16 | { 17 | public override int Compare(LocationRecord x, LocationRecord y) 18 | { 19 | return x.Timestamp.CompareTo(y.Timestamp); 20 | } 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/Persistence/InMemoryLocationRecordRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using StatlerWaldorfCorp.LocationService.Models; 4 | using System.Linq; 5 | 6 | namespace StatlerWaldorfCorp.LocationService.Persistence { 7 | 8 | public class InMemoryLocationRecordRepository : ILocationRecordRepository 9 | { 10 | private static Dictionary> locationRecords; 11 | 12 | public InMemoryLocationRecordRepository() { 13 | if (locationRecords == null) { 14 | locationRecords = new Dictionary>(); 15 | } 16 | } 17 | 18 | public LocationRecord Add(LocationRecord locationRecord) 19 | { 20 | var memberRecords = getMemberRecords(locationRecord.MemberID); 21 | 22 | memberRecords.Add(locationRecord.Timestamp, locationRecord); 23 | return locationRecord; 24 | } 25 | 26 | public ICollection AllForMember(Guid memberId) 27 | { 28 | var memberRecords = getMemberRecords(memberId); 29 | return memberRecords.Values.Where( l => l.MemberID == memberId).ToList(); 30 | } 31 | 32 | public LocationRecord Delete(Guid memberId, Guid recordId) 33 | { 34 | var memberRecords = getMemberRecords(memberId); 35 | LocationRecord lr = memberRecords.Values.Where( l => l.ID == recordId).FirstOrDefault(); 36 | 37 | if (lr != null) { 38 | memberRecords.Remove(lr.Timestamp); 39 | } 40 | 41 | return lr; 42 | } 43 | 44 | public LocationRecord Get(Guid memberId, Guid recordId) 45 | { 46 | var memberRecords = getMemberRecords(memberId); 47 | 48 | LocationRecord lr = memberRecords.Values.Where( l => l.ID == recordId).FirstOrDefault(); 49 | return lr; 50 | } 51 | 52 | public LocationRecord Update(LocationRecord locationRecord) 53 | { 54 | return Delete(locationRecord.MemberID, locationRecord.ID); 55 | } 56 | 57 | public LocationRecord GetLatestForMember(Guid memberId) { 58 | var memberRecords = getMemberRecords(memberId); 59 | 60 | LocationRecord lr = memberRecords.Values.LastOrDefault(); 61 | return lr; 62 | } 63 | 64 | private SortedList getMemberRecords(Guid memberId) { 65 | if (!locationRecords.ContainsKey(memberId)) { 66 | locationRecords.Add(memberId, new SortedList()); 67 | } 68 | 69 | var list = locationRecords[memberId]; 70 | return list; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/Persistence/LocationDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Infrastructure; 3 | using StatlerWaldorfCorp.LocationService.Models; 4 | using Npgsql.EntityFrameworkCore.PostgreSQL; 5 | 6 | namespace StatlerWaldorfCorp.LocationService.Persistence 7 | { 8 | public class LocationDbContext : DbContext 9 | { 10 | public LocationDbContext(DbContextOptions options) :base(options) 11 | { 12 | } 13 | 14 | protected override void OnModelCreating(ModelBuilder modelBuilder) 15 | { 16 | base.OnModelCreating(modelBuilder); 17 | modelBuilder.HasPostgresExtension("uuid-ossp"); 18 | } 19 | 20 | public DbSet LocationRecords {get; set;} 21 | } 22 | 23 | public class LocationDbContextFactory : IDbContextFactory 24 | { 25 | public LocationDbContext Create(DbContextFactoryOptions options) 26 | { 27 | var optionsBuilder = new DbContextOptionsBuilder(); 28 | var connectionString = Startup.Configuration.GetSection("postgres:cstr").Value; 29 | optionsBuilder.UseNpgsql(connectionString); 30 | 31 | return new LocationDbContext(optionsBuilder.Options); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/Persistence/LocationRecordRepository.cs: -------------------------------------------------------------------------------- 1 | // using Microsoft.EntityFrameworkCore; 2 | 3 | using System; 4 | using System.Linq; 5 | using System.Collections.Generic; 6 | using StatlerWaldorfCorp.LocationService.Models; 7 | using Microsoft.EntityFrameworkCore; 8 | 9 | namespace StatlerWaldorfCorp.LocationService.Persistence 10 | { 11 | public class LocationRecordRepository : ILocationRecordRepository 12 | { 13 | private LocationDbContext context; 14 | 15 | public LocationRecordRepository(LocationDbContext context) 16 | { 17 | this.context = context; 18 | } 19 | 20 | public LocationRecord Add(LocationRecord locationRecord) 21 | { 22 | this.context.Add(locationRecord); 23 | this.context.SaveChanges(); 24 | return locationRecord; 25 | } 26 | 27 | public LocationRecord Update(LocationRecord locationRecord) 28 | { 29 | this.context.Entry(locationRecord).State = EntityState.Modified; 30 | this.context.SaveChanges(); 31 | return locationRecord; 32 | } 33 | 34 | public LocationRecord Get(Guid memberId, Guid recordId) 35 | { 36 | return this.context.LocationRecords.FirstOrDefault(lr => lr.MemberID == memberId && lr.ID == recordId); 37 | } 38 | 39 | public LocationRecord Delete(Guid memberId, Guid recordId) 40 | { 41 | LocationRecord locationRecord = this.Get(memberId, recordId); 42 | this.context.Remove(locationRecord); 43 | this.context.SaveChanges(); 44 | return locationRecord; 45 | } 46 | 47 | public LocationRecord GetLatestForMember(Guid memberId) 48 | { 49 | LocationRecord locationRecord = this.context.LocationRecords. 50 | Where(lr => lr.MemberID == memberId). 51 | OrderBy(lr => lr.Timestamp). 52 | Last(); 53 | return locationRecord; 54 | } 55 | 56 | public ICollection AllForMember(Guid memberId) 57 | { 58 | return this.context.LocationRecords. 59 | Where(lr => lr.MemberID == memberId). 60 | OrderBy(lr => lr.Timestamp). 61 | ToList(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.Extensions.Configuration; 4 | 5 | namespace StatlerWaldorfCorp.LocationService 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | IConfiguration config = new ConfigurationBuilder() 12 | .AddCommandLine(args) 13 | .Build(); 14 | 15 | Startup.Args = args; 16 | 17 | var host = new WebHostBuilder() 18 | .UseKestrel() 19 | .UseStartup() 20 | .UseConfiguration(config) 21 | .Build(); 22 | 23 | host.Run(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using StatlerWaldorfCorp.LocationService.Models; 6 | using StatlerWaldorfCorp.LocationService.Persistence; 7 | using Microsoft.EntityFrameworkCore; 8 | using System; 9 | using Npgsql.EntityFrameworkCore.PostgreSQL; 10 | using Microsoft.Extensions.Logging; 11 | using System.Linq; 12 | 13 | namespace StatlerWaldorfCorp.LocationService { 14 | public class Startup 15 | { 16 | public static string[] Args {get; set;} = new string[] {}; 17 | private ILogger logger; 18 | private ILoggerFactory loggerFactory; 19 | 20 | public Startup(IHostingEnvironment env, ILoggerFactory loggerFactory) 21 | { 22 | var builder = new ConfigurationBuilder() 23 | .SetBasePath(System.IO.Directory.GetCurrentDirectory()) 24 | .AddJsonFile("appsettings.json", optional:true) 25 | .AddEnvironmentVariables() 26 | .AddCommandLine(Startup.Args); 27 | 28 | Configuration = builder.Build(); 29 | 30 | this.loggerFactory = loggerFactory; 31 | this.loggerFactory.AddConsole(LogLevel.Information); 32 | this.loggerFactory.AddDebug(); 33 | 34 | this.logger = this.loggerFactory.CreateLogger("Startup"); 35 | } 36 | 37 | public static IConfigurationRoot Configuration { get; set; } 38 | 39 | public void ConfigureServices(IServiceCollection services) 40 | { 41 | //var transient = Boolean.Parse(Configuration.GetSection("transient").Value); 42 | var transient = true; 43 | if (Configuration.GetSection("transient") != null) { 44 | transient = Boolean.Parse(Configuration.GetSection("transient").Value); 45 | } 46 | if (transient) { 47 | logger.LogInformation("Using transient location record repository."); 48 | services.AddScoped(); 49 | } else { 50 | var connectionString = Configuration.GetSection("postgres:cstr").Value; 51 | services.AddEntityFrameworkNpgsql().AddDbContext(options => 52 | options.UseNpgsql(connectionString)); 53 | logger.LogInformation("Using '{0}' for DB connection string.", connectionString); 54 | services.AddScoped(); 55 | } 56 | 57 | services.AddMvc(); 58 | } 59 | 60 | public void Configure(IApplicationBuilder app) 61 | { 62 | app.UseMvc(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/StatlerWaldorfCorp.LocationService.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp1.1 5 | StatlerWaldorfCorp.LocationService 6 | Exe 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "transient": false, 3 | "postgres": { 4 | "cstr": "Host=localhost;Port=5432;Database=locationservice;Username=integrator;Password=inteword" 5 | } 6 | } -------------------------------------------------------------------------------- /src/StatlerWaldorfCorp.LocationService/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/StatlerWaldorfCorp.LocationService.Integration/PostgresIntegrationTest.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | using StatlerWaldorfCorp.LocationService.Models; 4 | using StatlerWaldorfCorp.LocationService.Persistence; 5 | using System; 6 | using System.Linq; 7 | using System.Collections.Generic; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.EntityFrameworkCore; 10 | 11 | 12 | namespace StatlerWaldorfCorp.LocationService.Integration 13 | { 14 | 15 | public class PostgresIntegrationTest 16 | { 17 | private IConfigurationRoot config; 18 | private LocationDbContext context; 19 | 20 | public PostgresIntegrationTest() 21 | { 22 | config = new ConfigurationBuilder() 23 | .SetBasePath(System.IO.Directory.GetCurrentDirectory()) 24 | .AddEnvironmentVariables() 25 | .Build(); 26 | 27 | var connectionString = config.GetSection("postgres:cstr").Value; 28 | var optionsBuilder = new DbContextOptionsBuilder(); 29 | optionsBuilder.UseNpgsql(connectionString); 30 | this.context = new LocationDbContext(optionsBuilder.Options); 31 | } 32 | 33 | [Fact] 34 | public void ShouldPersistRecord() 35 | { 36 | LocationRecordRepository repository = new LocationRecordRepository(context); 37 | 38 | LocationRecord firstRecord = new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 1, 39 | MemberID = Guid.NewGuid(), Latitude = 12.3f }; 40 | repository.Add(firstRecord); 41 | 42 | LocationRecord targetRecord = repository.Get(firstRecord.MemberID, firstRecord.ID); 43 | 44 | // assert values equal first and targetRecord 45 | Assert.Equal(firstRecord.Timestamp, targetRecord.Timestamp); 46 | Assert.Equal(firstRecord.MemberID, targetRecord.MemberID); 47 | Assert.Equal(firstRecord.ID, targetRecord.ID); 48 | Assert.Equal(firstRecord.Latitude, targetRecord.Latitude); 49 | } 50 | 51 | [Fact] 52 | public void ShouldUpdateRecord() 53 | { 54 | LocationRecordRepository repository = new LocationRecordRepository(context); 55 | 56 | LocationRecord firstRecord = new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 1, 57 | MemberID = Guid.NewGuid(), Latitude = 12.3f }; 58 | repository.Add(firstRecord); 59 | 60 | LocationRecord targetRecord = repository.Get(firstRecord.MemberID, firstRecord.ID); 61 | 62 | // modify firstRecord. 63 | firstRecord.Longitude = 12.5f; 64 | firstRecord.Latitude = 47.09f; 65 | repository.Update(firstRecord); 66 | 67 | LocationRecord target2 = repository.Get(firstRecord.MemberID, firstRecord.ID); 68 | 69 | Assert.Equal(firstRecord.Timestamp, target2.Timestamp); 70 | Assert.Equal(firstRecord.Longitude, target2.Longitude); 71 | Assert.Equal(firstRecord.Latitude, target2.Latitude); 72 | Assert.Equal(firstRecord.ID, target2.ID); 73 | Assert.Equal(firstRecord.MemberID, target2.MemberID); 74 | } 75 | 76 | [Fact] 77 | public void ShouldDeleteRecord() 78 | { 79 | LocationRecordRepository repository = new LocationRecordRepository(context); 80 | Guid memberId = Guid.NewGuid(); 81 | 82 | LocationRecord firstRecord = new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 1, 83 | MemberID = memberId, Latitude = 12.3f }; 84 | repository.Add(firstRecord); 85 | LocationRecord secondRecord = new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 2, 86 | MemberID = memberId, Latitude = 24.4f }; 87 | repository.Add(secondRecord); 88 | 89 | int initialCount = repository.AllForMember(memberId).Count(); 90 | repository.Delete(memberId, secondRecord.ID); 91 | int afterCount = repository.AllForMember(memberId).Count(); 92 | 93 | LocationRecord target1 = repository.Get(firstRecord.MemberID, firstRecord.ID); 94 | LocationRecord target2 = repository.Get(firstRecord.MemberID, secondRecord.ID); 95 | 96 | Assert.Equal(initialCount -1, afterCount); 97 | Assert.Equal(target1.ID, firstRecord.ID); 98 | Assert.NotNull(target1); 99 | Assert.Null(target2); 100 | } 101 | 102 | [Fact] 103 | public void ShouldGetAllForMember() 104 | { 105 | LocationRecordRepository repository = new LocationRecordRepository(context); 106 | Guid memberId = Guid.NewGuid(); 107 | 108 | int initialCount = repository.AllForMember(memberId).Count(); 109 | 110 | LocationRecord firstRecord = new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 1, 111 | MemberID = memberId, Latitude = 12.3f }; 112 | repository.Add(firstRecord); 113 | LocationRecord secondRecord = new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 2, 114 | MemberID = memberId, Latitude = 24.4f }; 115 | repository.Add(secondRecord); 116 | 117 | ICollection records = repository.AllForMember(memberId); 118 | int afterCount = records.Count(); 119 | 120 | Assert.Equal(initialCount + 2, afterCount); 121 | Assert.NotNull(records.FirstOrDefault(r => r.ID == firstRecord.ID)); 122 | Assert.NotNull(records.FirstOrDefault(r => r.ID == secondRecord.ID)); 123 | } 124 | 125 | [Fact] 126 | public void ShouldGetLatestForMember() 127 | { 128 | LocationRecordRepository repository = new LocationRecordRepository(context); 129 | Guid memberId = Guid.NewGuid(); 130 | 131 | LocationRecord firstRecord = new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 1, 132 | MemberID = memberId, Latitude = 12.3f }; 133 | repository.Add(firstRecord); 134 | LocationRecord secondRecord = new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 2, 135 | MemberID = memberId, Latitude = 24.4f }; 136 | repository.Add(secondRecord); 137 | 138 | LocationRecord latest = repository.GetLatestForMember(memberId); 139 | 140 | Assert.NotNull(latest); 141 | Assert.Equal(latest.ID, secondRecord.ID); 142 | Assert.NotEqual(latest.ID, firstRecord.ID); 143 | } 144 | } 145 | } -------------------------------------------------------------------------------- /test/StatlerWaldorfCorp.LocationService.Integration/StatlerWaldorfCorp.LocationService.Integration.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp1.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/StatlerWaldorfCorp.LocationService.Integration/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "transient": false, 3 | "postgres": { 4 | "url": "postgres://integrator:inteword@localhost:5432/locationservice" 5 | } 6 | } -------------------------------------------------------------------------------- /test/StatlerWaldorfCorp.LocationService.Tests/LocationRecordControllerTest.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | using System.Collections.Generic; 3 | using StatlerWaldorfCorp.LocationService.Models; 4 | using StatlerWaldorfCorp.LocationService.Controllers; 5 | using StatlerWaldorfCorp.LocationService.Persistence; 6 | using Microsoft.AspNetCore.Mvc; 7 | using System; 8 | using System.Linq; 9 | 10 | namespace StatlerWaldorfCorp.LocationService 11 | { 12 | 13 | public class LocationRecordControllerTest 14 | { 15 | [Fact] 16 | public void ShouldAdd() 17 | { 18 | ILocationRecordRepository repository = new InMemoryLocationRecordRepository(); 19 | LocationRecordController controller = new LocationRecordController(repository); 20 | Guid memberGuid = Guid.NewGuid(); 21 | 22 | controller.AddLocation(memberGuid, new LocationRecord(){ ID = Guid.NewGuid(), 23 | MemberID = memberGuid, Timestamp = 1 }); 24 | controller.AddLocation(memberGuid, new LocationRecord(){ ID = Guid.NewGuid(), 25 | MemberID = memberGuid, Timestamp = 2 }); 26 | 27 | Assert.Equal(2, repository.AllForMember(memberGuid).Count()); 28 | } 29 | 30 | [Fact] 31 | public void ShouldReturnEmtpyListForNewMember() 32 | { 33 | ILocationRecordRepository repository = new InMemoryLocationRecordRepository(); 34 | LocationRecordController controller = new LocationRecordController(repository); 35 | Guid memberGuid = Guid.NewGuid(); 36 | 37 | ICollection locationRecords = 38 | ((controller.GetLocationsForMember(memberGuid) as ObjectResult).Value as ICollection); 39 | 40 | Assert.Equal(0, locationRecords.Count()); 41 | } 42 | 43 | [Fact] 44 | public void ShouldTrackAllLocationsForMember() 45 | { 46 | ILocationRecordRepository repository = new InMemoryLocationRecordRepository(); 47 | LocationRecordController controller = new LocationRecordController(repository); 48 | Guid memberGuid = Guid.NewGuid(); 49 | 50 | controller.AddLocation(memberGuid, new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 1, 51 | MemberID = memberGuid, Latitude = 12.3f }); 52 | controller.AddLocation(memberGuid, new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 2, 53 | MemberID = memberGuid, Latitude = 23.4f }); 54 | controller.AddLocation(Guid.NewGuid(), new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 3, 55 | MemberID = Guid.NewGuid(), Latitude = 23.4f }); 56 | 57 | ICollection locationRecords = 58 | ((controller.GetLocationsForMember(memberGuid) as ObjectResult).Value as ICollection); 59 | 60 | Assert.Equal(2, locationRecords.Count()); 61 | } 62 | 63 | [Fact] 64 | public void ShouldTrackNullLatestForNewMember() 65 | { 66 | ILocationRecordRepository repository = new InMemoryLocationRecordRepository(); 67 | LocationRecordController controller = new LocationRecordController(repository); 68 | Guid memberGuid = Guid.NewGuid(); 69 | 70 | LocationRecord latest = ((controller.GetLatestForMember(memberGuid) as ObjectResult).Value as LocationRecord); 71 | 72 | Assert.Null(latest); 73 | } 74 | 75 | [Fact] 76 | public void ShouldTrackLatestLocationsForMember() 77 | { 78 | ILocationRecordRepository repository = new InMemoryLocationRecordRepository(); 79 | LocationRecordController controller = new LocationRecordController(repository); 80 | Guid memberGuid = Guid.NewGuid(); 81 | 82 | Guid latestId = Guid.NewGuid(); 83 | controller.AddLocation(memberGuid, new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 1, 84 | MemberID = memberGuid, Latitude = 12.3f }); 85 | controller.AddLocation(memberGuid, new LocationRecord(){ ID = latestId, Timestamp = 3, 86 | MemberID = memberGuid, Latitude = 23.4f }); 87 | controller.AddLocation(memberGuid, new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 2, 88 | MemberID = memberGuid, Latitude = 23.4f }); 89 | controller.AddLocation(Guid.NewGuid(), new LocationRecord(){ ID = Guid.NewGuid(), Timestamp = 4, 90 | MemberID = Guid.NewGuid(), Latitude = 23.4f }); 91 | 92 | LocationRecord latest = ((controller.GetLatestForMember(memberGuid) as ObjectResult).Value as LocationRecord); 93 | 94 | Assert.NotNull(latest); 95 | Assert.Equal(latestId, latest.ID); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /test/StatlerWaldorfCorp.LocationService.Tests/StatlerWaldorfCorp.LocationService.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp1.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /wercker.yml: -------------------------------------------------------------------------------- 1 | box: microsoft/dotnet:1.1.1-sdk 2 | services: 3 | - id: postgres 4 | env: 5 | POSTGRES_PASSWORD: inteword 6 | POSTGRES_USER: integrator 7 | POSTGRES_DB: locationservice 8 | no-response-timeout: 10 9 | build: 10 | steps: 11 | # compile 12 | - script: 13 | name: restore 14 | cwd: src/StatlerWaldorfCorp.LocationService 15 | code: | 16 | dotnet restore 17 | - script: 18 | name: build 19 | cwd: src/StatlerWaldorfCorp.LocationService 20 | code: | 21 | dotnet build 22 | 23 | # unit tests 24 | - script: 25 | name: test-restore 26 | cwd: test/StatlerWaldorfCorp.LocationService.Tests 27 | code: | 28 | dotnet restore 29 | - script: 30 | name: test-build 31 | cwd: test/StatlerWaldorfCorp.LocationService.Tests 32 | code: | 33 | dotnet build 34 | - script: 35 | name: test-run 36 | cwd: test/StatlerWaldorfCorp.LocationService.Tests 37 | code: | 38 | dotnet test 39 | 40 | # integration tests 41 | - script: 42 | name: integration-migrate 43 | cwd: src/StatlerWaldorfCorp.LocationService 44 | code: | 45 | export TRANSIENT=false 46 | export POSTGRES__CSTR="Host=$POSTGRES_PORT_5432_TCP_ADDR" 47 | export POSTGRES__CSTR="$POSTGRES__CSTR;Username=integrator;Password=inteword;" 48 | export POSTGRES__CSTR="$POSTGRES__CSTR;Port=$POSTGRES_PORT_5432_TCP_PORT;Database=locationservice" 49 | dotnet ef database update 50 | - script: 51 | name: integration-restore 52 | cwd: test/StatlerWaldorfCorp.LocationService.Integration 53 | code: | 54 | dotnet restore 55 | - script: 56 | name: integration-build 57 | cwd: test/StatlerWaldorfCorp.LocationService.Integration 58 | code: | 59 | dotnet build 60 | - script: 61 | name: integration-test 62 | cwd: test/StatlerWaldorfCorp.LocationService.Integration 63 | code: | 64 | dotnet test 65 | 66 | # packaging 67 | - script: 68 | name: publish 69 | cwd: src/StatlerWaldorfCorp.LocationService 70 | code: | 71 | dotnet publish -o publish 72 | - script: 73 | name: copy binary 74 | cwd: src/StatlerWaldorfCorp.LocationService 75 | code: | 76 | cp -r . $WERCKER_OUTPUT_DIR/app 77 | - script: 78 | name: copy entrypoint 79 | code: | 80 | cp docker_entrypoint.sh $WERCKER_OUTPUT_DIR/app 81 | - script: 82 | name: copy config 83 | cwd: src/StatlerWaldorfCorp.LocationService 84 | code: | 85 | cp appsettings*json $WERCKER_OUTPUT_DIR/app/publish 86 | mkdir -p $WERCKER_OUTPUT_DIR/app/publish/app/tmp 87 | deploy: 88 | steps: 89 | - internal/docker-push: 90 | cwd: $WERCKER_OUTPUT_DIR/app 91 | username: $USERNAME 92 | password: $PASSWORD 93 | repository: dotnetcoreservices/locationservice 94 | registry: https://registry.hub.docker.com 95 | entrypoint: "/pipeline/source/app/docker_entrypoint.sh" 96 | --------------------------------------------------------------------------------