Categorygithub.com/gabrielsaiz/elasticfacker
modulepackage
1.3.0
Repository: https://github.com/gabrielsaiz/elasticfacker.git
Documentation: pkg.go.dev

# README

elasticfacker

Elasticsearch simulator for API endpoint with the proposal of make the ES Golang Client testable

Disclaimer: This is a work in progress...

Please note that this is a very simplified approach to mocking and may not be suitable for all use cases. 
In particular, this approach only allows you to define one mock response for each method, 
regardless of the arguments passed to it. If you need more complex behaviour, 
such as returning different responses depending on the arguments or changing responses over time, 
you would need a more sophisticated solution.


Operations

Implemented operations:

  • HEAD /{indexName} -> esapi.IndicesExistsRequest

  • GET /_cat/indices/{indexNamePattern} -> esapi.CatIndicesRequest

  • GET /{indexName}/_alias -> esapi.IndicesGetAliasRequest

  • GET /_alias/{aliasName} -> esapi.IndicesGetAliasRequest

  • PUT /{indexName} -> esapi.IndicesCreateRequest

  • PUT /{indexName}/_aliases/{aliasName} -> esapi.IndicesPutAliasRequest

  • DELETE /{indexName} -> esapi.IndicesDeleteRequest

  • DELETE /{indexName}/_aliases/{aliasName} -> esapi.IndicesDeleteAliasRequest

  • POST /{indexName}/_search/template -> esapi.SearchRequestTemplate

  • POST /{indexName}/_search -> esapi.SearchRequest

  • POST /{indexName}/_count -> esapi.CountRequest

How to use

There are 2 options to use this library:

  • Using the Elasticfacker as a in memory server
  • Using the Elasticfaceker with mock data

Starting the server

Starting the server is very simple:

  • Add this import to your code:
import "github.com/elasticfacker/elasticfacker"
  • Then you can start the server with the following code into your test:
esFacker := elasticfacker.NewInMemoryElasticsearch()
esFacker.Start("localhost:9200")
defer esFacker.Stop()
  • Then you can use the Elasticsearch client as you would normally do:
    esClient, error := elasticsearch.NewDefaultClient()

    req := esapi.IndicesExistsRequest{
        Index: []string{indexName},
    }

    res, err := req.Do(context.Background(), esClient)
    if err != nil {
        log.Get().Infof("Error when checking if index exists '%s': %s", indexName, err)
        return 
    }
    defer res.Body.Close()

    if res.StatusCode == 200 {
        log.Get().Infof("Index '%s' already exists", indexName)
        return
    } else {
		log.Get().Infof("Index '%s' does not exists", indexName)
		return
    }
}

Using as a memory server

Now you can use the server as a memory server:

After starting the elasticfaker server, you can use it as an Elasticsearch index, a facade, currently it store the name of the index, the alias and the relation between index and aliases...

So it's just an index to add or to get this info... for a better answer, you can use the mock data.

Memory server example

func TestElasticApiClient(t *testing.T) {
    subtests := []struct {
        name       string
		indexName  string
        expected   int
    }{
        {
            name: "Index not found",
			indexName: "products-test-not-found",
            expected: 404,
        },
        {
            name: "Index found",
			indexName: "products-test",
            expected: 200,
        },
	}

    esClient, error := elasticsearch.NewDefaultClient()
	if error != nil {
        t.Errorf("Error when creating the Elasticsearch client: %s", error)
    }

    esFacker := elasticfacker.NewInMemoryElasticsearch()
    esFacker.Start("localhost:9200")
    defer esFacker.Stop()
    time.Sleep(2 * time.Second)

    for _, subtest := range subtests {
    
        t.Run(subtest.name, func(t *testing.T) {
            req1 := esapi.IndicesCreateRequest{
                Index: subtest.indexName,
            }

            res1, err1 := req1.Do(context.Background(), esClient)
            assert.Nil(t, err1)
            defer res1.Body.Close()
            

            if res1.IsError() || res1.StatusCode != 200 {
                t.Errorf("Error when creating the index '%s': %s", subtest.indexName, res1.String())
            }
			
            req2 := esapi.IndicesExistsRequest{
                Index: []string{subtest.indexName},
            }
            
            res2, err2 := req2.Do(context.Background(), esClient)
            assert.Nil(t, err2)
			defer res2.Body.Close()
            
            assert.Equal(t, subtest.expected, res2.StatusCode)
        })
    }
}

Using the mock data

Elasticseach API uses an HTTP Rest API, so you can use the mock data to simulate the responses of the API.

The MockMethod is an struct that contains the following fields:

type MockMethods struct {
    StatusCode   int
    Status       string
    BodyAsString string
}

Mock data example


func TestElasticApiClient(t *testing.T) {
	subtests := []struct {
		name       string
		indexName  string
		expected   bool
		mockMethod elasticfacker.MockMethods
	}{
		{
			name: "Index not found",
			indexName: "products-test-not-found",
			mockMethod: elasticfacker.MockMethods{
				StatusCode: 404,
				Status:     "Not Found",
			},
			expected: false,
		},
		{
			name: "Index is a teapot",
			indexName: "products-test-teapot",
			mockMethod: elasticfacker.MockMethods{
				StatusCode: 418,
				Status:     "I'm a teapot",
			},
			expected: false,
		},
		{
			name: "Index found",
			indexName: "products-test",
			mockMethod: elasticfacker.MockMethods{
				StatusCode: 200,
				Status:     "OK",
			},
			expected: true,
		},
	}

    esClient, error := elasticsearch.NewDefaultClient()
        if error != nil {
        t.Errorf("Error when creating the Elasticsearch client: %s", error)
    }
	
	esFacker := elasticfacker.NewInMemoryElasticsearch()
	esFacker.Start("localhost:9200")
	defer esFacker.Stop()

	for _, subtest := range subtests {
		time.Sleep(1 * time.Second)

		t.Run(subtest.name, func(t *testing.T) {

			esFacker.SetMockMethods(&subtest.mockMethod)

            req := esapi.IndicesExistsRequest{
                Index: []string{subtest.indexName},
            }

            res, err := req.Do(context.Background(), esClient)
            assert.Nil(t, err)
            defer res.Body.Close()

			assert.Equal(t, subtest.expected, res.StatusCode == 200)
		})
	}
}

# Packages

No description provided by the author

# Functions

No description provided by the author

# Constants

No description provided by the author
No description provided by the author

# Structs

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Type aliases

No description provided by the author