Skip to content

Commit

Permalink
Merge pull request #62 from CS3219-AY2425S1/solomon/code-execute
Browse files Browse the repository at this point in the history
Solomon/code execute
  • Loading branch information
solomonng2001 authored Nov 5, 2024
2 parents f77bbfa + 911ff0f commit 3396c29
Show file tree
Hide file tree
Showing 55 changed files with 5,061 additions and 4,573 deletions.
23 changes: 21 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ jobs:
env:
QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }}
run: |
cd ./apps/question-service
echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env
echo "JWT_SECRET=$JWT_SECRET" >> .env
echo "EXECUTION_SERVICE_URL=$EXECUTION_SERVICE_URL" >> .env
- name: Set up credentials
env:
Expand All @@ -52,7 +53,7 @@ jobs:
run: curl -sL firebase.tools | bash

- name: Run Go tests with Firebase emulator
run: firebase emulators:exec --only firestore 'cd ./apps/question-service; go test ./...'
run: firebase emulators:exec --only firestore 'cd ./apps/question-service; go test -v ./tests'

frontend-unit-tests:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -103,14 +104,17 @@ jobs:
MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }}
HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }}
SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }}
EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }}
HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }}
EXECUTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.EXECUTION_SERVICE_FIREBASE_CREDENTIAL_PATH }}
DB_CLOUD_URI: ${{ secrets.USER_SERVICE_DB_CLOUD_URI }}
USER_SERVICE_PORT: ${{ vars.USER_SERVICE_PORT }}
MATCHING_SERVICE_PORT: ${{ vars.MATCHING_SERVICE_PORT }}
HISTORY_SERVICE_PORT: ${{ vars.HISTORY_SERVICE_PORT }}
SIGNALLING_SERVICE_PORT: ${{ vars.SIGNALLING_SERVICE_PORT }}
EXECUTION_SERVICE_PORT: ${{ vars.EXECUTION_SERVICE_PORT }}
MATCHING_SERVICE_TIMEOUT: ${{ vars.MATCHING_SERVICE_TIMEOUT }}
REDIS_URL: ${{ vars.REDIS_URL }}
QUESTION_SERVICE_GRPC_URL: ${{ vars.QUESTION_SERVICE_GPRC_URL }}
Expand All @@ -121,10 +125,12 @@ jobs:
echo "NEXT_PUBLIC_MATCHING_SERVICE_URL=$MATCHING_SERVICE_URL" >> .env
echo "NEXT_PUBLIC_HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env
echo "NEXT_PUBLIC_SIGNALLING_SERVICE_URL=$SIGNALLING_SERVICE_URL" >> .env
echo "NEXT_PUBLIC_EXECUTION_SERVICE_URL=EXECUTION_SERVICE_URL" >> .env
cd ../question-service
echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env
echo "JWT_SECRET=$JWT_SECRET" >> .env
echo "EXECUTION_SERVICE_URL=$EXECUTION_SERVICE_URL" >> .env
cd ../user-service
echo "DB_CLOUD_URI=$DB_CLOUD_URI" >> .env
Expand All @@ -141,6 +147,11 @@ jobs:
cd ../history-service
echo "FIREBASE_CREDENTIAL_PATH=$HISTORY_FIREBASE_CREDENTIAL_PATH" >> .env
echo "PORT=$HISTORY_SERVICE_PORT" >> .env
cd ../execution-service
echo "FIREBASE_CREDENTIAL_PATH=$EXECUTION_FIREBASE_CREDENTIAL_PATH" >> .env
echo "PORT=$EXECUTION_SERVICE_PORT" >> .env
echo "HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env
cd ../signalling-service
echo "PORT=$SIGNALLING_SERVICE_PORT" >> .env
Expand All @@ -151,12 +162,17 @@ jobs:
QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }}
HISTORY_FIREBASE_JSON: ${{ secrets.HISTORY_SERVICE_FIREBASE_CREDENTIAL }}
HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }}
EXECUTION_FIREBASE_JSON: ${{ secrets.EXECUTION_SERVICE_FIREBASE_CREDENTIAL }}
EXECUTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.EXECUTION_SERVICE_FIREBASE_CREDENTIAL_PATH }}
run: |
cd ./apps/question-service
echo "$QUESTION_FIREBASE_JSON" > "./$QUESTION_FIREBASE_CREDENTIAL_PATH"
cd ../history-service
echo "$HISTORY_FIREBASE_JSON" > "./$HISTORY_FIREBASE_CREDENTIAL_PATH"
cd ../execution-service
echo "$EXECUTION_FIREBASE_JSON" > "./$EXECUTION_FIREBASE_CREDENTIAL_PATH"
- name: Build and Run Services
run: |
Expand All @@ -180,6 +196,7 @@ jobs:
MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }}
HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }}
SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }}
EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }}
run: |
echo "Testing Question Service..."
curl -sSL -o /dev/null $QUESTION_SERVICE_URL && echo "Question Service is up"
Expand All @@ -189,6 +206,8 @@ jobs:
curl -fsSL -o /dev/null $FRONTEND_URL && echo "Frontend is up"
echo "Testing History Service..."
curl -fsSL -o /dev/null $HISTORY_SERVICE_URL && echo "History Service is up"
echo "Testing Execution Service..."
curl -fsSL -o /dev/null $EXECUTION_SERVICE_URL && echo "Execution Service is up"
echo "Testing Matching Service..."
if ! (echo "Hello" | websocat $MATCHING_SERVICE_URL); then
echo "WebSocket for Matching Service is not live"
Expand Down
22 changes: 22 additions & 0 deletions apps/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,20 @@ services:
volumes:
- ./signalling-service:/signalling-service

