cyberark/secretless-broker

View on GitHub
pkg/secretless/config/v2/config_env_test.go

Summary

Maintainability
A
3 hrs
Test Coverage
package v2_test

import (
    "fmt"
    "os"
    "testing"

    v2 "github.com/cyberark/secretless-broker/pkg/secretless/config/v2"
    loggermock "github.com/cyberark/secretless-broker/pkg/secretless/log/mock"
    "github.com/cyberark/secretless-broker/pkg/secretless/plugin/connector/http"
    "github.com/cyberark/secretless-broker/pkg/secretless/plugin/connector/tcp"
    "github.com/cyberark/secretless-broker/pkg/secretless/plugin/sharedobj/mock"
    "github.com/stretchr/testify/assert"
)

// TODO: move the log mock public

func TestConfigEnv(t *testing.T) {

    // Shared mocks and doubles

    logger := loggermock.NewLogger()

    availPlugins := &mock.Plugins{
        HTTPPluginsByID: map[string]http.Plugin{
            "HTTP1": mock.NewHTTPPlugin("HTTP1"),
            "HTTP2": mock.NewHTTPPlugin("HTTP2"),
        },
        TCPPluginsByID: map[string]tcp.Plugin{
            "TCP1": mock.NewTCPPlugin("TCP1"),
            "TCP2": mock.NewTCPPlugin("TCP2"),
        },
    }

    // Mock to simulate file existing.
    //
    // NOTE: We're cheating a little bit by returning nil, since we're
    // relying on knowing that our implementation doesn't actually use
    // FileInfo.  That said, this should be ok since the test will likely
    // break cleanly if the implementation is changed to use FileInfo.
    getInfoForExistingFile := func(_ string) (os.FileInfo, error) {
        return nil, nil
    }

    // Tests

    t.Run("succeeds when all connectors are available", func(t *testing.T) {
        cfg := v2.Config{
            Services: []*v2.Service{
                {Name: "HTTP1 Service", Connector: "HTTP1"},
                {Name: "HTTP2 Service", Connector: "HTTP2"},
                {Name: "TCP1 Service", Connector: "TCP1"},
                {Name: "TCP2 Service", Connector: "TCP2"},
            },
        }

        configEnv := v2.NewConfigEnv(logger, availPlugins)
        err := configEnv.Prepare(cfg)
        assert.Nil(t, err)
    })

    t.Run("errors when connectors aren't available", func(t *testing.T) {
        cfg := v2.Config{
            Services: []*v2.Service{
                {Name: "HTTP1 Service", Connector: "HTTP1"},
                {Name: "HTTP2 Service", Connector: "TCP2"},
                {Name: "Fake Service 1", Connector: "FAKE PLUGIN 1"},
                {Name: "Fake Service 2", Connector: "FAKE PLUGIN 2"},
            },
        }

        configEnv := v2.NewConfigEnv(logger, availPlugins)
        err := configEnv.Prepare(cfg)
        assert.NotNil(t, err)
        if err == nil {
            return
        }

        // Ensure error message mentions which plugins are missing.
        assert.Regexp(t, "FAKE PLUGIN 1", err)
        assert.Regexp(t, "FAKE PLUGIN 2", err)
    })

    // When a listenOn unix socket exists, it tries to delete it, and if the
    // deletion succeeds, it does not return an error.
    t.Run("can delete existing unix socket without error", func(t *testing.T) {

        // Mock to simulate successful file deletion.
        socketDeleted := ""
        deleteFile := func(name string) error {
            socketDeleted = name
            return nil
        }

        configEnv := v2.NewConfigEnvWithOptions(
            logger,
            availPlugins,
            getInfoForExistingFile,
            deleteFile,
        )

        cfg := v2.Config{
            Services: []*v2.Service{
                {Name: "HTTP1 Service", Connector: "HTTP1", ListenOn: "unix://xxx"},
            },
        }

        err := configEnv.Prepare(cfg)
        assert.Nil(t, err)
        if err != nil {
            return
        }

        assert.Equal(t, "xxx", socketDeleted)
    })

    t.Run("returns error if socket deletion fails", func(t *testing.T) {

        // Double to simulate failing file deletion.
        deleteFile := func(name string) error {
            return fmt.Errorf("failed to delete file")
        }

        configEnv := v2.NewConfigEnvWithOptions(
            logger,
            availPlugins,
            getInfoForExistingFile,
            deleteFile,
        )

        cfg := v2.Config{
            Services: []*v2.Service{
                {Name: "HTTP1 Service", Connector: "HTTP1", ListenOn: "unix://xxx"},
            },
        }

        err := configEnv.Prepare(cfg)
        assert.NotNil(t, err)
        if err == nil {
            return
        }

        assert.Regexp(t, "delete", err)
    })

    t.Run("doesn't delete non-unix sockets", func(t *testing.T) {

        // Mock to simulate successful file deletion.
        deleteFileCalled := false
        deleteFile := func(name string) error {
            deleteFileCalled = true
            return nil
        }

        configEnv := v2.NewConfigEnvWithOptions(
            logger,
            availPlugins,
            getInfoForExistingFile,
            deleteFile,
        )

        cfg := v2.Config{
            Services: []*v2.Service{
                {Name: "HTTP1 Service", Connector: "HTTP1", ListenOn: "tcp://xxx"},
            },
        }

        err := configEnv.Prepare(cfg)
        assert.Nil(t, err)
        if err != nil {
            return
        }

        assert.False(t, deleteFileCalled, "deleteFile should not be called")
    })
}