*: revendor
This commit is contained in:
glide.lock
vendor/github.com
cockroachdb
cockroach-go
go-sql-driver
mysql
.gitignore.travis.ymlAUTHORSCHANGELOG.mdCONTRIBUTING.mdISSUE_TEMPLATE.mdLICENSEPULL_REQUEST_TEMPLATE.mdREADME.mdappengine.gobenchmark_test.gobuffer.gocollations.goconnection.goconst.godriver.godriver_test.godsn.godsn_test.goerrors.goerrors_test.goinfile.gopackets.goresult.gorows.gostatement.gotransaction.goutils.goutils_test.go
lib
pq
mattn
go-sqlite3
.gitignore.travis.ymlLICENSEREADME.mdbackup.gobackup_test.gocallback.gocallback_test.godoc.goerror.goerror_test.gosqlite3-binding.csqlite3-binding.hsqlite3.gosqlite3_fts3_test.gosqlite3_fts5.gosqlite3_icu.gosqlite3_json1.gosqlite3_libsqlite3.gosqlite3_load_extension.gosqlite3_omit_load_extension.gosqlite3_other.gosqlite3_test.go
_example
custom_func
hook
mod_regexp
mod_vtable
simple
trace
sqlite3_test
sqlite3_windows.gosqlite3ext.htool
tracecallback.gotracecallback_noimpl.go
3
vendor/github.com/cockroachdb/cockroach-go/.gitignore
generated
vendored
Normal file
3
vendor/github.com/cockroachdb/cockroach-go/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*~
|
||||
.#*
|
||||
*.test
|
202
vendor/github.com/cockroachdb/cockroach-go/LICENSE
generated
vendored
Normal file
202
vendor/github.com/cockroachdb/cockroach-go/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {}
|
||||
|
||||
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.
|
||||
|
55
vendor/github.com/cockroachdb/cockroach-go/Makefile
generated
vendored
Normal file
55
vendor/github.com/cockroachdb/cockroach-go/Makefile
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
# Copyright 2016 The Cockroach 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. See the AUTHORS file
|
||||
# for names of contributors.
|
||||
#
|
||||
# Author: Spencer Kimball (spencer.kimball@gmail.com)
|
||||
#
|
||||
|
||||
# Cockroach build rules.
|
||||
GO ?= go
|
||||
# Allow setting of go build flags from the command line.
|
||||
GOFLAGS :=
|
||||
|
||||
.PHONY: all
|
||||
all: test check
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
$(GO) test -v -i ./...
|
||||
$(GO) test -v ./...
|
||||
|
||||
.PHONY: deps
|
||||
deps:
|
||||
$(GO) get -d -t ./...
|
||||
|
||||
.PHONY: check
|
||||
check:
|
||||
@echo "checking for \"path\" imports"
|
||||
@! git grep -F '"path"' -- '*.go'
|
||||
@echo "errcheck"
|
||||
@errcheck ./...
|
||||
@echo "vet"
|
||||
@! go tool vet . 2>&1 | \
|
||||
grep -vE '^vet: cannot process directory .git'
|
||||
@echo "vet --shadow"
|
||||
@! go tool vet --shadow . 2>&1 | \
|
||||
grep -vE '(declaration of err shadows|^vet: cannot process directory \.git)'
|
||||
@echo "golint"
|
||||
@! golint ./... | grep -vE '(\.pb\.go)'
|
||||
@echo "varcheck"
|
||||
@varcheck -e ./...
|
||||
@echo "gofmt (simplify)"
|
||||
@! gofmt -s -d -l . 2>&1 | grep -vE '^\.git/'
|
||||
@echo "goimports"
|
||||
@! goimports -l . | grep -vF 'No Exceptions'
|
2
vendor/github.com/cockroachdb/cockroach-go/README.md
generated
vendored
Normal file
2
vendor/github.com/cockroachdb/cockroach-go/README.md
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# testing
|
||||
Testing helpers for cockroach clients.
|
18
vendor/github.com/cockroachdb/cockroach-go/circle.yml
generated
vendored
Normal file
18
vendor/github.com/cockroachdb/cockroach-go/circle.yml
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
machine:
|
||||
environment:
|
||||
GOROOT: ${HOME}/go
|
||||
PATH: ${PATH}:${HOME}/go/bin
|
||||
post:
|
||||
- sudo rm -rf /usr/local/go
|
||||
- if [ ! -e go1.6.linux-amd64.tar.gz ]; then curl -O https://storage.googleapis.com/golang/go1.6.linux-amd64.tar.gz; fi
|
||||
- tar -C ${HOME} -xzf go1.6.linux-amd64.tar.gz
|
||||
|
||||
dependencies:
|
||||
override:
|
||||
- make deps
|
||||
cache_directories:
|
||||
- ~/go1.6.linux-amd64.tar.gz
|
||||
|
||||
test:
|
||||
override:
|
||||
- make test
|
95
vendor/github.com/cockroachdb/cockroach-go/crdb/tx.go
generated
vendored
Normal file
95
vendor/github.com/cockroachdb/cockroach-go/crdb/tx.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright 2016 The Cockroach 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.
|
||||
//
|
||||
// Author: Andrei Matei (andrei@cockroachlabs.com)
|
||||
|
||||
// Package crdb provides helpers for using CockroachDB in client
|
||||
// applications.
|
||||
package crdb
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
// AmbiguousCommitError represents an error that left a transaction in an
|
||||
// ambiguous state: unclear if it committed or not.
|
||||
type AmbiguousCommitError struct {
|
||||
error
|
||||
}
|
||||
|
||||
// ExecuteTx runs fn inside a transaction and retries it as needed.
|
||||
// On non-retryable failures, the transaction is aborted and rolled
|
||||
// back; on success, the transaction is committed.
|
||||
// There are cases where the state of a transaction is inherently ambiguous: if
|
||||
// we err on RELEASE with a communication error it's unclear if the transaction
|
||||
// has been committed or not (similar to erroring on COMMIT in other databases).
|
||||
// In that case, we return AmbiguousCommitError.
|
||||
//
|
||||
// For more information about CockroachDB's transaction model see
|
||||
// https://cockroachlabs.com/docs/transactions.html.
|
||||
//
|
||||
// NOTE: the supplied exec closure should not have external side
|
||||
// effects beyond changes to the database.
|
||||
func ExecuteTx(db *sql.DB, fn func(*sql.Tx) error) (err error) {
|
||||
// Start a transaction.
|
||||
var tx *sql.Tx
|
||||
tx, err = db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
// Ignore commit errors. The tx has already been committed by RELEASE.
|
||||
_ = tx.Commit()
|
||||
} else {
|
||||
// We always need to execute a Rollback() so sql.DB releases the
|
||||
// connection.
|
||||
_ = tx.Rollback()
|
||||
}
|
||||
}()
|
||||
// Specify that we intend to retry this txn in case of CockroachDB retryable
|
||||
// errors.
|
||||
if _, err = tx.Exec("SAVEPOINT cockroach_restart"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
released := false
|
||||
err = fn(tx)
|
||||
if err == nil {
|
||||
// RELEASE acts like COMMIT in CockroachDB. We use it since it gives us an
|
||||
// opportunity to react to retryable errors, whereas tx.Commit() doesn't.
|
||||
released = true
|
||||
if _, err = tx.Exec("RELEASE SAVEPOINT cockroach_restart"); err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// We got an error; let's see if it's a retryable one and, if so, restart. We look
|
||||
// for either the standard PG errcode SerializationFailureError:40001 or the Cockroach extension
|
||||
// errcode RetriableError:CR000. The Cockroach extension has been removed server-side, but support
|
||||
// for it has been left here for now to maintain backwards compatibility.
|
||||
pqErr, ok := err.(*pq.Error)
|
||||
if retryable := ok && (pqErr.Code == "CR000" || pqErr.Code == "40001"); !retryable {
|
||||
if released {
|
||||
err = &AmbiguousCommitError{err}
|
||||
}
|
||||
return err
|
||||
}
|
||||
if _, err = tx.Exec("ROLLBACK TO SAVEPOINT cockroach_restart"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
125
vendor/github.com/cockroachdb/cockroach-go/crdb/tx_test.go
generated
vendored
Normal file
125
vendor/github.com/cockroachdb/cockroach-go/crdb/tx_test.go
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright 2016 The Cockroach 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.
|
||||
//
|
||||
// Author: Spencer Kimball (spencer@cockroachlabs.com)
|
||||
|
||||
package crdb
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/cockroachdb/cockroach-go/testserver"
|
||||
)
|
||||
|
||||
// TestExecuteTx verifies transaction retry using the classic
|
||||
// example of write skew in bank account balance transfers.
|
||||
func TestExecuteTx(t *testing.T) {
|
||||
db, stop := testserver.NewDBForTest(t)
|
||||
defer stop()
|
||||
|
||||
initStmt := `
|
||||
CREATE DATABASE d;
|
||||
CREATE TABLE d.t (acct INT PRIMARY KEY, balance INT);
|
||||
INSERT INTO d.t (acct, balance) VALUES (1, 100), (2, 100);
|
||||
`
|
||||
if _, err := db.Exec(initStmt); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
type queryI interface {
|
||||
Query(string, ...interface{}) (*sql.Rows, error)
|
||||
}
|
||||
|
||||
getBalances := func(q queryI) (bal1, bal2 int, err error) {
|
||||
var rows *sql.Rows
|
||||
rows, err = q.Query(`SELECT balance FROM d.t WHERE acct IN (1, 2);`)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
balances := []*int{&bal1, &bal2}
|
||||
i := 0
|
||||
for ; rows.Next(); i += 1 {
|
||||
if err = rows.Scan(balances[i]); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if i != 2 {
|
||||
err = fmt.Errorf("expected two balances; got %d", i)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
runTxn := func(wg *sync.WaitGroup, iter *int) <-chan error {
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
*iter = 0
|
||||
errCh <- ExecuteTx(db, func(tx *sql.Tx) error {
|
||||
*iter++
|
||||
bal1, bal2, err := getBalances(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If this is the first iteration, wait for the other tx to also read.
|
||||
if *iter == 1 {
|
||||
wg.Done()
|
||||
wg.Wait()
|
||||
}
|
||||
// Now, subtract from one account and give to the other.
|
||||
if bal1 > bal2 {
|
||||
if _, err := tx.Exec(`
|
||||
UPDATE d.t SET balance=balance-100 WHERE acct=1;
|
||||
UPDATE d.t SET balance=balance+100 WHERE acct=2;
|
||||
`); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := tx.Exec(`
|
||||
UPDATE d.t SET balance=balance+100 WHERE acct=1;
|
||||
UPDATE d.t SET balance=balance-100 WHERE acct=2;
|
||||
`); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}()
|
||||
return errCh
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
var iters1, iters2 int
|
||||
txn1Err := runTxn(&wg, &iters1)
|
||||
txn2Err := runTxn(&wg, &iters2)
|
||||
if err := <-txn1Err; err != nil {
|
||||
t.Errorf("expected success in txn1; got %s", err)
|
||||
}
|
||||
if err := <-txn2Err; err != nil {
|
||||
t.Errorf("expected success in txn2; got %s", err)
|
||||
}
|
||||
if iters1+iters2 <= 2 {
|
||||
t.Errorf("expected at least one retry between the competing transactions; "+
|
||||
"got txn1=%d, txn2=%d", iters1, iters2)
|
||||
}
|
||||
bal1, bal2, err := getBalances(db)
|
||||
if err != nil || bal1 != 100 || bal2 != 100 {
|
||||
t.Errorf("expected balances to be restored without error; "+
|
||||
"got acct1=%d, acct2=%d: %s", bal1, bal2, err)
|
||||
}
|
||||
}
|
119
vendor/github.com/cockroachdb/cockroach-go/testserver/binaries.go
generated
vendored
Normal file
119
vendor/github.com/cockroachdb/cockroach-go/testserver/binaries.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
package testserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
awsBaseURL = "https://s3.amazonaws.com/cockroach/cockroach"
|
||||
latestSuffix = "LATEST"
|
||||
localBinaryPath = "/var/tmp"
|
||||
finishedFileMode = 0555
|
||||
)
|
||||
|
||||
func binaryName() string {
|
||||
return fmt.Sprintf("cockroach.%s-%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
func binaryNameWithSha(sha string) string {
|
||||
return fmt.Sprintf("%s.%s", binaryName(), sha)
|
||||
}
|
||||
|
||||
func binaryPath(sha string) string {
|
||||
return filepath.Join(localBinaryPath, binaryNameWithSha(sha))
|
||||
}
|
||||
|
||||
func latestMarkerURL() string {
|
||||
return fmt.Sprintf("%s/%s.%s", awsBaseURL, binaryName(), latestSuffix)
|
||||
}
|
||||
|
||||
func binaryURL(sha string) string {
|
||||
return fmt.Sprintf("%s/%s.%s", awsBaseURL, binaryName(), sha)
|
||||
}
|
||||
|
||||
func findLatestSha() (string, error) {
|
||||
markerURL := latestMarkerURL()
|
||||
marker, err := http.Get(markerURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not download %s: %s", markerURL)
|
||||
}
|
||||
if marker.StatusCode == 404 {
|
||||
return "", fmt.Errorf("for 404 from GET %s: make sure OS and ARCH are supported",
|
||||
markerURL)
|
||||
} else if marker.StatusCode != 200 {
|
||||
return "", fmt.Errorf("bad response got GET %s: %d (%s)",
|
||||
markerURL, marker.StatusCode, marker.Status)
|
||||
}
|
||||
|
||||
defer marker.Body.Close()
|
||||
body, err := ioutil.ReadAll(marker.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(string(body)), nil
|
||||
}
|
||||
|
||||
func downloadFile(url, filePath string) error {
|
||||
output, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0200)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating %s: %s", filePath, "-", err)
|
||||
}
|
||||
defer output.Close()
|
||||
|
||||
log.Printf("downloading %s to %s, this may take some time", url, filePath)
|
||||
|
||||
response, err := http.Get(url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error downloading %s: %s", url, err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
if response.StatusCode != 200 {
|
||||
return fmt.Errorf("error downloading %s: %d (%s)", url, response.StatusCode, response.Status)
|
||||
}
|
||||
|
||||
_, err = io.Copy(output, response.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("problem downloading %s to %s: %s", url, filePath, err)
|
||||
}
|
||||
|
||||
// Download was successful, add the rw bits.
|
||||
return os.Chmod(filePath, finishedFileMode)
|
||||
}
|
||||
|
||||
func downloadLatestBinary() (string, error) {
|
||||
sha, err := findLatestSha()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
localFile := binaryPath(sha)
|
||||
for {
|
||||
finfo, err := os.Stat(localFile)
|
||||
if err != nil {
|
||||
// File does not exist: download it.
|
||||
break
|
||||
}
|
||||
// File already present: check mode.
|
||||
if finfo.Mode().Perm() == finishedFileMode {
|
||||
return localFile, nil
|
||||
}
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
|
||||
err = downloadFile(binaryURL(sha), localFile)
|
||||
if err != nil {
|
||||
_ = os.Remove(localFile)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return localFile, nil
|
||||
}
|
415
vendor/github.com/cockroachdb/cockroach-go/testserver/testserver.go
generated
vendored
Normal file
415
vendor/github.com/cockroachdb/cockroach-go/testserver/testserver.go
generated
vendored
Normal file
@@ -0,0 +1,415 @@
|
||||
// Copyright 2016 The Cockroach 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.
|
||||
//
|
||||
// Author: Marc Berhault (marc@cockroachlabs.com)
|
||||
|
||||
// Package testserver provides helpers to run a cockroach binary within tests.
|
||||
// It automatically downloads the latest cockroach binary for your platform
|
||||
// (Linux-amd64 and Darwin-amd64 only for now), or attempts to run "cockroach"
|
||||
// from your PATH.
|
||||
//
|
||||
// A normal invocation is (check err every time):
|
||||
// ts, err := testserver.NewTestServer()
|
||||
// err = ts.Start()
|
||||
// defer ts.Stop()
|
||||
// url := ts.PGURL()
|
||||
//
|
||||
// To use, run as follows:
|
||||
// import "github.com/cockroachdb/cockroach-go/testserver"
|
||||
// import "testing"
|
||||
// import "time"
|
||||
//
|
||||
// func TestRunServer(t *testing.T) {
|
||||
// ts, err := testserver.NewTestServer()
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// err := ts.Start()
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// defer ts.Stop()
|
||||
//
|
||||
// url := ts.PGURL()
|
||||
// if url != nil {
|
||||
// t.FatalF("url not found")
|
||||
// }
|
||||
// t.Logf("URL: %s", url.String())
|
||||
//
|
||||
// db, err := sql.Open("postgres", url.String())
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// }
|
||||
package testserver
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var sqlURLRegexp = regexp.MustCompile("sql:\\s+(postgresql:.+)\n")
|
||||
|
||||
const (
|
||||
stateNew = iota
|
||||
stateRunning = iota
|
||||
stateStopped = iota
|
||||
stateFailed = iota
|
||||
|
||||
socketPort = 26257
|
||||
socketFileBase = ".s.PGSQL"
|
||||
)
|
||||
|
||||
// TestServer is a helper to run a real cockroach node.
|
||||
type TestServer struct {
|
||||
mu sync.RWMutex
|
||||
state int
|
||||
baseDir string
|
||||
pgURL *url.URL
|
||||
cmd *exec.Cmd
|
||||
args []string
|
||||
stdout string
|
||||
stderr string
|
||||
stdoutBuf logWriter
|
||||
stderrBuf logWriter
|
||||
}
|
||||
|
||||
// NewDBForTest creates a new CockroachDB TestServer instance and
|
||||
// opens a SQL database connection to it. Returns a sql *DB instance a
|
||||
// shutdown function. The caller is responsible for executing the
|
||||
// returned shutdown function on exit.
|
||||
func NewDBForTest(t *testing.T) (*sql.DB, func()) {
|
||||
return NewDBForTestWithDatabase(t, "")
|
||||
}
|
||||
|
||||
// NewDBForTestWithDatabase creates a new CockroachDB TestServer
|
||||
// instance and opens a SQL database connection to it. If database is
|
||||
// specified, the returned connection will explicitly connect to
|
||||
// it. Returns a sql *DB instance a shutdown function. The caller is
|
||||
// responsible for executing the returned shutdown function on exit.
|
||||
func NewDBForTestWithDatabase(t *testing.T, database string) (*sql.DB, func()) {
|
||||
ts, err := NewTestServer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ts.Start()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
url := ts.PGURL()
|
||||
if url == nil {
|
||||
t.Fatalf("url not found")
|
||||
}
|
||||
if len(database) > 0 {
|
||||
url.Path = database
|
||||
}
|
||||
|
||||
db, err := sql.Open("postgres", url.String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ts.WaitForInit(db)
|
||||
|
||||
return db, func() {
|
||||
_ = db.Close()
|
||||
ts.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
// NewTestServer creates a new TestServer, but does not start it.
|
||||
// The cockroach binary for your OS and ARCH is downloaded automatically.
|
||||
// If the download fails, we attempt just call "cockroach", hoping it is
|
||||
// found in your path.
|
||||
func NewTestServer() (*TestServer, error) {
|
||||
cockroachBinary, err := downloadLatestBinary()
|
||||
if err == nil {
|
||||
log.Printf("Using automatically-downloaded binary: %s", cockroachBinary)
|
||||
} else {
|
||||
log.Printf("Attempting to use cockroach binary from your PATH")
|
||||
cockroachBinary = "cockroach"
|
||||
}
|
||||
|
||||
// Force "/tmp/" so avoid OSX's really long temp directory names
|
||||
// which get us over the socket filename length limit.
|
||||
baseDir, err := ioutil.TempDir("/tmp", "cockroach-testserver")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create temp directory: %s", err)
|
||||
}
|
||||
|
||||
logDir := filepath.Join(baseDir, "logs")
|
||||
if err := os.MkdirAll(logDir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("could not create logs directory: %s: %s", logDir, err)
|
||||
}
|
||||
|
||||
options := url.Values{
|
||||
"host": []string{baseDir},
|
||||
}
|
||||
pgurl := &url.URL{
|
||||
Scheme: "postgres",
|
||||
User: url.User("root"),
|
||||
Host: fmt.Sprintf(":%d", socketPort),
|
||||
RawQuery: options.Encode(),
|
||||
}
|
||||
socketPath := filepath.Join(baseDir, fmt.Sprintf("%s.%d", socketFileBase, socketPort))
|
||||
|
||||
args := []string{
|
||||
cockroachBinary,
|
||||
"start",
|
||||
"--logtostderr",
|
||||
"--insecure",
|
||||
"--port=0",
|
||||
"--http-port=0",
|
||||
"--socket=" + socketPath,
|
||||
"--store=" + baseDir,
|
||||
}
|
||||
|
||||
ts := &TestServer{
|
||||
baseDir: baseDir,
|
||||
pgURL: pgurl,
|
||||
args: args,
|
||||
stdout: filepath.Join(logDir, "cockroach.stdout"),
|
||||
stderr: filepath.Join(logDir, "cockroach.stderr"),
|
||||
}
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
// Stdout returns the entire contents of the process' stdout.
|
||||
func (ts *TestServer) Stdout() string {
|
||||
return ts.stdoutBuf.String()
|
||||
}
|
||||
|
||||
// Stderr returns the entire contents of the process' stderr.
|
||||
func (ts *TestServer) Stderr() string {
|
||||
return ts.stderrBuf.String()
|
||||
}
|
||||
|
||||
// PGURL returns the postgres connection URL to reach the started
|
||||
// cockroach node.
|
||||
// It loops until the expected unix socket file exists.
|
||||
// This does not timeout, relying instead on test timeouts.
|
||||
func (ts *TestServer) PGURL() *url.URL {
|
||||
socketPath := filepath.Join(ts.baseDir, fmt.Sprintf("%s.%d", socketFileBase, socketPort))
|
||||
for {
|
||||
if _, err := os.Stat(socketPath); err == nil {
|
||||
return ts.pgURL
|
||||
}
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WaitForInit repeatedly looks up the list of databases until
|
||||
// the "system" database exists. It ignores all errors as we are
|
||||
// waiting for the process to start and complete initialization.
|
||||
// This does not timeout, relying instead on test timeouts.
|
||||
func (ts *TestServer) WaitForInit(db *sql.DB) {
|
||||
for {
|
||||
// We issue a query that fails both on connection errors and on the
|
||||
// system database not existing.
|
||||
if _, err := db.Query("SHOW DATABASES"); err == nil {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
}
|
||||
|
||||
// Start runs the process, returning an error on any problems,
|
||||
// including being unable to start, but not unexpected failure.
|
||||
// It should only be called once in the lifetime of a TestServer object.
|
||||
func (ts *TestServer) Start() error {
|
||||
ts.mu.Lock()
|
||||
if ts.state != stateNew {
|
||||
ts.mu.Unlock()
|
||||
return errors.New("Start() can only be called once")
|
||||
}
|
||||
ts.state = stateRunning
|
||||
ts.mu.Unlock()
|
||||
|
||||
ts.cmd = exec.Command(ts.args[0], ts.args[1:]...)
|
||||
ts.cmd.Env = []string{"COCKROACH_MAX_OFFSET=1ns"}
|
||||
|
||||
if len(ts.stdout) > 0 {
|
||||
wr, err := newFileLogWriter(ts.stdout)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to open file %s: %s", ts.stdout, err)
|
||||
}
|
||||
ts.stdoutBuf = wr
|
||||
}
|
||||
ts.cmd.Stdout = ts.stdoutBuf
|
||||
|
||||
if len(ts.stderr) > 0 {
|
||||
wr, err := newFileLogWriter(ts.stderr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to open file %s: %s", ts.stderr, err)
|
||||
}
|
||||
ts.stderrBuf = wr
|
||||
}
|
||||
ts.cmd.Stderr = ts.stderrBuf
|
||||
|
||||
for k, v := range defaultEnv() {
|
||||
ts.cmd.Env = append(ts.cmd.Env, k+"="+v)
|
||||
}
|
||||
|
||||
err := ts.cmd.Start()
|
||||
if ts.cmd.Process != nil {
|
||||
log.Printf("process %d started: %s", ts.cmd.Process.Pid, strings.Join(ts.args, " "))
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf(err.Error())
|
||||
ts.stdoutBuf.Close()
|
||||
ts.stderrBuf.Close()
|
||||
|
||||
ts.mu.Lock()
|
||||
ts.state = stateFailed
|
||||
ts.mu.Unlock()
|
||||
|
||||
return fmt.Errorf("failure starting process: %s", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
ts.cmd.Wait()
|
||||
|
||||
ts.stdoutBuf.Close()
|
||||
ts.stderrBuf.Close()
|
||||
|
||||
ps := ts.cmd.ProcessState
|
||||
sy := ps.Sys().(syscall.WaitStatus)
|
||||
|
||||
log.Printf("Process %d exited with status %d", ps.Pid(), sy.ExitStatus())
|
||||
log.Printf(ps.String())
|
||||
|
||||
ts.mu.Lock()
|
||||
if sy.ExitStatus() == 0 {
|
||||
ts.state = stateStopped
|
||||
} else {
|
||||
ts.state = stateFailed
|
||||
}
|
||||
ts.mu.Unlock()
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop kills the process if it is still running and cleans its directory.
|
||||
// It should only be called once in the lifetime of a TestServer object.
|
||||
// Logs fatal if the process has already failed.
|
||||
func (ts *TestServer) Stop() {
|
||||
ts.mu.RLock()
|
||||
defer ts.mu.RUnlock()
|
||||
|
||||
if ts.state == stateNew {
|
||||
log.Fatal("Stop() called, but Start() was never called")
|
||||
}
|
||||
if ts.state == stateFailed {
|
||||
log.Fatalf("Stop() called, but process exited unexpectedly. Stdout:\n%s\nStderr:\n%s\n",
|
||||
ts.Stdout(), ts.Stderr())
|
||||
return
|
||||
}
|
||||
|
||||
if ts.state != stateStopped {
|
||||
// Only call kill if not running. It could have exited properly.
|
||||
ts.cmd.Process.Kill()
|
||||
}
|
||||
|
||||
// Only cleanup on intentional stops.
|
||||
_ = os.RemoveAll(ts.baseDir)
|
||||
}
|
||||
|
||||
type logWriter interface {
|
||||
Write(p []byte) (n int, err error)
|
||||
String() string
|
||||
Len() int64
|
||||
Close()
|
||||
}
|
||||
|
||||
type fileLogWriter struct {
|
||||
filename string
|
||||
file *os.File
|
||||
}
|
||||
|
||||
func newFileLogWriter(file string) (*fileLogWriter, error) {
|
||||
f, err := os.Create(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &fileLogWriter{
|
||||
filename: file,
|
||||
file: f,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w fileLogWriter) Close() {
|
||||
w.file.Close()
|
||||
}
|
||||
|
||||
func (w fileLogWriter) Write(p []byte) (n int, err error) {
|
||||
return w.file.Write(p)
|
||||
}
|
||||
|
||||
func (w fileLogWriter) String() string {
|
||||
b, err := ioutil.ReadFile(w.filename)
|
||||
if err == nil {
|
||||
return string(b)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (w fileLogWriter) Len() int64 {
|
||||
s, err := os.Stat(w.filename)
|
||||
if err == nil {
|
||||
return s.Size()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func defaultEnv() map[string]string {
|
||||
vars := map[string]string{}
|
||||
u, err := user.Current()
|
||||
if err == nil {
|
||||
if _, ok := vars["USER"]; !ok {
|
||||
vars["USER"] = u.Username
|
||||
}
|
||||
if _, ok := vars["UID"]; !ok {
|
||||
vars["UID"] = u.Uid
|
||||
}
|
||||
if _, ok := vars["GID"]; !ok {
|
||||
vars["GID"] = u.Gid
|
||||
}
|
||||
if _, ok := vars["HOME"]; !ok {
|
||||
vars["HOME"] = u.HomeDir
|
||||
}
|
||||
}
|
||||
if _, ok := vars["PATH"]; !ok {
|
||||
vars["PATH"] = os.Getenv("PATH")
|
||||
}
|
||||
return vars
|
||||
}
|
35
vendor/github.com/cockroachdb/cockroach-go/testserver/testserver_test.go
generated
vendored
Normal file
35
vendor/github.com/cockroachdb/cockroach-go/testserver/testserver_test.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2016 The Cockroach 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.
|
||||
//
|
||||
// Author: Marc Berhault (marc@cockroachlabs.com)
|
||||
|
||||
package testserver_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
// Needed for postgres driver test.
|
||||
"github.com/cockroachdb/cockroach-go/testserver"
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
func TestRunServer(t *testing.T) {
|
||||
db, stop := testserver.NewDBForTest(t)
|
||||
defer stop()
|
||||
|
||||
_, err := db.Exec("SELECT 1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user