1
1
mirror of https://github.com/theoludwig/programming-challenges.git synced 2024-12-08 00:45:29 +01:00

fix(cli): add timeout for running solutions

This commit is contained in:
Divlo 2021-12-07 11:35:47 +01:00
parent 938702c23f
commit 0b59c19885
No known key found for this signature in database
GPG Key ID: 8F9478F220CE65E9
10 changed files with 638 additions and 284 deletions

45
.github/workflows/challenges.yml vendored Normal file
View File

@ -0,0 +1,45 @@
name: 'challenges'
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
test-solutions:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v2'
with:
fetch-depth: 0
- name: 'Use Docker'
uses: 'actions-hub/docker/cli@master'
env:
SKIP_LOGIN: true
- name: 'Use Node.js'
uses: 'actions/setup-node@v2.5.0'
with:
node-version: '16.x'
cache: 'npm'
- name: 'Install'
run: 'npm install'
- name: 'Build'
run: 'npm run build'
- name: 'Install programming-challenges'
run: 'npm install --global'
- uses: 'nrwl/last-successful-commit-action@v1'
id: 'last_successful_commit'
with:
branch: 'master'
workflow_id: 'ci.yml'
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: 'Test'
run: 'programming-challenges run test --affected --ci --base=${{ steps.last_successful_commit.outputs.commit_hash }}'

View File

@ -1,4 +1,4 @@
name: 'ci' name: 'cli'
on: on:
push: push:
@ -64,40 +64,3 @@ jobs:
- name: 'Test' - name: 'Test'
run: 'npm run test' run: 'npm run test'
challenges:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v2'
with:
fetch-depth: 0
- name: 'Use Docker'
uses: 'actions-hub/docker/cli@master'
env:
SKIP_LOGIN: true
- name: 'Use Node.js'
uses: 'actions/setup-node@v2.5.0'
with:
node-version: '16.x'
cache: 'npm'
- name: 'Install'
run: 'npm install'
- name: 'Build'
run: 'npm run build'
- name: 'Install programming-challenges'
run: 'npm install --global'
- uses: 'nrwl/last-successful-commit-action@v1'
id: 'last_successful_commit'
with:
branch: 'master'
workflow_id: 'ci.yml'
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: 'Test'
run: 'programming-challenges run test --affected --ci --base=${{ steps.last_successful_commit.outputs.commit_hash }}'

View File

