github.com/mre-fog/trillianxx@v1.1.2-0.20180615153820-ae375a99d36a/storage/testdb/testdb.go (about) 1 // Copyright 2017 Google Inc. All Rights Reserved. 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 testdb creates new databases for tests. 16 package testdb 17 18 import ( 19 "bytes" 20 "context" 21 "database/sql" 22 "fmt" 23 "io/ioutil" 24 "strings" 25 "testing" 26 "time" 27 28 "github.com/google/trillian/testonly" 29 30 _ "github.com/go-sql-driver/mysql" // mysql driver 31 ) 32 33 var ( 34 trillianSQL = testonly.RelativeToPackage("../mysql/storage.sql") 35 dataSource = "root@/" 36 ) 37 38 // MySQLAvailable indicates whether a default MySQL database is available. 39 func MySQLAvailable() bool { 40 db, err := sql.Open("mysql", dataSource) 41 if err != nil { 42 return false 43 } 44 defer db.Close() 45 if err := db.Ping(); err != nil { 46 return false 47 } 48 return true 49 } 50 51 // newEmptyDB creates a new, empty database. 52 func newEmptyDB(ctx context.Context) (*sql.DB, error) { 53 db, err := sql.Open("mysql", dataSource) 54 if err != nil { 55 return nil, err 56 } 57 58 // Create a randomly-named database and then connect using the new name. 59 name := fmt.Sprintf("trl_%v", time.Now().UnixNano()) 60 61 stmt := fmt.Sprintf("CREATE DATABASE %v", name) 62 if _, err := db.ExecContext(ctx, stmt); err != nil { 63 return nil, fmt.Errorf("error running statement %q: %v", stmt, err) 64 } 65 66 db.Close() 67 db, err = sql.Open("mysql", dataSource+name) 68 if err != nil { 69 return nil, err 70 } 71 72 return db, db.Ping() 73 } 74 75 // NewTrillianDB creates an empty database with the Trillian schema. The database name is randomly 76 // generated. 77 // NewTrillianDB is equivalent to Default().NewTrillianDB(ctx). 78 func NewTrillianDB(ctx context.Context) (*sql.DB, error) { 79 db, err := newEmptyDB(ctx) 80 if err != nil { 81 return nil, err 82 } 83 84 sqlBytes, err := ioutil.ReadFile(trillianSQL) 85 if err != nil { 86 return nil, err 87 } 88 89 for _, stmt := range strings.Split(sanitize(string(sqlBytes)), ";") { 90 stmt = strings.TrimSpace(stmt) 91 if stmt == "" { 92 continue 93 } 94 if _, err := db.ExecContext(ctx, stmt); err != nil { 95 return nil, fmt.Errorf("error running statement %q: %v", stmt, err) 96 } 97 } 98 return db, nil 99 } 100 101 func sanitize(script string) string { 102 buf := &bytes.Buffer{} 103 for _, line := range strings.Split(string(script), "\n") { 104 line = strings.TrimSpace(line) 105 if line == "" || line[0] == '#' || strings.Index(line, "--") == 0 { 106 continue // skip empty lines and comments 107 } 108 buf.WriteString(line) 109 buf.WriteString("\n") 110 } 111 return buf.String() 112 } 113 114 // SkipIfNoMySQL is a test helper that skips tests that require a local MySQL. 115 func SkipIfNoMySQL(t *testing.T) { 116 t.Helper() 117 if !MySQLAvailable() { 118 t.Skip("Skipping test as MySQL not available") 119 } 120 }