github.com/dolthub/go-mysql-server@v0.18.0/enginetest/mysqlshim/mysql_harness.go (about)

     1  // Copyright 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 mysqlshim
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strings"
    21  	"testing"
    22  
    23  	"github.com/dolthub/go-mysql-server/memory"
    24  
    25  	"github.com/dolthub/go-mysql-server/enginetest"
    26  	"github.com/dolthub/go-mysql-server/enginetest/scriptgen/setup"
    27  	"github.com/dolthub/go-mysql-server/sql"
    28  )
    29  
    30  // MySQLHarness is a harness for a local MySQL server. This will modify databases and tables as the tests see fit, which
    31  // may delete pre-existing data. Ensure that the MySQL instance may freely be modified without worry.
    32  type MySQLHarness struct {
    33  	shim           *MySQLShim
    34  	skippedQueries map[string]struct{}
    35  	setupData      []setup.SetupScript
    36  	session        sql.Session
    37  }
    38  
    39  // TODO: refactor to remove enginetest cycle
    40  var _ enginetest.Harness = (*MySQLHarness)(nil)
    41  var _ enginetest.IndexHarness = (*MySQLHarness)(nil)
    42  var _ enginetest.ForeignKeyHarness = (*MySQLHarness)(nil)
    43  var _ enginetest.KeylessTableHarness = (*MySQLHarness)(nil)
    44  var _ enginetest.ClientHarness = (*MySQLHarness)(nil)
    45  var _ enginetest.SkippingHarness = (*MySQLHarness)(nil)
    46  
    47  func (m *MySQLHarness) Setup(setupData ...[]setup.SetupScript) {
    48  	m.setupData = nil
    49  	for i := range setupData {
    50  		m.setupData = append(m.setupData, setupData[i]...)
    51  	}
    52  	return
    53  }
    54  
    55  func (m *MySQLHarness) NewEngine(t *testing.T) (enginetest.QueryEngine, error) {
    56  	return enginetest.NewEngine(t, m, m.Provider(), m.setupData, memory.NewStatsProv())
    57  }
    58  
    59  func (m *MySQLHarness) NewContextWithClient(client sql.Client) *sql.Context {
    60  	session := sql.NewBaseSessionWithClientServer("address", client, 1)
    61  	return sql.NewContext(
    62  		context.Background(),
    63  		sql.WithSession(session),
    64  	)
    65  }
    66  
    67  func (m *MySQLHarness) Cleanup() error {
    68  	return nil
    69  }
    70  
    71  // MySQLDatabase represents a database for a local MySQL server.
    72  type MySQLDatabase struct {
    73  	harness *MySQLHarness
    74  	dbName  string
    75  }
    76  
    77  // MySQLTable represents a table for a local MySQL server.
    78  type MySQLTable struct {
    79  	harness   *MySQLHarness
    80  	tableName string
    81  }
    82  
    83  // NewMySQLHarness returns a new MySQLHarness.
    84  func NewMySQLHarness(user string, password string, host string, port int) (*MySQLHarness, error) {
    85  	shim, err := NewMySQLShim(user, password, host, port)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	return &MySQLHarness{shim, make(map[string]struct{}), nil, nil}, nil
    90  }
    91  
    92  // Parallelism implements the interface Harness.
    93  func (m *MySQLHarness) Parallelism() int {
    94  	return 1
    95  }
    96  
    97  // NewDatabase implements the interface Harness.
    98  func (m *MySQLHarness) NewDatabase(name string) sql.Database {
    99  	return m.NewDatabases(name)[0]
   100  }
   101  
   102  // NewDatabases implements the interface Harness.
   103  func (m *MySQLHarness) NewDatabases(names ...string) []sql.Database {
   104  	var dbs []sql.Database
   105  	ctx := sql.NewEmptyContext()
   106  	for _, name := range names {
   107  		_ = m.shim.DropDatabase(ctx, name)
   108  		err := m.shim.CreateDatabase(ctx, name)
   109  		if err != nil {
   110  			panic(err)
   111  		}
   112  		db, err := m.shim.Database(ctx, name)
   113  		if err != nil {
   114  			panic(err)
   115  		}
   116  		dbs = append(dbs, db)
   117  	}
   118  	return dbs
   119  }
   120  
   121  // NewDatabaseProvider implements the interface Harness.
   122  func (m *MySQLHarness) NewDatabaseProvider() sql.MutableDatabaseProvider {
   123  	return m.shim
   124  }
   125  
   126  func (m *MySQLHarness) Provider() sql.MutableDatabaseProvider {
   127  	return m.shim
   128  }
   129  
   130  // NewTable implements the interface Harness.
   131  func (m *MySQLHarness) NewTable(db sql.Database, name string, schema sql.PrimaryKeySchema) (sql.Table, error) {
   132  	ctx := sql.NewEmptyContext()
   133  	err := db.(sql.TableCreator).CreateTable(ctx, name, schema, sql.Collation_Default, "")
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  	tbl, ok, err := db.GetTableInsensitive(ctx, name)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	if !ok {
   142  		return nil, fmt.Errorf("successfully created table `%s` but could not retrieve", name)
   143  	}
   144  	return tbl, nil
   145  }
   146  
   147  // NewContext implements the interface Harness.
   148  func (m *MySQLHarness) NewContext() *sql.Context {
   149  	if m.session == nil {
   150  		m.session = enginetest.NewBaseSession()
   151  	}
   152  
   153  	return sql.NewContext(
   154  		context.Background(),
   155  		sql.WithSession(m.session),
   156  	)
   157  }
   158  
   159  // SkipQueryTest implements the interface SkippingHarness.
   160  func (m *MySQLHarness) SkipQueryTest(query string) bool {
   161  	_, ok := m.skippedQueries[strings.ToLower(query)]
   162  	return ok
   163  }
   164  
   165  // QueriesToSkip adds queries that should be skipped.
   166  func (m *MySQLHarness) QueriesToSkip(queries ...string) {
   167  	for _, query := range queries {
   168  		m.skippedQueries[strings.ToLower(query)] = struct{}{}
   169  	}
   170  }
   171  
   172  // SupportsNativeIndexCreation implements the interface IndexHarness.
   173  func (m *MySQLHarness) SupportsNativeIndexCreation() bool {
   174  	return true
   175  }
   176  
   177  // SupportsForeignKeys implements the interface ForeignKeyHarness.
   178  func (m *MySQLHarness) SupportsForeignKeys() bool {
   179  	return true
   180  }
   181  
   182  // SupportsKeylessTables implements the interface KeylessTableHarness.
   183  func (m *MySQLHarness) SupportsKeylessTables() bool {
   184  	return true
   185  }
   186  
   187  // Close closes the connection. This will drop all databases created and accessed during the tests.
   188  func (m *MySQLHarness) Close() {
   189  	m.shim.Close()
   190  }