refactor: rename ScadaLink → ZB.MOM.WW.ScadaBridge (code + projects + namespaces)
Solution + 23 src projects + 26 test projects renamed; folders, csproj, namespaces, and ScadaLinkDbContext/ScadaBridgeDbContext class updated. ActorSystem "scadalink" → "scadabridge", Akka seed-node URLs migrated. SQL roles/logins, LDAP domains, CLI command name, and CLI config dir (~/.scadalink → ~/.scadabridge) also renamed. Build green; 5 Host.Tests fail awaiting SQL login rename in next commit. Pre-existing StaleTagMonitor timing flakes unchanged. Rename script committed at tools/rename-to-scadabridge.sh.
This commit is contained in:
+61
-61
@@ -53,12 +53,12 @@ SignalR Hub / Blazor UI │
|
||||
|
||||
### Site-Side (appsettings)
|
||||
|
||||
`ScadaLink:Node:GrpcPort` — explicit config setting, not derived from `RemotingPort`:
|
||||
`ScadaBridge:Node:GrpcPort` — explicit config setting, not derived from `RemotingPort`:
|
||||
|
||||
```json
|
||||
"Node": {
|
||||
"Role": "Site",
|
||||
"NodeHostname": "scadalink-site-a-a",
|
||||
"NodeHostname": "scadabridge-site-a-a",
|
||||
"RemotingPort": 8082,
|
||||
"GrpcPort": 8083
|
||||
}
|
||||
@@ -66,7 +66,7 @@ SignalR Hub / Blazor UI │
|
||||
|
||||
**Why explicit, not offset**: `RemotingPort` is itself a config value (8081 central, 8082 sites). A rigid offset silently breaks if someone changes `RemotingPort` to a non-standard value. Explicit ports are visible and independently configurable.
|
||||
|
||||
Add `GrpcPort` to `NodeOptions` (`src/ScadaLink.Host/NodeOptions.cs`):
|
||||
Add `GrpcPort` to `NodeOptions` (`src/ZB.MOM.WW.ScadaBridge.Host/NodeOptions.cs`):
|
||||
|
||||
```csharp
|
||||
public int GrpcPort { get; set; } = 8083;
|
||||
@@ -78,7 +78,7 @@ Add validation in `StartupValidator` (site role only — central doesn't host a
|
||||
|
||||
Central needs to know each site node's gRPC endpoint. Add two fields to the `Site` entity:
|
||||
|
||||
**Modify**: `src/ScadaLink.Commons/Entities/Sites/Site.cs`
|
||||
**Modify**: `src/ZB.MOM.WW.ScadaBridge.Commons/Entities/Sites/Site.cs`
|
||||
|
||||
```csharp
|
||||
public class Site
|
||||
@@ -87,8 +87,8 @@ public class Site
|
||||
public string Name { get; set; }
|
||||
public string SiteIdentifier { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? NodeAAddress { get; set; } // Akka: "akka.tcp://scadalink@host:8082"
|
||||
public string? NodeBAddress { get; set; } // Akka: "akka.tcp://scadalink@host:8082"
|
||||
public string? NodeAAddress { get; set; } // Akka: "akka.tcp://scadabridge@host:8082"
|
||||
public string? NodeBAddress { get; set; } // Akka: "akka.tcp://scadabridge@host:8082"
|
||||
public string? GrpcNodeAAddress { get; set; } // gRPC: "http://host:8083"
|
||||
public string? GrpcNodeBAddress { get; set; } // gRPC: "http://host:8083"
|
||||
}
|
||||
@@ -100,7 +100,7 @@ Add `GrpcNodeAAddress` and `GrpcNodeBAddress` nullable string columns to the `Si
|
||||
|
||||
### Management Commands
|
||||
|
||||
**Modify**: `src/ScadaLink.Commons/Messages/Management/SiteCommands.cs`
|
||||
**Modify**: `src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/SiteCommands.cs`
|
||||
|
||||
```csharp
|
||||
public record CreateSiteCommand(
|
||||
@@ -116,27 +116,27 @@ public record UpdateSiteCommand(
|
||||
|
||||
### ManagementActor Handlers
|
||||
|
||||
**Modify**: `src/ScadaLink.ManagementService/ManagementActor.cs`
|
||||
**Modify**: `src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs`
|
||||
|
||||
Update `HandleCreateSite` and `HandleUpdateSite` to pass gRPC addresses through to the repository.
|
||||
|
||||
### CLI
|
||||
|
||||
**Modify**: `src/ScadaLink.CLI/Commands/SiteCommands.cs`
|
||||
**Modify**: `src/ZB.MOM.WW.ScadaBridge.CLI/Commands/SiteCommands.cs`
|
||||
|
||||
Add `--grpc-node-a-address` and `--grpc-node-b-address` options to `site create` and `site update`:
|
||||
|
||||
```sh
|
||||
scadalink site create --name "Site A" --identifier site-a \
|
||||
--node-a-address "akka.tcp://scadalink@site-a-a:8082" \
|
||||
--node-b-address "akka.tcp://scadalink@site-a-b:8082" \
|
||||
scadabridge site create --name "Site A" --identifier site-a \
|
||||
--node-a-address "akka.tcp://scadabridge@site-a-a:8082" \
|
||||
--node-b-address "akka.tcp://scadabridge@site-a-b:8082" \
|
||||
--grpc-node-a-address "http://site-a-a:8083" \
|
||||
--grpc-node-b-address "http://site-a-b:8083"
|
||||
```
|
||||
|
||||
### Central UI
|
||||
|
||||
**Modify**: `src/ScadaLink.CentralUI/Components/Pages/Admin/Sites.razor`
|
||||
**Modify**: `src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Admin/Sites.razor`
|
||||
|
||||
Add two form fields below the existing Node A / Node B address inputs in the site create/edit form:
|
||||
|
||||
@@ -169,26 +169,26 @@ Expose gRPC ports for each site node (internal 8083):
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `src/ScadaLink.Host/NodeOptions.cs` | Add `GrpcPort` property |
|
||||
| `src/ScadaLink.Host/StartupValidator.cs` | Validate `GrpcPort` for site role |
|
||||
| `src/ScadaLink.Host/appsettings.Site.json` | Add `GrpcPort: 8083` |
|
||||
| `src/ScadaLink.Commons/Entities/Sites/Site.cs` | Add `GrpcNodeAAddress`, `GrpcNodeBAddress` |
|
||||
| `src/ScadaLink.Commons/Messages/Management/SiteCommands.cs` | Add gRPC address params |
|
||||
| `src/ScadaLink.ConfigurationDatabase/` | EF migration for new columns |
|
||||
| `src/ScadaLink.ManagementService/ManagementActor.cs` | Pass gRPC addresses in handlers |
|
||||
| `src/ScadaLink.CLI/Commands/SiteCommands.cs` | Add `--grpc-node-a-address` / `--grpc-node-b-address` |
|
||||
| `src/ScadaLink.CentralUI/Components/Pages/Admin/Sites.razor` | Add gRPC address form fields + table columns |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Host/NodeOptions.cs` | Add `GrpcPort` property |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Host/StartupValidator.cs` | Validate `GrpcPort` for site role |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Host/appsettings.Site.json` | Add `GrpcPort: 8083` |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Commons/Entities/Sites/Site.cs` | Add `GrpcNodeAAddress`, `GrpcNodeBAddress` |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/SiteCommands.cs` | Add gRPC address params |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/` | EF migration for new columns |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs` | Pass gRPC addresses in handlers |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.CLI/Commands/SiteCommands.cs` | Add `--grpc-node-a-address` / `--grpc-node-b-address` |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Admin/Sites.razor` | Add gRPC address form fields + table columns |
|
||||
| `docker/docker-compose.yml` | Expose gRPC ports |
|
||||
|
||||
## Proto Definition
|
||||
|
||||
**File**: `src/ScadaLink.Communication/Protos/sitestream.proto`
|
||||
**File**: `src/ZB.MOM.WW.ScadaBridge.Communication/Protos/sitestream.proto`
|
||||
|
||||
The `oneof event` pattern is extensible — future event types (health metrics, connection state changes, etc.) are added as new fields without breaking existing consumers.
|
||||
|
||||
```protobuf
|
||||
syntax = "proto3";
|
||||
option csharp_namespace = "ScadaLink.Communication.Grpc";
|
||||
option csharp_namespace = "ZB.MOM.WW.ScadaBridge.Communication.Grpc";
|
||||
package sitestream;
|
||||
|
||||
service SiteStreamService {
|
||||
@@ -230,7 +230,7 @@ message AlarmStateUpdate {
|
||||
}
|
||||
```
|
||||
|
||||
Pre-generate C# stubs and check into `src/ScadaLink.Communication/SiteStreamGrpc/` — no `protoc` in Docker for ARM64 compatibility.
|
||||
Pre-generate C# stubs and check into `src/ZB.MOM.WW.ScadaBridge.Communication/SiteStreamGrpc/` — no `protoc` in Docker for ARM64 compatibility.
|
||||
|
||||
## Server-Streaming Pattern (Site Side)
|
||||
|
||||
@@ -560,7 +560,7 @@ All three trigger the same cleanup path: `CancellationToken` cancels → `ReadAl
|
||||
|
||||
### Configuration Defaults
|
||||
|
||||
Add to `CommunicationOptions` (`src/ScadaLink.Communication/CommunicationOptions.cs`):
|
||||
Add to `CommunicationOptions` (`src/ZB.MOM.WW.ScadaBridge.Communication/CommunicationOptions.cs`):
|
||||
|
||||
```csharp
|
||||
public TimeSpan GrpcKeepAlivePingDelay { get; set; } = TimeSpan.FromSeconds(15);
|
||||
@@ -568,11 +568,11 @@ public TimeSpan GrpcKeepAlivePingTimeout { get; set; } = TimeSpan.FromSeconds(10
|
||||
public TimeSpan GrpcMaxStreamLifetime { get; set; } = TimeSpan.FromHours(4);
|
||||
```
|
||||
|
||||
Bind from `appsettings.json` under `ScadaLink:Communication` (existing options section).
|
||||
Bind from `appsettings.json` under `ScadaBridge:Communication` (existing options section).
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **Internal Docker network**: Plain HTTP/2 (no TLS) — all site↔central traffic flows within `scadalink-net` Docker bridge network. Same as current Akka.NET remoting (unencrypted by default).
|
||||
- **Internal Docker network**: Plain HTTP/2 (no TLS) — all site↔central traffic flows within `scadabridge-net` Docker bridge network. Same as current Akka.NET remoting (unencrypted by default).
|
||||
- **Production**: Enable TLS on the Kestrel gRPC endpoint via HTTPS certificate configuration. The `GrpcChannel` on central switches to `https://` scheme.
|
||||
- **No authentication on the gRPC channel**: The channel is internal infrastructure (site↔central only). Authentication happens at the user-facing boundaries (LDAP/JWT for UI, Basic Auth for CLI/Management API).
|
||||
|
||||
@@ -593,10 +593,10 @@ Example: adding `ScriptErrorEvent` to the stream.
|
||||
|
||||
#### 1. Define the domain record
|
||||
|
||||
**File**: `src/ScadaLink.Commons/Messages/Streaming/ScriptErrorEvent.cs`
|
||||
**File**: `src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Streaming/ScriptErrorEvent.cs`
|
||||
|
||||
```csharp
|
||||
namespace ScadaLink.Commons.Messages.Streaming;
|
||||
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Streaming;
|
||||
|
||||
public record ScriptErrorEvent(
|
||||
string InstanceUniqueName, // Required for filtering
|
||||
@@ -607,7 +607,7 @@ public record ScriptErrorEvent(
|
||||
|
||||
#### 2. Add the proto message
|
||||
|
||||
**File**: `src/ScadaLink.Communication/Protos/sitestream.proto`
|
||||
**File**: `src/ZB.MOM.WW.ScadaBridge.Communication/Protos/sitestream.proto`
|
||||
|
||||
Add the message definition and a new field to the `oneof`:
|
||||
|
||||
@@ -633,7 +633,7 @@ Re-generate the C# stubs and check them into `SiteStreamGrpc/`.
|
||||
|
||||
#### 3. Publish to SiteStreamManager
|
||||
|
||||
**File**: `src/ScadaLink.SiteRuntime/Streaming/SiteStreamManager.cs`
|
||||
**File**: `src/ZB.MOM.WW.ScadaBridge.SiteRuntime/Streaming/SiteStreamManager.cs`
|
||||
|
||||
Add a publish method (follows the existing pattern exactly):
|
||||
|
||||
@@ -658,7 +658,7 @@ _streamManager?.PublishScriptError(new ScriptErrorEvent(
|
||||
|
||||
#### 5. Handle in the gRPC server relay actor
|
||||
|
||||
**File**: `src/ScadaLink.Communication/Grpc/SiteStreamGrpcServer.cs` (the `StreamRelayActor`)
|
||||
**File**: `src/ZB.MOM.WW.ScadaBridge.Communication/Grpc/SiteStreamGrpcServer.cs` (the `StreamRelayActor`)
|
||||
|
||||
The relay actor receives events from `SiteStreamManager` and writes them to the `Channel<SiteStreamEvent>`. Add a `Receive<ScriptErrorEvent>` handler that converts to the proto message:
|
||||
|
||||
@@ -682,7 +682,7 @@ Receive<ScriptErrorEvent>(evt =>
|
||||
|
||||
#### 6. Handle in the gRPC client converter
|
||||
|
||||
**File**: `src/ScadaLink.Communication/Grpc/SiteStreamGrpcClient.cs` (the `ConvertToDomainEvent` method)
|
||||
**File**: `src/ZB.MOM.WW.ScadaBridge.Communication/Grpc/SiteStreamGrpcClient.cs` (the `ConvertToDomainEvent` method)
|
||||
|
||||
Add a case for the new proto `oneof` variant:
|
||||
|
||||
@@ -740,9 +740,9 @@ case ScriptErrorEvent error:
|
||||
|
||||
| Pattern | File | Relevance |
|
||||
|---------|------|-----------|
|
||||
| SiteStreamManager | `src/ScadaLink.SiteRuntime/Streaming/SiteStreamManager.cs` | Subscribe/filter by instance, per-subscriber buffer, DropHead overflow |
|
||||
| SiteStreamManager | `src/ZB.MOM.WW.ScadaBridge.SiteRuntime/Streaming/SiteStreamManager.cs` | Subscribe/filter by instance, per-subscriber buffer, DropHead overflow |
|
||||
| Per-site client caching | `CentralCommunicationActor._siteClients` dictionary | One client per site, refresh on address change |
|
||||
| Bridge actor pattern | `src/ScadaLink.Communication/Actors/DebugStreamBridgeActor.cs` | Per-session actor with callbacks, adapted to use gRPC instead of Akka messages |
|
||||
| Bridge actor pattern | `src/ZB.MOM.WW.ScadaBridge.Communication/Actors/DebugStreamBridgeActor.cs` | Per-session actor with callbacks, adapted to use gRPC instead of Akka messages |
|
||||
|
||||
## Implementation Summary
|
||||
|
||||
@@ -750,31 +750,31 @@ case ScriptErrorEvent error:
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `src/ScadaLink.Communication/Protos/sitestream.proto` | Proto definition |
|
||||
| `src/ScadaLink.Communication/SiteStreamGrpc/` | Pre-generated C# stubs |
|
||||
| `src/ScadaLink.Communication/Grpc/SiteStreamGrpcServer.cs` | Site-side gRPC streaming server |
|
||||
| `src/ScadaLink.Communication/Grpc/SiteStreamGrpcClient.cs` | Central-side gRPC streaming client |
|
||||
| `src/ScadaLink.Communication/Grpc/SiteStreamGrpcClientFactory.cs` | Per-site client factory/cache |
|
||||
| `src/ScadaLink.Communication/Grpc/SiteStreamGrpcClientFactory.cs` | Per-site gRPC client cache, reads GrpcNodeA/BAddress from Site entity |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Communication/Protos/sitestream.proto` | Proto definition |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Communication/SiteStreamGrpc/` | Pre-generated C# stubs |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Communication/Grpc/SiteStreamGrpcServer.cs` | Site-side gRPC streaming server |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Communication/Grpc/SiteStreamGrpcClient.cs` | Central-side gRPC streaming client |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Communication/Grpc/SiteStreamGrpcClientFactory.cs` | Per-site client factory/cache |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Communication/Grpc/SiteStreamGrpcClientFactory.cs` | Per-site gRPC client cache, reads GrpcNodeA/BAddress from Site entity |
|
||||
|
||||
### Modified Files
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `src/ScadaLink.Communication/ScadaLink.Communication.csproj` | Add `Grpc.AspNetCore` + `Grpc.Net.Client` packages |
|
||||
| `src/ScadaLink.Host/Program.cs` | Site: switch to WebApplicationBuilder + Kestrel gRPC |
|
||||
| `src/ScadaLink.Communication/Actors/DebugStreamBridgeActor.cs` | Use gRPC client for streaming (ClusterClient for snapshot only) |
|
||||
| `src/ScadaLink.Communication/DebugStreamService.cs` | Inject `SiteStreamGrpcClientFactory` |
|
||||
| `src/ScadaLink.SiteRuntime/Actors/InstanceActor.cs` | Remove `DebugStreamEvent` forwarding (publish to SiteStreamManager only) |
|
||||
| `src/ScadaLink.Communication/Actors/SiteCommunicationActor.cs` | Remove `Receive<DebugStreamEvent>` handler |
|
||||
| `src/ScadaLink.Communication/Actors/CentralCommunicationActor.cs` | Remove `HandleDebugStreamEvent` |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Communication/ZB.MOM.WW.ScadaBridge.Communication.csproj` | Add `Grpc.AspNetCore` + `Grpc.Net.Client` packages |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Host/Program.cs` | Site: switch to WebApplicationBuilder + Kestrel gRPC |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Communication/Actors/DebugStreamBridgeActor.cs` | Use gRPC client for streaming (ClusterClient for snapshot only) |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Communication/DebugStreamService.cs` | Inject `SiteStreamGrpcClientFactory` |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.SiteRuntime/Actors/InstanceActor.cs` | Remove `DebugStreamEvent` forwarding (publish to SiteStreamManager only) |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Communication/Actors/SiteCommunicationActor.cs` | Remove `Receive<DebugStreamEvent>` handler |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Communication/Actors/CentralCommunicationActor.cs` | Remove `HandleDebugStreamEvent` |
|
||||
| `docker/docker-compose.yml` | Expose gRPC ports for site nodes |
|
||||
|
||||
### Deleted Files
|
||||
|
||||
| File | Reason |
|
||||
|------|--------|
|
||||
| `src/ScadaLink.Commons/Messages/DebugView/DebugStreamEvent.cs` | No longer needed — events flow via gRPC, not ClusterClient |
|
||||
| `src/ZB.MOM.WW.ScadaBridge.Commons/Messages/DebugView/DebugStreamEvent.cs` | No longer needed — events flow via gRPC, not ClusterClient |
|
||||
|
||||
## Design Review Notes
|
||||
|
||||
@@ -910,21 +910,21 @@ Update the architecture diagram to show the gRPC streaming channel between site
|
||||
|
||||
| Test File | Change |
|
||||
|-----------|--------|
|
||||
| `tests/ScadaLink.SiteRuntime.Tests/Actors/InstanceActorIntegrationTests.cs` | Remove `DebugStreamEventForwarder` test helper and `DebugStreamEvent` expectations. Debug subscriber tests should verify events reach SiteStreamManager only (not direct forwarding). |
|
||||
| `tests/ScadaLink.Communication.Tests/` | Remove any tests for `DebugStreamEvent` routing through `CentralCommunicationActor` and `SiteCommunicationActor`. |
|
||||
| `tests/ScadaLink.Host.Tests/HealthCheckTests.cs` | May need updates if site host builder changes affect test factory setup. |
|
||||
| `tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Actors/InstanceActorIntegrationTests.cs` | Remove `DebugStreamEventForwarder` test helper and `DebugStreamEvent` expectations. Debug subscriber tests should verify events reach SiteStreamManager only (not direct forwarding). |
|
||||
| `tests/ZB.MOM.WW.ScadaBridge.Communication.Tests/` | Remove any tests for `DebugStreamEvent` routing through `CentralCommunicationActor` and `SiteCommunicationActor`. |
|
||||
| `tests/ZB.MOM.WW.ScadaBridge.Host.Tests/HealthCheckTests.cs` | May need updates if site host builder changes affect test factory setup. |
|
||||
|
||||
### New Tests Required
|
||||
|
||||
| Test | Project | What to Verify |
|
||||
|------|---------|----------------|
|
||||
| `SiteStreamGrpcServerTests` | `ScadaLink.Communication.Tests` | Server accepts subscription, relays events from mock SiteStreamManager to gRPC stream, cleans up on cancellation, rejects duplicate `correlation_id`, enforces max concurrent streams limit, rejects before actor system ready. |
|
||||
| `SiteStreamGrpcClientTests` | `ScadaLink.Communication.Tests` | Client connects, reads stream, converts proto→domain types, invokes callback, handles stream errors, reconnects to NodeB on failure. |
|
||||
| `SiteStreamGrpcClientFactoryTests` | `ScadaLink.Communication.Tests` | Creates and caches per-site clients, derives endpoints from Site entity, disposes on site removal. |
|
||||
| `DebugStreamBridgeActorTests` (update) | `ScadaLink.Communication.Tests` | Verify bridge actor opens gRPC stream after snapshot, receives events via gRPC callback (not Akka messages), reconnects on stream error with node failover, terminates after max retries. |
|
||||
| `GrpcStreamIntegrationTest` | `ScadaLink.IntegrationTests` | End-to-end: site gRPC server → central gRPC client → bridge actor → callback. Use in-process test server (`WebApplicationFactory` or `TestServer`). Verify event delivery, cancellation cleanup, keepalive behavior. |
|
||||
| `SiteHostStartupTests` | `ScadaLink.Host.Tests` | Site host starts with `WebApplicationBuilder`, gRPC port configured, `MapGrpcService` registered, rejects streams before actor system ready. |
|
||||
| `ProtoRoundtripTests` | `ScadaLink.Communication.Tests` | Serialize/deserialize each proto message type, verify `oneof` discrimination, verify enum mappings, verify `google.protobuf.Timestamp` conversion. |
|
||||
| `SiteStreamGrpcServerTests` | `ZB.MOM.WW.ScadaBridge.Communication.Tests` | Server accepts subscription, relays events from mock SiteStreamManager to gRPC stream, cleans up on cancellation, rejects duplicate `correlation_id`, enforces max concurrent streams limit, rejects before actor system ready. |
|
||||
| `SiteStreamGrpcClientTests` | `ZB.MOM.WW.ScadaBridge.Communication.Tests` | Client connects, reads stream, converts proto→domain types, invokes callback, handles stream errors, reconnects to NodeB on failure. |
|
||||
| `SiteStreamGrpcClientFactoryTests` | `ZB.MOM.WW.ScadaBridge.Communication.Tests` | Creates and caches per-site clients, derives endpoints from Site entity, disposes on site removal. |
|
||||
| `DebugStreamBridgeActorTests` (update) | `ZB.MOM.WW.ScadaBridge.Communication.Tests` | Verify bridge actor opens gRPC stream after snapshot, receives events via gRPC callback (not Akka messages), reconnects on stream error with node failover, terminates after max retries. |
|
||||
| `GrpcStreamIntegrationTest` | `ZB.MOM.WW.ScadaBridge.IntegrationTests` | End-to-end: site gRPC server → central gRPC client → bridge actor → callback. Use in-process test server (`WebApplicationFactory` or `TestServer`). Verify event delivery, cancellation cleanup, keepalive behavior. |
|
||||
| `SiteHostStartupTests` | `ZB.MOM.WW.ScadaBridge.Host.Tests` | Site host starts with `WebApplicationBuilder`, gRPC port configured, `MapGrpcService` registered, rejects streams before actor system ready. |
|
||||
| `ProtoRoundtripTests` | `ZB.MOM.WW.ScadaBridge.Communication.Tests` | Serialize/deserialize each proto message type, verify `oneof` discrimination, verify enum mappings, verify `google.protobuf.Timestamp` conversion. |
|
||||
|
||||
### Test Coverage Guardrails
|
||||
|
||||
@@ -932,7 +932,7 @@ To ensure the implementation stays compliant with this plan:
|
||||
|
||||
1. **Proto contract tests**: A test that loads `sitestream.proto` and verifies all `oneof` variants have handlers in both `StreamRelayActor` (server) and `ConvertToDomainEvent` (client). If a new proto field is added without handlers, the test fails. Prevents silent event type gaps.
|
||||
|
||||
2. **Architectural constraint test**: Add to `ScadaLink.Commons.Tests/ArchitecturalConstraintTests.cs` — verify that `DebugStreamEvent` type no longer exists in the assembly (ensures the ClusterClient streaming path is fully removed and doesn't creep back).
|
||||
2. **Architectural constraint test**: Add to `ZB.MOM.WW.ScadaBridge.Commons.Tests/ArchitecturalConstraintTests.cs` — verify that `DebugStreamEvent` type no longer exists in the assembly (ensures the ClusterClient streaming path is fully removed and doesn't creep back).
|
||||
|
||||
3. **Startup validation test**: Site host integration test that verifies gRPC server rejects `SubscribeInstance` calls with `StatusCode.Unavailable` before the actor system is ready, and accepts them after.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user