github.com/dolthub/go-mysql-server@v0.18.0/enginetest/harness.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package enginetest 16 17 import ( 18 "testing" 19 20 sqle "github.com/dolthub/go-mysql-server" 21 "github.com/dolthub/go-mysql-server/enginetest/scriptgen/setup" 22 "github.com/dolthub/go-mysql-server/server" 23 "github.com/dolthub/go-mysql-server/sql" 24 ) 25 26 // Harness provides a way for database integrators to validate their implementation against the standard set of queries 27 // used to develop and test the engine itself. See memory_engine_test.go for an example. 28 // The typical harness lifecycle during test setup looks like this: 29 // 1) Harness is instantiated, which should create a sql.MutableDatabaseProvider to use for the rest of setup 30 // 2) Harness.NewDatabase or Harness.NewTable is called to create the database and tables that will be used for the test 31 // 3) For some tests, harness.Setup() is called instead of Harness.NewDatabase and Harness.NewTable 32 // 4) Harness.NewEngine() is called to create an engine with the setup data provided prior. It can be called multiple 33 // times during a single test run, and must return a "fresh" engine instance each time, i.e. an instance that contains 34 // exactly the test data provided via other setup methods. 35 type Harness interface { 36 // Parallelism returns how many parallel go routines to use when constructing an engine for test. 37 Parallelism() int 38 // NewContext allows a harness to specify any sessions or context variables necessary for the proper functioning of 39 // their engine implementation. Every harnessed engine test uses the context created by this method, with some 40 // additional information (e.g. current DB) set uniformly. To replicate the behavior of tests during setup, 41 // harnesses should generally dispatch to enginetest.NewContext(harness), rather than calling this method themselves. 42 NewContext() *sql.Context 43 // Setup supplies a test suite's setup scripts, which must be stored and used to create a new Engine on demand via 44 // calls to the NewEngine method. 45 Setup(...[]setup.SetupScript) 46 // NewEngine creates a new sqle.Engine. The state of the engine returned must match what was previous specified 47 // by Setup, with no other data. See enginetest.NewEngine for help creating an engine suitable in tests. 48 NewEngine(*testing.T) (QueryEngine, error) 49 } 50 51 // ClientHarness allows for integrators to test user privileges, as mock clients are used to test functionality. 52 type ClientHarness interface { 53 Harness 54 55 // NewContextWithClient returns a context that will return the given client when requested from the session. 56 NewContextWithClient(client sql.Client) *sql.Context 57 } 58 59 type ServerHarness interface { 60 Harness 61 62 // SessionBuilder returns a function that creates a new session for connections to a server 63 SessionBuilder() server.SessionBuilder 64 } 65 66 // SkippingHarness provides a way for integrators to skip tests that are known to be broken. E.g., integrators that 67 // can't handle every possible SQL type. 68 type SkippingHarness interface { 69 // SkipQueryTest returns whether to skip a test of the provided query string. 70 SkipQueryTest(query string) bool 71 } 72 73 // IndexDriverHarness is an extension to Harness that lets an integrator test their implementation alongside an index 74 // driver they provide. 75 type IndexDriverHarness interface { 76 Harness 77 78 // InitializeIndexDriver initializes the index driver for this test run with the databases given 79 InitializeIndexDriver(dbs []sql.Database) 80 } 81 82 // IndexHarness is an extension to Harness that lets an integrator test their implementation with native 83 // (table-supplied) indexes. Integrator tables must implement sql.IndexAlterableTable. 84 type IndexHarness interface { 85 Harness 86 87 // SupportsNativeIndexCreation returns whether this harness should accept CREATE INDEX statements as part of test 88 // setup. 89 SupportsNativeIndexCreation() bool 90 } 91 92 // ForeignKeyHarness is an extension to Harness that lets an integrator test their implementation with foreign keys. 93 // Integrator tables must implement sql.ForeignKeyTable. 94 type ForeignKeyHarness interface { 95 Harness 96 97 // SupportsForeignKeys returns whether this harness should accept CREATE FOREIGN KEY statements as part of test 98 // setup. 99 SupportsForeignKeys() bool 100 } 101 102 // VersionedDBHarness is an extension to Harness that lets an integrator test their implementation of versioned (AS OF) 103 // queries. Integrators must implement sql.VersionedDatabase. For each table version being created, there will be a 104 // call to NewTableAsOf, some number of Delete and Insert operations, and then a call to SnapshotTable. 105 type VersionedDBHarness interface { 106 Harness 107 108 // NewDatabases returns a set of new databases used for the duration of a versioned test 109 NewDatabases(names ...string) []sql.Database 110 111 // NewTableAsOf creates a new table with the given name and schema, optionally handling snapshotting with the asOf 112 // identifier. NewTableAsOf must ignore tables that already exist in the database. Tables returned by this method do 113 // not need to have any previously created data in them, but they can. This behavior is implementation specific, and 114 // the harness works either way. 115 NewTableAsOf(db sql.VersionedDatabase, name string, schema sql.PrimaryKeySchema, asOf interface{}) sql.Table 116 // SnapshotTable creates a snapshot of the table named with the given asOf label. Depending on the implementation, 117 // NewTableAsOf might do all the necessary work to create such snapshots, so this could be a no-op. 118 SnapshotTable(db sql.VersionedDatabase, name string, asOf interface{}) error 119 } 120 121 // KeylessTableHarness is an extension to Harness that lets an integrator test their implementation with keyless tables. 122 type KeylessTableHarness interface { 123 Harness 124 125 // SupportsKeylessTables indicates integrator support for keyless tables. 126 SupportsKeylessTables() bool 127 } 128 129 type TransactionHarness interface { 130 Harness 131 132 // NewSession returns a context with a new Session, rather than reusing an existing session from previous calls to 133 // NewContext() 134 NewSession() *sql.Context 135 } 136 137 type ReadOnlyDatabaseHarness interface { 138 Harness 139 140 // NewReadOnlyEngine returns a new engine with read-only versions of the databases supplied by the provider. 141 // TODO: should this and NewEngine actually just be NewProvider? 142 NewReadOnlyEngine(provider sql.DatabaseProvider) (QueryEngine, error) 143 } 144 145 type ValidatingHarness interface { 146 Harness 147 148 // ValidateEngine runs post-test assertions against an engine. 149 ValidateEngine(ctx *sql.Context, e *sqle.Engine) error 150 }