github.com/rudderlabs/rudder-go-kit@v0.30.0/testhelper/docker/resource/transformer/transformer.go (about)

     1  package transformer
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/http"
     7  	"strings"
     8  
     9  	"github.com/samber/lo"
    10  
    11  	dockertesthelper "github.com/rudderlabs/rudder-go-kit/testhelper/docker"
    12  
    13  	"github.com/ory/dockertest/v3"
    14  	"github.com/ory/dockertest/v3/docker"
    15  
    16  	"github.com/rudderlabs/rudder-go-kit/httputil"
    17  	"github.com/rudderlabs/rudder-go-kit/testhelper/docker/resource"
    18  )
    19  
    20  type Resource struct {
    21  	TransformerURL string
    22  	Port           string
    23  }
    24  
    25  type config struct {
    26  	repository   string
    27  	tag          string
    28  	exposedPorts []string
    29  	envs         []string
    30  	extraHosts   []string
    31  }
    32  
    33  func (c *config) setBackendConfigURL(url string) {
    34  	c.envs = append(
    35  		lo.Filter(c.envs, func(s string, _ int) bool {
    36  			return !strings.HasPrefix(s, "CONFIG_BACKEND_URL=")
    37  		}),
    38  		"CONFIG_BACKEND_URL="+url)
    39  }
    40  
    41  // WithUserTransformations will mock BE config to set transformation for given transformation versionID to transformation function map
    42  //
    43  // - events with transformationVersionID not present in map will not be transformed and transformer will return 404 for those requests
    44  //
    45  // - WithUserTransformations should not be used with WithConfigBackendURL option
    46  //
    47  // - only javascript transformation functions are supported
    48  //
    49  // e.g.
    50  //
    51  //	WithUserTransformations(map[string]string{
    52  //				"transform-version-id-1": `export function transformEvent(event, metadata) {
    53  //											event.transformed=true
    54  //											return event;
    55  //										}`,
    56  //			})
    57  func WithUserTransformations(transformations map[string]string, cleaner resource.Cleaner) func(*config) {
    58  	return func(conf *config) {
    59  		backendConfigSvc := newTestBackendConfigServer(transformations)
    60  
    61  		conf.setBackendConfigURL(dockertesthelper.ToInternalDockerHost(backendConfigSvc.URL))
    62  		conf.extraHosts = append(conf.extraHosts, "host.docker.internal:host-gateway")
    63  		cleaner.Cleanup(func() {
    64  			backendConfigSvc.Close()
    65  		})
    66  	}
    67  }
    68  
    69  // WithConnectionToHostEnabled lets transformer container connect with the host machine
    70  // i.e. transformer container will be able to access localhost of the host machine
    71  func WithConnectionToHostEnabled() func(*config) {
    72  	return func(conf *config) {
    73  		conf.extraHosts = append(conf.extraHosts, "host.docker.internal:host-gateway")
    74  	}
    75  }
    76  
    77  // WithConfigBackendURL lets transformer use custom backend config server for transformations
    78  // WithConfigBackendURL should not be used with WithUserTransformations option
    79  func WithConfigBackendURL(url string) func(*config) {
    80  	return func(conf *config) {
    81  		conf.setBackendConfigURL(dockertesthelper.ToInternalDockerHost(url))
    82  	}
    83  }
    84  
    85  func WithDockerImageTag(tag string) func(*config) {
    86  	return func(conf *config) {
    87  		conf.tag = tag
    88  	}
    89  }
    90  
    91  func Setup(pool *dockertest.Pool, d resource.Cleaner, opts ...func(conf *config)) (*Resource, error) {
    92  	// Set Rudder Transformer
    93  	// pulls an image first to make sure we don't have an old cached version locally,
    94  	// then it creates a container based on it and runs it
    95  	conf := &config{
    96  		repository:   "rudderstack/rudder-transformer",
    97  		tag:          "latest",
    98  		exposedPorts: []string{"9090"},
    99  		envs: []string{
   100  			"CONFIG_BACKEND_URL=https://api.rudderstack.com",
   101  		},
   102  	}
   103  
   104  	for _, opt := range opts {
   105  		opt(conf)
   106  	}
   107  
   108  	err := pool.Client.PullImage(docker.PullImageOptions{
   109  		Repository: conf.repository,
   110  		Tag:        conf.tag,
   111  	}, docker.AuthConfiguration{})
   112  	if err != nil {
   113  		return nil, fmt.Errorf("failed to pull image: %w", err)
   114  	}
   115  	transformerContainer, err := pool.RunWithOptions(&dockertest.RunOptions{
   116  		Repository:   conf.repository,
   117  		Tag:          conf.tag,
   118  		ExposedPorts: conf.exposedPorts,
   119  		Env:          conf.envs,
   120  		ExtraHosts:   conf.extraHosts,
   121  	})
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	d.Cleanup(func() {
   127  		if err := pool.Purge(transformerContainer); err != nil {
   128  			d.Log("Could not purge resource:", err)
   129  		}
   130  	})
   131  
   132  	transformerResource := &Resource{
   133  		TransformerURL: fmt.Sprintf("http://localhost:%s", transformerContainer.GetPort("9090/tcp")),
   134  		Port:           transformerContainer.GetPort("9090/tcp"),
   135  	}
   136  
   137  	err = pool.Retry(func() (err error) {
   138  		resp, err := http.Get(transformerResource.TransformerURL + "/health")
   139  		if err != nil {
   140  			return err
   141  		}
   142  		defer func() { httputil.CloseResponse(resp) }()
   143  		if resp.StatusCode != http.StatusOK {
   144  			return errors.New(resp.Status)
   145  		}
   146  		return nil
   147  	})
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  
   152  	return transformerResource, nil
   153  }