Skip to content

Commit

Permalink
Merge pull request #2 from g0tiu5a/change_repo_layout
Browse files Browse the repository at this point in the history
Change repo layout
  • Loading branch information
ryosan-470 authored Aug 26, 2017
2 parents 6f34012 + 8303a69 commit 6c7cef0
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 69 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ jobs:
key: glide-cache-{{ checksum "glide.lock" }}
paths: vendor/

- run: go get -v -t -d ./...
- run: glide install
- run: go build
- run: go test -v $(go list ./... | grep -v /vendor/)
17 changes: 17 additions & 0 deletions _examples/events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

import (
"fmt"

"github.com/g0tiu5a/ctftime"
)

func main() {
url := ctftime.GetUrl("events", nil)
fmt.Printf("[==>] Requesting %s ...\n", url)
events := ctftime.GetAPIData("events", nil)
for idx, event := range events.([]ctftime.Event) {
fmt.Printf("[event%d]\n", idx)
fmt.Printf("%#v\n", event)
}
}
52 changes: 52 additions & 0 deletions api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package ctftime

import (
"log"
)

type apiClient interface {
GetUrl() string
GetAPIData() interface{}
}

type apiContext map[string]interface{}
type apiClientFactory func(ctx apiContext) apiClient

var apiClientFactories = make(map[string]apiClientFactory)

func registerAPIClient(name string, factory apiClientFactory) {
if factory == nil {
log.Panicf("API Client Factory %s does not exist.", name)
}

_, registered := apiClientFactories[name]
if registered {
log.Panicf("API Client Factory %s already registered. Ignoring.", name)
}

apiClientFactories[name] = factory
}

// この関数はパッケージがimportされた時に呼び出されます
func init() {
registerAPIClient("events", newEventsAPIClient)
}

func newAPIClient(name string, ctx apiContext) apiClient {
clientFactory, ok := apiClientFactories[name]
if !ok {
log.Panicf("Invalid API Client name!")
}

return clientFactory(ctx)
}

func GetUrl(name string, ctx apiContext) string {
client := newAPIClient(name, ctx)
return client.GetUrl()
}

func GetAPIData(name string, ctx map[string]interface{}) interface{} {
client := newAPIClient(name, ctx)
return client.GetAPIData()
}
61 changes: 61 additions & 0 deletions api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package ctftime

import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"testing"
)

func TestEventsAPIClient(t *testing.T) {
var client interface{} = newAPIClient("events", nil)

if valid, ok := client.(apiClient); ok {
valid.GetUrl()
valid.GetAPIData()
} else {
t.Errorf("Invalid Typeof API Client %#v!", client)
}
}

func TestGetUrl(t *testing.T) {
apiUrl := GetUrl("events", nil)

_, err := url.Parse(apiUrl)
if err != nil {
t.Errorf("Invalid URL %#v\n", apiUrl)
}
}

func TestGetAPIData(t *testing.T) {
data := GetAPIData("events", nil)

body, err := json.Marshal(data)
if err != nil {
t.Errorf("Invalid JSON Format %#v\n", body)
}

dummy_resp := &http.Response{
StatusCode: 200,
ProtoMajor: 1,
ProtoMinor: 0,
Body: ioutil.NopCloser(bytes.NewReader(body)),
}

var dummy_events []Event
httpResponseToStruct(dummy_resp, &dummy_events)
if len(dummy_events) != 3 {
t.Error("Invalid event length!")
}

for _, event := range dummy_events {
valid := reflect.TypeOf(Event{})
actual := reflect.TypeOf(event)
if actual != valid {
t.Errorf("Invalid event type of %v! (should be %v).", actual, valid)
}
}
}
6 changes: 4 additions & 2 deletions const.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package ctftime

const (
BUFSIZE = 1024
URL_PREFIX = "https://ctftime.org/api/v1" // API Endpoint
LIMIT = 3
BUFSIZE = 1024
API_ENDPOINT = "https://ctftime.org/api/v1"
test_dir = "./test_data/"
)
32 changes: 3 additions & 29 deletions event.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package ctftime

import (
"fmt"
"log"
"net/http"
"strconv"
"time"
)
import "time"

/* Struct */

