github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ccl/workloadccl/fixture_test.go (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Licensed as a CockroachDB Enterprise file under the Cockroach Community
     4  // License (the "License"); you may not use this file except in compliance with
     5  // the License. You may obtain a copy of the License at
     6  //
     7  //     https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
     8  
     9  package workloadccl_test
    10  
    11  import (
    12  	"context"
    13  	"fmt"
    14  	"net/http/httptest"
    15  	"os"
    16  	"strconv"
    17  	"strings"
    18  	"testing"
    19  	"time"
    20  
    21  	"cloud.google.com/go/storage"
    22  	"github.com/cockroachdb/cockroach/pkg/base"
    23  	_ "github.com/cockroachdb/cockroach/pkg/ccl"
    24  	"github.com/cockroachdb/cockroach/pkg/ccl/workloadccl"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/stats"
    26  	"github.com/cockroachdb/cockroach/pkg/testutils"
    27  	"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
    28  	"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
    29  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    30  	"github.com/cockroachdb/cockroach/pkg/util/timeutil"
    31  	"github.com/cockroachdb/cockroach/pkg/workload"
    32  	"github.com/spf13/pflag"
    33  	"github.com/stretchr/testify/require"
    34  	"golang.org/x/oauth2/google"
    35  	"google.golang.org/api/option"
    36  )
    37  
    38  const fixtureTestGenRows = 10
    39  
    40  type fixtureTestGen struct {
    41  	flags workload.Flags
    42  	val   string
    43  	empty string
    44  }
    45  
    46  func makeTestWorkload() workload.Flagser {
    47  	g := &fixtureTestGen{}
    48  	g.flags.FlagSet = pflag.NewFlagSet(`fx`, pflag.ContinueOnError)
    49  	g.flags.StringVar(&g.val, `val`, `default`, `The value for each row`)
    50  	g.flags.StringVar(&g.empty, `empty`, ``, `An empty flag`)
    51  	return g
    52  }
    53  
    54  var fixtureTestMeta = workload.Meta{
    55  	Name: `fixture`,
    56  	New: func() workload.Generator {
    57  		return makeTestWorkload()
    58  	},
    59  }
    60  
    61  func init() {
    62  	workload.Register(fixtureTestMeta)
    63  }
    64  
    65  func (fixtureTestGen) Meta() workload.Meta     { return fixtureTestMeta }
    66  func (g fixtureTestGen) Flags() workload.Flags { return g.flags }
    67  func (g fixtureTestGen) Tables() []workload.Table {
    68  	return []workload.Table{{
    69  		Name:   `fx`,
    70  		Schema: `(key INT PRIMARY KEY, value INT)`,
    71  		InitialRows: workload.Tuples(
    72  			fixtureTestGenRows,
    73  			func(rowIdx int) []interface{} {
    74  				return []interface{}{rowIdx, g.val}
    75  			},
    76  		),
    77  		Stats: []workload.JSONStatistic{
    78  			// Use stats that *don't* match reality, so we can test that these
    79  			// stats were injected and not calculated by CREATE STATISTICS.
    80  			workload.MakeStat([]string{"key"}, 100, 100, 0),
    81  			workload.MakeStat([]string{"value"}, 100, 1, 5),
    82  		},
    83  	}}
    84  }
    85  
    86  func TestFixture(t *testing.T) {
    87  	defer leaktest.AfterTest(t)()
    88  	ctx := context.Background()
    89  
    90  	gcsBucket := os.Getenv(`GS_BUCKET`)
    91  	gcsKey := os.Getenv(`GS_JSONKEY`)
    92  	if gcsBucket == "" || gcsKey == "" {
    93  		t.Skip("GS_BUCKET and GS_JSONKEY env vars must be set")
    94  	}
    95  
    96  	source, err := google.JWTConfigFromJSON([]byte(gcsKey), storage.ScopeReadWrite)
    97  	if err != nil {
    98  		t.Fatalf(`%+v`, err)
    99  	}
   100  	gcs, err := storage.NewClient(ctx,
   101  		option.WithScopes(storage.ScopeReadWrite),
   102  		option.WithTokenSource(source.TokenSource(ctx)))
   103  	if err != nil {
   104  		t.Fatalf(`%+v`, err)
   105  	}
   106  	defer func() { _ = gcs.Close() }()
   107  
   108  	s, db, _ := serverutils.StartServer(t, base.TestServerArgs{})
   109  	defer s.Stopper().Stop(ctx)
   110  	sqlDB := sqlutils.MakeSQLRunner(db)
   111  	sqlDB.Exec(t, `SET CLUSTER SETTING cloudstorage.gs.default.key = $1`, gcsKey)
   112  
   113  	gen := makeTestWorkload()
   114  	flag := fmt.Sprintf(`val=%d`, timeutil.Now().UnixNano())
   115  	if err := gen.Flags().Parse([]string{"--" + flag}); err != nil {
   116  		t.Fatalf(`%+v`, err)
   117  	}
   118  
   119  	config := workloadccl.FixtureConfig{
   120  		GCSBucket: gcsBucket,
   121  		GCSPrefix: fmt.Sprintf(`TestFixture-%d`, timeutil.Now().UnixNano()),
   122  	}
   123  
   124  	if _, err := workloadccl.GetFixture(ctx, gcs, config, gen); !testutils.IsError(err, `fixture not found`) {
   125  		t.Fatalf(`expected "fixture not found" error but got: %+v`, err)
   126  	}
   127  
   128  	fixtures, err := workloadccl.ListFixtures(ctx, gcs, config)
   129  	if err != nil {
   130  		t.Fatalf(`%+v`, err)
   131  	}
   132  	if len(fixtures) != 0 {
   133  		t.Errorf(`expected no fixtures but got: %+v`, fixtures)
   134  	}
   135  
   136  	const filesPerNode = 1
   137  	fixture, err := workloadccl.MakeFixture(ctx, db, gcs, config, gen, filesPerNode)
   138  	if err != nil {
   139  		t.Fatalf(`%+v`, err)
   140  	}
   141  
   142  	_, err = workloadccl.MakeFixture(ctx, db, gcs, config, gen, filesPerNode)
   143  	if !testutils.IsError(err, `already exists`) {
   144  		t.Fatalf(`expected 'already exists' error got: %+v`, err)
   145  	}
   146  
   147  	fixtures, err = workloadccl.ListFixtures(ctx, gcs, config)
   148  	if err != nil {
   149  		t.Fatalf(`%+v`, err)
   150  	}
   151  	if len(fixtures) != 1 || !strings.Contains(fixtures[0], flag) {
   152  		t.Errorf(`expected exactly one %s fixture but got: %+v`, flag, fixtures)
   153  	}
   154  
   155  	sqlDB.Exec(t, `CREATE DATABASE test`)
   156  	if _, err := workloadccl.RestoreFixture(ctx, db, fixture, `test`, false); err != nil {
   157  		t.Fatalf(`%+v`, err)
   158  	}
   159  	sqlDB.CheckQueryResults(t,
   160  		`SELECT count(*) FROM test.fx`, [][]string{{strconv.Itoa(fixtureTestGenRows)}})
   161  }
   162  
   163  func TestImportFixture(t *testing.T) {
   164  	defer leaktest.AfterTest(t)()
   165  	ctx := context.Background()
   166  
   167  	defer func(oldRefreshInterval, oldAsOf time.Duration) {
   168  		stats.DefaultRefreshInterval = oldRefreshInterval
   169  		stats.DefaultAsOfTime = oldAsOf
   170  	}(stats.DefaultRefreshInterval, stats.DefaultAsOfTime)
   171  	stats.DefaultRefreshInterval = time.Millisecond
   172  	stats.DefaultAsOfTime = 10 * time.Millisecond
   173  
   174  	s, db, _ := serverutils.StartServer(t, base.TestServerArgs{})
   175  	defer s.Stopper().Stop(ctx)
   176  	sqlDB := sqlutils.MakeSQLRunner(db)
   177  
   178  	sqlDB.Exec(t, `SET CLUSTER SETTING sql.stats.automatic_collection.enabled=true`)
   179  
   180  	gen := makeTestWorkload()
   181  	flag := fmt.Sprintf(`val=%d`, timeutil.Now().UnixNano())
   182  	if err := gen.Flags().Parse([]string{"--" + flag}); err != nil {
   183  		t.Fatalf(`%+v`, err)
   184  	}
   185  
   186  	const filesPerNode = 1
   187  
   188  	sqlDB.Exec(t, `CREATE DATABASE ingest`)
   189  	_, err := workloadccl.ImportFixture(
   190  		ctx, db, gen, `ingest`, filesPerNode, false, /* injectStats */
   191  		``, /* csvServer */
   192  	)
   193  	require.NoError(t, err)
   194  	sqlDB.CheckQueryResults(t,
   195  		`SELECT count(*) FROM ingest.fx`, [][]string{{strconv.Itoa(fixtureTestGenRows)}})
   196  
   197  	// Since we did not inject stats, the IMPORT should have triggered
   198  	// automatic stats collection.
   199  	sqlDB.CheckQueryResultsRetry(t,
   200  		`SELECT statistics_name, column_names, row_count, distinct_count, null_count
   201             FROM [SHOW STATISTICS FOR TABLE ingest.fx]`,
   202  		[][]string{
   203  			{"__auto__", "{key}", "10", "10", "0"},
   204  			{"__auto__", "{value}", "10", "1", "0"},
   205  		})
   206  }
   207  
   208  func TestImportFixtureCSVServer(t *testing.T) {
   209  	defer leaktest.AfterTest(t)()
   210  	ctx := context.Background()
   211  	ts := httptest.NewServer(workload.CSVMux(workload.Registered()))
   212  	defer ts.Close()
   213  
   214  	s, db, _ := serverutils.StartServer(t, base.TestServerArgs{UseDatabase: `d`})
   215  	defer s.Stopper().Stop(ctx)
   216  	sqlDB := sqlutils.MakeSQLRunner(db)
   217  
   218  	gen := makeTestWorkload()
   219  	flag := fmt.Sprintf(`val=%d`, timeutil.Now().UnixNano())
   220  	if err := gen.Flags().Parse([]string{"--" + flag}); err != nil {
   221  		t.Fatalf(`%+v`, err)
   222  	}
   223  
   224  	const filesPerNode = 1
   225  	const noInjectStats = false
   226  	sqlDB.Exec(t, `CREATE DATABASE d`)
   227  	_, err := workloadccl.ImportFixture(
   228  		ctx, db, gen, `d`, filesPerNode, noInjectStats, ts.URL,
   229  	)
   230  	require.NoError(t, err)
   231  	sqlDB.CheckQueryResults(t,
   232  		`SELECT count(*) FROM d.fx`, [][]string{{strconv.Itoa(fixtureTestGenRows)}})
   233  }