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
3 changes: 1 addition & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ jobs:
run:
kosli create flow "${KOSLI_FLOW}"
--description="Test runner"
--template-file=.kosli.yml

- name: Begin Kosli Trail
if: ${{ github.ref == 'refs/heads/main' }}
run:
kosli begin trail "${KOSLI_TRAIL}"
--template-file=.kosli.yml

- name: Write Trail URL to GitHub Step Summary
if: ${{ github.ref == 'refs/heads/main' }}
Expand Down Expand Up @@ -326,7 +326,6 @@ jobs:
- rubocop-lint
- unit-tests
- integration-tests
- snyk-code-scan
env:
KOSLI_FINGERPRINT: ${{ needs.build-image.outputs.digest }}
steps:
Expand Down
3 changes: 0 additions & 3 deletions .kosli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,3 @@ trail:
type: custom:test-metrics
- name: integration-test-coverage-metrics
type: custom:coverage-metrics

- name: snyk-code-scan
type: snyk
34 changes: 23 additions & 11 deletions source/server/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -169,30 +169,38 @@ def docker_run_cyber_dojo_sh_command(id, image_name, container_name)
end

def ulimits(image_name)
# [1] Some start-points have large dll files, eg C# dotnet
# [2] The nproc --limit is per user across all containers. See
# [0] We could allow cores as binary files are not tar piped out of the container.
# [1] The nproc --limit is per user across all containers. See
# [2] Some start-points have large DLL files
# https://docs.docker.com/engine/reference/commandline/run/#set-ulimits-in-container---ulimit
# There is no cpu-ulimit. See
# https://github.com/cyber-dojo-retired/runner-stateless/issues/2
options = [
ulimit('core', 0), # no core file
ulimit('fsize', 256 * MB), # file size [1]
ulimit('locks', 1024), # number of file locks
ulimit('nofile', 1024), # number of files
ulimit('nproc', 1024), # number of processes [2]
ulimit('core', 0), # no core file [0]
ulimit('locks', 1024), # number of file locks
ulimit('nofile', 1024), # number of files
ulimit('nproc', 1024), # number of processes [1]
ulimit('stack', 16 * MB), # stack size
'--kernel-memory=768m', # limited
'--memory=768m', # max 768MB ram (same swap)
'--kernel-memory=2g', # limited
'--memory=2g', # max 768MB ram (same swap)
'--net=none', # no network
'--pids-limit=128', # no fork bombs
'--security-opt=no-new-privileges' # no escalation
'--security-opt=no-new-privileges' # no escalation
]
# Special handling of clang/clang++'s -fsanitize=address
options << if clang?(image_name)
'--cap-add=SYS_PTRACE'
else
ulimit('data', 4 * GB) # data segment size
end

# C# reqnroll creates very large files [2]
options << if csharp_reqnroll?(image_name)
ulimit('fsize', 2048 * GB) # file size
else
ulimit('fsize', 256 * MB) # file size
end

options.join(SPACE)
end

Expand All @@ -205,6 +213,10 @@ def clang?(image_name)
image_name.start_with?('ghcr.io/cyber-dojo-languages/clang')
end

def csharp_reqnroll?(image_name)
image_name.start_with?('ghcr.io/cyber-dojo-languages/csharp_reqnroll')
end

# - - - - - - - - - - - - - - - - - - - - - -
# temporary file systems
# - - - - - - - - - - - - - - - - - - - - - -
Expand All @@ -226,7 +238,7 @@ def clang?(image_name)
# eg, C#'s "dotnet restore"
# - - - - - - - - - - - - - - - - - - - - - -

TMP_FS_SANDBOX_DIR = "--tmpfs #{Sandbox::DIR}:exec,size=250M,uid=#{UID},gid=#{GID}".freeze
TMP_FS_SANDBOX_DIR = "--tmpfs #{Sandbox::DIR}:exec,size=250G,uid=#{UID},gid=#{GID}".freeze
TMP_FS_TMP_DIR = '--tmpfs /tmp:exec,size=250M,mode=1777'.freeze # Set /tmp sticky-bit

