From f707ddcf23f3641fe31c15c7905116dd76a357df Mon Sep 17 00:00:00 2001 From: Jeffrey Duroyon Date: Fri, 20 Sep 2019 00:23:56 +0200 Subject: [PATCH] ci: add acceptance test --- .github/workflows/main.yml | 3 + Dockerfile | 27 +++++++ Makefile | 105 ++++++++++++++++++++++++++++ containers/docker-compose.yml | 8 +++ go.mod | 2 + go.sum | 2 + hamster_tycoon/{Cage.go => cage.go} | 1 - hamster_tycoon/{Game.go => game.go} | 4 +- hamster_tycoon/hamster.go | 105 +++++++++++++++------------- hamster_tycoon/hamster_test.go | 32 ++++----- main.go | 6 ++ 11 files changed, 225 insertions(+), 70 deletions(-) create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 containers/docker-compose.yml create mode 100644 go.sum rename hamster_tycoon/{Cage.go => cage.go} (98%) rename hamster_tycoon/{Game.go => game.go} (75%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 45e79af..f73a629 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,3 +22,6 @@ jobs: - name: Testing run: go test ./... + - name: Acceptance test + run: make + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..816a6a5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +FROM golang:1.12-alpine as builder + +# Remove the cache to avoid warning message during `apk info` +RUN rm -rf /var/cache/apk/* && \ + rm -rf /tmp/* + +RUN apk update + +# GO and PATH env variables already set in golang image +# to reduce download time +RUN apk --no-cache add -U make git musl-dev gcc + +COPY . . + +RUN GO111MODULE=on make local-build + +# final stage +FROM alpine:3.7 +RUN apk --no-cache add ca-certificates + + +WORKDIR /app +COPY --from=builder /go/bin/HamsterTycoon . +EXPOSE 8080 + +ENTRYPOINT ["/app/HamsterTycoon"] +CMD ["serve", "--logformat", "json", "--loglevel", "debug"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3b806be --- /dev/null +++ b/Makefile @@ -0,0 +1,105 @@ +# Set an output prefix, which is the local directory if not specified +PREFIX?=$(shell pwd) +.DEFAULT_GOAL := build + +# Version tag +VERSION := 1.0 + +# Setup name variables for the package/tool +NAME := hamster-tycoon +BIN_NAME := HamsterTycoon +PKG := github.com/kratisto/hamster-tycoon + +DOCKER_IMAGE_NAME := $(NAME) +# GO env vars +ifeq ($(GOPATH),) + GOPATH:=~/go +endif +GO=$(firstword $(subst :, ,$(GOPATH))) + +.PHONY: ensure-vendor +ensure-vendor: ## Get all vendor dependencies + @echo "+ $@" + dep ensure + +.PHONY: update-vendor +update-vendor: ## Get all vendor dependencies + @echo "+ $@" + dep ensure -update + +.PHONY: clean +clean: local-clean ## Clean your generated files + @echo "+ $@" + docker image rm poketools:$(VERSION) || true + +.PHONY: local-build +local-build: local-clean local-format ## Build locally the binary + @echo "+ $@" + GO111MODULE=on go build -o $(GO)/bin/$(BIN_NAME) . + +.PHONY: local-clean +local-clean: ## Cleanup locally any build binaries or packages + @echo "+ $@" + @$(RM) $(BIN_NAME) + +.PHONY: local-format +local-format: ## format locally all files + @echo "+ $@" + gofmt -s -l -w . + +.PHONY: build +build: sources-image ## Build the docker image with application binary + @echo "+ $@" + docker build --no-cache \ + -f containers/Dockerfile \ + --build-arg SOURCES_IMAGE=$(NAME)-sources:$(VERSION) \ + -t poketools:$(VERSION) . + +GIT_CREDENTIALS?=$(shell cat ~/.git-credentials 2> /dev/null) +.PHONY: sources-image +sources-image: ## Generate a Docker image with only the sources + @echo "+ $@" + docker build -t $(NAME)-sources:$(VERSION) -f containers/Dockerfile.sources . + + +.PHONY: local-run-dependencies +local-run-dependencies: ## Run the dependencies of the server (launch the containers/docker-compose.local.yml) + @echo "+ $@" + @docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.local.yml down || true; + @docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.local.yml pull; + @docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.local.yml up -d --build + +.PHONY: local-run-golang +local-run-golang: ## Build the server and run it + @echo "+ $@" + BUILD_GOLANG_CMD=local-build \ + LAUNCH_GOLANG_CMD="$(GO)/bin/$(BIN_NAME)" \ + $(MAKE) local-launch-golang + +.PHONY: local-launch-golang +local-launch-golang: ## Build the server and run it + @echo "+ $@" + PID=`ps -ax | egrep "\b$(BIN_NAME)"| cut -d " " -f 1`; \ + kill $$PID || true + $(MAKE) $(BUILD_GOLANG_CMD) + DB_PORT=`docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.local.yml port database 5432 | cut -f2 -d':'`; \ + $(LAUNCH_GOLANG_CMD) serve --loglevel debug --logformat text --postgreshost localhost:$$DB_PORT + +.PHONY: local-run +local-run: local-run-dependencies local-run-golang ## Run the server with its dependencies + +.PHONY: local-run-app +local-run-app: ## Run the app of the server (launch the containers/docker-compose.yml) + @echo "+ $@" + @docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.yml down || true; + @docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.yml pull; + @docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.yml up -d --build + +.PHONY: bdd-test +bdd-test: local-run-app + go get github.com/DATA-DOG/godog/cmd/godog + DB_PORT=`docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.yml port database 5432 | cut -f2 -d':'`; + API_PORT=`docker-compose -p $(DOCKER_IMAGE_NAME)-uuid -f containers/docker-compose.yml port api 8080 | cut -f2 -d':'`; + $GOPATH/bin/godog + + diff --git a/containers/docker-compose.yml b/containers/docker-compose.yml new file mode 100644 index 0000000..9c36fa1 --- /dev/null +++ b/containers/docker-compose.yml @@ -0,0 +1,8 @@ +version: "2.1" + +services: + api: + build: ../. + ports: + - 8080 + diff --git a/go.mod b/go.mod index 846d1bf..b58e472 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module hamster-tycoon go 1.13 + +require github.com/DATA-DOG/godog v0.7.13 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a398a5a --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/DATA-DOG/godog v0.7.13 h1:JmgpKcra7Vf3yzI9vPsWyoQRx13tyKziHtXWDCUUgok= +github.com/DATA-DOG/godog v0.7.13/go.mod h1:z2OZ6a3X0/YAKVqLfVzYBwFt3j6uSt3Xrqa7XTtcQE0= diff --git a/hamster_tycoon/Cage.go b/hamster_tycoon/cage.go similarity index 98% rename from hamster_tycoon/Cage.go rename to hamster_tycoon/cage.go index 8fdff3a..6b66310 100644 --- a/hamster_tycoon/Cage.go +++ b/hamster_tycoon/cage.go @@ -1,6 +1,5 @@ package hamster_tycoon - type Cage struct { Hamsters []*Hamster } diff --git a/hamster_tycoon/Game.go b/hamster_tycoon/game.go similarity index 75% rename from hamster_tycoon/Game.go rename to hamster_tycoon/game.go index 15b9d92..d7c5f99 100644 --- a/hamster_tycoon/Game.go +++ b/hamster_tycoon/game.go @@ -1,8 +1,6 @@ package hamster_tycoon - type Game struct { - Cages []*Cage + Cages []*Cage SelledHamster []*Hamster - } diff --git a/hamster_tycoon/hamster.go b/hamster_tycoon/hamster.go index 7992524..e907494 100644 --- a/hamster_tycoon/hamster.go +++ b/hamster_tycoon/hamster.go @@ -15,44 +15,43 @@ const ( ) const ( - TotalGestationPeriod = 15 - MinChild = 5 - MaxCild = 9 - GestationCooldown = (3*7) + 2 - GestationMinAge = 10*6 - MaxAge = 365*2 - GestationLuck = 70 - FEMALE = "F" - MALE = "M" - + TotalGestationPeriod = 15 + MinChild = 5 + MaxCild = 9 + GestationCooldown = (3 * 7) + 2 + GestationMinAge = 10 * 6 + MaxAge = 365 * 2 + GestationLuck = 70 + FEMALE = "F" + MALE = "M" ) var GlobalHamsterNumber = 1 type Hamster struct { - Name string - Number int - Sexe string - Age int - Father *Hamster - Mother *Hamster - HungerLevel int8 - ThirstLevel int8 - Weight float64 - Height float64 - Alive bool - Selled bool - Gestation bool - GestationPeriod int8 + Name string + Number int + Sexe string + Age int + Father *Hamster + Mother *Hamster + HungerLevel int8 + ThirstLevel int8 + Weight float64 + Height float64 + Alive bool + Selled bool + Gestation bool + GestationPeriod int8 GestationCooldown int8 - Child []*Hamster + Child []*Hamster } -func(h *Hamster) Die(){ +func (h *Hamster) Die() { h.Alive = false } -func (h *Hamster) Fuck(another *Hamster) (bool,error){ +func (h *Hamster) Fuck(another *Hamster) (bool, error) { if h.Sexe == another.Sexe { return false, errors.New("can't fuck together") } @@ -61,10 +60,16 @@ func (h *Hamster) Fuck(another *Hamster) (bool,error){ return false, errors.New("one of the hamster is too young") } - rand := randNumber(1,100) + rand := randNumber(1, 100) if rand <= GestationLuck { - female := func() *Hamster{if h.Sexe == FEMALE {return h } else {return another}}() + female := func() *Hamster { + if h.Sexe == FEMALE { + return h + } else { + return another + } + }() female.Gestation = true female.GestationPeriod = 0 female.GestationCooldown = TotalGestationPeriod + GestationCooldown @@ -72,7 +77,7 @@ func (h *Hamster) Fuck(another *Hamster) (bool,error){ return rand <= GestationLuck, nil } -func Born(father *Hamster, mother *Hamster)([]*Hamster,error){ +func Born(father *Hamster, mother *Hamster) ([]*Hamster, error) { if !mother.Alive || mother.Selled { return nil, errors.New("the mother is not here") } @@ -85,43 +90,43 @@ func Born(father *Hamster, mother *Hamster)([]*Hamster,error){ mother.GestationPeriod = 0 numberOfChild := randNumberChild() - child := make([]*Hamster,numberOfChild) - for i := 1; i <= numberOfChild; i++{ + child := make([]*Hamster, numberOfChild) + for i := 1; i <= numberOfChild; i++ { child[i] = &Hamster{ - Name: fmt.Sprintf("Hamster %d",GlobalHamsterNumber), - Number: GlobalHamsterNumber, - Age : 1, - Sexe: randSexe(), - Father: father, - Mother: mother, - HungerLevel: Full, - ThirstLevel: Full, - Alive: true, - Selled: false, - Gestation: false, - GestationPeriod: 0, + Name: fmt.Sprintf("Hamster %d", GlobalHamsterNumber), + Number: GlobalHamsterNumber, + Age: 1, + Sexe: randSexe(), + Father: father, + Mother: mother, + HungerLevel: Full, + ThirstLevel: Full, + Alive: true, + Selled: false, + Gestation: false, + GestationPeriod: 0, GestationCooldown: 30, } } mother.Child = append(mother.Child, child...) father.Child = append(father.Child, child...) - return child,nil + return child, nil } func randNumberChild() int { - return randNumber(MinChild,MaxCild) + return randNumber(MinChild, MaxCild) } func randSexe() string { - return func () string{ - if randNumber(1,2) == 2 { + return func() string { + if randNumber(1, 2) == 2 { return MALE } else { - return FEMALE + return FEMALE } }() } -func randNumber(min int ,max int) int { +func randNumber(min int, max int) int { return min + rand.Intn(max-min) } diff --git a/hamster_tycoon/hamster_test.go b/hamster_tycoon/hamster_test.go index bd0e9fe..5a57876 100644 --- a/hamster_tycoon/hamster_test.go +++ b/hamster_tycoon/hamster_test.go @@ -7,8 +7,8 @@ import ( func TestDie(t *testing.T) { testCases := []struct { - caseName string - hamster *Hamster + caseName string + hamster *Hamster expectedAlive bool }{ { @@ -39,41 +39,41 @@ func TestDie(t *testing.T) { func TestFuck(t *testing.T) { testCases := []struct { - caseName string - hamster1 *Hamster - hamster2 *Hamster + caseName string + hamster1 *Hamster + hamster2 *Hamster expectedResult bool - expectedError error + expectedError error }{ { caseName: "Hamster 1 too young", hamster1: &Hamster{ Alive: true, - Sexe: MALE, - Age: GestationMinAge - 1, + Sexe: MALE, + Age: GestationMinAge - 1, }, hamster2: &Hamster{ Alive: true, - Sexe: FEMALE, - Age: GestationMinAge + 1, + Sexe: FEMALE, + Age: GestationMinAge + 1, }, expectedResult: false, - expectedError: errors.New("one of the hamster is too young"), + expectedError: errors.New("one of the hamster is too young"), }, { caseName: "Hamster 2 too young", hamster1: &Hamster{ Alive: false, - Sexe: MALE, - Age: GestationMinAge + 1, + Sexe: MALE, + Age: GestationMinAge + 1, }, hamster2: &Hamster{ Alive: true, - Sexe: FEMALE, - Age: GestationMinAge - 1, + Sexe: FEMALE, + Age: GestationMinAge - 1, }, expectedResult: false, - expectedError: errors.New("one of the hamster is too young"), + expectedError: errors.New("one of the hamster is too young"), }, } diff --git a/main.go b/main.go index 892f89d..823ddf7 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,5 @@ package main + import ( "fmt" "math/rand" @@ -9,4 +10,9 @@ func main() { rand.Seed(time.Now().UTC().UnixNano()) fmt.Print("hello") + + for { + fmt.Println("Infinite Loop 1") + time.Sleep(time.Second) + } }