Skip to content

Commit 54b8d9d

Browse files
author
Günther Cwioro
committed
Merge main
2 parents 019fa33 + f3c98cb commit 54b8d9d

Some content is hidden

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

44 files changed

+1293
-723
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,12 @@ Your data will be stored in the `/data/db.json` file on the volume `/data`.
8989

9090
### Liveness & Readiness Probes
9191

92-
Contexture provides HTTP based [Liveness & Readiness Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) to determine if the container is health & operational
92+
Contexture provides HTTP based [Liveness & Readiness Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) to determine if the container is healthy & operational
9393

9494
#### Liveness
9595

9696
A `GET` request to `$BASE_URL/meta/health` will return `200 OK` if the application is healthy and currently processing requests.
97+
It will return a `503 ServiceUnavailable` in case information about subscriptions can not be obtained or any of the subscriptions have Failed.
9798

9899
#### Readiness
99100

backend/Contexture.Api.Tests/Contexture.Api.Tests.fsproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<Compile Include="EventStore.Tests.fs" />
1616
<Compile Include="PositionStorage.Tests.fs" />
1717
<Compile Include="Security.Tests.fs" />
18+
<Compile Include="ReadModels.Tests.fs" />
1819
<Compile Include="Tests.fs" />
1920
<Compile Include="Specs\Scenario.fs" />
2021
<Compile Include="Specs\Fixtures.fs" />
@@ -38,7 +39,8 @@
3839
</PackageReference>
3940
<PackageReference Update="FSharp.Core" Version="7.0.300" />
4041
<PackageReference Include="NStore.Persistence.MsSql" Version="0.14.0" />
41-
<PackageReference Include="Testcontainers" Version="2.4.0" />
42+
<PackageReference Include="Testcontainers" Version="4.0.0" />
43+
<PackageReference Include="Testcontainers.MsSql" Version="4.0.0" />
4244
</ItemGroup>
4345

4446
<ItemGroup>

backend/Contexture.Api.Tests/EventStore.Tests.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ type MsSqlBackedEventStore(msSql: MsSqlFixture) =
264264
let config =
265265
MsSqlPersistenceOptions(
266266
loggerFactory,
267-
ConnectionString = msSql.Container.ConnectionString,
267+
ConnectionString = msSql.Container.GetConnectionString(),
268268
StreamsTableName = $"streams_{Interlocked.Increment(counter)}_{this.GetType().Name}",
269269
Serializer = NStoreBased.JsonMsSqlSerializer.Default
270270
)

backend/Contexture.Api.Tests/PositionStorage.Tests.fs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ type SqlServerPositionStorage(msSql: MsSqlFixture) =
8181
inherit PositionStorageBehavior()
8282

8383
override this.EmptyStorage() =
84-
SqlServer.PositionStorage(msSql.Container.ConnectionString)
84+
SqlServer.PositionStorage(msSql.Container.GetConnectionString())
8585

8686
override this.StorageWith items = task {
87-
use client = new SqlConnection(msSql.Container.ConnectionString)
87+
use client = new SqlConnection(msSql.Container.GetConnectionString())
8888
do! client.OpenAsync()
8989

9090
// using string concatenation over parameters here is OK because it's just (unit) test code
@@ -98,15 +98,15 @@ type SqlServerPositionStorage(msSql: MsSqlFixture) =
9898
let! result = command.ExecuteNonQueryAsync()
9999
Assert.Equal(items |> List.length, result)
100100

101-
return SqlServer.PositionStorage(msSql.Container.ConnectionString) :> IStorePositions
101+
return SqlServer.PositionStorage(msSql.Container.GetConnectionString()) :> IStorePositions
102102
}
103103

104104
interface IAsyncLifetime with
105105
member this.DisposeAsync() =
106-
SqlServer.PositionStorage.RemoveSchema(msSql.Container.ConnectionString)
106+
SqlServer.PositionStorage.RemoveSchema(msSql.Container.GetConnectionString())
107107

108108
member this.InitializeAsync() =
109-
SqlServer.PositionStorage.CreateSchema(msSql.Container.ConnectionString)
109+
SqlServer.PositionStorage.CreateSchema(msSql.Container.GetConnectionString())
110110

111111
interface IClassFixture<MsSqlFixture> with
112112

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module Contexture.Api.ReadModels.Tests
2+
3+
open System
4+
open System.Threading.Tasks
5+
open Xunit
6+
7+
open Contexture.Api.Infrastructure.ReadModels
8+
open Contexture.Api.Infrastructure
9+
10+
module State =
11+
let Initial = "initialstate"
12+
13+
let timeoutms = (TimeSpan.FromSeconds 1).TotalMilliseconds |> int
14+
let testReadModel: ReadModel<string,string> =
15+
readModel (fun state _events -> state) State.Initial (Some timeoutms)
16+
17+
[<Fact>]
18+
let ``fetching state when requested position is ahead of processed should throw after timeout``() = task{
19+
let getState = fun () -> testReadModel.State(Some(Position.from 1)) :> Task
20+
do! Assert.ThrowsAsync<TimeoutException>(fun () -> Task.Run(getState, (new Threading.CancellationTokenSource(TimeSpan.FromSeconds(2))).Token)) :> Task
21+
}

backend/Contexture.Api.Tests/Specs/PublicApiEndpoint.Tests.fs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ open Xunit
1212
open Xunit.Sdk
1313
open Contexture.Api.Tests.EnvironmentSimulation
1414
open ValueObjects
15+
open Fixtures
16+
open Fixtures.Builders
17+
1518
module Namespaces =
1619