execution-service:
build:
context: ./execution-service
dockerfile: Dockerfile
ports:
- 8083:8083
env_file:
- ./execution-service/.env
networks:
- apps_network
volumes:
- ./execution-service:/execution-service
- /var/run/docker.sock:/var/run/docker.sock

redis:
image: redis:latest
networks:
Expand All @@ -90,5 +104,13 @@ services:
- 6379:6379
container_name: redis-container

python-sandbox:
build:
context: ./execution-service/execution/python
dockerfile: Dockerfile
networks:
- apps_network
container_name: python-sandbox

networks:
apps_network:
9 changes: 9 additions & 0 deletions apps/execution-service/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.env.example

.git
.gitignore

.dockerignore
Dockerfile

README.md
8 changes: 8 additions & 0 deletions apps/execution-service/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FIREBASE_CREDENTIAL_PATH=cs3219-staging-codeexecution-firebase-adminsdk-ce48j-00ab09514c.json
PORT=8083

# If you are NOT USING docker, use the below variables
# HISTORY_SERVICE_URL=http://localhost:8082/

# If you are USING docker, use the below variables
HISTORY_SERVICE_URL=http://history-service:8082/
2 changes: 2 additions & 0 deletions apps/execution-service/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.env
cs3219-staging-codeexecution-firebase-adminsdk-ce48j-00ab09514c.json
22 changes: 22 additions & 0 deletions apps/execution-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM golang:1.23

WORKDIR /usr/src/app

# Install Docker CLI
RUN apt-get update && apt-get install -y \
docker.io \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change
COPY go.mod go.sum ./

RUN go mod tidy && go mod download && go mod verify

COPY . .

RUN go build -v -o /usr/local/bin/app ./main.go

EXPOSE 8083

CMD ["app"]
217 changes: 217 additions & 0 deletions apps/execution-service/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
# Execution Service

### Installation

1. Install dependencies:

```bash
go mod tidy
```

2. Create the `.env` file from copying the `.env.example`, and copy the firebase JSON file into execution-service/ fill in the `FIREBASE_CREDENTIAL_PATH` with the path of the firebase credential JSON file.

### Running the Application

To start the server, run the following command:

```bash
go run main.go
```

The server will be available at http://localhost:8083.

## Running the Application via Docker

To run the application via Docker, run the following command:

```bash
docker build -t execution-service .
```

