<commit_before>/*
Copyright 2022 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package utils

import (
	"context"
	"fmt"
	"os"
	"path"
	"testing"

	"github.com/stretchr/testify/assert"

	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/sqlparser"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/test/endtoend/cluster"
	"vitess.io/vitess/go/vt/mysqlctl"
)

// NewMySQL creates a new MySQL server using the local mysqld binary. The name of the database
// will be set to `dbName`. SQL queries that need to be executed on the new MySQL instance
// can be passed through the `schemaSQL` argument.
// The mysql.ConnParams to connect to the new database is returned, along with a function to
// teardown the database.
func NewMySQL(cluster *cluster.LocalProcessCluster, dbName string, schemaSQL ...string) (mysql.ConnParams, func(), error) {
	return NewMySQLWithDetails(cluster.GetAndReservePort(), cluster.Hostname, dbName, schemaSQL...)
}

func NewMySQLWithDetails(port int, hostname, dbName string, schemaSQL ...string) (mysql.ConnParams, func(), error) {
	mysqlDir, err := createMySQLDir()
	if err != nil {
		return mysql.ConnParams{}, nil, err
	}
	initMySQLFile, err := createInitSQLFile(mysqlDir, dbName)
	if err != nil {
		return mysql.ConnParams{}, nil, err
	}

	mysqlPort := port
	mysqld, mycnf, err := mysqlctl.CreateMysqldAndMycnf(0, "", int32(mysqlPort))
	if err != nil {
		return mysql.ConnParams{}, nil, err
	}
	err = initMysqld(mysqld, mycnf, initMySQLFile)
	if err != nil {
		return mysql.ConnParams{}, nil, err
	}

	params := mysql.ConnParams{
		UnixSocket: mycnf.SocketFile,
		Host:       hostname,
		Uname:      "root",
		DbName:     dbName,
	}
	for _, sql := range schemaSQL {
		err = prepareMySQLWithSchema(params, sql)
		if err != nil {
			return mysql.ConnParams{}, nil, err
		}
	}
	return params, func() {
		ctx := context.Background()
		_ = mysqld.Teardown(ctx, mycnf, true)
	}, nil
}

func createMySQLDir() (string, error) {
	mysqlDir := mysqlctl.TabletDir(0)
	err := os.Mkdir(mysqlDir, 0700)<commit_msg>endtoend: fix dbconfig initialization for endtoend tests (#11609)<commit_after>/*
Copyright 2022 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package utils

import (
	"context"
	"fmt"
	"os"
	"path"
	"testing"

	"github.com/stretchr/testify/assert"

	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/dbconfigs"
	"vitess.io/vitess/go/vt/sqlparser"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/test/endtoend/cluster"
	"vitess.io/vitess/go/vt/mysqlctl"
)

// NewMySQL creates a new MySQL server using the local mysqld binary. The name of the database
// will be set to `dbName`. SQL queries that need to be executed on the new MySQL instance
// can be passed through the `schemaSQL` argument.
// The mysql.ConnParams to connect to the new database is returned, along with a function to
// teardown the database.
func NewMySQL(cluster *cluster.LocalProcessCluster, dbName string, schemaSQL ...string) (mysql.ConnParams, func(), error) {
	return NewMySQLWithDetails(cluster.GetAndReservePort(), cluster.Hostname, dbName, schemaSQL...)
}

// CreateMysqldAndMycnf returns a Mysqld and a Mycnf object to use for working with a MySQL
// installation that hasn't been set up yet.
func CreateMysqldAndMycnf(tabletUID uint32, mysqlSocket string, mysqlPort int32) (*mysqlctl.Mysqld, *mysqlctl.Mycnf, error) {
	mycnf := mysqlctl.NewMycnf(tabletUID, mysqlPort)
	if err := mycnf.RandomizeMysqlServerID(); err != nil {
		return nil, nil, fmt.Errorf("couldn't generate random MySQL server_id: %v", err)
	}
	if mysqlSocket != "" {
		mycnf.SocketFile = mysqlSocket
	}
	var cfg dbconfigs.DBConfigs
	// ensure the DBA username is 'root' instead of the system's default username so that mysqladmin can shutdown
	cfg.Dba.User = "root"
	cfg.InitWithSocket(mycnf.SocketFile)
	return mysqlctl.NewMysqld(&cfg), mycnf, nil
}

func NewMySQLWithDetails(port int, hostname, dbName string, schemaSQL ...string) (mysql.ConnParams, func(), error) {
	mysqlDir, err := createMySQLDir()
	if err != nil {
		return mysql.ConnParams{}, nil, err
	}
	initMySQLFile, err := createInitSQLFile(mysqlDir, dbName)
	if err != nil {
		return mysql.ConnParams{}, nil, err
	}

	mysqlPort := port
	mysqld, mycnf, err := CreateMysqldAndMycnf(0, "", int32(mysqlPort))
	if err != nil {
		return mysql.ConnParams{}, nil, err
	}
	err = initMysqld(mysqld, mycnf, initMySQLFile)
	if err != nil {
		return mysql.ConnParams{}, nil, err
	}

	params := mysql.ConnParams{
		UnixSocket: mycnf.SocketFile,
		Host:       hostname,
		Uname:      "root",
		DbName:     dbName,
	}
	for _, sql := range schemaSQL {
		err = prepareMySQLWithSchema(params, sql)
		if err != nil {
			return mysql.ConnParams{}, nil, err
		}
	}
	return params, func() {
		ctx := context.Background()
		_ = mysqld.Teardown(ctx, mycnf, true)
	}, nil
}

func createMySQLDir() (string, error) {
	mysqlDir := mysqlctl.TabletDir(0)
	err := os.Mkdir(mysqlDir, 0700)
{'fraction_non_alphanumeric': 0.1111674269302247, 'fraction_numerical': 0.006926845750971448, 'mean_word_length': 4.215859030837004, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '644468', 'n_tokens_mistral': 2065, 'n_tokens_neox': 1955, 'n_words': 628}