1720
[<Fact>]
@@ -22,8 +25,7 @@ module Namespaces =
2225
let domainId = environment |> PseudoRandom.guid
2326
let contextId = environment |> PseudoRandom.guid
2427

25-
let given =
26-
Fixtures.Builders.givenADomainWithOneBoundedContext domainId contextId
28+
let given = givenADomainWithOneBoundedContext domainId contextId
2729

2830
use! testEnvironment = Prepare.withGiven environment given
2931

@@ -62,6 +64,56 @@ module Namespaces =
6264
| e -> raise (XunitException $"Unexpected event: %O{e}")
6365
}
6466

67+
[<Fact>]
68+
let ``can edit namespace label``() = task {
69+
// arrange
70+
let environment = FixedTimeEnvironment.FromSystemClock()
71+
let domainId = environment |> PseudoRandom.guid
72+
let contextId = environment |> PseudoRandom.guid
73+
let namespaceId = environment |> PseudoRandom.guid
74+
let labelId = environment |> PseudoRandom.guid
75+
let labelDefinition = {
76+
LabelId = labelId
77+
Name = "initial name"
78+
Value = Some "initial value"
79+
Template = None
80+
}
81+
82+
let given =
83+
givenADomainWithOneBoundedContext domainId contextId
84+
|> Given.andOneEvent (
85+
Namespace.definition contextId namespaceId
86+
|> Namespace.appendLabel (labelDefinition)
87+
|> Namespace.namespaceAdded
88+
)
89+
90+
use! testEnvironment = Prepare.withGiven environment given
91+
92+
let updateLabelBody = """
93+
{
94+
"name": "updated name",
95+
"value": "updated value"
96+
}
97+
"""
98+
let! response = When.postingJson $"api/boundedcontexts/{contextId}/namespaces/{namespaceId}/labels/{labelId}" updateLabelBody testEnvironment
99+
let! result = response |> WhenResult.asJsonResponse<Projections.Namespace list>
100+
101+
let namespaceLabels =
102+
result.Result
103+
|> List.find(fun n -> n.Id = namespaceId)
104+
|> fun ns -> ns.Labels
105+
106+
let expectedLabel: Projections.Label = {
107+
Id = labelId
108+
Name = "updated name"
109+
Value = "updated value"
110+
Template = None
111+
}
112+
113+
Then.Single namespaceLabels
114+
|> fun label -> Then.Equal(expectedLabel, label)
115+
}
116+
65117
module BoundedContexts =
66118

67119
[<Fact>]

backend/Contexture.Api.Tests/SqlServerFixture.fs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,20 @@
11
namespace Contexture.Api.Tests
22

3-
#nowarn "44" // ContainerBuilder<MsSqlTestcontainer>() is deprecated but does not provide a clear guidance yet
4-
53
open System
64
open System.Threading
7-
open DotNet.Testcontainers.Builders
8-
open DotNet.Testcontainers.Configurations
9-
open DotNet.Testcontainers.Containers
5+
open Testcontainers.MsSql
106
open Xunit
117

128
type MsSqlFixture() =
139
static let mutable counter = ref 0
14-
let container =
10+
let container =
1511
let containerConfiguration =
16-
ContainerBuilder<MsSqlTestcontainer>()
17-
.WithDatabase(new MsSqlTestcontainerConfiguration(Password = "localdevpassword#123"))
18-
.WithImage("mcr.microsoft.com/mssql/server:2019-latest")
12+
MsSqlBuilder()
1913
.WithName($"MS-SQL-Integration-Tests-{Interlocked.Increment counter}")
2014
.WithCleanUp(false)
2115
.WithAutoRemove(true)
2216

23-
let instance = containerConfiguration.Build()
24-
instance
17+
containerConfiguration.Build()
2518

2619
member _.Container = container
2720

backend/Contexture.Api/Apis/Namespaces.fs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ module Namespaces =
2828
| Ok (updatedContext,version,position) ->
2929
let! namespaceState = ctx.GetService<ReadModels.Namespace.AllNamespacesReadModel>().State(position)
3030
// for namespaces we don't use redirects ATM
31-
let boundedContext =
31+
let namespaces =
3232
updatedContext
3333
|> ReadModels.Namespace.namespacesOf namespaceState
3434

35-
return! json boundedContext next ctx
35+
return! json namespaces next ctx
3636
| Error (DomainError error) ->
3737
return! RequestErrors.BAD_REQUEST(sprintf "Domain Error %A" error) next ctx
3838
| Error e -> return! ServerErrors.INTERNAL_ERROR e next ctx
@@ -47,6 +47,9 @@ module Namespaces =
4747
let removeLabel contextId (command: RemoveLabel) =
4848
updateAndReturnNamespaces (RemoveLabel(contextId, command))
4949

50+
let updateLabel contextId (command: UpdateLabel) =
51+
updateAndReturnNamespaces (UpdateLabel(contextId, command))
52+
5053
let newLabel contextId namespaceId (command: NewLabelDefinition) =
5154
updateAndReturnNamespaces (AddLabel(contextId, namespaceId, command))
5255

@@ -143,6 +146,10 @@ module Namespaces =
143146
boundedContextId
144147
{ Namespace = namespaceId
145148
Label = labelId }
149+
POST >=> bindJson<{|Name:string; Value:string|}>(fun p ->
150+
{Label = labelId; Namespace = namespaceId; Name = p.Name; Value = p.Value}
151+
|> CommandEndpoints.updateLabel boundedContextId
152+
)
146153
RequestErrors.NOT_FOUND "Not found"
147154
]
148155
let routesForOneNamespace =

0 commit comments

Comments
 (0)