Skip to content

Commit

Permalink
feat: in-memory provider for sdk testing (#192)
Browse files Browse the repository at this point in the history
Signed-off-by: Kavindu Dodanduwa <kavindudodanduwa@gmail.com>
  • Loading branch information
Kavindu-Dodan authored Jul 28, 2023
1 parent 2bc3c38 commit 366674f
Show file tree
Hide file tree
Showing 12 changed files with 1,372 additions and 76 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ jobs:
uses: actions/checkout@v3
with:
submodules: recursive
- name: Run flagd-testbed
run: docker run -d -p 8013:8013 -v ${{ github.workspace }}/test-harness/testing-flags.json:/testing-flags.json ghcr.io/open-feature/flagd-testbed:v0.2.2
- name: Setup Environment
run: |
echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
Expand Down
27 changes: 13 additions & 14 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,37 +34,36 @@ Run unit tests with `make test`.

#### End-to-End tests

The continuous integration runs a set of [gherkin e2e tests](https://github.com/open-feature/test-harness/blob/main/features) using the [flagd provider](https://github.com/open-feature/go-sdk-contrib/tree/main/providers/flagd), [flagd](https://github.com/open-feature/flagd) and [the flagd test module](https://github.com/open-feature/go-sdk-contrib/tree/main/tests/flagd).
The continuous integration runs a set of [gherkin e2e tests](https://github.com/open-feature/test-harness/blob/main/features).

If you'd like to run them locally, first pull the `test-harness` git submodule

```
git submodule update --init --recursive
```
then start the flagd testbed with
```
docker run -p 8013:8013 -v $PWD/test-harness/testing-flags.json:/testing-flags.json ghcr.io/open-feature/flagd-testbed:latest
```
and finally run

and run tests with,
```
make e2e-test
```

#### Fuzzing

[Go supports fuzzing natively as of 1.18](https://go.dev/security/fuzz/).
The fuzzing suite is implemented as an integration of `go-sdk` with the [flagd provider](https://github.com/open-feature/go-sdk-contrib/tree/main/providers/flagd) and [flagd](https://github.com/open-feature/flagd).
The fuzzing tests are found in [./integration/evaluation_fuzz_test.go](./integration/evaluation_fuzz_test.go), they are dependent on the flagd testbed running, you can start it with
```
docker run -p 8013:8013 ghcr.io/open-feature/flagd-testbed:latest
```
then, to execute a fuzzing test, run the following
The fuzzing suite is implemented as an integration of `go-sdk`.
The fuzzing tests are found in [./integration/evaluation_fuzz_test.go](./e2e/evaluation_fuzz_test.go).


To execute a fuzzing test, run the following
```
go test -fuzz=FuzzBooleanEvaluation ./integration/evaluation_fuzz_test.go
go test -fuzz=FuzzBooleanEvaluation ./e2e/evaluation_fuzz_test.go
```
substituting the name of the fuzz as appropriate.

### Releases

This repo uses Release Please to release packages. Release Please sets up a running PR that tracks all changes for the library components, and maintains the versions according to conventional commits, generated when PRs are merged. When Release Please's running PR is merged, any changed artifacts are published.
This repo uses Release Please to release packages. Release Please set up a running PR that tracks all changes for the library components, and maintains the versions according to conventional commits, generated when PRs are merged.
When Release Please PR is merged, any changed artifacts will be published.

## Contacting us

Expand Down
6 changes: 2 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ mockgen:
mockgen -source=pkg/openfeature/hooks.go -destination=pkg/openfeature/hooks_mock_test.go -package=openfeature
test:
go test --short -cover ./...
e2e-test: # dependent on: docker run -p 8013:8013 -v $PWD/test-harness/testing-flags.json:/testing-flags.json ghcr.io/open-feature/flagd-testbed:latest
go test -cover ./...
cd test-harness; git restore testing-flags.json; cd .. # reset testing-flags.json

e2e-test:
go test -race -cover ./e2e/...
lint:
go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@latest
${GOPATH}/bin/golangci-lint run --deadline=3m --timeout=3m ./... # Run linters
5 changes: 5 additions & 0 deletions e2e/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## end-to-end tests

This folder contains e2e tests for go-sdk. Tests written here rely on `InMemoryProvider` to perform flag evaluations.
Some tests require `test-harness` Git submodule and use behaviour driven tests defined with [Gherkin](https://cucumber.io/docs/gherkin/reference/) syntax.

36 changes: 0 additions & 36 deletions e2e/caching_test.go

This file was deleted.

112 changes: 112 additions & 0 deletions e2e/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package e2e_test

import (
"github.com/open-feature/go-sdk/pkg/openfeature"
"github.com/open-feature/go-sdk/pkg/openfeature/memprovider"
)

// ctxFunction is a context based evaluation callback
var ctxFunction = func(this memprovider.InMemoryFlag, evalCtx openfeature.FlattenedContext) (
interface{}, openfeature.ProviderResolutionDetail) {

defaultValue := this.Variants[this.DefaultVariant]
defaultResolution := openfeature.ProviderResolutionDetail{
Reason: openfeature.DefaultReason,
Variant: this.DefaultVariant,
}

expects := openfeature.FlattenedContext{
"fn": "Sulisław",
"ln": "Świętopełk",
"age": int64(29),
"customer": false,
}

for k, v := range expects {
if v != evalCtx[k] {
return defaultValue, defaultResolution
}
}

return this.Variants["internal"], openfeature.ProviderResolutionDetail{
Reason: openfeature.TargetingMatchReason,
Variant: "internal",
}
}

var memoryFlags = map[string]memprovider.InMemoryFlag{
"boolean-flag": {
Key: "boolean-flag",
State: memprovider.Enabled,
DefaultVariant: "on",
Variants: map[string]interface{}{
"on": true,
"off": false,
},
ContextEvaluator: nil,
},
"string-flag": {
Key: "string-flag",
State: memprovider.Enabled,
DefaultVariant: "greeting",
Variants: map[string]interface{}{
"greeting": "hi",
"parting": "bye",
},
ContextEvaluator: nil,
},
"integer-flag": {
Key: "integer-flag",
State: memprovider.Enabled,
DefaultVariant: "ten",
Variants: map[string]interface{}{
"one": 1,
"ten": 10,
},
ContextEvaluator: nil,
},
"float-flag": {
Key: "float-flag",
State: memprovider.Enabled,
DefaultVariant: "half",
Variants: map[string]interface{}{
"tenth": 0.1,
"half": 0.5,
},
ContextEvaluator: nil,
},
"object-flag": {
Key: "object-flag",
State: memprovider.Enabled,
DefaultVariant: "template",
Variants: map[string]interface{}{
"empty": map[string]interface{}{},
"template": map[string]interface{}{
"showImages": true,
"title": "Check out these pics!",
"imagesPerPage": 100,
},
},
ContextEvaluator: nil,
},
"wrong-flag": {
Key: "wrong-flag",
State: memprovider.Enabled,
DefaultVariant: "one",
Variants: map[string]interface{}{
"one": "uno",
"two": "dos",
},
ContextEvaluator: nil,
},
"context-aware": {
Key: "context-aware",
State: memprovider.Enabled,
DefaultVariant: "external",
Variants: map[string]interface{}{
"internal": "INTERNAL",
"external": "EXTERNAL",
},
ContextEvaluator: &ctxFunction,
},
}
16 changes: 4 additions & 12 deletions e2e/evaluation_fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,21 @@ package e2e_test

import (
"context"
"github.com/open-feature/go-sdk/pkg/openfeature"
"github.com/open-feature/go-sdk/pkg/openfeature/memprovider"
"strings"
"testing"
"time"

flagd "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg"
"github.com/open-feature/go-sdk/pkg/openfeature"
)

func setupFuzzClient(f *testing.F) *openfeature.Client {
f.Helper()

provider := flagd.NewProvider(flagd.WithPort(8013), flagd.WithoutCache())
err := openfeature.SetProvider(provider)
memoryProvider := memprovider.NewInMemoryProvider(map[string]memprovider.InMemoryFlag{})
err := openfeature.SetProvider(memoryProvider)
if err != nil {
f.Errorf("error setting up provider %v", err)
}

select {
case <-provider.IsReady():
case <-time.After(500 * time.Millisecond):
f.Fatal("provider not ready after 500 milliseconds")
}

return openfeature.NewClient("fuzzing")
}

Expand Down
Loading

0 comments on commit 366674f

Please sign in to comment.