diff --git a/CHANGELOG.md b/CHANGELOG.md index 3369a8db..2613254d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ # Unreleased +- Added the possibility to run without any validations against the Oracle. Simply do not + supply a host for the Oracle and Gemini will assume you want to only run against Test. - Replication strategy is now configurable via the CLI argument `--replication-strategy`. # 1.4.4 diff --git a/cmd/gemini/root.go b/cmd/gemini/root.go index 89c05746..9bbefe32 100644 --- a/cmd/gemini/root.go +++ b/cmd/gemini/root.go @@ -261,6 +261,9 @@ func createClusters(consistency gocql.Consistency) (*gocql.ClusterConfig, *gocql testCluster.Timeout = 5 * time.Second testCluster.RetryPolicy = retryPolicy testCluster.Consistency = consistency + if len(oracleClusterHost) == 0 { + return testCluster, nil + } oracleCluster := gocql.NewCluster(oracleClusterHost...) oracleCluster.Timeout = 5 * time.Second oracleCluster.RetryPolicy = retryPolicy @@ -327,8 +330,7 @@ func init() { rootCmd.Version = version + ", commit " + commit + ", date " + date rootCmd.Flags().StringSliceVarP(&testClusterHost, "test-cluster", "t", []string{}, "Host names or IPs of the test cluster that is system under test") rootCmd.MarkFlagRequired("test-cluster") - rootCmd.Flags().StringSliceVarP(&oracleClusterHost, "oracle-cluster", "o", []string{}, "Host names or IPs of the oracle cluster that provides correct answers") - rootCmd.MarkFlagRequired("oracle-cluster") + rootCmd.Flags().StringSliceVarP(&oracleClusterHost, "oracle-cluster", "o", []string{}, "Host names or IPs of the oracle cluster that provides correct answers. If omitted no oracle will be used") rootCmd.Flags().StringVarP(&schemaFile, "schema", "", "", "Schema JSON config file") rootCmd.Flags().StringVarP(&mode, "mode", "m", mixedMode, "Query operation mode. Mode options: write, read, mixed (default)") rootCmd.Flags().Uint64VarP(&concurrency, "concurrency", "c", 10, "Number of threads per table to run concurrently") diff --git a/docs/cli-arguments.md b/docs/cli-arguments.md index b70c6e79..b77f1c3d 100644 --- a/docs/cli-arguments.md +++ b/docs/cli-arguments.md @@ -8,34 +8,35 @@ Gemini has a large number of CLI arguments and this document is an attempt to do part of the so called `Oracle` which is to say the super stable bug free cluster that Gemini uses as the blueprint for it's validations. -2. ___--test-cluster___, ___-t___: This parameter takes a comma separated list of hosts that are -part of the ___SUT___ or commonly, ___system under test___. - ## Optional arguments -1. ___---mode___, ___-m___: This is a string parameter with the acceptable values "mixed","read" and "write". +1. ___--test-cluster___, ___-t___: This parameter takes a comma separated list of hosts that are +part of the ___SUT___ or commonly, ___system under test___. If omitted then Gemini will not use the Oracle +at all and simply execute a lot of queries against the ___SUT___. + +2. ___---mode___, ___-m___: This is a string parameter with the acceptable values "mixed","read" and "write". -2. ___--concurrency___, ___-c___: An int describing the number of concurrent jobs in the case of "read" +3. ___--concurrency___, ___-c___: An int describing the number of concurrent jobs in the case of "read" or "write" mode. In the case of "mixed" mode it represents half of the number of jobs that will be executed concurrently. -3. ___--schema___: The path to a file containing a JSON representation of the schema to be +4. ___--schema___: The path to a file containing a JSON representation of the schema to be used during a run. -4. ___--seed___, ___-s___: The seed parameter denotes the seed from where to start the random number +5. ___--seed___, ___-s___: The seed parameter denotes the seed from where to start the random number generators that Gemini is using. -5. ___--drop-schema___, ___-d___: Boolean value that instructs Gemini to issue a __DROP SCHEMA__ +6. ___--drop-schema___, ___-d___: Boolean value that instructs Gemini to issue a __DROP SCHEMA__ statement before starting to run. Make sure you use it with care. -6. ___--fail-fast___, ___-f___: Boolean value that instructs Gemini to stop running as soon as it +7. ___--fail-fast___, ___-f___: Boolean value that instructs Gemini to stop running as soon as it encounters a validation error. If set to false, then Gemini will collect the errors and report them once normal program end is reached. -7. ___--duration___: The duration of a run. Defaults to 30 seconds. +8. ___--duration___: The duration of a run. Defaults to 30 seconds. -8. ___--warmup___: The duration of the warmup phase during which only additive mutations will be +9. ___--warmup___: The duration of the warmup phase during which only additive mutations will be performed. Default is 30 seconds. -9. ___--outfile___: Path to a file where Gemini should store it's result. If not provided then +10. ___--outfile___: Path to a file where Gemini should store it's result. If not provided then standard out is used. \ No newline at end of file diff --git a/store/store.go b/store/store.go index 913bb470..5d226ff7 100644 --- a/store/store.go +++ b/store/store.go @@ -54,6 +54,26 @@ func New(schema *gemini.Schema, testCluster *gocql.ClusterConfig, oracleCluster Help: "How many CQL requests processed, partitioned by system and CQL query type aka 'method' (batch, delete, insert, update).", }, []string{"system", "method"}, ) + + var oracleStore storeLoader + var validations bool + if oracleCluster != nil { + oracleStore = &cqlStore{ + session: newSession(oracleCluster), + schema: schema, + system: "oracle", + ops: ops, + maxRetriesMutate: cfg.MaxRetriesMutate + 10, + maxRetriesMutateSleep: cfg.MaxRetriesMutateSleep, + logger: logger, + } + validations = true + } else { + oracleStore = &noOpStore{ + system: "oracle", + } + } + return &delegatingStore{ testStore: &cqlStore{ session: newSession(testCluster), @@ -64,22 +84,40 @@ func New(schema *gemini.Schema, testCluster *gocql.ClusterConfig, oracleCluster maxRetriesMutateSleep: cfg.MaxRetriesMutateSleep, logger: logger, }, - oracleStore: &cqlStore{ - session: newSession(oracleCluster), - schema: schema, - system: "oracle", - ops: ops, - maxRetriesMutate: cfg.MaxRetriesMutate + 10, - maxRetriesMutateSleep: cfg.MaxRetriesMutateSleep, - logger: logger, - }, - logger: logger.Named("delegating_store"), + oracleStore: oracleStore, + validations: validations, + logger: logger.Named("delegating_store"), } } +type noOpStore struct { + system string +} + +func (n *noOpStore) mutate(context.Context, qb.Builder, time.Time, ...interface{}) error { + return nil +} + +func (n *noOpStore) load(context.Context, qb.Builder, []interface{}) ([]map[string]interface{}, error) { + return nil, nil +} + +func (n *noOpStore) Close() error { + return nil +} + +func (n *noOpStore) name() string { + return n.system +} + +func (n *noOpStore) close() error { + return nil +} + type delegatingStore struct { oracleStore storeLoader testStore storeLoader + validations bool logger *zap.Logger } @@ -109,7 +147,9 @@ func (ds delegatingStore) Check(ctx context.Context, table *gemini.Table, builde if err != nil { return errors.Wrapf(err, "unable to load check data from the oracle store") } - + if !ds.validations { + return nil + } if len(testRows) != len(oracleRows) { testSet := strset.New(pks(table, testRows)...) oracleSet := strset.New(pks(table, oracleRows)...)