Skip to content

Commit b737d0f

Browse files
author
Mathis Van Eetvelde
authored
Merge pull request #4 from Coding-Web-Community/mathis/development/api
Added test code + fetch route
2 parents 1e1261c + 94aa9d9 commit b737d0f

File tree

5 files changed

+314
-9
lines changed

5 files changed

+314
-9
lines changed

api/README.md

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ go run .
1717
This is where we describe the API endpoints and how they react to certain data.
1818

1919

20-
## bump
20+
# bump
2121

2222
**URL** Structure:
2323
```
@@ -31,7 +31,7 @@ Method: **POST**
3131
{"guildId": 636145886279237652}
3232
```
3333

34-
# **Responses**:
34+
## **Responses**:
3535

3636

3737
### **200**
@@ -112,3 +112,40 @@ allowed characters: 0-9
112112

113113
*Additional note*:
114114
The **payload** is always a direct and latest representation of the stored guild in the database. That means when getting a `200` or `425` status code, the `timestamp` attribute represents the time that guild was last bumped in a UNIX timestamp.
115+
116+
# fetch
117+
118+
**URL** Structure:
119+
```
120+
http://localhost:8080/V1/fetch
121+
```
122+
123+
Method: **GET**
124+
125+
## **Responses**:
126+
127+
128+
### **200**
129+
- *200 - Ok* | **guildId** successfully bumped!
130+
```json
131+
{
132+
"code":200,
133+
"message":"Ok",
134+
"paypload":[
135+
{"guildId":636145886279237699,"timestamp":1602394289},
136+
{"guildId":636123886245557612,"timestamp":1602394230}
137+
]
138+
}
139+
```
140+
141+
### **400**
142+
- *400 - BadRequest*
143+
```json
144+
{
145+
"code":400,
146+
"message":"BadRequest",
147+
"paypload":[
148+
{}
149+
]
150+
}
151+
```

