Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build/build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ class Build : NukeBuild
Solution.Persistence.Wolverine_RavenDb,
Solution.Persistence.Wolverine_SqlServer,
Solution.Persistence.Wolverine_MySql,
Solution.Persistence.Wolverine_Oracle,
Solution.Persistence.Wolverine_Sqlite,
Solution.Extensions.Wolverine_FluentValidation,
Solution.Extensions.Wolverine_MemoryPack,
Expand Down
13 changes: 12 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,15 @@ services:
- "3306:3306"
environment:
- "MYSQL_ROOT_PASSWORD=P@55w0rd"
- "MYSQL_DATABASE=wolverine"
- "MYSQL_DATABASE=wolverine"

oracle:
image: "gvenzl/oracle-free:23-slim"
ports:
- "1521:1521"
environment:
- "ORACLE_PASSWORD=P@55w0rd"
- "APP_USER=wolverine"
- "APP_USER_PASSWORD=wolverine"
volumes:
- ./docker/oracle:/container-entrypoint-initdb.d
46 changes: 46 additions & 0 deletions docker/oracle/init-wolverine-permissions.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
-- Grant the wolverine user permissions to create and drop schemas (users in Oracle)
-- This script runs after the APP_USER is created by the container

ALTER SESSION SET CONTAINER = FREEPDB1;

-- Grant privileges to create and drop users (schemas)
GRANT CREATE USER TO wolverine;
GRANT DROP USER TO wolverine;
GRANT ALTER USER TO wolverine;

-- Grant ability to create sessions and manage objects in other schemas
GRANT CREATE SESSION TO wolverine WITH ADMIN OPTION;
GRANT CREATE TABLE TO wolverine WITH ADMIN OPTION;
GRANT CREATE SEQUENCE TO wolverine WITH ADMIN OPTION;
GRANT CREATE PROCEDURE TO wolverine WITH ADMIN OPTION;
GRANT CREATE VIEW TO wolverine WITH ADMIN OPTION;

-- Grant ability to create/drop/alter objects in ANY schema (needed for cross-schema testing)
GRANT CREATE ANY TABLE TO wolverine;
GRANT DROP ANY TABLE TO wolverine;
GRANT ALTER ANY TABLE TO wolverine;
GRANT SELECT ANY TABLE TO wolverine;
GRANT INSERT ANY TABLE TO wolverine;
GRANT UPDATE ANY TABLE TO wolverine;
GRANT DELETE ANY TABLE TO wolverine;
GRANT CREATE ANY INDEX TO wolverine;
GRANT DROP ANY INDEX TO wolverine;
GRANT CREATE ANY SEQUENCE TO wolverine;
GRANT DROP ANY SEQUENCE TO wolverine;
GRANT CREATE ANY PROCEDURE TO wolverine;
GRANT DROP ANY PROCEDURE TO wolverine;
GRANT EXECUTE ANY PROCEDURE TO wolverine;

-- Grant unlimited tablespace so wolverine can allocate space to schemas it creates
GRANT UNLIMITED TABLESPACE TO wolverine WITH ADMIN OPTION;

-- Grant ability to select from system views for schema introspection
GRANT SELECT ON sys.all_tables TO wolverine;
GRANT SELECT ON sys.all_tab_columns TO wolverine;
GRANT SELECT ON sys.all_constraints TO wolverine;
GRANT SELECT ON sys.all_cons_columns TO wolverine;
GRANT SELECT ON sys.all_indexes TO wolverine;
GRANT SELECT ON sys.all_ind_columns TO wolverine;
GRANT SELECT ON sys.all_sequences TO wolverine;
GRANT SELECT ON sys.all_users TO wolverine;
GRANT SELECT ON sys.all_objects TO wolverine;
47 changes: 47 additions & 0 deletions src/Persistence/Oracle/OracleTests/Agents/node_persistence.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using IntegrationTests;
using Microsoft.Extensions.Logging.Abstractions;
using Oracle.ManagedDataAccess.Client;
using Weasel.Oracle;
using Wolverine;
using Wolverine.ComplianceTests;
using Wolverine.Oracle;
using Wolverine.Persistence.Durability;
using Wolverine.RDBMS;
using Wolverine.RDBMS.Sagas;

namespace OracleTests.Agents;

[Collection("oracle")]
public class node_persistence : NodePersistenceCompliance
{
protected override async Task<IMessageStore> buildCleanMessageStore()
{
// Clean up Oracle schema objects
await using var conn = new OracleConnection(Servers.OracleConnectionString);
await conn.OpenAsync();
try
{
// Drop and recreate the schema by clearing tables
// Oracle doesn't have DROP SCHEMA CASCADE like PostgreSQL
}
finally
{
await conn.CloseAsync();
}

var dataSource = new OracleDataSource(Servers.OracleConnectionString);
var settings = new DatabaseSettings
{
ConnectionString = Servers.OracleConnectionString,
SchemaName = "WOLVERINE",
Role = MessageStoreRole.Main
};

var database = new OracleMessageStore(settings, new DurabilitySettings(), dataSource,
NullLogger<OracleMessageStore>.Instance, Array.Empty<SagaTableDefinition>());

await database.Admin.RebuildAsync();

return database;
}
}
1 change: 1 addition & 0 deletions src/Persistence/Oracle/OracleTests/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Xunit;
1 change: 1 addition & 0 deletions src/Persistence/Oracle/OracleTests/NoParallelization.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[assembly: CollectionBehavior(DisableTestParallelization = true)]
4 changes: 4 additions & 0 deletions src/Persistence/Oracle/OracleTests/OracleContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace OracleTests;