def utf8_clean(result)
Expand Down
53 changes: 28 additions & 25 deletions test/data/languages_start_points.manifests.json
Original file line number Diff line number Diff line change
Expand Up @@ -300,43 +300,46 @@
}
}
},
"C#, Moq": {
"display_name": "C#, Moq",
"C# 10.0.103, NUnit 4.3.2": {
"display_name": "C# 10.0.103, NUnit 4.3.2",
"filename_extension": [
".cs"
],
"image_name": "cyberdojofoundation/csharp_moq:368990c",
"max_seconds": 10,
"image_name": "ghcr.io/cyber-dojo-languages/csharp_nunit:80e3fae",
"max_seconds": 15,
"tab_size": 4,
"visible_files": {
"HikerTest.cs": {
"content": "using Moq;\nusing NUnit.Framework;\n\n[TestFixture]\npublic class HikerTest\n{\n [Test]\n public void life_the_universe_and_everything()\n {\n var arthur = new Mock<IHiker>();\n arthur.Setup((foo => foo.Answer())).Returns(6 * 9);\n\n // a simple example to start you off\n Assert.AreEqual(42, arthur.Object.Answer());\n }\n}\n"
"Hiker.cs": {
"content": "public class Hiker\n{\n public static int Answer()\n {\n return 6 * 9;\n }\n}\n"
},
"IHiker.cs": {
"content": "\npublic interface IHiker\n{\n int Answer();\n}\n"
"HikerTest.cs": {
"content": "using NUnit.Framework;\n\npublic class HikerTest\n{\n [Test]\n public void life_the_universe_and_everything()\n {\n // a simple example to start you off\n Assert.That(Hiker.Answer(), Is.EqualTo(42));\n }\n}\n"
},
"cyber-dojo.sh": {
"content": "\ntrap tidy_up EXIT\nfunction tidy_up()\n{\n # cyber-dojo returns text files under /sandbox that are\n # created/deleted/changed. In here you can remove any\n # such files you don't want returned to the browser.\n [ ! -f TestResult.xml ] || rm TestResult.xml\n}\n\nMOQ_PATH=/moq/Moq.4.7.99/lib/net45\nCASTLE_PATH=/moq/Castle.Core.4.1.1/lib/net45\nNUNIT_PATH=/moq/lib/net45\n\nexport MONO_PATH=${MOQ_PATH}:${CASTLE_PATH}:${NUNIT_PATH}\n\nmcs -t:library \\\n -r:${MOQ_PATH}/Moq.dll \\\n -r:${CASTLE_PATH}/Castle.Core.dll \\\n -r:${NUNIT_PATH}/nunit.framework.dll \\\n -out:RunTests.dll *.cs\n\nif [ $? -eq 0 ]; then\n NUNIT_RUNNERS_PATH=/moq/tools\n mono ${NUNIT_RUNNERS_PATH}/nunit3-console.exe --noheader ./RunTests.dll\nfi\n"
"content": "# --------------------------------------------------------------\n# Text files under /sandbox are automatically returned...\nsource ~/cyber_dojo_fs_cleaners.sh\n\nfunction cyber_dojo_enter()\n{\n : # 1. Only return _newly_ generated reports.\n #cyber_dojo_reset_dirs ${...}\n}\nfunction cyber_dojo_exit()\n{\n : # 2. Remove text files we don't want returned.\n cyber_dojo_delete_dirs /sandbox/bin \n cyber_dojo_delete_dirs /sandbox/obj\n #cyber_dojo_delete_files ...\n}\ncyber_dojo_enter\ntrap cyber_dojo_exit EXIT SIGTERM\n\ndotnet restore --source /home/sandbox/.nuget/packages/\ndotnet test --no-restore\n"
},
"dojo.csproj": {
"content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <TargetFramework>net10.0</TargetFramework>\n <LangVersion>latest</LangVersion>\n <ImplicitUsings>enable</ImplicitUsings>\n <Nullable>enable</Nullable>\n <IsPackable>false</IsPackable>\n </PropertyGroup>\n\n <ItemGroup>\n <PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\" />\n <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.14.0\" />\n <PackageReference Include=\"NUnit\" Version=\"4.3.2\" />\n <PackageReference Include=\"NUnit.Analyzers\" Version=\"4.7.0\" />\n <PackageReference Include=\"NUnit3TestAdapter\" Version=\"5.0.0\" />\n </ItemGroup>\n\n <ItemGroup>\n <Using Include=\"NUnit.Framework\" />\n </ItemGroup>\n\n</Project>"
}
}
},
"C#, NUnit": {
"display_name": "C#, NUnit",
"C#, Moq": {
"display_name": "C#, Moq",
"filename_extension": [
".cs"
],
"image_name": "cyberdojofoundation/csharp_nunit:1452bb7",
"image_name": "cyberdojofoundation/csharp_moq:368990c",
"max_seconds": 10,
"tab_size": 4,
"visible_files": {
"Hiker.cs": {
"content": "public class Hiker\n{\n public static int Answer()\n {\n return 6 * 9;\n }\n}\n"
},
"HikerTest.cs": {
"content": "using NUnit.Framework;\n\n[TestFixture]\npublic class HikerTest\n{\n [Test]\n public void life_the_universe_and_everything()\n {\n // a simple example to start you off\n Assert.AreEqual(42, Hiker.Answer());\n }\n}\n"
"content": "using Moq;\nusing NUnit.Framework;\n\n[TestFixture]\npublic class HikerTest\n{\n [Test]\n public void life_the_universe_and_everything()\n {\n var arthur = new Mock<IHiker>();\n arthur.Setup((foo => foo.Answer())).Returns(6 * 9);\n\n // a simple example to start you off\n Assert.AreEqual(42, arthur.Object.Answer());\n }\n}\n"
},
"IHiker.cs": {
"content": "\npublic interface IHiker\n{\n int Answer();\n}\n"
},
"cyber-dojo.sh": {
"content": "\ntrap tidy_up EXIT\nfunction tidy_up()\n{\n # cyber-dojo returns text files under /sandbox that are\n # created/deleted/changed. In here you can remove any\n # such files you don't want returned to the browser.\n [ ! -f TestResult.xml ] || rm TestResult.xml\n}\n\nNUNIT_PATH=/nunit/lib/net45\nexport MONO_PATH=${NUNIT_PATH}\n\nmcs -t:library \\\n -r:${NUNIT_PATH}/nunit.framework.dll \\\n -out:RunTests.dll *.cs\n\nif [ $? -eq 0 ]; then\n NUNIT_RUNNERS_PATH=/nunit/tools\n mono ${NUNIT_RUNNERS_PATH}/nunit3-console.exe --noheader ./RunTests.dll\nfi\n"
"content": "\ntrap tidy_up EXIT\nfunction tidy_up()\n{\n # cyber-dojo returns text files under /sandbox that are\n # created/deleted/changed. In here you can remove any\n # such files you don't want returned to the browser.\n [ ! -f TestResult.xml ] || rm TestResult.xml\n}\n\nMOQ_PATH=/moq/Moq.4.7.99/lib/net45\nCASTLE_PATH=/moq/Castle.Core.4.1.1/lib/net45\nNUNIT_PATH=/moq/lib/net45\n\nexport MONO_PATH=${MOQ_PATH}:${CASTLE_PATH}:${NUNIT_PATH}\n\nmcs -t:library \\\n -r:${MOQ_PATH}/Moq.dll \\\n -r:${CASTLE_PATH}/Castle.Core.dll \\\n -r:${NUNIT_PATH}/nunit.framework.dll \\\n -out:RunTests.dll *.cs\n\nif [ $? -eq 0 ]; then\n NUNIT_RUNNERS_PATH=/moq/tools\n mono ${NUNIT_RUNNERS_PATH}/nunit3-console.exe --noheader ./RunTests.dll\nfi\n"
}
}
},
Expand Down Expand Up @@ -676,8 +679,8 @@
}
}
},
"C++ (g++ 15.2.0), Cucumber-cpp 0.8.0": {
"display_name": "C++ (g++ 15.2.0), Cucumber-cpp 0.8.0",
"C++ (g++ 15.2.0), Cucumber 0.8.0": {
"display_name": "C++ (g++ 15.2.0), Cucumber 0.8.0",
"filename_extension": [
".cpp",
".hpp",
Expand Down Expand Up @@ -935,12 +938,12 @@
}
}
},
"D, unittest": {
"display_name": "D, unittest",
"D 13.3.0, unittest": {
"display_name": "D 13.3.0, unittest",
"filename_extension": [
".d"
],
"image_name": "cyberdojofoundation/d_unittest:c125c91",
"image_name": "ghcr.io/cyber-dojo-languages/d_unittest:8cbc812",
"max_seconds": 10,
"tab_size": 4,
"visible_files": {
Expand Down Expand Up @@ -1027,13 +1030,13 @@
}
}
},
"Fortran, FUnit": {
"display_name": "Fortran, FUnit",
"Fortran 15.2.0, FUnit 0.12.4": {
"display_name": "Fortran 15.2.0, FUnit 0.12.4",
"filename_extension": [
".f90",
".fun"
],
"image_name": "cyberdojofoundation/fortran_funit:f13f8ad",
"image_name": "ghcr.io/cyber-dojo-languages/fortran_funit:b659ce9",
"max_seconds": 10,
"tab_size": 4,
"visible_files": {
Expand Down
8 changes: 4 additions & 4 deletions test/server/check_test_metrics.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,21 @@ def table_data

[
[ nil ],
[ 'test.count', stats['test_count'], '>=', 101 ],
[ 'test.count', stats['test_count'], '>=', 102 ],
[ 'test.duration', stats['total_time'], '<=', 10 ],
[ nil ],
[ 'test.failures', stats['failure_count'], '<=', 0 ],
[ 'test.errors', stats['error_count' ], '<=', 0 ],
[ 'test.skips', stats['skip_count' ], '<=', 0 ],
[ nil ],
[ 'test.lines.total', test_cov['lines' ]['total' ], '<=', 936 ],
[ 'test.lines.total', test_cov['lines' ]['total' ], '<=', 954 ],
[ 'test.lines.missed', test_cov['lines' ]['missed'], '<=', 0 ],
[ 'test.branches.total', test_cov['branches']['total' ], '<=', 0 ],
[ 'test.branches.missed', test_cov['branches']['missed'], '<=', 0 ],
[ nil ],
[ 'code.lines.total', code_cov['lines' ]['total' ], '<=', 549 ],
[ 'code.lines.total', code_cov['lines' ]['total' ], '<=', 554 ],
[ 'code.lines.missed', code_cov['lines' ]['missed'], '<=', 0 ],
[ 'code.branches.total', code_cov['branches']['total' ], '<=', 66 ],
[ 'code.branches.total', code_cov['branches']['total' ], '<=', 68 ],
[ 'code.branches.missed', code_cov['branches']['missed'], '<=', 0 ],
]
end
Expand Down
31 changes: 31 additions & 0 deletions test/server/run_csharp_reqnroll_fsize_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require_relative '../test_base'

class RunCSharpReqnRollFSizeTest < TestBase

test 'Ea3d93', %w[
csharp_reqnroll image requires very large ulimit file-size
] do
stdout_tgz = TGZ.of({ 'stderr' => 'any' })
set_context(
logger: StdoutLoggerSpy.new,
piper: piper = PipeMakerStub.new(stdout_tgz),
process: process = ProcessSpawnerStub.new
)
image_name = "ghcr.io/cyber-dojo-languages/csharp_reqnroll:1234567"
puller.add(image_name)
command = nil
process.spawn { |cmd| command = cmd }
process.detach { ThreadValueStub.new(42) }
process.kill {}

run_cyber_dojo_sh({ :image_name => image_name })

name = 'fsize'
limit = 2048 * GB
assert command.include?("--ulimit #{name}=#{limit}"), command
end
end

KB = 1024
MB = 1024 * KB
GB = 1024 * MB
Loading