api/src/bump_test.go

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"crypto/md5"
6+
"encoding/json"
7+
"fmt"
8+
"io/ioutil"
9+
"net/http"
10+
"os"
11+
"testing"
12+
"time"
13+
)
14+
15+
func startServer() {
16+
path := "store.json"
17+
err := os.Remove(path)
18+
if err != nil {
19+
fmt.Println(err)
20+
}
21+
22+
go HandleRequests()
23+
}
24+
25+
var (
26+
bumpRoute = fmt.Sprintf("http://%v%v/V1/bump",URL ,PORT)
27+
fetchRoute = fmt.Sprintf("http://%v%v/V1/fetch",URL ,PORT)
28+
)
29+
30+
func sendInt(guildId int) (br BumpResponse) {
31+
reqBody, _ := json.Marshal(map[string]int{
32+
"guildId": guildId,
33+
})
34+
35+
resp, _ := http.Post(bumpRoute, "application/json", bytes.NewBuffer(reqBody))
36+
37+
defer resp.Body.Close()
38+
body, _ := ioutil.ReadAll(resp.Body)
39+
40+
_ = json.Unmarshal(body, &br)
41+
42+
return br
43+
}
44+
45+
func sendString(guildId string) (br BumpResponse) {
46+
reqBody, _ := json.Marshal(map[string]string{
47+
"guildId": guildId,
48+
})
49+
50+
resp, _ := http.Post(bumpRoute, "application/json", bytes.NewBuffer(reqBody))
51+
52+
defer resp.Body.Close()
53+
body, _ := ioutil.ReadAll(resp.Body)
54+
55+
_ = json.Unmarshal(body, &br)
56+
57+
return br
58+
}
59+
60+
func Hash(guilds []Guild) [16]byte {
61+
guildBytes := []byte{}
62+
for _, item := range guilds {
63+
jsonBytes, _ := json.Marshal(item)
64+
guildBytes = append(guildBytes, jsonBytes...)
65+
}
66+
return md5.Sum(guildBytes)
67+
}
68+
69+
func TestServerStart(t *testing.T) {
70+
go startServer()
71+
72+
TempTestInterval = 1
73+
Logging = false
74+
75+
time.Sleep(time.Millisecond * 200)
76+
}
77+
78+
func TestBumpNormal(t *testing.T) {
79+
var guildId int = 636145886279237611
80+
81+
var expected = BumpResponse{
82+
Code: 200, // OK
83+
Payload: Guild{
84+
GuildId: guildId,
85+
},
86+
}
87+
88+
// Normal send, returns 200
89+
resp := sendInt(guildId)
90+
91+
if resp.Code != expected.Code {
92+
t.Errorf("Status codes were not equal: %v != %v", resp.Code, expected.Code)
93+
}
94+
if resp.Payload.GuildId != expected.Payload.GuildId {
95+
t.Errorf("GuilId's were not equal: %v != %v", resp.Payload.GuildId, expected.Payload.GuildId)
96+
}
97+
98+
}
99+
100+
func TestBumpEarly(t *testing.T) {
101+
var guildId int = 636145886279237699
102+
103+
_ = sendInt(guildId) // send first bump request
104+
105+
var expected = BumpResponse{
106+
Code: 425, // Too Early
107+
Payload: Guild{
108+
GuildId: guildId,
109+
},
110+
}
111+
112+
resp := sendInt(guildId) // send second (early) bump request
113+
114+
if resp.Code != expected.Code {
115+
t.Errorf("Status codes were not equal: %v != %v", resp.Code, expected.Code)
116+
}
117+
118+
time.Sleep(time.Second * 2)
119+
120+
expected = BumpResponse{
121+
Code: 200, // OK
122+
Payload: Guild{
123+
GuildId: guildId,
124+
},
125+
}
126+
127+
resp = sendInt(guildId) // send third (late) bump request!
128+
129+
if resp.Code != expected.Code {
130+
t.Errorf("Status codes were not equal: %v != %v", resp.Code, expected.Code)
131+
}
132+
if resp.Payload.GuildId != expected.Payload.GuildId {
133+
t.Errorf("GuilId's were not equal: %v != %v", resp.Payload.GuildId, expected.Payload.GuildId)
134+
}
135+
136+
}
137+
138+
func TestBumpString(t *testing.T) {
139+
var expected = BumpResponse{
140+
Code: 400, // Bad Request
141+
Message: "Unable to process request body",
142+
Payload: Guild{
143+
GuildId: 0,
144+
},
145+
}
146+
147+
resp := sendString("636145886279237652")
148+
149+
if resp.Code != expected.Code {
150+
t.Errorf("Status codes were not equal: %v != %v", resp.Code, expected.Code)
151+
}
152+
if resp.Payload.GuildId != expected.Payload.GuildId {
153+
t.Errorf("GuilId's were not equal: %v != %v", resp.Payload.GuildId, expected.Payload.GuildId)
154+
}
155+
if resp.Message != expected.Message {
156+
t.Errorf("Messages were not equal: %v != %v", resp.Message, expected.Message)
157+
}
158+
}
159+
160+
func TestBumpTooFewChars(t *testing.T) {
161+
var guildId int = 636145
162+
var expected = BumpResponse{
163+
Code: 400, // Bad Request
164+
Message: "GuildId does not conform to 18 character long integer requirement",
165+
Payload: Guild{
166+
GuildId: guildId,
167+
},
168+
}
169+
170+
resp := sendInt(guildId)
171+
172+
if resp.Code != expected.Code {
173+
t.Errorf("Status codes were not equal: %v != %v", resp.Code, expected.Code)
174+
}
175+
if resp.Payload.GuildId != expected.Payload.GuildId {
176+
t.Errorf("GuilId's were not equal: %v != %v", resp.Payload.GuildId, expected.Payload.GuildId)
177+
}
178+
if resp.Message != expected.Message {
179+
t.Errorf("Messages were not equal: %v != %v", resp.Message, expected.Message)
180+
}
181+
}
182+
183+
func TestFetch(t *testing.T) {
184+
var fr FetchResponse
185+
guilds, _ := LoadStore()
186+
187+
resp, _ := http.Get(fetchRoute)
188+
189+
defer resp.Body.Close()
190+
body, _ := ioutil.ReadAll(resp.Body)
191+
192+
_ = json.Unmarshal(body, &fr)
193+
194+
if len(fr.Payload) != len(guilds) {
195+
t.Errorf("Length of stored guilds not equal to length of /V1/fetch result: %v != %v", len(fr.Payload), len(guilds))
196+
}
197+
198+
if Hash(fr.Payload) != Hash(guilds) {
199+
t.Errorf("Guilds hash from GuildStore are not equal to /V1/fetch hash: %v != %v", Hash(fr.Payload), Hash(guilds))
200+
}
201+
202+
}

