Giter Site home page Giter Site logo

Fake Unleash for Go about unleash-client-go HOT 9 CLOSED

unleash avatar unleash commented on July 19, 2024
Fake Unleash for Go

from unleash-client-go.

Comments (9)

jrbarron avatar jrbarron commented on July 19, 2024 1

@apexskier Feature is now public on the v3 branch actually after we added the ListFeatures() function. I wrote a quick hacky version of a FakeUnleash for someone so I can share that here. It creates a fake server instead of mocking the client so might not be what you are looking for, but maybe it helps:

package unleash

import (
	"encoding/json"
	"github.com/Unleash/unleash-client-go/v3/api"
	"net/http"
	"net/http/httptest"
	"sync"
	"time"
)

type FakeUnleashServer struct {
	sync.RWMutex
	srv      *httptest.Server
	features map[string]bool
}

func (f *FakeUnleashServer) Url() string {
	return f.srv.URL
}

func (f *FakeUnleashServer) Enable(feature string) {
	f.setEnabled(feature, true)
}

func (f *FakeUnleashServer) Disable(feature string) {
	f.setEnabled(feature, false)
}

func (f *FakeUnleashServer) setEnabled(feature string, enabled bool) {
	f.Lock()
	wasEnabled := f.features[feature]
	if enabled != wasEnabled {
		f.features[feature] = enabled
	}
	f.Unlock()
}

func (f *FakeUnleashServer) IsEnabled(feature string) bool {
	f.RLock()
	enabled := f.features[feature]
	f.RUnlock()
	return enabled
}

func (f *FakeUnleashServer) setAll(enabled bool) {
	for k := range f.features {
		f.setEnabled(k, enabled)
	}
}

func (f *FakeUnleashServer) EnableAll() {
	f.setAll(true)
}

func (f *FakeUnleashServer) DisableAll() {
	f.setAll(false)
}

func (f *FakeUnleashServer) handler(w http.ResponseWriter, req *http.Request) {
	switch req.Method + " " + req.URL.Path {
	case "GET /client/features":

		features := []api.Feature{}
		for k, v := range f.features {
			features = append(features, api.Feature{
				Name:    k,
				Enabled: v,
				Strategies: []api.Strategy{
					{
						Id:   0,
						Name: "default",
					},
				},
				CreatedAt: time.Time{},
			})
		}

		res := api.FeatureResponse{
			Response: api.Response{Version: 2},
			Features: features,
		}
		dec := json.NewEncoder(w)
		if err := dec.Encode(res); err != nil {
			println(err.Error())
		}
	case "POST /client/register":
		fallthrough
	case "POST /client/metrics":
		w.WriteHeader(200)
	default:
		w.Write([]byte("Unknown route"))
		w.WriteHeader(500)
	}
}

func NewFakeUnleash() *FakeUnleashServer {
	faker := &FakeUnleashServer{
		features: map[string]bool{},
	}
	faker.srv = httptest.NewServer(http.HandlerFunc(faker.handler))
	return faker
}

The way it works is that you create call NewFakeUnleash() to get an instance of the fake server and pass the URL of this server to your unleash client. You then toggle features on the server by calling Enable() and Disable().

from unleash-client-go.

jrbarron avatar jrbarron commented on July 19, 2024 1

@yofriadi I'm not sure what you mean by not compatible 🤔

Here's a quick example of configuring your client to talk to the fake server:

func TestFakeUnleashServer(t *testing.T) {
	faker := unleash.NewFakeUnleash()

	unleash.Initialize(
		unleash.WithListener(&unleash.DebugListener{}),
		unleash.WithAppName("my-application"),
		unleash.WithUrl(faker.Url()),
		unleash.WithRefreshInterval(1*time.Millisecond),
	)
	unleash.WaitForReady()

	faker.Enable("foo")
	<-time.After(5 * time.Millisecond) // wait until client refreshes

	if unleash.IsEnabled("foo") != true {
		t.Errorf("expected IsEnabled to be true")
	}

	faker.Disable("foo")
	<-time.After(5 * time.Millisecond) // wait until client refreshes

	if unleash.IsEnabled("foo") != false {
		t.Errorf("expected IsEnabled to be false")
	}
}

from unleash-client-go.

ivarconr avatar ivarconr commented on July 19, 2024

That would be nice. What do you think @jrbarron ?

from unleash-client-go.

jrbarron avatar jrbarron commented on July 19, 2024

This is the first I've heard of it so no plans yet, but it sounds like a good idea. This will probably involve some refactoring internally since both the repository and the metrics stuff should be abstracted into interfaces so we can stub out the network behavior.

I haven't had much free time lately and the time I have spent on Unleash has been adding support for v4 and variants so if someone else would like to take a stab at this, they are certainly welcome. Otherwise I will try to find some time after I finish the v4 changes.

from unleash-client-go.

jrmullins avatar jrmullins commented on July 19, 2024

Thanks for the feedback. Do you guys have any recommendations on unit testing in general? Do you guys set up an httptest handler's to mock unleash responses?

from unleash-client-go.

jrbarron avatar jrbarron commented on July 19, 2024

@jrmullins I have used a library called gock for mocking the http traffic in the Unleash.

from unleash-client-go.

apexskier avatar apexskier commented on July 19, 2024

From my perspective, the easiest way to make this package mockable would be to allow defining a custom storage implementation that we can mock the results of. WithStorage is already public, but it's not usable because the repository requires it's return data to be of type api.Feature, which is in an internal package and can't be used by consumers. If Feature was public, this would be much easier.

https://play.golang.org/p/KIr8rYKTjUD

from unleash-client-go.

apexskier avatar apexskier commented on July 19, 2024

@jrbarron Thanks! This ended up allowing us to mock unleash in tests; everything's working well now.

from unleash-client-go.

yofriadi avatar yofriadi commented on July 19, 2024

hi @jrbarron could we have some example implementation for mocking using FakeUnleashServer

because as far as I can try, type FakeUnleashServer is not compatible with type unleash.Client, or maybe I am missing something here, thankyou

from unleash-client-go.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.