Skip to content

Commit 87a1e04

Browse files
d
1 parent 66a8a15 commit 87a1e04

File tree

16 files changed

+189
-40
lines changed

16 files changed

+189
-40
lines changed

backend/.vscode/settings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"go.testTimeout": "60s",
3+
"cSpell.words": [
4+
"cout",
5+
"endl"
6+
]
7+
}

backend/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ COPY . .
1313
WORKDIR /code-grader/backend
1414
RUN go build
1515

16+
VOLUME [ "/var/run/docker.sock" ]
1617
EXPOSE 8080
1718
ENV GIN_MODE=release
1819
ENV APP_ROOT=/code-grader

backend/internal/api/setup_router.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import (
44
"net/http"
55

66
"github.com/gin-gonic/gin"
7+
"github.com/markhuang1212/code-grader/backend/internal/core"
8+
"github.com/markhuang1212/code-grader/backend/internal/types"
9+
"github.com/markhuang1212/code-grader/backend/internal/util"
710
)
811

9-
func SetupRouter() *gin.Engine {
12+
func SetupRouter(cc *core.CoreController) *gin.Engine {
1013

1114
r := gin.Default()
1215

@@ -18,6 +21,20 @@ func SetupRouter() *gin.Engine {
1821

1922
authorized.POST("/grade", func(c *gin.Context) {
2023

24+
gr := types.GradeRequest{}
25+
26+
err := c.BindJSON(&gr)
27+
if err != nil {
28+
return
29+
}
30+
31+
gr.Id = util.RandomHex(10)
32+
33+
cc.GradeQueue <- gr
34+
35+
c.Header("Location", "/api/result/"+gr.Id)
36+
c.Status(202)
37+
2138
})
2239

2340
return r

backend/internal/api/setup_router_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ import (
66
"testing"
77

88
"github.com/markhuang1212/code-grader/backend/internal/api"
9+
"github.com/markhuang1212/code-grader/backend/internal/core"
910
"github.com/stretchr/testify/assert"
1011
)
1112

1213
func TestPingRoute(t *testing.T) {
13-
router := api.SetupRouter()
14+
router := api.SetupRouter(core.NewCoreController(1))
1415

1516
w := httptest.NewRecorder()
1617
req, _ := http.NewRequest("GET", "/ping", nil)

backend/internal/core/cache.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package core
2+
3+
import (
4+
"sync"
5+
6+
"github.com/markhuang1212/code-grader/backend/internal/types"
7+
)
8+
9+
type GradeResultCache struct {
10+
Data map[string]types.GradeResult
11+
Lock sync.RWMutex
12+
}
13+
14+
func NewGradeResultCache() *GradeResultCache {
15+
ret := GradeResultCache{
16+
Data: make(map[string]types.GradeResult),
17+
}
18+
19+
return &ret
20+
}
21+
22+
func (c *GradeResultCache) Add(key string, val types.GradeResult) {
23+
c.Lock.Lock()
24+
defer c.Lock.Unlock()
25+
c.Data[key] = val
26+
}
27+
28+
func (c *GradeResultCache) Del(key string) {
29+
c.Lock.Lock()
30+
defer c.Lock.Unlock()
31+
delete(c.Data, key)
32+
}
33+
34+
func (c *GradeResultCache) Get(key string) (types.GradeResult, bool) {
35+
c.Lock.RLock()
36+
defer c.Lock.RUnlock()
37+
val, ok := c.Data[key]
38+
return val, ok
39+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package core_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/markhuang1212/code-grader/backend/internal/core"
7+
"github.com/markhuang1212/code-grader/backend/internal/types"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestCache(t *testing.T) {
12+
c := core.NewGradeResultCache()
13+
c.Add("id1", types.GradeResult{
14+
Status: types.GradeResultCompilationError,
15+
Msg: "Hello",
16+
})
17+
ret, ok := c.Get("id1")
18+
assert.True(t, ok)
19+
assert.Equal(t, "Hello", ret.Msg)
20+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package core
2+
3+
import (
4+
"context"
5+
6+
"github.com/markhuang1212/code-grader/backend/internal/grader"
7+
"github.com/markhuang1212/code-grader/backend/internal/types"
8+
)
9+
10+
type CoreController struct {
11+
Cache *GradeResultCache
12+
GradeQueue chan types.GradeRequest
13+
}
14+
15+
func (cc *CoreController) handleRequest() {
16+
for {
17+
request, ok := <-cc.GradeQueue
18+
19+
if !ok {
20+
break
21+
}
22+
23+
ctx := context.Background()
24+
result, err := grader.GradeUserCode(ctx, request)
25+
26+
if err != nil {
27+
cc.Cache.Add(request.Id, types.GradeResult{
28+
Status: types.GradeResultInternalError,
29+
Msg: "internal error",
30+
})
31+
} else {
32+
cc.Cache.Add(request.Id, *result)
33+
}
34+
}
35+
}
36+
37+
func NewCoreController(concurrent int) *CoreController {
38+
39+
ret := CoreController{
40+
Cache: NewGradeResultCache(),
41+
GradeQueue: make(chan types.GradeRequest, 1024),
42+
}
43+
44+
for i := 0; i < concurrent; i++ {
45+
go ret.handleRequest()
46+
}
47+
48+
return &ret
49+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package core_test
2+
3+
import (
4+
"runtime"
5+
"testing"
6+
7+
"github.com/markhuang1212/code-grader/backend/internal/core"
8+
"github.com/markhuang1212/code-grader/backend/internal/types"
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestCoreController(t *testing.T) {
13+
14+
cc := core.NewCoreController(1)
15+
16+
cc.GradeQueue <- types.GradeRequest{
17+
Id: "test1",
18+
TestCaseName: "example-1",
19+
UserCode: "int main() { cout << \"Hello\" << endl; }",
20+
}
21+
22+
for {
23+
val, ok := cc.Cache.Get("test1")
24+
if ok == true {
25+
assert.Equal(t, types.GradeResultSuccess, val.Status)
26+
return
27+
}
28+
runtime.Gosched()
29+
}
30+
}

backend/internal/grader/exec_user_code_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/stretchr/testify/assert"
1212
)
1313

14+
// success
1415
func TestExecUserCode1(t *testing.T) {
1516

1617
ctx := context.Background()
@@ -37,6 +38,7 @@ func TestExecUserCode1(t *testing.T) {
3738

3839
}
3940

41+
// execution error
4042
func TestExecUserCode2(t *testing.T) {
4143

4244
ctx := context.Background()
@@ -64,6 +66,7 @@ func TestExecUserCode2(t *testing.T) {
6466

6567
}
6668

69+
// memory limit exceed
6770
func TestExecUserCode3(t *testing.T) {
6871

6972
ctx := context.Background()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package types
22

33
type GradeRequest struct {
4+
Id string
45
TestCaseName string
56
UserCode string
67
}

0 commit comments

Comments
 (0)