api/src/fetch.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package main
2+
3+
import (
4+
"net/http"
5+
)
6+
7+
func FetchGuilds(w http.
8+
ResponseWriter, r *http.Request) {
9+
guilds := gs.GetGuilds()
10+
11+
if len(guilds) > 0 {
12+
WriteFetchResponse(w, 200, "Ok", guilds)
13+
return
14+
}
15+
16+
WriteFetchResponse(w, 400, "BadRequest", guilds)
17+
}

api/src/main.go

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,17 @@ import (
1111
)
1212

1313
const (
14+
URL = "localhost"
1415
PORT = ":8080"
1516
BUMP_INTERVAL = 60 // 1 minute in seconds
1617
STORE_FILE_NAME = "store.json"
1718
)
1819

19-
var gs GuildStore
20+
var (
21+
TempTestInterval = 0 // used to set lower interval during testing
22+
Logging = true // used to disable logging during testing
23+
gs GuildStore
24+
)
2025

2126
type Guild struct {
2227
GuildId int `json:"guildId"`
@@ -34,6 +39,12 @@ type BumpResponse struct {
3439
Payload Guild `json:"payload"`
3540
}
3641

42+
type FetchResponse struct {
43+
Code int `json:"code"`
44+
Message string `json:"message"`
45+
Payload []Guild `json:"paypload"`
46+
}
47+
3748
func init() {
3849
var err error
3950
gs.Guilds, err = LoadStore()
@@ -47,33 +58,51 @@ func init() {
4758

4859
func middleware(f http.HandlerFunc) http.HandlerFunc {
4960
return func(w http.ResponseWriter, r *http.Request) {
50-
log.Print(fmt.Sprintf("%s%s - %s", r.Host, r.URL.Path, r.Method))
61+
if Logging {
62+
log.Print(fmt.Sprintf("%s%s - %s", r.Host, r.URL.Path, r.Method))
63+
}
5164
f(w, r)
5265
}
5366
}
5467

5568
func HandleRequests() {
5669
router := mux.NewRouter().StrictSlash(true)
5770
router.HandleFunc("/V1/bump", middleware(BumpGuild)).Methods("POST")
58-
log.Print(fmt.Sprintf("Now serving: localhost%s", PORT))
71+
router.HandleFunc("/V1/fetch", middleware(FetchGuilds)).Methods("GET")
72+
73+
log.Print(fmt.Sprintf("Now serving: %s%s",URL ,PORT))
5974
err := http.ListenAndServe(PORT, router)
6075
if err != nil {
6176
log.Print(err)
6277
}
6378
}
6479

6580
// makes BumpResponse object and writes it to ResponseWriter
66-
func WriteBumpResponse(w http.ResponseWriter, code int, message string, guild Guild) {
81+
func WriteBumpResponse(w http.ResponseWriter, code int, message string, payload Guild) {
6782
br := BumpResponse{
6883
Code: code,
6984
Message: message,
70-
Payload: guild,
85+
Payload: payload,
7186
}
7287

7388
payloadByte, _ := json.Marshal(br)
7489

90+
w.WriteHeader(code)
91+
w.Header().Set("Content-Type", "application/json")
92+
w.Write(payloadByte)
93+
}
94+
95+
func WriteFetchResponse(w http.ResponseWriter, code int, message string, payload []Guild) {
96+
fr := FetchResponse{
97+
Code: code,
98+
Message: message,
99+
Payload: payload,
100+
}
101+
102+
payloadByte, _ := json.Marshal(fr)
103+
104+
w.WriteHeader(code)
75105
w.Header().Set("Content-Type", "application/json")
76-
w.WriteHeader(http.StatusBadRequest)
77106
w.Write(payloadByte)
78107
}
79108

0 commit comments

Comments
 (0)