github.com/esnet/gdg@v0.6.1-0.20240412190737-6b6eba9c14d8/test/common_test.go (about)

     1  package test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"github.com/esnet/gdg/internal/config"
     7  	"github.com/esnet/gdg/internal/service"
     8  	"github.com/google/uuid"
     9  	"github.com/testcontainers/testcontainers-go"
    10  	"github.com/testcontainers/testcontainers-go/wait"
    11  	"golang.org/x/exp/maps"
    12  	"gopkg.in/yaml.v3"
    13  	"log"
    14  	"log/slog"
    15  	"os"
    16  	"slices"
    17  	"sync"
    18  	"time"
    19  
    20  	"strings"
    21  	"testing"
    22  
    23  	"github.com/spf13/viper"
    24  	"github.com/stretchr/testify/assert"
    25  )
    26  
    27  var minioContainer testcontainers.Container
    28  var grafnaContainer testcontainers.Container
    29  
    30  type Containers struct {
    31  	Cancel    context.CancelFunc
    32  	Container testcontainers.Container
    33  }
    34  
    35  func setupMinioContainer(wg *sync.WaitGroup, channels chan Containers) {
    36  	// pulls an image, creates a container based on it and runs it
    37  	defer wg.Done()
    38  
    39  	ctx := context.Background()
    40  	req := testcontainers.ContainerRequest{
    41  		Image:        "bitnami/minio:latest",
    42  		ExposedPorts: []string{"9000/tcp"},
    43  		Env:          map[string]string{"MINIO_ROOT_USER": "test", "MINIO_ROOT_PASSWORD": "secretsss"},
    44  		WaitingFor:   wait.ForListeningPort("9000/tcp"),
    45  	}
    46  	minioC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
    47  		ContainerRequest: req,
    48  		Started:          true,
    49  	})
    50  	if err != nil {
    51  		panic(err)
    52  	}
    53  
    54  	slog.Info("Minio container is up and running")
    55  	cancel := func() {
    56  		if err := minioC.Terminate(ctx); err != nil {
    57  			panic(err)
    58  		} else {
    59  			slog.Info("Minio container has been terminated")
    60  		}
    61  	}
    62  	result := Containers{
    63  		Cancel:    cancel,
    64  		Container: minioC,
    65  	}
    66  	channels <- result
    67  
    68  }
    69  
    70  func setupGrafanaContainer(wg *sync.WaitGroup, channels chan Containers) {
    71  	// pulls an image, creates a container based on it and runs it
    72  	defer wg.Done()
    73  	ctx := context.Background()
    74  	req := testcontainers.ContainerRequest{
    75  		Image:        "grafana/grafana:10.0.0-ubuntu",
    76  		ExposedPorts: []string{"3000/tcp"},
    77  		Env: map[string]string{
    78  			"GF_INSTALL_PLUGINS":        "grafana-googlesheets-datasource",
    79  			"GF_AUTH_ANONYMOUS_ENABLED": "true",
    80  		},
    81  		WaitingFor: wait.ForListeningPort("3000/tcp"),
    82  	}
    83  	grafanaC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
    84  		ContainerRequest: req,
    85  		Started:          true,
    86  	})
    87  	if err != nil {
    88  		panic(err)
    89  	}
    90  	cancel := func() {
    91  		if err := grafanaC.Terminate(ctx); err != nil {
    92  			panic(err)
    93  		} else {
    94  			slog.Info("Grafana Container has been terminated")
    95  		}
    96  	}
    97  	result := Containers{
    98  		Cancel:    cancel,
    99  		Container: grafanaC,
   100  	}
   101  	channels <- result
   102  
   103  }
   104  
   105  func TestMain(m *testing.M) {
   106  	channels := make(chan Containers, 2)
   107  	var wg = new(sync.WaitGroup)
   108  	wg.Add(2)
   109  	slog.Info("Starting at", "time", time.Now().String())
   110  	go setupMinioContainer(wg, channels)
   111  	go setupGrafanaContainer(wg, channels)
   112  	wg.Wait()
   113  	close(channels)
   114  	slog.Info("Ending at", "end", time.Now().String())
   115  
   116  	for entry := range channels {
   117  		defer entry.Cancel()
   118  		str, err := entry.Container.Ports(context.Background())
   119  		if err != nil {
   120  			slog.Error("unable to obtain bound ports for container")
   121  			continue
   122  		}
   123  		keys := maps.Keys(str)
   124  		if slices.Contains(keys, "9000/tcp") {
   125  			minioContainer = entry.Container
   126  		}
   127  		if slices.Contains(keys, "3000/tcp") {
   128  			grafnaContainer = entry.Container
   129  
   130  		}
   131  
   132  	}
   133  	exitVal := m.Run()
   134  
   135  	os.Exit(exitVal)
   136  }
   137  
   138  func initTest(t *testing.T, cfgName *string) (service.GrafanaService, *viper.Viper, func() error) {
   139  	apiClient, v := createSimpleClient(t, cfgName)
   140  	noOp := func() error { return nil }
   141  
   142  	if os.Getenv("TEST_TOKEN_CONFIG") != "1" {
   143  		return apiClient, v, noOp
   144  	}
   145  
   146  	testData, _ := os.ReadFile(v.ConfigFileUsed())
   147  	data := map[string]interface{}{}
   148  	err := yaml.Unmarshal(testData, &data)
   149  	assert.Nil(t, err)
   150  
   151  	apiClient.DeleteAllTokens() //Remove any old data
   152  	tokenName, _ := uuid.NewUUID()
   153  	newKey, err := apiClient.CreateAPIKey(tokenName.String(), "admin", 0)
   154  	assert.Nil(t, err)
   155  
   156  	wrapper := map[string]*config.GrafanaConfig{}
   157  	_ = wrapper
   158  
   159  	level1 := data["contexts"].(map[string]interface{})
   160  	level2 := level1["testing"].(map[string]interface{})
   161  	level2["token"] = newKey.Key
   162  	level2["user_name"] = ""
   163  	level2["password"] = ""
   164  
   165  	updatedCfg, err := yaml.Marshal(data)
   166  	assert.Nil(t, err)
   167  	tokenCfg, err := os.CreateTemp("config", "token*.yml")
   168  	assert.Nil(t, err, "Unable to create token configuration file")
   169  	newCfg := tokenCfg.Name()
   170  	err = os.WriteFile(newCfg, updatedCfg, 0644)
   171  	assert.Nil(t, err)
   172  
   173  	cleanUp := func() error {
   174  		return os.Remove(newCfg)
   175  	}
   176  
   177  	apiClient, v = createSimpleClient(t, &newCfg)
   178  	return apiClient, v, cleanUp
   179  
   180  }
   181  
   182  func createSimpleClient(t *testing.T, cfgName *string) (service.GrafanaService, *viper.Viper) {
   183  	if cfgName == nil {
   184  		cfgName = new(string)
   185  		*cfgName = "testing.yml"
   186  	}
   187  
   188  	actualPort, err := grafnaContainer.Endpoint(context.Background(), "")
   189  	err = os.Setenv("GDG_CONTEXTS__TESTING__URL", fmt.Sprintf("http://%s", actualPort))
   190  	assert.Nil(t, err)
   191  
   192  	config.InitGdgConfig(*cfgName, "'")
   193  	conf := config.Config().GetViperConfig(config.ViperGdgConfig)
   194  	assert.NotNil(t, conf)
   195  	//Hack for Local testing
   196  	contextName := conf.GetString("context_name")
   197  	conf.Set(fmt.Sprintf("context.%s.url", contextName), fmt.Sprintf("http://localhost:%s", actualPort))
   198  	assert.Equal(t, contextName, "testing")
   199  	client := service.NewApiService("dummy")
   200  	path, _ := os.Getwd()
   201  	if strings.Contains(path, "test") {
   202  		err := os.Chdir("..")
   203  		if err != nil {
   204  			slog.Warn("unable to set directory to parent")
   205  		}
   206  	}
   207  	return client, conf
   208  }
   209  
   210  func SetupCloudFunction(params []string) (context.Context, service.GrafanaService) {
   211  	_ = os.Setenv(service.InitBucket, "true")
   212  	bucketName := params[1]
   213  
   214  	actualPort, err := minioContainer.Endpoint(context.Background(), "")
   215  	var m = map[string]string{
   216  		service.InitBucket: "true",
   217  		service.CloudType:  params[0],
   218  		service.Prefix:     "dummy",
   219  		service.AccessId:   "test",
   220  		service.SecretKey:  "secretsss",
   221  		service.BucketName: bucketName,
   222  		service.Kind:       "cloud",
   223  		service.Custom:     "true",
   224  		service.Endpoint:   fmt.Sprintf("http://%s", actualPort),
   225  		service.SSLEnabled: "false",
   226  	}
   227  
   228  	cfgObj := config.Config().GetGDGConfig()
   229  	defaultCfg := config.Config().GetDefaultGrafanaConfig()
   230  	defaultCfg.Storage = "test"
   231  	cfgObj.StorageEngine["test"] = m
   232  	apiClient := service.NewApiService("dummy")
   233  
   234  	ctx := context.Background()
   235  	ctx = context.WithValue(ctx, service.StorageContext, m)
   236  	configMap := map[string]string{}
   237  	for key, value := range m {
   238  		configMap[key] = fmt.Sprintf("%v", value)
   239  	}
   240  
   241  	s, err := service.NewCloudStorage(ctx)
   242  	if err != nil {
   243  		log.Fatalf("Could not instantiate cloud storage for type: %s", params[0])
   244  	}
   245  	dash := apiClient.(*service.DashNGoImpl)
   246  	dash.SetStorage(s)
   247  
   248  	return ctx, apiClient
   249  }