type Event struct {
Organizers []Organizer `json:"organizers"`
Expand Down Expand Up @@ -41,25 +37,3 @@ type Duration struct {
Hours int `json:"hours"`
Days int `json:"days"`
}

const (
LIMIT = 3
)

func BuildUrl() string {
now := time.Now().Unix()
url := URL_PREFIX + "/events/?limit=" + fmt.Sprintf("%d", LIMIT) + "&start=" + strconv.FormatInt(now, 10)
return url
}

func GetAPIData() []Event {
var events []Event
url := BuildUrl()
response, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
HttpResponseToStruct(response, &events)

return events
}
33 changes: 0 additions & 33 deletions event_test.go

This file was deleted.

49 changes: 49 additions & 0 deletions events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ctftime

import (
"fmt"
"log"
"net/http"
"strconv"
"time"
)

type eventsAPIClient struct {
Ctx apiContext
}

func newEventsAPIClient(ctx apiContext) apiClient {
return &eventsAPIClient{
Ctx: ctx,
}
}

func (client *eventsAPIClient) GetUrl() string {
now := time.Now().Unix()

req, err := http.NewRequest("GET", API_ENDPOINT+"/events/", nil)
if err != nil {
log.Fatal(err)
}

q := req.URL.Query()
q.Add("limit", fmt.Sprintf("%d", LIMIT))
q.Add("start", strconv.FormatInt(now, 10))
req.URL.RawQuery = q.Encode()

return req.URL.String()
}

func (client *eventsAPIClient) GetAPIData() interface{} {
url := client.GetUrl()

resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()

var events []Event
httpResponseToStruct(resp, &events)
return events
}
43 changes: 43 additions & 0 deletions events_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package ctftime

import (
"bytes"
"encoding/json"
"io/ioutil"
"log"
"net/http"
"reflect"
"testing"
)

func TestGetEventsData(t *testing.T) {
client := newAPIClient("events", nil)

result := client.GetAPIData()

body, err := json.Marshal(result)
if err != nil {
log.Fatal(err)
}

dummy_resp := &http.Response{
StatusCode: 200,
ProtoMajor: 1,
ProtoMinor: 0,
Body: ioutil.NopCloser(bytes.NewReader(body)),
}

var dummy_events []Event
httpResponseToStruct(dummy_resp, &dummy_events)
if len(dummy_events) != 3 {
t.Error("Invalid event length!")
}

for _, event := range dummy_events {
valid := reflect.TypeOf(Event{})
actual := reflect.TypeOf(event)
if actual != valid {
t.Errorf("Invalid event type of %v! (should be %v).", actual, valid)
}
}
}
4 changes: 4 additions & 0 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 17 additions & 1 deletion util.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,25 @@ import (
"io/ioutil"
"log"
"net/http"
"path"
)

func HttpResponseToStruct(r *http.Response, v interface{}) {
/* Test */

func getTestData(fname string) []byte {
fpath := path.Join(test_dir, fname)

data, err := ioutil.ReadFile(fpath)
if err != nil {
log.Fatal(err)
}

return data
}

/* HTTP */

func httpResponseToStruct(r *http.Response, v interface{}) {
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
Expand Down
21 changes: 18 additions & 3 deletions util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,30 @@ import (
"io/ioutil"
"log"
"net/http"
"path"
"testing"
)

func TestDecodeJsonResponse(t *testing.T) {
buf, err := ioutil.ReadFile("./test_data/event_1.json")
const (
testFile = "event_1.json"
)

func TestGetTestData(t *testing.T) {
buf := getTestData(testFile)

data, err := ioutil.ReadFile(path.Join(test_dir, testFile))
if err != nil {
log.Fatal(err)
}

if string(buf) != string(data) {
t.Errorf("Data doesn't match %v != %v\n", buf, data)
}
}

func TestDecodeJsonResponse(t *testing.T) {
buf := getTestData("event_1.json")

// Create HTTP Response
// 200 OK HTTP/1.0
// <TEST_FILE json data>
Expand All @@ -27,5 +42,5 @@ func TestDecodeJsonResponse(t *testing.T) {
}

var events []interface{}
HttpResponseToStruct(response, &events)
httpResponseToStruct(response, &events)
}

0 comments on commit 6c7cef0

Please sign in to comment.