```bash
docker run -p 8083:8083 --env-file .env -d execution-service
```

The server will be available at http://localhost:8083.

## API Endpoints

- `POST /tests/populate`
- `GET /tests/{questionDocRefId}/`
- `POST /tests/{questionDocRefId}/execute`
- `POST /tests/{questionDocRefId}/submit`

## Managing Firebase

To reset and repopulate the database, run the following command:

```bash
go run main.go
```

## Repopulate test cases

To repopulate test cases, you need to repopulate the questions in the question-service, which will automatically call the execution-service to populate the test cases.

In question-service, run the following command:

```bash
go run main.go -populate
```

## API Documentation

`GET /tests/{questionDocRefId}/`

To read visible test cases via a question ID, run the following command:

```bash
curl -X GET http://localhost:8083/tests/{questioinDocRefId}/ \
-H "Content-Type: application/json"
```

The following json format will be returned:

```json
[
{
"input":"hello",
"expected":"olleh"
}
]
```

`POST /tests/{questionDocRefId}/execute`

To execute test cases via a question ID without custom test cases, run the following command, with custom code and language:

```bash
curl -X POST http://localhost:8083/tests/{questioinDocRefId}/execute \
-H "Content-Type: application/json" \
-d '{
"code": "name = input()\nprint(name[::-1])",
"language": "Python"
}'
```

The following json format will be returned:

```json
{
"visibleTestResults":[
{
"input":"hello",
"expected":"olleh",
"actual":"olleh",
"passed":true,
"error":""
}
],
"customTestResults":null
}
```

To execute visible and custom test cases via a question ID with custom test cases, run the following command, with custom code, language and custom test cases:

```bash
curl -X POST http://localhost:8083/tests/{questioinDocRefId}/execute \
-H "Content-Type: application/json" \
-d '{
"code": "name = input()\nprint(name[::-1])",
"language": "Python",
"customTestCases": "2\nHannah\nhannaH\nabcdefg\ngfedcba\n"
}'
```

The following json format will be returned:

```json
{
"visibleTestResults":[
{
"input":"hello",
"expected":"olleh",
"actual":"olleh",
"passed":true,
"error":""
}
],
"customTestResults":[
{
"input":"Hannah",
"expected":"hannaH",
"actual":"hannaH",
"passed":true,
"error":""
},
{
"input":"abcdefg",
"expected":"gfedcba",
"actual":"gfedcba",
"passed":true,
"error":""
}
]
}
```

`POST /tests/{questionDocRefId}/submit`

To submit a solution and execute visible and hidden test cases via a question ID, run the following command, with custom code and language:

```bash
curl -X POST http://localhost:8083/tests/{questioinDocRefId}/submit \
-H "Content-Type: application/json" \
-d '{
"title": "Example Title",
"code": "name = input()\nprint(name[::-1])",
"language": "Python",
"user": "user123",
"matchedUser": "user456",
"matchedTopics": ["topic1", "topic2"],
"questionDifficulty": "Medium",
"questionTopics": ["Loops", "Strings"]
}'
```

The following json format will be returned:

```json
{
"visibleTestResults":[
{
"input":"hello",
"expected":"olleh",
"actual":"olleh",
"passed":true,
"error":""
}
],
"hiddenTestResults":{
"passed":2,
"total":2
},
"status":"Accepted"
}
```

If compilation error exists or any of the tests (visible and hidden) fails, status "Attempted" will be returned:

```json
{
"visibleTestResults":[
{
"input":"hello",
"expected":"olleh",
"actual":"",
"passed":false,
"error":"Command execution failed: Traceback (most recent call last):\n File \"/tmp/4149249165.py\", line 2, in \u003cmodule\u003e\n prit(name[::-1])\n ^^^^\nNameError: name 'prit' is not defined. Did you mean: 'print'?\n: %!w(*exec.ExitError=\u0026{0x4000364678 []})"
}
],
"hiddenTestResults":{
"passed":0,
"total":2
},
"status":"Attempted"
}
```
Loading

0 comments on commit 3396c29

Please sign in to comment.