@ -1,7 +0,0 @@
# sorting-algorithms/python/bubble-sort
Created by [@Divlo](https://github.com/Divlo) on 29 June 2021.
| Algorithm | Best Case | Average Case | Worst Case |
| ----------------------------------------------------------- | ----------- | ------------ | ----------- |
| [Bubble sort](https://wikipedia.org/wiki/Bubble_sort) | O(n) | O(n²) | O(n²) |

View File

@ -1,24 +0,0 @@
from typing import List
import sys
def bubble_sort(numbersInput: List[int]) -> List[int]:
numbers = list(numbersInput)
length = len(numbers)
for index_1 in range(length):
for index_2 in range(length - index_1 - 1):
if numbers[index_2] > numbers[index_2 + 1]:
temporary = numbers[index_2]
numbers[index_2] = numbers[index_2 + 1]
numbers[index_2 + 1] = temporary
return numbers
numbers: List[int] = []
for value in sys.stdin:
numbers.append(int(value.rstrip('\n')))
numbers = numbers[1:]
sorted_numbers = bubble_sort(numbers)
for number in sorted_numbers:
print(number)

View File

@ -1,7 +0,0 @@
# sorting-algorithms/python/insertion-sort
Created by [@Divlo](https://github.com/Divlo) on 29 June 2021.
| Algorithm | Best Case | Average Case | Worst Case |
| ----------------------------------------------------------- | ----------- | ------------ | ----------- |
| [Insertion sort](https://wikipedia.org/wiki/Insertion_sort) | O(n) | O(n²) | O(n²) |

View File

@ -1,24 +0,0 @@
from typing import List
import sys
def insertion_sort(numbersInput: List[int]) -> List[int]:
numbers = list(numbersInput)
for index_1 in range(1, len(numbers)):
current = numbers[index_1]
index_2 = index_1 - 1
while index_2 >= 0 and numbers[index_2] > current:
numbers[index_2 + 1] = numbers[index_2]
index_2 -= 1
numbers[index_2 + 1] = current
return numbers
numbers: List[int] = []
for value in sys.stdin:
numbers.append(int(value.rstrip('\n')))
numbers = numbers[1:]
sorted_numbers = insertion_sort(numbers)
for number in sorted_numbers:
print(number)

View File

@ -1,2 +1,3 @@
const ONE_MINUTE_IN_MILLISECONDS = 60 * 1000 import { Docker } from '../services/Docker'
jest.setTimeout(ONE_MINUTE_IN_MILLISECONDS)
jest.setTimeout(Docker.MAXIMUM_TIMEOUT_MILLISECONDS)

View File

@ -1,9 +1,12 @@
import execa from 'execa' import execa from 'execa'
import ora from 'ora' import ora from 'ora'
import ms from 'ms'
class Docker { export class Docker {
static CONTAINER_TAG = 'programming-challenges' static CONTAINER_TAG = 'programming-challenges'
static SIGSEGV_EXIT_CODE = 139 static SIGSEGV_EXIT_CODE = 139
static MAXIMUM_TIMEOUT = '1 minute'
static MAXIMUM_TIMEOUT_MILLISECONDS = ms(Docker.MAXIMUM_TIMEOUT)
public async build (): Promise<void> { public async build (): Promise<void> {
const loader = ora('Building the Docker image').start() const loader = ora('Building the Docker image').start()
@ -23,13 +26,22 @@ class Docker {
input input
} }
) )
let isValid = true
const timeout = setTimeout(() => {
subprocess.kill()
isValid = false
}, Docker.MAXIMUM_TIMEOUT_MILLISECONDS)
try { try {
const { stdout, stderr } = await subprocess const { stdout, stderr } = await subprocess
if (stderr.length !== 0) { if (stderr.length !== 0) {
throw new Error(stderr) throw new Error(stderr)
} }
clearTimeout(timeout)
return stdout return stdout
} catch (error: any) { } catch (error: any) {
if (!isValid) {
throw new Error(`Timeout: time limit exceeded (${Docker.MAXIMUM_TIMEOUT}), try to optimize your solution.`)
}
if (error.exitCode === Docker.SIGSEGV_EXIT_CODE) { if (error.exitCode === Docker.SIGSEGV_EXIT_CODE) {
throw new Error('Docker run failed: SIGSEGV indicates a segmentation fault (attempts to access a memory location that it\'s not allowed to access).') throw new Error('Docker run failed: SIGSEGV indicates a segmentation fault (attempts to access a memory location that it\'s not allowed to access).')
} }

747
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,7 @@
"execa": "5.1.1", "execa": "5.1.1",
"ora": "5.4.1", "ora": "5.4.1",
"replace-in-file": "6.3.2", "replace-in-file": "6.3.2",
"table": "6.7.3", "table": "6.7.5",
"typanion": "3.7.1", "typanion": "3.7.1",
"validate-npm-package-name": "3.0.0" "validate-npm-package-name": "3.0.0"
}, },
@ -52,15 +52,17 @@
"@types/date-and-time": "0.13.0", "@types/date-and-time": "0.13.0",
"@types/jest": "27.0.3", "@types/jest": "27.0.3",
"@types/mock-fs": "4.13.1", "@types/mock-fs": "4.13.1",
"@types/node": "16.11.11", "@types/ms": "0.7.31",
"@types/node": "16.11.12",
"@types/validate-npm-package-name": "3.0.3", "@types/validate-npm-package-name": "3.0.3",
"editorconfig-checker": "4.0.2", "editorconfig-checker": "4.0.2",
"get-stream": "6.0.1", "get-stream": "6.0.1",
"jest": "27.4.2", "jest": "27.4.3",
"markdownlint-cli": "0.30.0", "markdownlint-cli": "0.30.0",
"mock-fs": "5.1.2", "mock-fs": "5.1.2",
"ms": "2.1.3",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"ts-jest": "27.0.7", "ts-jest": "27.1.0",
"ts-standard": "11.0.0", "ts-standard": "11.0.0",
"typescript": "4.5.2" "typescript": "4.5.2"
} }