Skip to content

Commit

Permalink
Merge pull request #3 from drone/v1
Browse files Browse the repository at this point in the history
isolated test fixtures
  • Loading branch information
enver-bisevac authored Jul 11, 2022
2 parents 561740a + 6f22647 commit 1a199ba
Show file tree
Hide file tree
Showing 18 changed files with 1,625 additions and 323 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: CI workflow

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.18.1

- name: Test
run: go test -v ./...
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.DS_Store
cmd/eval-server/server
.idea/
100 changes: 100 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
GOLANGCI_LINT_VERSION=v1.37.1

ifndef GOPATH
GOPATH := $(shell go env GOPATH)
endif

# Default target will fetch deps, build and run tests.
all: tidy generate build check test

generate:
oapi-codegen -generate types -package=validator client-v1.yaml > types.gen.go

tidy:
go mod tidy

build:
go build ./...

check: format lint sec

clean:
go clean

# Format go code and error if any changes are made
PHONY+= format
format:
@echo "Checking that go fmt does not make any changes..."
@test -z $$(go fmt $(go list ./...)) || (echo "go fmt would make a change. Please verify and commit the proposed changes"; exit 1)
@echo "Checking go fmt complete"
@echo "Running goimports"
@test -z $$(goimports -w ./..) || (echo "goimports would make a change. Please verify and commit the proposed changes"; exit 1)

PHONY+= lint
lint: $(GOPATH)/bin/golangci-lint $(GOPATH)/bin/golint
@echo "Linting $(1)"
@golint -set_exit_status ./...
@go vet ./...
@golangci-lint run \
-E asciicheck \
-E bodyclose \
-E exhaustive \
-E exportloopref \
-E gofmt \
-E goimports \
-E gosec \
-E noctx \
-E nolintlint \
-E rowserrcheck \
-E exportloopref \
-E sqlclosecheck \
-E stylecheck \
-E unconvert \
-E unparam
@echo "Lint-free"

#
# Install Tools
#
PHONY+= sec
sec: $(GOPATH)/bin/gosec
@echo "Checking for security problems ..."
@gosec -quiet -confidence high -severity medium ./...
@echo "No problems found"; \

$(GOPATH)/bin/golangci-lint:
@echo "🔘 Installing golangci-lint... (`date '+%H:%M:%S'`)"
@curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin

$(GOPATH)/bin/golint:
@echo "🔘 Installing golint ... (`date '+%H:%M:%S'`)"
@GO111MODULE=off go get -u golang.org/x/lint/golint

$(GOPATH)/bin/goimports:
@echo "🔘 Installing goimports ... (`date '+%H:%M:%S'`)"
@GO111MODULE=off go get -u golang.org/x/tools/cmd/goimports

$(GOPATH)/bin/gosec:
@echo "🔘 Installing gosec ... (`date '+%H:%M:%S'`)"
@curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $(GOPATH)/bin


$(GOPATH)/bin/oapi-codegen:
@echo "🔘 Installing oapicodegen ... (`date '+%H:%M:%S'`)"
@go get github.com/deepmap/oapi-codegen/cmd/[email protected]

PHONY+= tools
tools: $(GOPATH)/bin/golangci-lint $(GOPATH)/bin/golint $(GOPATH)/bin/gosec $(GOPATH)/bin/goimports $(GOPATH)/bin/oapi-codegen

PHONY+= update-tools
update-tools: delete-tools $(GOPATH)/bin/golangci-lint $(GOPATH)/bin/golint $(GOPATH)/bin/gosec $(GOPATH)/bin/goimports

PHONY+= delete-tools
delete-tools:
@rm $(GOPATH)/bin/golangci-lint
@rm $(GOPATH)/bin/gosec
@rm $(GOPATH)/bin/golint
@rm $(GOPATH)/bin/goimports


.PHONY: all tidy generate build clean test lint
134 changes: 134 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,135 @@
# Server SDK - Evaluator test cases


## Example
Evaluator integration test in golang. This test model can be implemented in any programming language.
```go
package tests

import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"reflect"
"testing"

"github.com/harness/ff-golang-server-sdk/evaluation"

"github.com/harness/ff-golang-server-sdk/log"
"github.com/harness/ff-golang-server-sdk/pkg/repository"
"github.com/harness/ff-golang-server-sdk/rest"
)

const source = "./ff-test-cases/tests"

type test struct {
Flag string `json:"flag"`
Target *string `json:"target"`
Expected interface{} `json:"expected"`
}

type testFile struct {
Filename string
Flags []rest.FeatureConfig `json:"flags"`
Segments []rest.Segment `json:"segments"`
Targets []evaluation.Target `json:"targets"`
Tests []test `json:"tests"`
}

func loadFiles() []testFile {
files, err := ioutil.ReadDir(source)
if err != nil {
log.Error(err)
}

slice := make([]testFile, 0, len(files))
for _, file := range files {
if file.IsDir() || filepath.Ext(file.Name()) != ".json" {
continue
}
if f, err := loadFile(file.Name()); err == nil {
slice = append(slice, f)
}
}
return slice
}

func loadFile(filename string) (testFile, error) {
fp := filepath.Clean(filepath.Join(source, filename))
content, err := ioutil.ReadFile(fp)
if err != nil {
log.Error(err)
return testFile{}, err
}

result := testFile{
Filename: filename,
}
err = json.Unmarshal(content, &result)
if err != nil {
log.Error(err)
return testFile{}, err
}
return result, nil
}

func TestEvaluator(t *testing.T) {
t.Parallel()
fixtures := loadFiles()
for _, fixture := range fixtures {
lruCache, err := repository.NewLruCache(1000)
if err != nil {
t.Error(err)
}
repo := repository.New(lruCache)
evaluator, err := evaluation.NewEvaluator(repo, nil)
if err != nil {
t.Error(err)
}
for _, flag := range fixture.Flags {
repo.SetFlag(flag)
}
for _, segment := range fixture.Segments {
repo.SetSegment(segment)
}

for _, testCase := range fixture.Tests {
testName := fmt.Sprintf("test fixture %s with flag %s", fixture.Filename, testCase.Flag)
if testCase.Target != nil {
testName = fmt.Sprintf("%s and target %s", testName, *testCase.Target)
}
t.Run(testName, func(t *testing.T) {
var target *evaluation.Target
if testCase.Target != nil {
for i, val := range fixture.Targets {
if val.Identifier == *testCase.Target {
target = &fixture.Targets[i]
}
}
}
var got interface{}
flag, err := repo.GetFlag(testCase.Flag)
if err != nil {
t.Errorf("flag %s not found", testCase.Flag)
}
switch flag.Kind {
case "boolean":
got = evaluator.BoolVariation(testCase.Flag, target, false)
case "string":
got = evaluator.StringVariation(testCase.Flag, target, "blue")
case "int":
got = evaluator.IntVariation(testCase.Flag, target, 100)
case "number":
got = evaluator.NumberVariation(testCase.Flag, target, 50.00)
case "json":
got = evaluator.JSONVariation(testCase.Flag, target, map[string]interface{}{})
}
if !reflect.DeepEqual(got, testCase.Expected) {
t.Errorf("eval engine got = %v, want %v", got, testCase.Expected)
}
})
}
}
}
```
Loading

0 comments on commit 1a199ba

Please sign in to comment.