Skip to content

Commit fb026ad

Browse files
authored
1 parent 86abb05 commit fb026ad

File tree

10 files changed

+508
-0
lines changed

10 files changed

+508
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Run Integration Tests
2+
3+
on:
4+
schedule:
5+
- cron: "0 0 * * *" # Runs every night at 12:00 AM UTC
6+
workflow_dispatch:
7+
8+
jobs:
9+
integration-tests:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout repository
14+
uses: actions/checkout@v4
15+
16+
- name: Setup .NET
17+
uses: actions/setup-dotnet@v4
18+
with:
19+
dotnet-version: '8.0.x'
20+
21+
- name: Restore dependencies
22+
run: dotnet restore
23+
24+
- name: Build solution
25+
run: dotnet build --no-restore --configuration Release
26+
27+
- name: Run IntegrationTests.Worker
28+
run: dotnet test --logger "console;verbosity=detailed"

OpenJudgeSystem.sln

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OJS.Services.Mentor.Busines
9494
EndProject
9595
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OJS.Services.Mentor.Models", "Services\Mentor\OJS.Services.Mentor.Models\OJS.Services.Mentor.Models.csproj", "{D04B099B-AA9D-4668-B4E8-85C0692CB3A8}"
9696
EndProject
97+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests/IntergrationTests", "Tests/IntergrationTests", "{3FB6A17B-1C6B-4839-AF1D-13F0F2F33F07}"
98+
EndProject
99+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntegrationTests.Worker", "Tests\IntegrationTests\IntegrationTests.Worker\IntegrationTests.Worker.csproj", "{F74414B6-AB1A-43F2-9F64-9FC467FDEAA4}"
100+
EndProject
97101
Global
98102
GlobalSection(SolutionConfigurationPlatforms) = preSolution
99103
Debug|Any CPU = Debug|Any CPU
@@ -292,5 +296,9 @@ Global
292296
{D04B099B-AA9D-4668-B4E8-85C0692CB3A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
293297
{D04B099B-AA9D-4668-B4E8-85C0692CB3A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
294298
{D04B099B-AA9D-4668-B4E8-85C0692CB3A8}.Release|Any CPU.Build.0 = Release|Any CPU
299+
{F74414B6-AB1A-43F2-9F64-9FC467FDEAA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
300+
{F74414B6-AB1A-43F2-9F64-9FC467FDEAA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
301+
{F74414B6-AB1A-43F2-9F64-9FC467FDEAA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
302+
{F74414B6-AB1A-43F2-9F64-9FC467FDEAA4}.Release|Any CPU.Build.0 = Release|Any CPU
295303
EndGlobalSection
296304
EndGlobal
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace IntegrationTests.Worker;
2+
3+
public abstract class BaseStrategyTest<TFactory, TParameters>
4+
where TFactory : BaseSubmissionFactory<TParameters>
5+
{
6+
protected BaseStrategyTest(RabbitMqAndWorkerFixture fixture, TFactory factory)
7+
{
8+
this.Fixture = fixture;
9+
this.Factory = factory;
10+
}
11+
12+
protected TFactory Factory { get; set; }
13+
14+
protected RabbitMqAndWorkerFixture Fixture { get; set; }
15+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
namespace IntegrationTests.Worker;
2+
3+
using OJS.PubSub.Worker.Models.Submissions;
4+
5+
public abstract class BaseSubmissionFactory<TParams>
6+
{
7+
private int id;
8+
9+
/// <summary>
10+
/// A method for getting a submission for test execution.
11+
/// <param name="strategyParameters">These are the unique properties the strategy's test requires to be changed in order to get the expected result.</param>
12+
/// </summary>
13+
public abstract SubmissionForProcessingPubSubModel GetSubmission(TParams strategyParameters);
14+
15+
/// <summary>
16+
/// A thread-safe way for creating a unique id for each submission. Based on the 'fixture' implementation, the IDs MUST be unique.
17+
/// This is faster than using 'lock'.
18+
/// </summary>
19+
protected int GetNextId()
20+
=> Interlocked.Increment(ref this.id);
21+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
namespace IntegrationTests.Worker.CSharp;
2+
3+
public record CSharpCodeParameters(string Code);
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
namespace IntegrationTests.Worker.CSharp;
2+
3+
using OJS.PubSub.Worker.Models.Submissions;
4+
using OJS.Services.Common.Models.Submissions.ExecutionDetails;
5+
using OJS.Workers.Common.Models;
6+
7+
public class CSharpCodeSubmissionFactory : BaseSubmissionFactory<CSharpCodeParameters>
8+
{
9+
public override SubmissionForProcessingPubSubModel GetSubmission(CSharpCodeParameters strategyParameters)
10+
{
11+
var submission = new SubmissionForProcessingPubSubModel
12+
{
13+
Id = this.GetNextId(),
14+
ExecutionType = ExecutionType.TestsExecution,
15+
ExecutionStrategy = ExecutionStrategyType.DotNetCore6CompileExecuteAndCheck,
16+
CompilerType = CompilerType.CSharpDotNetCore,
17+
FileContent = null,
18+
AdditionalFiles = null,
19+
Code = strategyParameters.Code,
20+
TimeLimit = 100,
21+
ExecutionStrategyBaseTimeLimit = null,
22+
MemoryLimit = 16777216,
23+
ExecutionStrategyBaseMemoryLimit = null,
24+
Verbosely = false,
25+
SimpleExecutionDetails = null,
26+
TestsExecutionDetails = new TestsExecutionDetailsServiceModel
27+
{
28+
MaxPoints = 100,
29+
TaskId = null,
30+
CheckerType = "trim",
31+
CheckerParameter = null,
32+
Tests =
33+
[
34+
new TestContext
35+
{ Id = 172459, Input = "0", Output = "Hello SoftUni", IsTrialTest = true, OrderBy = 0 },
36+
new TestContext
37+
{ Id = 172460, Input = "0", Output = "Hello SoftUni", IsTrialTest = false, OrderBy = 0 }
38+
],
39+
TaskSkeleton = null,
40+
TaskSkeletonAsString = null
41+
}
42+
};
43+
44+
return submission;
45+
}
46+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
namespace IntegrationTests.Worker.CSharp;
2+
3+
using OJS.Workers.Common.Models;
4+
5+
public class CSharpCodeTests : BaseStrategyTest<CSharpCodeSubmissionFactory, CSharpCodeParameters>, IClassFixture<RabbitMqAndWorkerFixture>
6+
{
7+
public CSharpCodeTests(RabbitMqAndWorkerFixture fixture)
8+
: base(fixture, new CSharpCodeSubmissionFactory()) { }
9+
10+
[Fact]
11+
public async Task DotNet6_ShouldReturnCorrectAnswer_WhenCodeIsValid()
12+
{
13+
// Arrange
14+
var submission = this.Factory.GetSubmission(new("Console.WriteLine(\"Hello SoftUni\");"));
15+
16+
// Act
17+
var result = await this.Fixture.ProcessSubmission(submission);
18+
19+
// Assert
20+
Assert.NotNull(result);
21+
Assert.Equal(submission.Id, result!.Id);
22+
Assert.NotNull(result.ExecutionResult);
23+
Assert.True(result.ExecutionResult.TaskResult!.TestResults.All(tr => tr.ResultType == TestRunResultType.CorrectAnswer));
24+
}
25+
26+
[Fact]
27+
public async Task DotNet6_ShouldFailCompilation_WhenCodeIsInvalid()
28+
{
29+
// Arrange
30+
var submission = this.Factory.GetSubmission(new("This is not proper c# code!"));
31+
32+
// Act
33+
var result = await this.Fixture.ProcessSubmission(submission);
34+
35+
// Assert
36+
Assert.NotNull(result);
37+
Assert.Equal(submission.Id, result.Id);
38+
Assert.NotNull(result.ExecutionResult);
39+
Assert.False(result.ExecutionResult.IsCompiledSuccessfully);
40+
}
41+
42+
[Fact]
43+
public async Task DotNet6_ShouldTimeout_WhenCodeRunsIndefinitely()
44+
{
45+
// Arrange
46+
var submission = this.Factory.GetSubmission(new("while (true) { }"));
47+
48+
// Act
49+
var result = await this.Fixture.ProcessSubmission(submission);
50+
51+
// Assert
52+
Assert.NotNull(result);
53+
Assert.Equal(submission.Id, result!.Id);
54+
Assert.NotNull(result.ExecutionResult);
55+
Assert.True(result.ExecutionResult.TaskResult!.TestResults.All(tr => tr.ResultType == TestRunResultType.TimeLimit));
56+
}
57+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
8+
<IsPackable>false</IsPackable>
9+
<IsTestProject>true</IsTestProject>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
14+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
15+
<PackageReference Include="RabbitMQ.Client" Version="7.1.2" />
16+
<PackageReference Include="xunit" Version="2.5.3"/>
17+
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
18+
<PackageReference Include="MassTransit" Version="8.4.0" />
19+
<PackageReference Include="MassTransit.RabbitMQ" Version="8.4.0" />
20+
<PackageReference Include="Testcontainers.RabbitMq" Version="4.3.0" />
21+
</ItemGroup>
22+
23+
<ItemGroup>
24+
<Using Include="Xunit"/>
25+
</ItemGroup>
26+
27+
<ItemGroup>
28+
<ProjectReference Include="..\..\..\PubSub\OJS.PubSub.Worker.Models\OJS.PubSub.Worker.Models.csproj" />
29+
<ProjectReference Include="..\..\..\Servers\UI\OJS.Servers.Ui\OJS.Servers.Ui.csproj" />
30+
<ProjectReference Include="..\..\..\Servers\Worker\OJS.Servers.Worker\OJS.Servers.Worker.csproj" />
31+
</ItemGroup>
32+
33+
</Project>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
namespace IntegrationTests.Worker;
2+
3+
public class MassTransitEnvelope
4+
{
5+
// Used for deserialization
6+
public MassTransitEnvelope()
7+
{
8+
}
9+
10+
public MassTransitEnvelope(
11+
int rabbitMqPort,
12+
string endpointFullyQualifiedName,
13+
string modelNamespace,
14+
string modelName,
15+
object message)
16+
{
17+
this.SourceAddress = $"rabbitmq://localhost:{rabbitMqPort}/test-source";
18+
this.DestinationAddress = $"rabbitmq://localhost:{rabbitMqPort}/ojs/{endpointFullyQualifiedName}";
19+
this.MessageType = [$"urn:message:{modelNamespace}:{modelName}"];
20+
this.Message = message;
21+
}
22+
23+
/// <summary>
24+
/// The envelope's id.
25+
/// </summary>
26+
public Guid MessageId { get; set; } = Guid.NewGuid();
27+
28+
/// <summary>
29+
/// The source from which the message is sent. Using 'test-source' by default.
30+
/// </summary>
31+
public string SourceAddress { get; set; }
32+
33+
/// <summary>
34+
/// The destination to which the message is sent.
35+
/// -> endpointFullyQualifiedName is the endpoint's fully qualified name, as this is the way we register Mass Transit's endpoints.
36+
/// </summary>
37+
public string DestinationAddress { get; set; }
38+
39+
/// <summary>
40+
/// The type of the message to be sent.
41+
/// -> modelNamespace is the model's namespace.
42+
/// -> modelName is the model's class name.
43+
/// </summary>
44+
public string[] MessageType { get; set; }
45+
46+
/// <summary>
47+
/// The message to be sent.
48+
/// </summary>
49+
public object Message { get; set; }
50+
}

0 commit comments

Comments
 (0)