[Collection("oracle")]
public abstract class OracleContext;
101 changes: 101 additions & 0 deletions src/Persistence/Oracle/OracleTests/OracleMessageStoreTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using IntegrationTests;
using JasperFx.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging.Abstractions;
using Shouldly;
using Wolverine;
using Wolverine.ComplianceTests;
using Wolverine.Oracle;
using Wolverine.Persistence.Durability;
using Wolverine.RDBMS;
using Wolverine.Transports.Tcp;

namespace OracleTests;

[Collection("oracle")]
public class OracleMessageStoreTests : MessageStoreCompliance
{
public override async Task<IHost> BuildCleanHost()
{
var dataSource = new OracleDataSource(Servers.OracleConnectionString);
var settings = new DatabaseSettings
{
SchemaName = "WOLVERINE",
CommandQueuesEnabled = true,
Role = MessageStoreRole.Main
};
var durabilitySettings = new DurabilitySettings();
var store = new OracleMessageStore(settings, durabilitySettings, dataSource,
NullLogger<OracleMessageStore>.Instance);

await store.Admin.MigrateAsync();

var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
{
opts.PersistMessagesWithOracle(Servers.OracleConnectionString, "WOLVERINE");
opts.ListenAtPort(2345).UseDurableInbox();
opts.Durability.Mode = DurabilityMode.Solo;
}).StartAsync();

var hostStore = host.Get<IMessageStore>();
await hostStore.Admin.ClearAllAsync();

return host;
}

[Fact]
public async Task can_persist_and_delete_outgoing_envelope()
{
var envelope = ObjectMother.Envelope();

await thePersistence.Outbox.StoreOutgoingAsync(envelope, 1);

var counts = await thePersistence.Admin.FetchCountsAsync();
counts.Outgoing.ShouldBeGreaterThanOrEqualTo(1);

await thePersistence.Outbox.DeleteOutgoingAsync([envelope]);

var counts2 = await thePersistence.Admin.FetchCountsAsync();
counts2.Outgoing.ShouldBe(counts.Outgoing - 1);
}

[Fact]
public async Task can_move_envelope_to_dead_letter_queue()
{
var envelope = ObjectMother.Envelope();
await thePersistence.Inbox.StoreIncomingAsync(envelope);

var exception = new InvalidOperationException("Test error");
await thePersistence.Inbox.MoveToDeadLetterStorageAsync(envelope, exception);

var counts = await thePersistence.Admin.FetchCountsAsync();
counts.DeadLetter.ShouldBeGreaterThanOrEqualTo(1);
}

[Fact]
public async Task can_mark_envelope_as_handled()
{
var envelope = ObjectMother.Envelope();
await thePersistence.Inbox.StoreIncomingAsync(envelope);

await thePersistence.Inbox.MarkIncomingEnvelopeAsHandledAsync(envelope);

var counts = await thePersistence.Admin.FetchCountsAsync();
counts.Handled.ShouldBeGreaterThanOrEqualTo(1);
}

[Fact]
public async Task can_schedule_envelope()
{
var envelope = ObjectMother.Envelope();
envelope.ScheduleDelay = 1.Hours();
envelope.Status = EnvelopeStatus.Scheduled;

await thePersistence.Inbox.StoreIncomingAsync(envelope);

var counts = await thePersistence.Admin.FetchCountsAsync();
counts.Scheduled.ShouldBeGreaterThanOrEqualTo(1);
}
}
34 changes: 34 additions & 0 deletions src/Persistence/Oracle/OracleTests/OracleTests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="GitHubActionsTestLogger" Version="2.4.1" PrivateAssets="All" />
<PackageReference Include="xunit" Version="2.9.0"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Wolverine.RDBMS\Wolverine.RDBMS.csproj"/>
<ProjectReference Include="..\Wolverine.Oracle\Wolverine.Oracle.csproj"/>
<ProjectReference Include="..\..\..\Testing\Wolverine.ComplianceTests\Wolverine.ComplianceTests.csproj" />
</ItemGroup>

<ItemGroup>
<Content Include="$(SolutionDir)xunit.runner.json" CopyToOutputDirectory="PreserveNewest"/>
</ItemGroup>

<ItemGroup>
<Compile Include="..\..\..\Servers.cs">
<Link>Servers.cs</Link>
</Compile>
</ItemGroup>

</Project>
Loading
Loading