├── .codecov.yml ├── .github └── workflows │ ├── xenon-build.yml │ ├── xenon-coverage.yml │ └── xenon-test.yml ├── .gitignore ├── LICENSE ├── README.md ├── conf ├── xenon-sample.conf.json └── xenon-simple.conf.json ├── docs ├── advanced_article.md ├── config │ ├── 192.168.0.11_keepalived.md │ ├── 192.168.0.11_xenon.md │ ├── 192.168.0.2_keepalived.md │ ├── 192.168.0.2_xenon.md │ ├── 192.168.0.3_xenon.md │ ├── MySQL.md │ └── xenon-simple.conf.json ├── config_template.md ├── how_to_build_and_run_xenon.md ├── how_xenon_upgrades.md ├── how_xenon_works.md ├── images │ └── xenon.png └── xenoncli_commands.md ├── makefile └── src ├── build ├── info.go └── ldflags.sh ├── cli ├── callx │ └── callx.go ├── cli.go └── cmd │ ├── cluster.go │ ├── cluster_test.go │ ├── common.go │ ├── init.go │ ├── mock.go │ ├── mysql.go │ ├── mysql_test.go │ ├── perf.go │ ├── raft.go │ ├── raft_test.go │ ├── version.go │ ├── xenon.go │ └── xenon_test.go ├── config ├── config.go └── config_test.go ├── ctl ├── admin.go ├── router.go └── v1 │ ├── cluster.go │ ├── cluster_test.go │ ├── raft.go │ ├── raft_test.go │ ├── xenon.go │ └── xenon_test.go ├── model ├── backup.go ├── error.go ├── ha.go ├── mysql.go ├── mysqld.go ├── node.go ├── raft.go └── server.go ├── mysql ├── api.go ├── api_test.go ├── attr.go ├── db.go ├── db_test.go ├── mock.go ├── mysql.go ├── mysql56.go ├── mysql56_test.go ├── mysql57.go ├── mysql57_test.go ├── mysql80.go ├── mysql80_test.go ├── mysql_handler.go ├── mysql_test.go ├── mysqlbase.go ├── mysqlbase_test.go ├── rpc_mysql.go ├── rpc_mysql_test.go └── stats.go ├── mysqld ├── args_handler.go ├── backup.go ├── backup_test.go ├── linux_args.go ├── linux_args_test.go ├── mock.go ├── mysqld.go ├── mysqld_test.go ├── rpc_backup.go ├── rpc_backup_test.go ├── rpc_mysqld.go ├── rpc_mysqld_test.go └── stats.go ├── raft ├── api.go ├── attr.go ├── candidate.go ├── cmd.go ├── follower.go ├── idle.go ├── invalid.go ├── leader.go ├── learner.go ├── mock.go ├── peer.go ├── peersjson.go ├── peersjson_test.go ├── raft.go ├── raft_test.go ├── rpc_ha.go ├── rpc_ha_test.go ├── rpc_raft.go ├── rpc_raft_test.go ├── stats.go └── trace.go ├── server ├── mock.go ├── rpc_node.go ├── rpc_node_test.go ├── rpc_server.go ├── rpc_server_test.go ├── rpc_user.go ├── rpc_user_test.go ├── server.go ├── server_test.go └── stats.go ├── vendor ├── github.com │ ├── ant0ine │ │ └── go-json-rest │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ └── rest │ │ │ ├── access_log_apache.go │ │ │ ├── access_log_apache_test.go │ │ │ ├── access_log_json.go │ │ │ ├── access_log_json_test.go │ │ │ ├── api.go │ │ │ ├── api_test.go │ │ │ ├── auth_basic.go │ │ │ ├── auth_basic_test.go │ │ │ ├── content_type_checker.go │ │ │ ├── content_type_checker_test.go │ │ │ ├── cors.go │ │ │ ├── cors_test.go │ │ │ ├── doc.go │ │ │ ├── gzip.go │ │ │ ├── gzip_test.go │ │ │ ├── if.go │ │ │ ├── if_test.go │ │ │ ├── json_indent.go │ │ │ ├── json_indent_test.go │ │ │ ├── jsonp.go │ │ │ ├── jsonp_test.go │ │ │ ├── middleware.go │ │ │ ├── middleware_test.go │ │ │ ├── powered_by.go │ │ │ ├── powered_by_test.go │ │ │ ├── recorder.go │ │ │ ├── recorder_test.go │ │ │ ├── recover.go │ │ │ ├── recover_test.go │ │ │ ├── request.go │ │ │ ├── request_test.go │ │ │ ├── response.go │ │ │ ├── response_test.go │ │ │ ├── route.go │ │ │ ├── route_test.go │ │ │ ├── router.go │ │ │ ├── router_benchmark_test.go │ │ │ ├── router_test.go │ │ │ ├── status.go │ │ │ ├── status_test.go │ │ │ ├── test │ │ │ ├── doc.go │ │ │ └── util.go │ │ │ ├── timer.go │ │ │ ├── timer_test.go │ │ │ └── trie │ │ │ ├── impl.go │ │ │ └── impl_test.go │ ├── go-sql-driver │ │ └── mysql │ │ │ ├── .travis.yml │ │ │ ├── AUTHORS │ │ │ ├── CHANGELOG.md │ │ │ ├── CONTRIBUTING.md │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── appengine.go │ │ │ ├── auth.go │ │ │ ├── auth_test.go │ │ │ ├── benchmark_go18_test.go │ │ │ ├── benchmark_test.go │ │ │ ├── buffer.go │ │ │ ├── collations.go │ │ │ ├── connection.go │ │ │ ├── connection_go18.go │ │ │ ├── connection_go18_test.go │ │ │ ├── connection_test.go │ │ │ ├── const.go │ │ │ ├── driver.go │ │ │ ├── driver_go18_test.go │ │ │ ├── driver_test.go │ │ │ ├── dsn.go │ │ │ ├── dsn_test.go │ │ │ ├── errors.go │ │ │ ├── errors_test.go │ │ │ ├── fields.go │ │ │ ├── infile.go │ │ │ ├── packets.go │ │ │ ├── packets_test.go │ │ │ ├── result.go │ │ │ ├── rows.go │ │ │ ├── statement.go │ │ │ ├── statement_test.go │ │ │ ├── transaction.go │ │ │ ├── utils.go │ │ │ ├── utils_go17.go │ │ │ ├── utils_go18.go │ │ │ ├── utils_go18_test.go │ │ │ └── utils_test.go │ ├── mattn │ │ └── go-runewidth │ │ │ ├── .travis.yml │ │ │ ├── README.mkd │ │ │ ├── runewidth.go │ │ │ ├── runewidth_js.go │ │ │ ├── runewidth_posix.go │ │ │ ├── runewidth_test.go │ │ │ └── runewidth_windows.go │ ├── olekukonko │ │ └── tablewriter │ │ │ ├── .travis.yml │ │ │ ├── LICENCE.md │ │ │ ├── README.md │ │ │ ├── csv.go │ │ │ ├── csv2table │ │ │ ├── README.md │ │ │ └── csv2table.go │ │ │ ├── table.go │ │ │ ├── table_test.go │ │ │ ├── test.csv │ │ │ ├── test_info.csv │ │ │ ├── util.go │ │ │ ├── wrap.go │ │ │ └── wrap_test.go │ ├── pierrre │ │ └── gotestcover │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── gotestcover.go │ │ │ └── gotestcover_test.go │ ├── pkg │ │ └── errors │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── appveyor.yml │ │ │ ├── bench_test.go │ │ │ ├── errors.go │ │ │ ├── errors_test.go │ │ │ ├── example_test.go │ │ │ ├── format_test.go │ │ │ ├── stack.go │ │ │ └── stack_test.go │ ├── spf13 │ │ ├── cobra │ │ │ ├── .gitignore │ │ │ ├── .mailmap │ │ │ ├── .travis.yml │ │ │ ├── LICENSE.txt │ │ │ ├── README.md │ │ │ ├── bash_completions.go │ │ │ ├── bash_completions.md │ │ │ ├── bash_completions_test.go │ │ │ ├── cobra.go │ │ │ ├── cobra │ │ │ │ ├── cmd │ │ │ │ │ ├── add.go │ │ │ │ │ ├── helpers.go │ │ │ │ │ ├── helpers_test.go │ │ │ │ │ ├── init.go │ │ │ │ │ ├── licenses.go │ │ │ │ │ └── root.go │ │ │ │ └── main.go │ │ │ ├── cobra_test.go │ │ │ ├── command.go │ │ │ ├── command_notwin.go │ │ │ ├── command_test.go │ │ │ ├── command_win.go │ │ │ └── doc │ │ │ │ ├── cmd_test.go │ │ │ │ ├── man_docs.go │ │ │ │ ├── man_docs.md │ │ │ │ ├── man_docs_test.go │ │ │ │ ├── man_examples_test.go │ │ │ │ ├── md_docs.go │ │ │ │ ├── md_docs.md │ │ │ │ ├── md_docs_test.go │ │ │ │ └── util.go │ │ └── pflag │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── bool.go │ │ │ ├── bool_test.go │ │ │ ├── count.go │ │ │ ├── count_test.go │ │ │ ├── duration.go │ │ │ ├── example_test.go │ │ │ ├── export_test.go │ │ │ ├── flag.go │ │ │ ├── flag_test.go │ │ │ ├── float32.go │ │ │ ├── float64.go │ │ │ ├── golangflag.go │ │ │ ├── golangflag_test.go │ │ │ ├── int.go │ │ │ ├── int32.go │ │ │ ├── int64.go │ │ │ ├── int8.go │ │ │ ├── int_slice.go │ │ │ ├── int_slice_test.go │ │ │ ├── ip.go │ │ │ ├── ip_test.go │ │ │ ├── ipmask.go │ │ │ ├── ipnet.go │ │ │ ├── ipnet_test.go │ │ │ ├── string.go │ │ │ ├── string_array.go │ │ │ ├── string_array_test.go │ │ │ ├── string_slice.go │ │ │ ├── string_slice_test.go │ │ │ ├── uint.go │ │ │ ├── uint16.go │ │ │ ├── uint32.go │ │ │ ├── uint64.go │ │ │ ├── uint8.go │ │ │ └── verify │ │ │ ├── all.sh │ │ │ ├── gofmt.sh │ │ │ └── golint.sh │ └── stretchr │ │ └── testify │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── Godeps │ │ ├── Godeps.json │ │ └── Readme │ │ ├── LICENCE.txt │ │ ├── LICENSE │ │ ├── README.md │ │ ├── _codegen │ │ └── main.go │ │ ├── assert │ │ ├── assertion_forward.go │ │ ├── assertion_forward.go.tmpl │ │ ├── assertions.go │ │ ├── assertions_test.go │ │ ├── doc.go │ │ ├── errors.go │ │ ├── forward_assertions.go │ │ ├── forward_assertions_test.go │ │ ├── http_assertions.go │ │ └── http_assertions_test.go │ │ ├── doc.go │ │ ├── http │ │ ├── doc.go │ │ ├── test_response_writer.go │ │ └── test_round_tripper.go │ │ ├── mock │ │ ├── doc.go │ │ ├── mock.go │ │ └── mock_test.go │ │ ├── package_test.go │ │ ├── require │ │ ├── doc.go │ │ ├── forward_requirements.go │ │ ├── forward_requirements_test.go │ │ ├── require.go │ │ ├── require.go.tmpl │ │ ├── require_forward.go │ │ ├── require_forward.go.tmpl │ │ ├── requirements.go │ │ └── requirements_test.go │ │ ├── suite │ │ ├── doc.go │ │ ├── interfaces.go │ │ ├── suite.go │ │ └── suite_test.go │ │ └── vendor │ │ └── github.com │ │ ├── davecgh │ │ └── go-spew │ │ │ ├── LICENSE │ │ │ └── spew │ │ │ ├── bypass.go │ │ │ ├── bypasssafe.go │ │ │ ├── common.go │ │ │ ├── config.go │ │ │ ├── doc.go │ │ │ ├── dump.go │ │ │ ├── format.go │ │ │ └── spew.go │ │ ├── pmezard │ │ └── go-difflib │ │ │ ├── LICENSE │ │ │ └── difflib │ │ │ └── difflib.go │ │ └── stretchr │ │ └── objx │ │ ├── .gitignore │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── accessors.go │ │ ├── codegen │ │ ├── array-access.txt │ │ ├── index.html │ │ ├── template.txt │ │ └── types_list.txt │ │ ├── constants.go │ │ ├── conversions.go │ │ ├── doc.go │ │ ├── map.go │ │ ├── mutations.go │ │ ├── security.go │ │ ├── tests.go │ │ ├── type_specific_codegen.go │ │ └── value.go └── gopkg.in │ └── DATA-DOG │ └── go-sqlmock.v1 │ ├── .gitignore │ ├── .travis.yml │ ├── LICENSE │ ├── README.md │ ├── argument.go │ ├── argument_test.go │ ├── driver.go │ ├── driver_test.go │ ├── examples │ ├── basic │ │ ├── basic.go │ │ └── basic_test.go │ ├── blog │ │ ├── blog.go │ │ └── blog_test.go │ ├── doc.go │ └── orders │ │ ├── orders.go │ │ └── orders_test.go │ ├── expectations.go │ ├── expectations_test.go │ ├── result.go │ ├── result_test.go │ ├── rows.go │ ├── rows_test.go │ ├── sqlmock.go │ ├── sqlmock_test.go │ ├── statement.go │ ├── statement_test.go │ ├── stubs_test.go │ ├── util.go │ └── util_test.go ├── xbase ├── common │ ├── common.go │ ├── common_test.go │ ├── handler.go │ ├── linux.go │ ├── linux_test.go │ └── mock.go ├── xlog │ ├── options.go │ ├── xlog.go │ └── xlog_test.go └── xrpc │ ├── options.go │ ├── xrpc.go │ └── xrpc_test.go └── xenon └── xenon.go /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | precision: 0 3 | round: down 4 | range: "70...100" 5 | status: 6 | project: 7 | default: 8 | enabled: yes 9 | threshold: 1% 10 | patch: 11 | default: 12 | enabled: no 13 | threshold: 1% 14 | -------------------------------------------------------------------------------- /.github/workflows/xenon-build.yml: -------------------------------------------------------------------------------- 1 | name: Xenon Build 2 | on: [push, pull_request] 3 | jobs: 4 | 5 | build: 6 | name: Build 7 | runs-on: ubuntu-latest 8 | steps: 9 | 10 | - name: Set up Go 1.13 11 | uses: actions/setup-go@v1 12 | with: 13 | go-version: 1.13 14 | id: go 15 | 16 | - name: Check out code 17 | uses: actions/checkout@v2 18 | 19 | - name: Build 20 | run: | 21 | export PATH=$PATH:$(go env GOPATH)/bin 22 | make build 23 | -------------------------------------------------------------------------------- /.github/workflows/xenon-coverage.yml: -------------------------------------------------------------------------------- 1 | name: Xenon Coverage 2 | on: [push, pull_request] 3 | jobs: 4 | 5 | coverage: 6 | name: Coverage 7 | runs-on: ubuntu-latest 8 | steps: 9 | 10 | - name: Set up Go 1.13 11 | uses: actions/setup-go@v1 12 | with: 13 | go-version: 1.13 14 | id: go 15 | 16 | - name: Check out code 17 | uses: actions/checkout@v2 18 | 19 | - name: Coverage 20 | run: | 21 | export PATH=$PATH:$(go env GOPATH)/bin 22 | make coverage 23 | bash <(curl -s https://codecov.io/bash) -f "!mock.go" -t f05df45a-c970-448b-b4ac-79a628014441 24 | -------------------------------------------------------------------------------- /.github/workflows/xenon-test.yml: -------------------------------------------------------------------------------- 1 | name: Xenon Test 2 | on: [push, pull_request] 3 | jobs: 4 | 5 | test: 6 | name: Test 7 | runs-on: ubuntu-latest 8 | steps: 9 | 10 | - name: Set up Go 1.13 11 | uses: actions/setup-go@v1 12 | with: 13 | go-version: 1.13 14 | id: go 15 | 16 | - name: Check out code 17 | uses: actions/checkout@v2 18 | 19 | - name: Test 20 | run: | 21 | export PATH=$PATH:$(go env GOPATH)/bin 22 | make test 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | pkg/* 3 | rdb-* 4 | testdir 5 | coverage* 6 | peers.json 7 | config.path 8 | *.outs 9 | tags 10 | .vscode 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Github Actions Status](https://github.com/radondb/xenon/workflows/Xenon%20Build/badge.svg?event=push)](https://github.com/radondb/xenon/actions?query=workflow%3A%22Xenon+Build%22+event%3Apush) 2 | [![Github Actions Status](https://github.com/radondb/xenon/workflows/Xenon%20Test/badge.svg?event=push)](https://github.com/radondb/xenon/actions?query=workflow%3A%22Xenon+Test%22+event%3Apush) 3 | [![Github Actions Status](https://github.com/radondb/xenon/workflows/Xenon%20Coverage/badge.svg)](https://github.com/radondb/xenon/actions?query=workflow%3A%22Xenon+Coverage%22) 4 | [![Go Report Card](https://goreportcard.com/badge/github.com/radondb/xenon)](https://goreportcard.com/report/github.com/radondb/xenon) 5 | [![codecov.io](https://codecov.io/gh/radondb/xenon/graphs/badge.svg)](https://codecov.io/gh/radondb/xenon/branch/master) 6 | 7 | # Xenon 8 | 9 | ## Overview 10 | 11 | `Xenon` is a MySQL HA and Replication Management tool using Raft protocol. 12 | 13 | Xenon has many cool features, such as: 14 | 15 | * Fast Failover with no lost transactions 16 | * Streaming & Speed-Unmatched backup/restore 17 | * MySQL Operation and Maintenance 18 | * No central control and easy-to-deploy 19 | * As a Cloud App 20 | 21 | ## Architecture 22 | 23 | ![](docs/images/xenon.png) 24 | 25 | ## Documentation 26 | 27 | - [build and run xenon](docs/how_to_build_and_run_xenon.md) : How to build and run xenon. 28 | - [xenon cli commands](docs/xenoncli_commands.md) : Xenon client commands. 29 | - [how xenon works](docs/how_xenon_works.md) : How xenon works. 30 | - [how xenon upgrades](docs/how_xenon_upgrades.md): How xenon upgrades. 31 | 32 | ## Use case 33 | 34 | Xenon is production ready, it has been used in production like: 35 | - [MySQL Plus](https://www.qingcloud.com/products/mysql-plus/) - A Highly Available MySQL Clusters 36 | - [RadonDB](https://www.qingcloud.com/products/radondb) - A cloud-native MySQL database for building global, scalable cloud services 37 | 38 | ## Issues 39 | 40 | The [integrated github issue tracker](https://github.com/radondb/xenon/issues) 41 | is used for this project. 42 | 43 | ## License 44 | 45 | Xenon is released under the GPLv3. See [LICENSE](LICENSE) 46 | -------------------------------------------------------------------------------- /conf/xenon-sample.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": 3 | { 4 | "endpoint":"${YOUR-HOST}:8801" 5 | }, 6 | 7 | "raft": 8 | { 9 | "meta-datadir":"raft.meta", 10 | "leader-start-command":"${YOUR-LEADER-START-COMMAND}", 11 | "leader-stop-command":"${YOUR-LEADER-STOP-COMMAND}" 12 | }, 13 | 14 | "mysql": 15 | { 16 | "admin":"root", 17 | "version":"mysql80", 18 | "passwd":"", 19 | "host":"localhost", 20 | "port":"${YOUR-MYSQL-PORT}", 21 | "basedir":"${YOUR-MYSQL-BIN-DIR}", 22 | "defaults-file":"${YOUR-MYSQL-CNF-PATH}" 23 | }, 24 | 25 | "replication": 26 | { 27 | "user":"${YOUR-MYSQL-REPL-USER}", 28 | "passwd":"${YOUR-MYSQL-REPL-PWD}" 29 | }, 30 | 31 | "backup": 32 | { 33 | "ssh-host":"%{YOUR-HOST}", 34 | "ssh-user":"${YOUR-SSH-USER}", 35 | "ssh-passwd":"${YOUR-SSH-PWD}", 36 | "basedir":"${YOUR-MYSQL-BIN-DIR}", 37 | "backupdir":"${YOUR-BACKUP-DIR}", 38 | "xtrabackup-bindir":"${YOUR-XTRABACKUP-BIN-DIR}", 39 | "max-allowed-local-trx-count": "${YOUR-MAX-ALLOWED-LOCAL-TRX-COUNT}" 40 | }, 41 | 42 | "rpc": 43 | { 44 | "request-timeout":500 45 | }, 46 | 47 | "log": 48 | { 49 | "level":"INFO" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /conf/xenon-simple.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": 3 | { 4 | "endpoint":"192.168.0.1:8801" 5 | }, 6 | 7 | "raft": 8 | { 9 | "meta-datadir":"raft.meta", 10 | "heartbeat-timeout":1000, 11 | "election-timeout":3000, 12 | "leader-start-command":"", 13 | "leader-stop-command":"" 14 | }, 15 | 16 | "mysql": 17 | { 18 | "admin":"root", 19 | "passwd":"", 20 | "host":"127.0.0.1", 21 | "port":3306, 22 | "basedir":"/home/ubuntu/mysql_20161216", 23 | "defaults-file":"/etc/my3306.cnf", 24 | "ping-timeout":1000, 25 | "master-sysvars":"tokudb_fsync_log_period=default;sync_binlog=default;innodb_flush_log_at_trx_commit=default", 26 | "slave-sysvars": "tokudb_fsync_log_period=1000;sync_binlog=1000;innodb_flush_log_at_trx_commit=2" 27 | }, 28 | 29 | "replication": 30 | { 31 | "user":"repl", 32 | "passwd":"repl" 33 | }, 34 | 35 | "backup": 36 | { 37 | "ssh-host":"192.168.0.1", 38 | "ssh-user":"ubuntu", 39 | "ssh-passwd":"ubuntu", 40 | "ssh-port":22, 41 | "backupdir":"/home/ubuntu/data3306", 42 | "xtrabackup-bindir":"/home/ubuntu/xtrabackup_20161216", 43 | "backup-iops-limits":100000, 44 | "backup-use-memory": "2GB", 45 | "backup-parallel": 2 46 | }, 47 | 48 | "rpc": 49 | { 50 | "request-timeout":500 51 | }, 52 | 53 | "log": 54 | { 55 | "level":"INFO" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /docs/config/192.168.0.11_keepalived.md: -------------------------------------------------------------------------------- 1 | ``` 2 | global_defs { 3 | router_id 192.168.0.252 4 | } 5 | 6 | vrrp_instance VI_1 { 7 | state BACKUP 8 | 9 | interface eth0 10 | virtual_router_id 100 11 | priority 201 12 | 13 | 14 | unicast_src_ip 192.168.0.11 15 | unicast_peer { 16 | 192.168.0.2 17 | 192.168.0.3 18 | 19 | } 20 | 21 | 22 | advert_int 2 23 | authentication { 24 | auth_type PASS 25 | auth_pass pass 26 | } 27 | virtual_ipaddress { 28 | 192.168.0.252 29 | } 30 | } 31 | virtual_server fwmark 1 { 32 | delay_loop 3 33 | lb_algo rr 34 | lb_kind DR 35 | nat_mask 255.255.255.0 36 | protocol TCP 37 | 38 | 39 | real_server 192.168.0.11 3306 { 40 | weight 1 41 | TCP_CHECK { 42 | connect_timeout 5 43 | nb_get_retry 3 44 | delay_before_retry 3 45 | } 46 | } 47 | 48 | real_server 192.168.0.2 3306 { 49 | weight 1 50 | TCP_CHECK { 51 | connect_timeout 5 52 | nb_get_retry 3 53 | delay_before_retry 3 54 | } 55 | } 56 | 57 | real_server 192.168.0.3 3306 { 58 | weight 1 59 | TCP_CHECK { 60 | connect_timeout 5 61 | nb_get_retry 3 62 | delay_before_retry 3 63 | } 64 | } 65 | } 66 | ``` 67 | -------------------------------------------------------------------------------- /docs/config/192.168.0.11_xenon.md: -------------------------------------------------------------------------------- 1 | ``` 2 | { 3 | "server": 4 | { 5 | "endpoint":"192.168.0.11:8801" 6 | }, 7 | 8 | "raft": 9 | { 10 | "meta-datadir":"/data/raft", 11 | "leader-start-command":"ip a a 192.168.0.253/32 dev eth0 && sudo arping -c 3 -A 192.16.0.253 -I eth0", 12 | "leader-stop-command":"ip a d 192.168.0.253/32 dev eth0" 13 | }, 14 | 15 | "mysql": 16 | { 17 | "admin":"root", 18 | "passwd":"123456", 19 | "host":"localhost", 20 | "port":3306, 21 | "basedir":"/usr/bin", 22 | "defaults-file":"/etc/mysql/mysql.conf.d/mysqld.cnf" 23 | }, 24 | 25 | "replication": 26 | { 27 | "user":"repl", 28 | "passwd":"repl" 29 | }, 30 | 31 | "backup": 32 | { 33 | "ssh-host":"192.168.0.11", 34 | "ssh-user":"ubuntu", 35 | "ssh-passwd":"", 36 | "basedir":"/usr", 37 | "backupdir":"/data/mysql", 38 | "xtrabackup-bindir":"/opt/xtrabackup/bin" 39 | }, 40 | 41 | "rpc": 42 | { 43 | "request-timeout":500 44 | }, 45 | 46 | "log": 47 | { 48 | "level":"INFO" 49 | } 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/config/192.168.0.2_keepalived.md: -------------------------------------------------------------------------------- 1 | ``` 2 | global_defs { 3 | router_id 192.168.0.252 4 | } 5 | 6 | vrrp_instance VI_1 { 7 | state BACKUP 8 | 9 | interface eth0 10 | virtual_router_id 100 11 | priority 200 12 | 13 | 14 | unicast_src_ip 192.168.0.2 15 | unicast_peer { 16 | 192.168.0.3 17 | 192.168.0.11 18 | } 19 | 20 | 21 | advert_int 2 22 | authentication { 23 | auth_type PASS 24 | auth_pass pass 25 | } 26 | virtual_ipaddress { 27 | 192.168.0.252 28 | } 29 | } 30 | virtual_server fwmark 1 { 31 | delay_loop 3 32 | lb_algo rr 33 | lb_kind DR 34 | nat_mask 255.255.255.0 35 | protocol TCP 36 | 37 | 38 | real_server 192.168.0.2 3306 { 39 | weight 1 40 | TCP_CHECK { 41 | connect_timeout 5 42 | nb_get_retry 3 43 | delay_before_retry 3 44 | } 45 | } 46 | 47 | real_server 192.168.0.3 3306 { 48 | weight 1 49 | TCP_CHECK { 50 | connect_timeout 5 51 | nb_get_retry 3 52 | delay_before_retry 3 53 | } 54 | } 55 | 56 | 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /docs/config/192.168.0.2_xenon.md: -------------------------------------------------------------------------------- 1 | ``` 2 | { 3 | "server": 4 | { 5 | "endpoint":"192.168.0.2:8801" 6 | }, 7 | 8 | "raft": 9 | { 10 | "meta-datadir":"/data/raft", 11 | "leader-start-command":"ip a a 192.168.0.253/32 dev eth0 && sudo arping -c 3 -A 192.16.0.253 -I eth0", 12 | "leader-stop-command":"ip a d 192.168.0.253/32 dev eth0" 13 | }, 14 | 15 | "mysql": 16 | { 17 | "admin":"root", 18 | "passwd":"123456", 19 | "host":"localhost", 20 | "port":3306, 21 | "basedir":"/usr/bin", 22 | "defaults-file":"/etc/mysql/mysql.conf.d/mysqld.cnf" 23 | }, 24 | 25 | "replication": 26 | { 27 | "user":"repl", 28 | "passwd":"repl" 29 | }, 30 | 31 | "backup": 32 | { 33 | "ssh-host":"192.168.0.11", 34 | "ssh-user":"ubuntu", 35 | "ssh-passwd":"", 36 | "basedir":"/usr", 37 | "backupdir":"/data/mysql", 38 | "xtrabackup-bindir":"/opt/xtrabackup/bin" 39 | }, 40 | 41 | "rpc": 42 | { 43 | "request-timeout":500 44 | }, 45 | 46 | "log": 47 | { 48 | "level":"INFO" 49 | } 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/config/192.168.0.3_xenon.md: -------------------------------------------------------------------------------- 1 | ``` 2 | { 3 | "server": 4 | { 5 | "endpoint":"192.168.0.3:8801" 6 | }, 7 | 8 | "raft": 9 | { 10 | "meta-datadir":"/data/raft", 11 | "leader-start-command":"sudo ip a a 192.168.0.253/32 dev eth0 && sudo arping -c 3 -A 192.16.0.253 -I eth0", 12 | "leader-stop-command":"sudo ip a d 192.168.0.253/32 dev eth0" 13 | }, 14 | 15 | "mysql": 16 | { 17 | "admin":"root", 18 | "passwd":"123456", 19 | "host":"localhost", 20 | "port":3306, 21 | "basedir":"/usr/bin", 22 | "defaults-file":"/etc/mysql/mysql.conf.d/mysqld.cnf" 23 | }, 24 | 25 | "replication": 26 | { 27 | "user":"repl", 28 | "passwd":"repl" 29 | }, 30 | 31 | "backup": 32 | { 33 | "ssh-host":"192.168.0.11", 34 | "ssh-user":"ubuntu", 35 | "ssh-passwd":"", 36 | "basedir":"/usr", 37 | "backupdir":"/data/mysql", 38 | "xtrabackup-bindir":"/opt/xtrabackup/bin" 39 | }, 40 | 41 | "rpc": 42 | { 43 | "request-timeout":500 44 | }, 45 | 46 | "log": 47 | { 48 | "level":"INFO" 49 | } 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/config/MySQL.md: -------------------------------------------------------------------------------- 1 | ``` 2 | [mysqld_safe] 3 | socket = /tmp/mysql.sock 4 | nice = 0 5 | [mysqld] 6 | user = mysql 7 | pid-file = /tmp/mysql.pid 8 | socket = /tmp/mysql.sock 9 | port = 3306 10 | basedir = /usr 11 | datadir = /var/lib/mysql 12 | tmpdir = /tmp 13 | lc-messages-dir = /usr/share/mysql 14 | skip-external-locking 15 | key_buffer_size = 16M 16 | max_allowed_packet = 16M 17 | thread_stack = 192K 18 | thread_cache_size = 8 19 | myisam-recover-options = BACKUP 20 | query_cache_limit = 1M 21 | query_cache_size = 16M 22 | log_error = /var/log/mysql/error.log 23 | server-id=12 24 | log_bin = /var/log/mysql/mysql-bin.log 25 | expire_logs_days = 10 26 | max_binlog_size = 100M 27 | read_only = ON 28 | plugin-load="semisync_master.so;semisync_slave.so" 29 | rpl_semi_sync_master_enabled=OFF 30 | rpl_semi_sync_slave_enabled=ON 31 | rpl_semi_sync_master_wait_no_slave=ON 32 | rpl_semi_sync_master_timeout=1000000000000000000 33 | skip-slave-start 34 | gtid-mode = ON 35 | enforce-gtid-consistency = ON 36 | slave_parallel_type = LOGICAL_CLOCK 37 | slave_parallel_workers=64 38 | log-slave-updates 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/config/xenon-simple.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": 3 | { 4 | "endpoint":"192.168.0.1:8801" 5 | }, 6 | 7 | "raft": 8 | { 9 | "meta-datadir":"raft.meta", 10 | "heartbeat-timeout":1000, 11 | "election-timeout":3000, 12 | "leader-start-command":"", 13 | "leader-stop-command":"" 14 | }, 15 | 16 | "mysql": 17 | { 18 | "admin":"root", 19 | "passwd":"", 20 | "host":"127.0.0.1", 21 | "port":3306, 22 | "basedir":"/home/ubuntu/mysql_20161216", 23 | "defaults-file":"/etc/my3306.cnf", 24 | "ping-timeout":1000, 25 | "master-sysvars":"tokudb_fsync_log_period=default;sync_binlog=default;innodb_flush_log_at_trx_commit=default", 26 | "slave-sysvars": "tokudb_fsync_log_period=1000;sync_binlog=1000;innodb_flush_log_at_trx_commit=2" 27 | }, 28 | 29 | "replication": 30 | { 31 | "user":"repl", 32 | "passwd":"repl" 33 | }, 34 | 35 | "backup": 36 | { 37 | "ssh-host":"192.168.0.1", 38 | "ssh-user":"ubuntu", 39 | "ssh-passwd":"ubuntu", 40 | "ssh-port":22, 41 | "backupdir":"/home/ubuntu/data3306", 42 | "xtrabackup-bindir":"/home/ubuntu/xtrabackup_20161216", 43 | "backup-iops-limits":100000, 44 | "backup-use-memory": "2GB", 45 | "backup-parallel": 2, 46 | "max-allowed-local-trx-count": 0 47 | }, 48 | 49 | "rpc": 50 | { 51 | "request-timeout":500 52 | }, 53 | 54 | "log": 55 | { 56 | "level":"INFO" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /docs/images/xenon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radondb/xenon/bae9e0de5a3bd41a15ce49bc12a078e351e5b2b7/docs/images/xenon.png -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | PREFIX :=/usr/local 2 | export GOPATH := $(shell pwd) 3 | export PATH := $(GOPATH)/bin:$(PATH) 4 | 5 | build: LDFLAGS += $(shell GOPATH=${GOPATH} src/build/ldflags.sh) 6 | build: 7 | @echo "--> Building..." 8 | @mkdir -p bin/ 9 | go build -v -o bin/xenon --ldflags '$(LDFLAGS)' src/xenon/xenon.go 10 | go build -v -o bin/xenoncli --ldflags '$(LDFLAGS)' src/cli/cli.go 11 | @chmod 755 bin/* 12 | 13 | clean: 14 | @echo "--> Cleaning..." 15 | @mkdir -p bin/ 16 | @go clean 17 | @rm -f bin/* 18 | @rm -f coverage* 19 | 20 | install: 21 | @echo "--> Installing..." 22 | @install bin/xenon bin/xenonctl $(PREFIX)/sbin/ 23 | 24 | fmt: 25 | go fmt ./... 26 | 27 | test: 28 | @echo "--> Testing..." 29 | @$(MAKE) testcommon 30 | @$(MAKE) testlog 31 | @$(MAKE) testrpc 32 | @$(MAKE) testconfig 33 | @$(MAKE) testmysql 34 | @$(MAKE) testmysqld 35 | @$(MAKE) testserver 36 | @$(MAKE) testraft 37 | @$(MAKE) testcli 38 | @$(MAKE) testctl 39 | 40 | testcommon: 41 | go test -v xbase/common 42 | testlog: 43 | go test -v xbase/xlog 44 | testrpc: 45 | go test -v xbase/xrpc 46 | testconfig: 47 | go test -v config 48 | testmysql: 49 | go test -v mysql 50 | testmysqld: 51 | go test -v mysqld 52 | testserver: 53 | go test -v server 54 | testraft: 55 | go test -v raft 56 | testcli: 57 | go test -v cli/cmd 58 | testctl: 59 | go test -v ctl/v1 60 | 61 | COVPKGS = xbase/common\ 62 | xbase/xlog\ 63 | xbase/xrpc\ 64 | config\ 65 | mysql\ 66 | mysqld\ 67 | raft\ 68 | server\ 69 | ctl/v1/ 70 | vet: 71 | go vet $(COVPKGS) 72 | 73 | coverage: 74 | go build -v -o bin/gotestcover \ 75 | src/vendor/github.com/pierrre/gotestcover/*.go; 76 | bin/gotestcover -coverprofile=coverage.out -v $(COVPKGS) 77 | go tool cover -html=coverage.out 78 | -------------------------------------------------------------------------------- /src/build/info.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package build 10 | 11 | import ( 12 | "fmt" 13 | "runtime" 14 | ) 15 | 16 | var ( 17 | tag = "unknown" // tag of this build 18 | git string // git hash 19 | time string // build time 20 | platform = fmt.Sprintf("%s %s", runtime.GOOS, runtime.GOARCH) 21 | ) 22 | 23 | type Info struct { 24 | Tag string 25 | Time string 26 | Git string 27 | GoVersion string 28 | Platform string 29 | } 30 | 31 | func GetInfo() Info { 32 | return Info{ 33 | GoVersion: runtime.Version(), 34 | Tag: tag, 35 | Time: time, 36 | Git: git, 37 | Platform: platform, 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/build/ldflags.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -eu 4 | 5 | cd "$(dirname "${0}")/.." 6 | 7 | echo '-X "build.tag='$(git describe --tags --always)'"' \ 8 | '-X "build.time='$(date -u '+%Y/%m/%d %H:%M:%S')'"' \ 9 | '-X "build.git='$(git rev-parse --short HEAD)'"' 10 | -------------------------------------------------------------------------------- /src/cli/cli.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package main 10 | 11 | import ( 12 | "cli/cmd" 13 | "fmt" 14 | "os" 15 | 16 | "github.com/spf13/cobra" 17 | ) 18 | 19 | const ( 20 | cliName = "xenoncli" 21 | cliDescription = "A simple command line client for xenon" 22 | ) 23 | 24 | var ( 25 | rootCmd = &cobra.Command{ 26 | Use: cliName, 27 | Short: cliDescription, 28 | SuggestFor: []string{"xenonctl"}, 29 | } 30 | ) 31 | 32 | func init() { 33 | rootCmd.AddCommand(cmd.NewVersionCommand()) 34 | rootCmd.AddCommand(cmd.NewInitCommand()) 35 | rootCmd.AddCommand(cmd.NewClusterCommand()) 36 | rootCmd.AddCommand(cmd.NewMysqlCommand()) 37 | rootCmd.AddCommand(cmd.NewRaftCommand()) 38 | rootCmd.AddCommand(cmd.NewXenonCommand()) 39 | rootCmd.AddCommand(cmd.NewPerfCommand()) 40 | } 41 | 42 | func main() { 43 | if err := rootCmd.Execute(); err != nil { 44 | fmt.Println(err) 45 | os.Exit(-1) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cli/cmd/mock.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "config" 5 | "os" 6 | ) 7 | 8 | var defaultConfig = config.Config{ 9 | Server: &config.ServerConfig{ 10 | Endpoint: "127.0.0.1:8080", 11 | }, 12 | 13 | Raft: &config.RaftConfig{ 14 | MetaDatadir: "", 15 | HeartbeatTimeout: 1000, 16 | ElectionTimeout: 3000, 17 | LeaderStartCommand: "", 18 | LeaderStopCommand: "", 19 | }, 20 | 21 | Mysql: &config.MysqlConfig{ 22 | Admin: "root", 23 | Passwd: "", 24 | Host: "127.0.0.1", 25 | Port: 8080, 26 | Basedir: "/u01/mysql_20160606/", 27 | DefaultsFile: "/etc/my3306.cnf", 28 | PingTimeout: 1000, 29 | }, 30 | 31 | Replication: &config.ReplicationConfig{ 32 | User: "repl", 33 | Passwd: "repl", 34 | }, 35 | 36 | Backup: &config.BackupConfig{ 37 | SSHHost: "127.0.0.1", 38 | SSHUser: "backup", 39 | SSHPasswd: "backup", 40 | SSHPort: 22, 41 | BackupDir: "/u01/backup", 42 | XtrabackupBinDir: ".", 43 | BackupIOPSLimits: 100000, 44 | }, 45 | 46 | RPC: &config.RPCConfig{ 47 | RequestTimeout: 500, 48 | }, 49 | 50 | Log: &config.LogConfig{ 51 | Level: "INFO", 52 | }, 53 | } 54 | 55 | func createConfig() error { 56 | path := "/tmp/test.cli.config.json" 57 | err := config.WriteConfig(path, &defaultConfig) 58 | if err != nil { 59 | return err 60 | } 61 | 62 | flag := os.O_RDWR | os.O_TRUNC | os.O_CREATE 63 | f, err := os.OpenFile("./config.path", flag, 0644) 64 | if err != nil { 65 | return err 66 | } 67 | defer f.Close() 68 | 69 | _, err = f.WriteString(path) 70 | return err 71 | } 72 | 73 | func removeConfig() error { 74 | os.Remove("/tmp/test.cli.config.json") 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /src/cli/cmd/perf.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package cmd 10 | 11 | import ( 12 | "encoding/json" 13 | "fmt" 14 | "xbase/common" 15 | "xbase/xlog" 16 | 17 | "github.com/spf13/cobra" 18 | ) 19 | 20 | func quickStack(log *xlog.Log) (string, error) { 21 | timeout := 10 * 1000 // 10s 22 | cmds := "bash" 23 | args := []string{ 24 | "-c", 25 | "sudo quickstack -s -k 10 -p `pidof mysqld`", 26 | } 27 | 28 | cmd := common.NewLinuxCommand(log) 29 | return cmd.RunCommandWithTimeout(timeout, cmds, args) 30 | } 31 | 32 | func NewPerfCommand() *cobra.Command { 33 | cmd := &cobra.Command{ 34 | Use: "perf ", 35 | Short: "perf related commands", 36 | } 37 | 38 | cmd.AddCommand(NewQuickStackCommand()) 39 | 40 | return cmd 41 | } 42 | 43 | func NewQuickStackCommand() *cobra.Command { 44 | cmd := &cobra.Command{ 45 | Use: "quickstack", 46 | Short: "capture the stack of mysqld using quickstack", 47 | Run: quickStackCommandFn, 48 | } 49 | cmd.AddCommand(NewQuickStackJsonCommand()) 50 | 51 | return cmd 52 | } 53 | 54 | func quickStackCommandFn(cmd *cobra.Command, args []string) { 55 | outs, err := quickStack(log) 56 | ErrorOK(err) 57 | fmt.Printf("%v", outs) 58 | } 59 | 60 | func NewQuickStackJsonCommand() *cobra.Command { 61 | cmd := &cobra.Command{ 62 | Use: "json", 63 | Short: "json format", 64 | Run: quickStackJsonCommandFn, 65 | } 66 | 67 | return cmd 68 | } 69 | 70 | func quickStackJsonCommandFn(cmd *cobra.Command, args []string) { 71 | type Status struct { 72 | Results string `json:"status"` 73 | } 74 | status := &Status{} 75 | outs, err := quickStack(log) 76 | ErrorOK(err) 77 | status.Results = outs 78 | 79 | statusB, _ := json.Marshal(status) 80 | fmt.Printf("%s", string(statusB)) 81 | } 82 | -------------------------------------------------------------------------------- /src/cli/cmd/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package cmd 10 | 11 | import ( 12 | "build" 13 | "fmt" 14 | 15 | "github.com/spf13/cobra" 16 | ) 17 | 18 | func NewVersionCommand() *cobra.Command { 19 | cmd := &cobra.Command{ 20 | Use: "version", 21 | Short: "Print the version number of xenon client", 22 | Run: versionCommandFn, 23 | } 24 | 25 | return cmd 26 | } 27 | 28 | func versionCommandFn(cmd *cobra.Command, args []string) { 29 | build := build.GetInfo() 30 | fmt.Printf("xenoncli:[%+v]\n", build) 31 | } 32 | -------------------------------------------------------------------------------- /src/cli/cmd/xenon.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package cmd 10 | 11 | import ( 12 | "cli/callx" 13 | "fmt" 14 | "github.com/spf13/cobra" 15 | ) 16 | 17 | func NewXenonCommand() *cobra.Command { 18 | cmd := &cobra.Command{ 19 | Use: "xenon ", 20 | Short: "xenon related commands", 21 | } 22 | 23 | cmd.AddCommand(NewXenonStatusCommand()) 24 | 25 | return cmd 26 | } 27 | 28 | func NewXenonStatusCommand() *cobra.Command { 29 | cmd := &cobra.Command{ 30 | Use: "ping", 31 | Short: "check node work or not", 32 | Run: xenonPingCommandFn, 33 | } 34 | 35 | return cmd 36 | } 37 | 38 | func xenonPingCommandFn(cmd *cobra.Command, args []string) { 39 | if len(args) != 0 { 40 | ErrorOK(fmt.Errorf("too.many.args")) 41 | } 42 | 43 | // send ping to self 44 | { 45 | conf, err := GetConfig() 46 | ErrorOK(err) 47 | self := conf.Server.Endpoint 48 | rsp, err := callx.ServerPingRPC(self) 49 | ErrorOK(err) 50 | RspOK(rsp.RetCode) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/cli/cmd/xenon_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package cmd 10 | 11 | import ( 12 | "server" 13 | "testing" 14 | "xbase/common" 15 | "xbase/xlog" 16 | 17 | "github.com/stretchr/testify/assert" 18 | ) 19 | 20 | func TestCLIXenonCommand(t *testing.T) { 21 | 22 | err := createConfig() 23 | ErrorOK(err) 24 | defer removeConfig() 25 | 26 | log := xlog.NewStdLog(xlog.Level(xlog.PANIC)) 27 | port := common.RandomPort(8000, 9000) 28 | servers, cleanup := server.MockServers(log, port, 1) 29 | defer cleanup() 30 | 31 | // setting xenon is leader 32 | { 33 | conf, err := GetConfig() 34 | ErrorOK(err) 35 | conf.Server.Endpoint = servers[0].Address() 36 | err = SaveConfig(conf) 37 | ErrorOK(err) 38 | } 39 | 40 | // ping 41 | { 42 | cmd := NewXenonCommand() 43 | _, err := executeCommand(cmd, "ping") 44 | assert.Nil(t, err) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/config/config_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package config 10 | 11 | import ( 12 | "os" 13 | "testing" 14 | 15 | "github.com/stretchr/testify/assert" 16 | ) 17 | 18 | func TestParseConfig(t *testing.T) { 19 | data := []byte( 20 | `{ 21 | "server": 22 | { 23 | "endpoint":"127.0.0.1:8080", 24 | "enable-apis":false, 25 | "peer-address":":6060" 26 | }, 27 | 28 | "raft": 29 | { 30 | "meta-datadir":".", 31 | "heartbeat-timeout":1000, 32 | "election-timeout":3000, 33 | "leader-start-command":"nop", 34 | "leader-stop-command":"nop" 35 | }, 36 | 37 | "mysql": 38 | { 39 | "admin":"root", 40 | "passwd":"", 41 | "host":"localhost", 42 | "port":3306, 43 | "basedir":"/u01/mysql_20160606/", 44 | "defaults-file":"/etc/my3306.cnf", 45 | "ping-timeout":1000 46 | }, 47 | 48 | "replication": 49 | { 50 | "user":"repl", 51 | "passwd":"repl", 52 | "master-log" :"mysql-bin.000001", 53 | "master-log-pos":590 54 | }, 55 | 56 | "backup": 57 | { 58 | "ssh-port":22, 59 | "backupdir":"/u01/backup", 60 | "xtrabackup-bindir":".", 61 | "backup-iops-limits":100000, 62 | "backup-use-memory":"2GB", 63 | "backup-parallel": 2, 64 | "mysqld-monitor-interval": 1000 65 | }, 66 | 67 | "rpc": 68 | { 69 | "request-timeout":1000 70 | }, 71 | 72 | "log": 73 | { 74 | "level":"INFO" 75 | } 76 | } 77 | `) 78 | 79 | got, err := parseConfig(data) 80 | want := DefaultConfig() 81 | assert.Nil(t, err) 82 | assert.Equal(t, want, got) 83 | } 84 | 85 | func TestWriteConfig(t *testing.T) { 86 | path := "/tmp/test.config.json" 87 | os.Remove(path) 88 | conf := DefaultConfig() 89 | err := WriteConfig(path, conf) 90 | assert.Nil(t, err) 91 | } 92 | 93 | func TestLoadConfig(t *testing.T) { 94 | path := "/tmp/test.config.json" 95 | want := DefaultConfig() 96 | got, err := LoadConfig(path) 97 | assert.Nil(t, err) 98 | assert.Equal(t, want, got) 99 | os.Remove(path) 100 | } 101 | -------------------------------------------------------------------------------- /src/ctl/admin.go: -------------------------------------------------------------------------------- 1 | /* 2 | * RadonDB 3 | * 4 | * Copyright 2021 The RadonDB Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package ctl 10 | 11 | import ( 12 | "context" 13 | "log" 14 | "net/http" 15 | _ "net/http/pprof" 16 | 17 | "server" 18 | "xbase/xlog" 19 | "xbase/xrpc" 20 | 21 | "github.com/ant0ine/go-json-rest/rest" 22 | ) 23 | 24 | func init() { 25 | go func() { 26 | log.Println(http.ListenAndServe(":6060", nil)) 27 | }() 28 | } 29 | 30 | // Admin tuple. 31 | type Admin struct { 32 | log *xlog.Log 33 | server *http.Server 34 | xenon *server.Server 35 | } 36 | 37 | // NewAdmin creates the new admin. 38 | func NewAdmin(log *xlog.Log, xenon *server.Server) *Admin { 39 | return &Admin{ 40 | log: log, 41 | xenon: xenon, 42 | } 43 | } 44 | 45 | // Start starts http server. 46 | func (admin *Admin) Start() { 47 | api := rest.NewApi() 48 | router, err := admin.NewRouter() 49 | if err != nil { 50 | panic(err) 51 | } 52 | 53 | authMiddleware := &rest.AuthBasicMiddleware{ 54 | Realm: "xenon zone", 55 | Authenticator: func(userId string, password string) bool { 56 | if userId == admin.xenon.MySQLAdmin() && password == admin.xenon.MySQLPasswd() { 57 | return true 58 | } 59 | return false 60 | }, 61 | } 62 | api.Use(authMiddleware) 63 | 64 | api.SetApp(router) 65 | handlers := api.MakeHandler() 66 | admin.server = &http.Server{Addr: admin.xenon.PeerAddress(), Handler: handlers} 67 | 68 | go func() { 69 | log := admin.log 70 | log.Info("http.server.start[%v]...", admin.xenon.PeerAddress()) 71 | 72 | ln, err := xrpc.SetListener(admin.server.Addr) 73 | if err != nil { 74 | log.Panic("%v", err) 75 | } 76 | 77 | if err := admin.server.Serve(ln); err != http.ErrServerClosed { 78 | log.Panic("%v", err) 79 | } 80 | }() 81 | } 82 | 83 | // Stop stops http server. 84 | func (admin *Admin) Stop() { 85 | log := admin.log 86 | admin.server.Shutdown(context.Background()) 87 | log.Info("http.server.gracefully.stop") 88 | } 89 | -------------------------------------------------------------------------------- /src/ctl/router.go: -------------------------------------------------------------------------------- 1 | /* 2 | * RadonDB 3 | * 4 | * Copyright 2021 The RadonDB Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package ctl 10 | 11 | import ( 12 | v1 "ctl/v1" 13 | 14 | "github.com/ant0ine/go-json-rest/rest" 15 | ) 16 | 17 | // NewRouter creates the new router. 18 | func (admin *Admin) NewRouter() (rest.App, error) { 19 | log := admin.log 20 | xenon := admin.xenon 21 | 22 | return rest.MakeRouter( 23 | // cluster. 24 | rest.Post("/v1/cluster/add", v1.ClusterAddHandler(log, xenon)), 25 | rest.Post("/v1/cluster/remove", v1.ClusterRemoveHandler(log, xenon)), 26 | 27 | // raft. 28 | rest.Get("/v1/raft/status", v1.RaftStatusHandler(log, xenon)), 29 | rest.Post("/v1/raft/trytoleader", v1.RaftTryToLeaderHandler(log, xenon)), 30 | rest.Put("/v1/raft/disablechecksemisync", v1.RaftDisableCheckSemiSyncHandler(log, xenon)), 31 | rest.Put("/v1/raft/disable", v1.RaftDisableHandler(log, xenon)), 32 | 33 | // xenon. 34 | rest.Get("/v1/xenon/ping", v1.XenonPingHandler(log, xenon)), 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /src/ctl/v1/xenon.go: -------------------------------------------------------------------------------- 1 | /* 2 | * RadonDB 3 | * 4 | * Copyright 2021 The RadonDB Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package v1 10 | 11 | import ( 12 | "net/http" 13 | 14 | "cli/callx" 15 | "model" 16 | "server" 17 | "xbase/xlog" 18 | 19 | "github.com/ant0ine/go-json-rest/rest" 20 | ) 21 | 22 | // RaftStatusHandler impl. 23 | func XenonPingHandler(log *xlog.Log, xenon *server.Server) rest.HandlerFunc { 24 | f := func(w rest.ResponseWriter, r *rest.Request) { 25 | xenonPingHandler(log, xenon, w, r) 26 | } 27 | return f 28 | } 29 | 30 | func xenonPingHandler(log *xlog.Log, xenon *server.Server, w rest.ResponseWriter, r *rest.Request) { 31 | address := xenon.Address() 32 | rsp, err := callx.ServerPingRPC(address) 33 | if err != nil { 34 | log.Error("api.v1.xenon.ping.error:%+v", err) 35 | rest.Error(w, err.Error(), http.StatusInternalServerError) 36 | } 37 | if rsp == nil { 38 | log.Error("api.v1.xenon.ping.error:rsp[nil] != [OK]") 39 | rest.Error(w, err.Error(), http.StatusInternalServerError) 40 | return 41 | } 42 | if rsp.RetCode != model.OK { 43 | log.Error("api.v1.xenon.ping.error:rsp[%v] != [OK]", rsp.RetCode) 44 | rest.Error(w, err.Error(), http.StatusInternalServerError) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/ctl/v1/xenon_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * RadonDB 3 | * 4 | * Copyright 2021 The RadonDB Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package v1 10 | 11 | import ( 12 | "encoding/base64" 13 | "testing" 14 | 15 | "server" 16 | "xbase/common" 17 | "xbase/xlog" 18 | 19 | "github.com/ant0ine/go-json-rest/rest" 20 | "github.com/ant0ine/go-json-rest/rest/test" 21 | ) 22 | 23 | func TestXenonPing(t *testing.T) { 24 | log := xlog.NewStdLog(xlog.Level(xlog.PANIC)) 25 | port := common.RandomPort(8000, 9000) 26 | servers, cleanup := server.MockServers(log, port, 1) 27 | defer cleanup() 28 | 29 | xenon := servers[0] 30 | api := rest.NewApi() 31 | authMiddleware := &rest.AuthBasicMiddleware{ 32 | Realm: "xenon zone", 33 | Authenticator: func(userId string, password string) bool { 34 | if userId == xenon.MySQLAdmin() && password == xenon.MySQLPasswd() { 35 | return true 36 | } 37 | return false 38 | }, 39 | } 40 | api.Use(authMiddleware) 41 | 42 | router, _ := rest.MakeRouter( 43 | rest.Get("/v1/xenon/ping", XenonPingHandler(log, xenon)), 44 | ) 45 | api.SetApp(router) 46 | handler := api.MakeHandler() 47 | 48 | // 200. 49 | { 50 | req := test.MakeSimpleRequest("GET", "http://localhost/v1/xenon/ping", nil) 51 | encoded := base64.StdEncoding.EncodeToString([]byte("root:")) 52 | req.Header.Set("Authorization", "Basic "+encoded) 53 | recorded := test.RunRequest(t, handler, req) 54 | recorded.CodeIs(200) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/model/backup.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package model 10 | 11 | const ( 12 | RPCBackupStatus = "BackupRPC.GetBackupStatus" 13 | RPCBackupDo = "BackupRPC.DoBackup" 14 | RPCBackupCancel = "BackupRPC.CancelBackup" 15 | RPCBackupApplyLog = "BackupRPC.DoApplyLog" 16 | ) 17 | 18 | type BackupStats struct { 19 | // How many times backup have been called 20 | Backups uint64 21 | 22 | // How many times backup have failed 23 | BackupErrs uint64 24 | 25 | // How many times apply-log have been called 26 | AppLogs uint64 27 | 28 | // How many times apply-log have failed 29 | AppLogErrs uint64 30 | 31 | // How many times cannel have been taken 32 | Cancels uint64 33 | 34 | // The last error message of backup/applylog 35 | LastError string 36 | 37 | // The last backup command info we call 38 | LastCMD string 39 | } 40 | 41 | type BackupRPCRequest struct { 42 | // The IP of this request 43 | From string 44 | 45 | // The Backup dir of this request 46 | BackupDir string 47 | 48 | // The SSH IP of this request 49 | SSHHost string 50 | 51 | // The SSH user of this request 52 | SSHUser string 53 | 54 | // The SSH password of this request 55 | SSHPasswd string 56 | 57 | // The SSH port(default is 22) of this request 58 | SSHPort int 59 | 60 | // The Backup IOPS throttle of this request 61 | IOPSLimits int 62 | 63 | // The xtrabackup/xbstream binary dir 64 | XtrabackupBinDir string 65 | } 66 | 67 | type BackupRPCResponse struct { 68 | // Return code to rpc client: 69 | // OK or other errors 70 | RetCode string 71 | } 72 | 73 | func NewBackupRPCRequest() *BackupRPCRequest { 74 | return &BackupRPCRequest{} 75 | } 76 | 77 | func NewBackupRPCResponse(code string) *BackupRPCResponse { 78 | return &BackupRPCResponse{RetCode: code} 79 | } 80 | -------------------------------------------------------------------------------- /src/model/error.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package model 10 | 11 | const ( 12 | OK = "OK" 13 | ErrorRPCCall = "ErrorRpcCall" 14 | ErrorMySQLDown = "ErrorMySQLDown" 15 | ErrorServerDown = "ErrorServerDown" 16 | ErrorInvalidGTID = "ErrorInvalidGTID" 17 | ErrorInvalidViewID = "ErrorInvalidViewID" 18 | ErrorVoteNotGranted = "ErrorVoteNotGranted" 19 | ErrorInvalidRequest = "ErrorInvalidRequest" 20 | ErrorChangeMaster = "ErrorChangeMaster" 21 | ErrorBackupNotFound = "ErrorBackupNotFound" 22 | ErrorMysqldNotRunning = "ErrorMysqldNotRunning" 23 | ) 24 | 25 | const ( 26 | RPCError_MySQLUnpromotable = "RPCError_MySQLUnpromotable" 27 | ) 28 | -------------------------------------------------------------------------------- /src/model/ha.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package model 10 | 11 | const ( 12 | RPCHASetLearner = "HARPC.HASetLearner" 13 | RPCHADisable = "HARPC.HADisable" 14 | RPCHAEnable = "HARPC.HAEnable" 15 | RPCHATryToLeader = "HARPC.HATryToLeader" 16 | ) 17 | 18 | type HARPCRequest struct { 19 | // My RPC client IP 20 | From string 21 | } 22 | 23 | type HARPCResponse struct { 24 | // Return code to rpc client 25 | RetCode string 26 | } 27 | 28 | func NewHARPCRequest() *HARPCRequest { 29 | return &HARPCRequest{} 30 | } 31 | 32 | func (req *HARPCRequest) GetFrom() string { 33 | return req.From 34 | } 35 | 36 | func NewHARPCResponse(code string) *HARPCResponse { 37 | return &HARPCResponse{RetCode: code} 38 | } 39 | -------------------------------------------------------------------------------- /src/model/node.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package model 10 | 11 | const ( 12 | RPCNodesAdd = "NodeRPC.AddNodes" 13 | RPCIdleNodesAdd = "NodeRPC.AddIdleNodes" 14 | RPCNodesRemove = "NodeRPC.RemoveNodes" 15 | RPCIdleNodesRemove = "NodeRPC.RemoveIdleNodes" 16 | RPCNodes = "NodeRPC.GetNodes" 17 | ) 18 | 19 | type NodeRPCRequest struct { 20 | // The IP of this request 21 | From string 22 | 23 | // Node endpoint lists 24 | Nodes []string 25 | } 26 | 27 | type NodeRPCResponse struct { 28 | // The Epoch ID of the raft 29 | EpochID uint64 30 | 31 | // The View ID of the raft 32 | ViewID uint64 33 | 34 | // The State of the raft: 35 | // FOLLOWER/CANDIDATE/LEADER/IDLE/INVALID 36 | State string 37 | 38 | // The Leader endpoint of the cluster 39 | Leader string 40 | 41 | // The Nodes(endpoint) of the cluster 42 | Nodes []string 43 | 44 | // Return code to rpc client: 45 | // OK or other errors 46 | RetCode string 47 | } 48 | 49 | func NewNodeRPCRequest() *NodeRPCRequest { 50 | return &NodeRPCRequest{} 51 | } 52 | 53 | func (req *NodeRPCRequest) GetFrom() string { 54 | return req.From 55 | } 56 | 57 | func (req *NodeRPCRequest) GetNodes() []string { 58 | return req.Nodes 59 | } 60 | 61 | func NewNodeRPCResponse(code string) *NodeRPCResponse { 62 | return &NodeRPCResponse{RetCode: code} 63 | } 64 | 65 | func (rsp *NodeRPCResponse) GetNodes() []string { 66 | return rsp.Nodes 67 | } 68 | 69 | func (rsp *NodeRPCResponse) GetLeader() string { 70 | return rsp.Leader 71 | } 72 | -------------------------------------------------------------------------------- /src/model/server.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package model 10 | 11 | const ( 12 | RRCServerPing = "ServerRPC.Ping" 13 | RPCServerStatus = "ServerRPC.Status" 14 | ) 15 | 16 | type ServerRPCRequest struct { 17 | From string 18 | Msg string 19 | } 20 | 21 | type ConfigStatus struct { 22 | // log 23 | LogLevel string 24 | 25 | // backup 26 | BackupDir string 27 | BackupIOPSLimits int 28 | XtrabackupBinDir string 29 | 30 | // mysqld 31 | MysqldBaseDir string 32 | MysqldDefaultsFile string 33 | 34 | // mysql 35 | MysqlAdmin string 36 | MysqlHost string 37 | MysqlPort int 38 | MysqlReplUser string 39 | MysqlPingTimeout int 40 | 41 | // raft 42 | RaftDataDir string 43 | RaftHeartbeatTimeout int 44 | RaftElectionTimeout int 45 | RaftRPCRequestTimeout int 46 | RaftStartVipCommand string 47 | RaftStopVipCommand string 48 | } 49 | 50 | // stats 51 | type ServerStats struct { 52 | Uptimes uint64 53 | } 54 | 55 | type ServerRPCResponse struct { 56 | Config *ConfigStatus 57 | Stats *ServerStats 58 | ServerUptimes uint64 59 | RetCode string 60 | } 61 | 62 | func NewServerRPCRequest() *ServerRPCRequest { 63 | return &ServerRPCRequest{} 64 | } 65 | 66 | func (req *ServerRPCRequest) GetFrom() string { 67 | return req.From 68 | } 69 | 70 | func NewServerRPCResponse(code string) *ServerRPCResponse { 71 | return &ServerRPCResponse{RetCode: code} 72 | } 73 | -------------------------------------------------------------------------------- /src/mysql/attr.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package mysql 10 | 11 | import ( 12 | "fmt" 13 | "model" 14 | ) 15 | 16 | func (m *Mysql) setState(state model.MysqlState) { 17 | m.mutex.Lock() 18 | defer m.mutex.Unlock() 19 | m.state = state 20 | } 21 | 22 | func (m *Mysql) getState() model.MysqlState { 23 | m.mutex.RLock() 24 | defer m.mutex.RUnlock() 25 | return m.state 26 | } 27 | 28 | func (m *Mysql) setOption(o Option) { 29 | m.option = o 30 | } 31 | 32 | func (m *Mysql) getOption() Option { 33 | return m.option 34 | } 35 | 36 | func (m *Mysql) getConnStr() string { 37 | return fmt.Sprintf("%s:%d", m.conf.Host, m.conf.Port) 38 | } 39 | -------------------------------------------------------------------------------- /src/mysql/mysql57.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018-2019 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package mysql 10 | 11 | var ( 12 | _ MysqlHandler = &Mysql57{} 13 | ) 14 | 15 | // Mysql57 tuple. 16 | type Mysql57 struct { 17 | MysqlBase 18 | } 19 | -------------------------------------------------------------------------------- /src/mysql/mysql57_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package mysql 10 | 11 | import ( 12 | "testing" 13 | 14 | "config" 15 | "xbase/xlog" 16 | 17 | _ "github.com/go-sql-driver/mysql" 18 | "github.com/stretchr/testify/assert" 19 | ) 20 | 21 | func TestMysql57Handler(t *testing.T) { 22 | log := xlog.NewStdLog(xlog.Level(xlog.PANIC)) 23 | conf := config.DefaultMysqlConfig() 24 | 25 | mysql := NewMysql(conf, 10000, log) 26 | want := new(Mysql57) 27 | want.SetQueryTimeout(10000) 28 | got := mysql.mysqlHandler 29 | assert.Equal(t, want, got) 30 | } 31 | -------------------------------------------------------------------------------- /src/mysql/mysql80.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018-2019 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package mysql 10 | 11 | var ( 12 | _ MysqlHandler = &Mysql80{} 13 | ) 14 | 15 | // Mysql80 tuple. 16 | type Mysql80 struct { 17 | MysqlBase 18 | } 19 | -------------------------------------------------------------------------------- /src/mysql/mysql80_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package mysql 10 | 11 | import ( 12 | "testing" 13 | 14 | "config" 15 | "xbase/xlog" 16 | 17 | _ "github.com/go-sql-driver/mysql" 18 | "github.com/stretchr/testify/assert" 19 | ) 20 | 21 | func TestMysql80Handler(t *testing.T) { 22 | log := xlog.NewStdLog(xlog.Level(xlog.PANIC)) 23 | conf := config.DefaultMysqlConfig() 24 | conf.Version = "mysql80" 25 | 26 | mysql := NewMysql(conf, 10000, log) 27 | want := new(Mysql80) 28 | want.SetQueryTimeout(10000) 29 | got := mysql.mysqlHandler 30 | assert.Equal(t, want, got) 31 | } 32 | -------------------------------------------------------------------------------- /src/mysql/stats.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package mysql 10 | 11 | import ( 12 | "model" 13 | "sync/atomic" 14 | ) 15 | 16 | // IncMysqlDowns used to increase the mysql down counter. 17 | func (s *Mysql) IncMysqlDowns() { 18 | atomic.AddUint64(&s.stats.MysqlDowns, 1) 19 | } 20 | 21 | func (s *Mysql) getStats() *model.MysqlStats { 22 | return &model.MysqlStats{ 23 | MysqlDowns: atomic.LoadUint64(&s.stats.MysqlDowns), 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/mysqld/args_handler.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package mysqld 10 | 11 | // ArgsHandler for mysqld operation. 12 | type ArgsHandler interface { 13 | // mysqld start args 14 | Start() []string 15 | 16 | // mysqld stop args 17 | Stop() []string 18 | 19 | // mysqld isrunning args 20 | IsRunning() []string 21 | 22 | // mysqld kill args 23 | Kill() []string 24 | } 25 | -------------------------------------------------------------------------------- /src/mysqld/linux_args.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package mysqld 10 | 11 | import ( 12 | "config" 13 | "fmt" 14 | "path/filepath" 15 | ) 16 | 17 | var ( 18 | _ ArgsHandler = &LinuxArgs{} 19 | ) 20 | 21 | const ( 22 | bash = "bash" 23 | mysqldsafe = "bin/mysqld_safe" 24 | mysqladmin = "bin/mysqladmin" 25 | ) 26 | 27 | // LinuxArgs tuple. 28 | type LinuxArgs struct { 29 | conf *config.BackupConfig 30 | ArgsHandler 31 | } 32 | 33 | // NewLinuxArgs creates new LinuxArgs. 34 | func NewLinuxArgs(conf *config.BackupConfig) *LinuxArgs { 35 | return &LinuxArgs{ 36 | conf: conf, 37 | } 38 | } 39 | 40 | // Start used to start mysqld. 41 | func (l *LinuxArgs) Start() []string { 42 | safe57 := filepath.Join(l.conf.Basedir, mysqldsafe) 43 | args := []string{ 44 | "-c", 45 | fmt.Sprintf("%s --defaults-file=%s > /dev/null&", safe57, l.conf.DefaultsFile), 46 | } 47 | return args 48 | } 49 | 50 | // Stop used to stop the mysqld. 51 | func (l *LinuxArgs) Stop() []string { 52 | admin57 := filepath.Join(l.conf.Basedir, mysqladmin) 53 | args := []string{ 54 | "-c", 55 | } 56 | if l.conf.Passwd == "" { 57 | args = append(args, fmt.Sprintf("%s -h%s -u%s -P%d shutdown", admin57, l.conf.Host, l.conf.Admin, l.conf.Port)) 58 | } else { 59 | args = append(args, fmt.Sprintf("%s -h%s -u%s -p%s -P%d shutdown", admin57, l.conf.Host, l.conf.Admin, l.conf.Passwd, l.conf.Port)) 60 | } 61 | return args 62 | } 63 | 64 | // IsRunning used to check the mysqld is running or not. 65 | func (l *LinuxArgs) IsRunning() []string { 66 | // [m] is a trick to stop you picking up the actual grep process itself 67 | safe57 := fmt.Sprintf("[m]ysqld_safe --defaults-file=%s", l.conf.DefaultsFile) 68 | args := []string{ 69 | "-c", 70 | fmt.Sprintf("ps aux | grep '%s' | wc -l", safe57), 71 | } 72 | return args 73 | } 74 | 75 | // Kill used to kill -9 the mysqld process. 76 | func (l *LinuxArgs) Kill() []string { 77 | args := []string{ 78 | "-c", 79 | } 80 | args = append(args, 81 | fmt.Sprintf("kill -9 $(ps aux | grep '[-]-defaults-file=%s' | awk '{print $2}')", l.conf.DefaultsFile)) 82 | return args 83 | } 84 | -------------------------------------------------------------------------------- /src/mysqld/linux_args_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package mysqld 10 | 11 | import ( 12 | "config" 13 | "strings" 14 | "testing" 15 | 16 | "github.com/stretchr/testify/assert" 17 | ) 18 | 19 | func TestLinuxStartArgs(t *testing.T) { 20 | conf := config.DefaultBackupConfig() 21 | linuxargs := NewLinuxArgs(conf) 22 | want := `-c /u01/mysql_20160606/bin/mysqld_safe --defaults-file=/etc/my3306.cnf > /dev/null&` 23 | got := strings.Join(linuxargs.Start(), " ") 24 | assert.Equal(t, want, got) 25 | } 26 | 27 | func TestLinuxStopArgs(t *testing.T) { 28 | conf := config.DefaultBackupConfig() 29 | linuxargs := NewLinuxArgs(conf) 30 | 31 | // 1. passwords is null 32 | { 33 | want := `-c /u01/mysql_20160606/bin/mysqladmin -hlocalhost -uroot -P3306 shutdown` 34 | got := strings.Join(linuxargs.Stop(), " ") 35 | assert.Equal(t, want, got) 36 | } 37 | 38 | // 2. with passwords 39 | { 40 | conf.Passwd = `ddd"` 41 | want := `-c /u01/mysql_20160606/bin/mysqladmin -hlocalhost -uroot -pddd" -P3306 shutdown` 42 | got := strings.Join(linuxargs.Stop(), " ") 43 | assert.Equal(t, want, got) 44 | } 45 | } 46 | 47 | func TestLinuxIsRunningArgs(t *testing.T) { 48 | linuxargs := NewLinuxArgs(config.DefaultBackupConfig()) 49 | want := `-c ps aux | grep '[m]ysqld_safe --defaults-file=/etc/my3306.cnf' | wc -l` 50 | got := strings.Join(linuxargs.IsRunning(), " ") 51 | assert.Equal(t, want, got) 52 | } 53 | 54 | func TestLinuxKillArgs(t *testing.T) { 55 | linuxargs := NewLinuxArgs(config.DefaultBackupConfig()) 56 | want := `-c kill -9 $(ps aux | grep '[-]-defaults-file=/etc/my3306.cnf' | awk '{print $2}')` 57 | got := strings.Join(linuxargs.Kill(), " ") 58 | assert.Equal(t, want, got) 59 | } 60 | -------------------------------------------------------------------------------- /src/mysqld/rpc_backup.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package mysqld 10 | 11 | import ( 12 | "model" 13 | ) 14 | 15 | // BackupRPC tuple. 16 | type BackupRPC struct { 17 | mysqld *Mysqld 18 | } 19 | 20 | // GetBackupRPC returns BackupRPC tuple. 21 | func (m *Mysqld) GetBackupRPC() *BackupRPC { 22 | return &BackupRPC{m} 23 | } 24 | 25 | // DoBackup used to execute the xtrabackup command. 26 | func (b *BackupRPC) DoBackup(req *model.BackupRPCRequest, rsp *model.BackupRPCResponse) error { 27 | rsp.RetCode = model.OK 28 | err := b.mysqld.backup.Backup(req) 29 | if err != nil { 30 | rsp.RetCode = err.Error() 31 | return nil 32 | } 33 | return nil 34 | } 35 | 36 | // DoApplyLog used to execute the apply log command. 37 | func (b *BackupRPC) DoApplyLog(req *model.BackupRPCRequest, rsp *model.BackupRPCResponse) error { 38 | rsp.RetCode = model.OK 39 | err := b.mysqld.backup.ApplyLog(req) 40 | if err != nil { 41 | rsp.RetCode = err.Error() 42 | return nil 43 | } 44 | return nil 45 | } 46 | 47 | // CancelBackup used to cancel the job of backup. 48 | func (b *BackupRPC) CancelBackup(req *model.BackupRPCRequest, rsp *model.BackupRPCResponse) error { 49 | rsp.RetCode = model.OK 50 | err := b.mysqld.backup.Cancel() 51 | if err != nil { 52 | rsp.RetCode = err.Error() 53 | return nil 54 | } 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /src/mysqld/stats.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package mysqld 10 | 11 | import ( 12 | "model" 13 | "sync/atomic" 14 | ) 15 | 16 | // IncBackups used to increase the backup counter. 17 | func (s *Backup) IncBackups() { 18 | atomic.AddUint64(&s.stats.Backups, 1) 19 | } 20 | 21 | // IncBackupErrs used to increase the backup error counter. 22 | func (s *Backup) IncBackupErrs() { 23 | atomic.AddUint64(&s.stats.BackupErrs, 1) 24 | } 25 | 26 | // IncCancels used to increase the backup cancel counter. 27 | func (s *Backup) IncCancels() { 28 | atomic.AddUint64(&s.stats.Cancels, 1) 29 | } 30 | 31 | // IncApplyLogs used to increase the apply counter. 32 | func (s *Backup) IncApplyLogs() { 33 | atomic.AddUint64(&s.stats.AppLogs, 1) 34 | } 35 | 36 | // IncApplyLogErrs used to increase the apply error counter. 37 | func (s *Backup) IncApplyLogErrs() { 38 | atomic.AddUint64(&s.stats.AppLogErrs, 1) 39 | } 40 | 41 | func (s *Backup) getStats() *model.BackupStats { 42 | return &model.BackupStats{ 43 | Backups: atomic.LoadUint64(&s.stats.Backups), 44 | BackupErrs: atomic.LoadUint64(&s.stats.BackupErrs), 45 | AppLogs: atomic.LoadUint64(&s.stats.AppLogs), 46 | AppLogErrs: atomic.LoadUint64(&s.stats.AppLogErrs), 47 | Cancels: atomic.LoadUint64(&s.stats.Cancels), 48 | } 49 | } 50 | 51 | // IncMysqldStarts used to increase the mysql start counter. 52 | func (s *Mysqld) IncMysqldStarts() { 53 | atomic.AddUint64(&s.stats.MysqldStarts, 1) 54 | } 55 | 56 | // IncMysqldStops used to increase the mysql stop counter. 57 | func (s *Mysqld) IncMysqldStops() { 58 | atomic.AddUint64(&s.stats.MysqldStops, 1) 59 | } 60 | 61 | // IncMonitorStarts used to increase the monitor start counter. 62 | func (s *Mysqld) IncMonitorStarts() { 63 | atomic.AddUint64(&s.stats.MonitorStarts, 1) 64 | } 65 | 66 | // IncMonitorStops used to increase the monitor stop counter. 67 | func (s *Mysqld) IncMonitorStops() { 68 | atomic.AddUint64(&s.stats.MonitorStops, 1) 69 | } 70 | 71 | func (s *Mysqld) getStats() *model.MysqldStats { 72 | return &model.MysqldStats{ 73 | MysqldStarts: atomic.LoadUint64(&s.stats.MysqldStarts), 74 | MysqldStops: atomic.LoadUint64(&s.stats.MysqldStops), 75 | MonitorStarts: atomic.LoadUint64(&s.stats.MonitorStarts), 76 | MonitorStops: atomic.LoadUint64(&s.stats.MonitorStops), 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/raft/cmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package raft 10 | 11 | const ( 12 | bash = "bash" 13 | ) 14 | 15 | // leaderStartShellCommand execute the shell commands 16 | // when leader start, such as START-VIP command 17 | func (r *Raft) leaderStartShellCommand() error { 18 | args := []string{ 19 | "-c", 20 | r.conf.LeaderStartCommand, 21 | } 22 | 23 | if out, err := r.cmd.RunCommand(bash, args); err != nil { 24 | r.ERROR("leaderStartShellCommand[%v].out[%v].error[%+v]", args, out, err) 25 | return err 26 | } 27 | r.WARNING("leaderStartShellCommand[%v].done", args) 28 | return nil 29 | } 30 | 31 | // leaderStopShellCommand executes the shell commands 32 | // when leader stop, such as STOP-VIP command 33 | func (r *Raft) leaderStopShellCommand() error { 34 | args := []string{ 35 | "-c", 36 | r.conf.LeaderStopCommand, 37 | } 38 | 39 | if out, err := r.cmd.RunCommand(bash, args); err != nil { 40 | r.ERROR("leaderStopShellCommand[%v].out[%v].error[%+v]", args, out, err) 41 | return err 42 | } 43 | r.WARNING("leaderStopShellCommand[%v].done", args) 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /src/raft/peersjson.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package raft 10 | 11 | import ( 12 | "encoding/json" 13 | "io/ioutil" 14 | 15 | "github.com/pkg/errors" 16 | ) 17 | 18 | func writePeersJSON(path string, peers []string, idlePeers []string) error { 19 | allPeers := make(map[string][]string) 20 | 21 | allPeers["peers"] = peers 22 | allPeers["idlepeers"] = idlePeers 23 | 24 | jsonStr, err := json.Marshal(allPeers) 25 | if err != nil { 26 | return errors.WithStack(err) 27 | } 28 | 29 | if err := ioutil.WriteFile(path, []byte(jsonStr), 0755); err != nil { 30 | return errors.WithStack(err) 31 | } 32 | return nil 33 | } 34 | 35 | func readPeersJSON(path string) ([]string, []string, error) { 36 | //var peers []string 37 | //var idlePeers []string 38 | allPeers := make(map[string][]string) 39 | 40 | buf, err := ioutil.ReadFile(path) 41 | if err != nil { 42 | return []string{}, []string{}, errors.WithStack(err) 43 | } 44 | 45 | err = json.Unmarshal(buf, &allPeers) 46 | if err != nil { 47 | return []string{}, []string{}, errors.WithStack(err) 48 | } 49 | return allPeers["peers"], allPeers["idlepeers"], nil 50 | } 51 | -------------------------------------------------------------------------------- /src/raft/peersjson_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package raft 10 | 11 | import ( 12 | "fmt" 13 | "os" 14 | "testing" 15 | 16 | "github.com/stretchr/testify/assert" 17 | ) 18 | 19 | func TestPeersJson(t *testing.T) { 20 | path := "/tmp/test.peersjson" 21 | peers := []string{":0101", ":0202"} 22 | idlePeers := []string{":0303", ":0404"} 23 | 24 | { 25 | err := writePeersJSON(path, peers, idlePeers) 26 | assert.Nil(t, err) 27 | os.Remove(path) 28 | } 29 | 30 | // read error 31 | { 32 | _, _, err := readPeersJSON(path) 33 | want := fmt.Sprintf("open %s: no such file or directory", path) 34 | got := err.Error() 35 | assert.Equal(t, want, got) 36 | } 37 | 38 | // write json 39 | { 40 | err := writePeersJSON(path, peers, idlePeers) 41 | assert.Nil(t, err) 42 | } 43 | 44 | // read json OK 45 | { 46 | ps, ips, err := readPeersJSON(path) 47 | assert.Nil(t, err) 48 | assert.Equal(t, peers, ps) 49 | assert.Equal(t, idlePeers, ips) 50 | } 51 | 52 | // json broken 53 | { 54 | f, err := os.OpenFile(path, os.O_RDWR, 0644) 55 | assert.Nil(t, err) 56 | defer f.Close() 57 | 58 | _, err = f.WriteString("inject") 59 | assert.Nil(t, err) 60 | } 61 | 62 | // read error 63 | { 64 | _, _, err := readPeersJSON(path) 65 | want := "invalid character 'i' looking for beginning of value" 66 | got := err.Error() 67 | assert.Equal(t, want, got) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/raft/trace.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package raft 10 | 11 | import ( 12 | "fmt" 13 | ) 14 | 15 | // log wrapper for raft 16 | func (r *Raft) logMsg(format string, v ...interface{}) string { 17 | return fmt.Sprintf("%v[ID:%v, V:%v, E:%v].%v", r.state.String(), r.getID(), r.getViewID(), r.getEpochID(), fmt.Sprintf(format, v...)) 18 | } 19 | 20 | // DEBUG level log. 21 | func (r *Raft) DEBUG(format string, v ...interface{}) { 22 | r.log.Debug("%v", r.logMsg(format, v...)) 23 | } 24 | 25 | // INFO level log. 26 | func (r *Raft) INFO(format string, v ...interface{}) { 27 | r.log.Info("%v", r.logMsg(format, v...)) 28 | } 29 | 30 | // WARNING level log. 31 | func (r *Raft) WARNING(format string, v ...interface{}) { 32 | r.log.Warning("%v", r.logMsg(format, v...)) 33 | } 34 | 35 | // ERROR level log. 36 | func (r *Raft) ERROR(format string, v ...interface{}) { 37 | r.log.Error("%v", r.logMsg(format, v...)) 38 | } 39 | 40 | // PANIC level log. 41 | func (r *Raft) PANIC(format string, v ...interface{}) { 42 | r.log.Panic("%v", r.logMsg(format, v...)) 43 | } 44 | -------------------------------------------------------------------------------- /src/server/mock.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package server 10 | 11 | import ( 12 | "config" 13 | "fmt" 14 | "mysql" 15 | "mysqld" 16 | "os" 17 | "raft" 18 | "testing" 19 | "xbase/common" 20 | "xbase/xlog" 21 | "xbase/xrpc" 22 | 23 | "github.com/stretchr/testify/assert" 24 | ) 25 | 26 | var ( 27 | shortHeartbeatTimeoutForTest = 100 28 | ) 29 | 30 | func MockServers(log *xlog.Log, port int, count int) ([]*Server, func()) { 31 | names := []string{} 32 | servers := []*Server{} 33 | ip, _ := common.GetLocalIP() 34 | 35 | os.Remove("peers.json") 36 | for i := 0; i < count; i++ { 37 | name := fmt.Sprintf("%s:%d", ip, port+i) 38 | names = append(names, name) 39 | 40 | conf := config.DefaultConfig() 41 | conf.Server.Endpoint = name 42 | conf.Raft.HeartbeatTimeout = shortHeartbeatTimeoutForTest 43 | conf.Raft.ElectionTimeout = shortHeartbeatTimeoutForTest * 3 44 | 45 | server := NewServer(conf, log, raft.FOLLOWER) 46 | 47 | // mock mysqld 48 | _, mysqld, _ := mysqld.MockMysqld(log, port) 49 | server.mysqld = mysqld 50 | 51 | // mock mysql 52 | server.mysql.SetMysqlHandler(mysql.NewMockGTIDA()) 53 | 54 | server.Init() 55 | servers = append(servers, server) 56 | } 57 | 58 | for _, server := range servers { 59 | for _, name := range names { 60 | server.raft.AddPeer(name) 61 | } 62 | } 63 | 64 | for _, server := range servers { 65 | server.Start() 66 | } 67 | 68 | return servers, func() { 69 | os.Remove("peers.json") 70 | for i, s := range servers { 71 | log.Info("mock.server[%v].shutdown", names[i]) 72 | s.Shutdown() 73 | } 74 | } 75 | } 76 | 77 | // wait the leader eggs when leadernums >0 78 | // if leadernums == 0, we just want to sleep for a heartbeat broadcast 79 | func MockWaitLeaderEggs(servers []*Server, leadernums int) { 80 | rafts := []*raft.Raft{} 81 | for _, server := range servers { 82 | rafts = append(rafts, server.raft) 83 | } 84 | raft.MockWaitLeaderEggs(rafts, leadernums) 85 | } 86 | 87 | // xrpc client 88 | func MockGetClient(t *testing.T, svrConn string) (*xrpc.Client, func()) { 89 | client, err := xrpc.NewClient(svrConn, 100) 90 | assert.Nil(t, err) 91 | 92 | return client, func() { 93 | client.Close() 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/server/rpc_server.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package server 10 | 11 | import ( 12 | "model" 13 | ) 14 | 15 | type ServerRPC struct { 16 | server *Server 17 | } 18 | 19 | func (s *Server) GetServerRPC() *ServerRPC { 20 | return &ServerRPC{s} 21 | } 22 | 23 | // check the server connection whether OK 24 | func (s *ServerRPC) Ping(req *model.ServerRPCRequest, rsp *model.ServerRPCResponse) error { 25 | rsp.RetCode = model.OK 26 | return nil 27 | } 28 | 29 | func (s *ServerRPC) Status(req *model.ServerRPCRequest, rsp *model.ServerRPCResponse) error { 30 | rsp.RetCode = model.OK 31 | config := &model.ConfigStatus{ 32 | LogLevel: s.server.conf.Log.Level, 33 | BackupDir: s.server.conf.Backup.BackupDir, 34 | BackupIOPSLimits: s.server.conf.Backup.BackupIOPSLimits, 35 | XtrabackupBinDir: s.server.conf.Backup.XtrabackupBinDir, 36 | MysqldBaseDir: s.server.conf.Backup.Basedir, 37 | MysqldDefaultsFile: s.server.conf.Backup.DefaultsFile, 38 | MysqlAdmin: s.server.conf.Mysql.Admin, 39 | MysqlHost: s.server.conf.Mysql.Host, 40 | MysqlPort: s.server.conf.Mysql.Port, 41 | MysqlReplUser: s.server.conf.Mysql.ReplUser, 42 | MysqlPingTimeout: s.server.conf.Mysql.PingTimeout, 43 | RaftDataDir: s.server.conf.Raft.MetaDatadir, 44 | RaftHeartbeatTimeout: s.server.conf.Raft.HeartbeatTimeout, 45 | RaftElectionTimeout: s.server.conf.Raft.ElectionTimeout, 46 | RaftRPCRequestTimeout: s.server.conf.Raft.RequestTimeout, 47 | RaftStartVipCommand: s.server.conf.Raft.LeaderStartCommand, 48 | RaftStopVipCommand: s.server.conf.Raft.LeaderStopCommand, 49 | } 50 | rsp.Config = config 51 | rsp.Stats = s.server.getStats() 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /src/server/stats.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package server 10 | 11 | import ( 12 | "model" 13 | "time" 14 | ) 15 | 16 | func (s *Server) getStats() *model.ServerStats { 17 | return &model.ServerStats{ 18 | Uptimes: uint64(time.Since(s.begin).Seconds()), 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: go 3 | go: 4 | - 1.3 5 | - 1.4 6 | - 1.5 7 | - 1.6 8 | - 1.7 9 | - 1.8 10 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2016 Antoine Imbert 2 | 3 | The MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/access_log_apache_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "bytes" 5 | "github.com/ant0ine/go-json-rest/rest/test" 6 | "log" 7 | "regexp" 8 | "testing" 9 | ) 10 | 11 | func TestAccessLogApacheMiddleware(t *testing.T) { 12 | 13 | api := NewApi() 14 | 15 | // the middlewares stack 16 | buffer := bytes.NewBufferString("") 17 | api.Use(&AccessLogApacheMiddleware{ 18 | Logger: log.New(buffer, "", 0), 19 | Format: CommonLogFormat, 20 | textTemplate: nil, 21 | }) 22 | api.Use(&TimerMiddleware{}) 23 | api.Use(&RecorderMiddleware{}) 24 | 25 | // a simple app 26 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 27 | w.WriteJson(map[string]string{"Id": "123"}) 28 | })) 29 | 30 | // wrap all 31 | handler := api.MakeHandler() 32 | 33 | req := test.MakeSimpleRequest("GET", "http://localhost/", nil) 34 | req.RemoteAddr = "127.0.0.1:1234" 35 | recorded := test.RunRequest(t, handler, req) 36 | recorded.CodeIs(200) 37 | recorded.ContentTypeIsJson() 38 | 39 | // log tests, eg: '127.0.0.1 - - 29/Nov/2014:22:28:34 +0000 "GET / HTTP/1.1" 200 12' 40 | apacheCommon := regexp.MustCompile(`127.0.0.1 - - \d{2}/\w{3}/\d{4}:\d{2}:\d{2}:\d{2} [+\-]\d{4}\ "GET / HTTP/1.1" 200 12`) 41 | 42 | if !apacheCommon.Match(buffer.Bytes()) { 43 | t.Errorf("Got: %s", buffer.String()) 44 | } 45 | } 46 | 47 | func TestAccessLogApacheMiddlewareMissingData(t *testing.T) { 48 | 49 | api := NewApi() 50 | 51 | // the uncomplete middlewares stack 52 | buffer := bytes.NewBufferString("") 53 | api.Use(&AccessLogApacheMiddleware{ 54 | Logger: log.New(buffer, "", 0), 55 | Format: CommonLogFormat, 56 | textTemplate: nil, 57 | }) 58 | 59 | // a simple app 60 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 61 | w.WriteJson(map[string]string{"Id": "123"}) 62 | })) 63 | 64 | // wrap all 65 | handler := api.MakeHandler() 66 | 67 | req := test.MakeSimpleRequest("GET", "http://localhost/", nil) 68 | recorded := test.RunRequest(t, handler, req) 69 | recorded.CodeIs(200) 70 | recorded.ContentTypeIsJson() 71 | 72 | // not much to log when the Env data is missing, but this should still work 73 | apacheCommon := regexp.MustCompile(` - - "GET / HTTP/1.1" 0 -`) 74 | 75 | if !apacheCommon.Match(buffer.Bytes()) { 76 | t.Errorf("Got: %s", buffer.String()) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/access_log_json_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "github.com/ant0ine/go-json-rest/rest/test" 7 | "log" 8 | "testing" 9 | ) 10 | 11 | func TestAccessLogJsonMiddleware(t *testing.T) { 12 | 13 | api := NewApi() 14 | 15 | // the middlewares stack 16 | buffer := bytes.NewBufferString("") 17 | api.Use(&AccessLogJsonMiddleware{ 18 | Logger: log.New(buffer, "", 0), 19 | }) 20 | api.Use(&TimerMiddleware{}) 21 | api.Use(&RecorderMiddleware{}) 22 | 23 | // a simple app 24 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 25 | w.WriteJson(map[string]string{"Id": "123"}) 26 | })) 27 | 28 | // wrap all 29 | handler := api.MakeHandler() 30 | 31 | req := test.MakeSimpleRequest("GET", "http://localhost/", nil) 32 | req.RemoteAddr = "127.0.0.1:1234" 33 | recorded := test.RunRequest(t, handler, req) 34 | recorded.CodeIs(200) 35 | recorded.ContentTypeIsJson() 36 | 37 | // log tests 38 | decoded := &AccessLogJsonRecord{} 39 | err := json.Unmarshal(buffer.Bytes(), decoded) 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | 44 | if decoded.StatusCode != 200 { 45 | t.Errorf("StatusCode 200 expected, got %d", decoded.StatusCode) 46 | } 47 | if decoded.RequestURI != "/" { 48 | t.Errorf("RequestURI / expected, got %s", decoded.RequestURI) 49 | } 50 | if decoded.HttpMethod != "GET" { 51 | t.Errorf("HttpMethod GET expected, got %s", decoded.HttpMethod) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/content_type_checker.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "mime" 5 | "net/http" 6 | "strings" 7 | ) 8 | 9 | // ContentTypeCheckerMiddleware verifies the request Content-Type header and returns a 10 | // StatusUnsupportedMediaType (415) HTTP error response if it's incorrect. The expected 11 | // Content-Type is 'application/json' if the content is non-null. Note: If a charset parameter 12 | // exists, it MUST be UTF-8. 13 | type ContentTypeCheckerMiddleware struct{} 14 | 15 | // MiddlewareFunc makes ContentTypeCheckerMiddleware implement the Middleware interface. 16 | func (mw *ContentTypeCheckerMiddleware) MiddlewareFunc(handler HandlerFunc) HandlerFunc { 17 | 18 | return func(w ResponseWriter, r *Request) { 19 | 20 | mediatype, params, _ := mime.ParseMediaType(r.Header.Get("Content-Type")) 21 | charset, ok := params["charset"] 22 | if !ok { 23 | charset = "UTF-8" 24 | } 25 | 26 | // per net/http doc, means that the length is known and non-null 27 | if r.ContentLength > 0 && 28 | !(mediatype == "application/json" && strings.ToUpper(charset) == "UTF-8") { 29 | 30 | Error(w, 31 | "Bad Content-Type or charset, expected 'application/json'", 32 | http.StatusUnsupportedMediaType, 33 | ) 34 | return 35 | } 36 | 37 | // call the wrapped handler 38 | handler(w, r) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/content_type_checker_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "github.com/ant0ine/go-json-rest/rest/test" 5 | "testing" 6 | ) 7 | 8 | func TestContentTypeCheckerMiddleware(t *testing.T) { 9 | 10 | api := NewApi() 11 | 12 | // the middleware to test 13 | api.Use(&ContentTypeCheckerMiddleware{}) 14 | 15 | // a simple app 16 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 17 | w.WriteJson(map[string]string{"Id": "123"}) 18 | })) 19 | 20 | // wrap all 21 | handler := api.MakeHandler() 22 | 23 | // no payload, no content length, no check 24 | recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/", nil)) 25 | recorded.CodeIs(200) 26 | 27 | // JSON payload with correct content type 28 | recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("POST", "http://localhost/", map[string]string{"Id": "123"})) 29 | recorded.CodeIs(200) 30 | 31 | // JSON payload with correct content type specifying the utf-8 charset 32 | req := test.MakeSimpleRequest("POST", "http://localhost/", map[string]string{"Id": "123"}) 33 | req.Header.Set("Content-Type", "application/json; charset=utf-8") 34 | recorded = test.RunRequest(t, handler, req) 35 | recorded.CodeIs(200) 36 | 37 | // JSON payload with incorrect content type 38 | req = test.MakeSimpleRequest("POST", "http://localhost/", map[string]string{"Id": "123"}) 39 | req.Header.Set("Content-Type", "text/x-json") 40 | recorded = test.RunRequest(t, handler, req) 41 | recorded.CodeIs(415) 42 | 43 | // JSON payload with correct content type but incorrect charset 44 | req = test.MakeSimpleRequest("POST", "http://localhost/", map[string]string{"Id": "123"}) 45 | req.Header.Set("Content-Type", "application/json; charset=ISO-8859-1") 46 | recorded = test.RunRequest(t, handler, req) 47 | recorded.CodeIs(415) 48 | } 49 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/cors_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | 7 | "github.com/ant0ine/go-json-rest/rest/test" 8 | ) 9 | 10 | func TestCorsMiddlewareEmptyAccessControlRequestHeaders(t *testing.T) { 11 | api := NewApi() 12 | 13 | // the middleware to test 14 | api.Use(&CorsMiddleware{ 15 | OriginValidator: func(_ string, _ *Request) bool { 16 | return true 17 | }, 18 | AllowedMethods: []string{ 19 | "GET", 20 | "POST", 21 | "PUT", 22 | }, 23 | AllowedHeaders: []string{ 24 | "Origin", 25 | "Referer", 26 | }, 27 | }) 28 | 29 | // wrap all 30 | handler := api.MakeHandler() 31 | 32 | req, _ := http.NewRequest("OPTIONS", "http://localhost", nil) 33 | req.Header.Set("Origin", "http://another.host") 34 | req.Header.Set("Access-Control-Request-Method", "PUT") 35 | req.Header.Set("Access-Control-Request-Headers", "") 36 | 37 | recorded := test.RunRequest(t, handler, req) 38 | t.Logf("recorded: %+v\n", recorded.Recorder) 39 | recorded.CodeIs(200) 40 | recorded.HeaderIs("Access-Control-Allow-Methods", "GET,POST,PUT") 41 | recorded.HeaderIs("Access-Control-Allow-Headers", "Origin,Referer") 42 | recorded.HeaderIs("Access-Control-Allow-Origin", "http://another.host") 43 | } 44 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/doc.go: -------------------------------------------------------------------------------- 1 | // A quick and easy way to setup a RESTful JSON API 2 | // 3 | // http://ant0ine.github.io/go-json-rest/ 4 | // 5 | // Go-Json-Rest is a thin layer on top of net/http that helps building RESTful JSON APIs easily. 6 | // It provides fast and scalable request routing using a Trie based implementation, helpers to deal 7 | // with JSON requests and responses, and middlewares for functionalities like CORS, Auth, Gzip, 8 | // Status, ... 9 | // 10 | // Example: 11 | // 12 | // package main 13 | // 14 | // import ( 15 | // "github.com/ant0ine/go-json-rest/rest" 16 | // "log" 17 | // "net/http" 18 | // ) 19 | // 20 | // type User struct { 21 | // Id string 22 | // Name string 23 | // } 24 | // 25 | // func GetUser(w rest.ResponseWriter, req *rest.Request) { 26 | // user := User{ 27 | // Id: req.PathParam("id"), 28 | // Name: "Antoine", 29 | // } 30 | // w.WriteJson(&user) 31 | // } 32 | // 33 | // func main() { 34 | // api := rest.NewApi() 35 | // api.Use(rest.DefaultDevStack...) 36 | // router, err := rest.MakeRouter( 37 | // rest.Get("/users/:id", GetUser), 38 | // ) 39 | // if err != nil { 40 | // log.Fatal(err) 41 | // } 42 | // api.SetApp(router) 43 | // log.Fatal(http.ListenAndServe(":8080", api.MakeHandler())) 44 | // } 45 | // 46 | // 47 | package rest 48 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/gzip_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "github.com/ant0ine/go-json-rest/rest/test" 5 | "testing" 6 | ) 7 | 8 | func TestGzipEnabled(t *testing.T) { 9 | 10 | api := NewApi() 11 | 12 | // the middleware to test 13 | api.Use(&GzipMiddleware{}) 14 | 15 | // router app with success and error paths 16 | router, err := MakeRouter( 17 | Get("/ok", func(w ResponseWriter, r *Request) { 18 | w.WriteJson(map[string]string{"Id": "123"}) 19 | }), 20 | Get("/error", func(w ResponseWriter, r *Request) { 21 | Error(w, "gzipped error", 500) 22 | }), 23 | ) 24 | if err != nil { 25 | t.Fatal(err) 26 | } 27 | 28 | api.SetApp(router) 29 | 30 | // wrap all 31 | handler := api.MakeHandler() 32 | 33 | recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/ok", nil)) 34 | recorded.CodeIs(200) 35 | recorded.ContentTypeIsJson() 36 | recorded.ContentEncodingIsGzip() 37 | recorded.HeaderIs("Vary", "Accept-Encoding") 38 | 39 | recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/error", nil)) 40 | recorded.CodeIs(500) 41 | recorded.ContentTypeIsJson() 42 | recorded.ContentEncodingIsGzip() 43 | recorded.HeaderIs("Vary", "Accept-Encoding") 44 | } 45 | 46 | func TestGzipDisabled(t *testing.T) { 47 | 48 | api := NewApi() 49 | 50 | // router app with success and error paths 51 | router, err := MakeRouter( 52 | Get("/ok", func(w ResponseWriter, r *Request) { 53 | w.WriteJson(map[string]string{"Id": "123"}) 54 | }), 55 | ) 56 | if err != nil { 57 | t.Fatal(err) 58 | } 59 | 60 | api.SetApp(router) 61 | handler := api.MakeHandler() 62 | 63 | recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/ok", nil)) 64 | recorded.CodeIs(200) 65 | recorded.ContentTypeIsJson() 66 | recorded.HeaderIs("Content-Encoding", "") 67 | recorded.HeaderIs("Vary", "") 68 | } 69 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/if.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | // IfMiddleware evaluates at runtime a condition based on the current request, and decides to 8 | // execute one of the other Middleware based on this boolean. 9 | type IfMiddleware struct { 10 | 11 | // Runtime condition that decides of the execution of IfTrue of IfFalse. 12 | Condition func(r *Request) bool 13 | 14 | // Middleware to run when the condition is true. Note that the middleware is initialized 15 | // weather if will be used or not. (Optional, pass-through if not set) 16 | IfTrue Middleware 17 | 18 | // Middleware to run when the condition is false. Note that the middleware is initialized 19 | // weather if will be used or not. (Optional, pass-through if not set) 20 | IfFalse Middleware 21 | } 22 | 23 | // MiddlewareFunc makes TimerMiddleware implement the Middleware interface. 24 | func (mw *IfMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { 25 | 26 | if mw.Condition == nil { 27 | log.Fatal("IfMiddleware Condition is required") 28 | } 29 | 30 | var ifTrueHandler HandlerFunc 31 | if mw.IfTrue != nil { 32 | ifTrueHandler = mw.IfTrue.MiddlewareFunc(h) 33 | } else { 34 | ifTrueHandler = h 35 | } 36 | 37 | var ifFalseHandler HandlerFunc 38 | if mw.IfFalse != nil { 39 | ifFalseHandler = mw.IfFalse.MiddlewareFunc(h) 40 | } else { 41 | ifFalseHandler = h 42 | } 43 | 44 | return func(w ResponseWriter, r *Request) { 45 | 46 | if mw.Condition(r) { 47 | ifTrueHandler(w, r) 48 | } else { 49 | ifFalseHandler(w, r) 50 | } 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/if_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "github.com/ant0ine/go-json-rest/rest/test" 5 | "testing" 6 | ) 7 | 8 | func TestIfMiddleware(t *testing.T) { 9 | 10 | api := NewApi() 11 | 12 | // the middleware to test 13 | api.Use(&IfMiddleware{ 14 | Condition: func(r *Request) bool { 15 | if r.URL.Path == "/true" { 16 | return true 17 | } 18 | return false 19 | }, 20 | IfTrue: MiddlewareSimple(func(handler HandlerFunc) HandlerFunc { 21 | return func(w ResponseWriter, r *Request) { 22 | r.Env["TRUE_MIDDLEWARE"] = true 23 | handler(w, r) 24 | } 25 | }), 26 | IfFalse: MiddlewareSimple(func(handler HandlerFunc) HandlerFunc { 27 | return func(w ResponseWriter, r *Request) { 28 | r.Env["FALSE_MIDDLEWARE"] = true 29 | handler(w, r) 30 | } 31 | }), 32 | }) 33 | 34 | // a simple app 35 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 36 | w.WriteJson(r.Env) 37 | })) 38 | 39 | // wrap all 40 | handler := api.MakeHandler() 41 | 42 | recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/", nil)) 43 | recorded.CodeIs(200) 44 | recorded.ContentTypeIsJson() 45 | recorded.BodyIs("{\"FALSE_MIDDLEWARE\":true}") 46 | 47 | recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/true", nil)) 48 | recorded.CodeIs(200) 49 | recorded.ContentTypeIsJson() 50 | recorded.BodyIs("{\"TRUE_MIDDLEWARE\":true}") 51 | } 52 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/json_indent_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "github.com/ant0ine/go-json-rest/rest/test" 5 | "testing" 6 | ) 7 | 8 | func TestJsonIndentMiddleware(t *testing.T) { 9 | 10 | api := NewApi() 11 | 12 | // the middleware to test 13 | api.Use(&JsonIndentMiddleware{}) 14 | 15 | // a simple app 16 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 17 | w.WriteJson(map[string]string{"Id": "123"}) 18 | })) 19 | 20 | // wrap all 21 | handler := api.MakeHandler() 22 | 23 | req := test.MakeSimpleRequest("GET", "http://localhost/", nil) 24 | recorded := test.RunRequest(t, handler, req) 25 | recorded.CodeIs(200) 26 | recorded.ContentTypeIsJson() 27 | recorded.BodyIs("{\n \"Id\": \"123\"\n}") 28 | } 29 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/jsonp_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ant0ine/go-json-rest/rest/test" 7 | ) 8 | 9 | func TestJsonpMiddleware(t *testing.T) { 10 | 11 | api := NewApi() 12 | 13 | // the middleware to test 14 | api.Use(&JsonpMiddleware{}) 15 | 16 | // router app with success and error paths 17 | router, err := MakeRouter( 18 | Get("/ok", func(w ResponseWriter, r *Request) { 19 | w.WriteJson(map[string]string{"Id": "123"}) 20 | }), 21 | Get("/error", func(w ResponseWriter, r *Request) { 22 | Error(w, "jsonp error", 500) 23 | }), 24 | ) 25 | if err != nil { 26 | t.Fatal(err) 27 | } 28 | 29 | api.SetApp(router) 30 | 31 | // wrap all 32 | handler := api.MakeHandler() 33 | 34 | recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/ok?callback=parseResponse", nil)) 35 | recorded.CodeIs(200) 36 | recorded.HeaderIs("Content-Type", "text/javascript") 37 | recorded.HeaderIs("Content-Disposition", "filename=f.txt") 38 | recorded.HeaderIs("X-Content-Type-Options", "nosniff") 39 | recorded.BodyIs("/**/parseResponse({\"Id\":\"123\"})") 40 | 41 | recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/error?callback=parseResponse", nil)) 42 | recorded.CodeIs(500) 43 | recorded.HeaderIs("Content-Type", "text/javascript") 44 | recorded.HeaderIs("Content-Disposition", "filename=f.txt") 45 | recorded.HeaderIs("X-Content-Type-Options", "nosniff") 46 | recorded.BodyIs("/**/parseResponse({\"Error\":\"jsonp error\"})") 47 | } 48 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/middleware_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | type testMiddleware struct { 8 | name string 9 | } 10 | 11 | func (mw *testMiddleware) MiddlewareFunc(handler HandlerFunc) HandlerFunc { 12 | return func(w ResponseWriter, r *Request) { 13 | if r.Env["BEFORE"] == nil { 14 | r.Env["BEFORE"] = mw.name 15 | } else { 16 | r.Env["BEFORE"] = r.Env["BEFORE"].(string) + mw.name 17 | } 18 | handler(w, r) 19 | if r.Env["AFTER"] == nil { 20 | r.Env["AFTER"] = mw.name 21 | } else { 22 | r.Env["AFTER"] = r.Env["AFTER"].(string) + mw.name 23 | } 24 | } 25 | } 26 | 27 | func TestWrapMiddlewares(t *testing.T) { 28 | 29 | a := &testMiddleware{"A"} 30 | b := &testMiddleware{"B"} 31 | c := &testMiddleware{"C"} 32 | 33 | app := func(w ResponseWriter, r *Request) { 34 | // do nothing 35 | } 36 | 37 | handlerFunc := WrapMiddlewares([]Middleware{a, b, c}, app) 38 | 39 | // fake request 40 | r := &Request{ 41 | nil, 42 | nil, 43 | map[string]interface{}{}, 44 | } 45 | 46 | handlerFunc(nil, r) 47 | 48 | before := r.Env["BEFORE"].(string) 49 | if before != "ABC" { 50 | t.Error("middleware executed in the wrong order, expected ABC") 51 | } 52 | 53 | after := r.Env["AFTER"].(string) 54 | if after != "CBA" { 55 | t.Error("middleware executed in the wrong order, expected CBA") 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/powered_by.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | const xPoweredByDefault = "go-json-rest" 4 | 5 | // PoweredByMiddleware adds the "X-Powered-By" header to the HTTP response. 6 | type PoweredByMiddleware struct { 7 | 8 | // If specified, used as the value for the "X-Powered-By" response header. 9 | // Defaults to "go-json-rest". 10 | XPoweredBy string 11 | } 12 | 13 | // MiddlewareFunc makes PoweredByMiddleware implement the Middleware interface. 14 | func (mw *PoweredByMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { 15 | 16 | poweredBy := xPoweredByDefault 17 | if mw.XPoweredBy != "" { 18 | poweredBy = mw.XPoweredBy 19 | } 20 | 21 | return func(w ResponseWriter, r *Request) { 22 | 23 | w.Header().Add("X-Powered-By", poweredBy) 24 | 25 | // call the handler 26 | h(w, r) 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/powered_by_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "github.com/ant0ine/go-json-rest/rest/test" 5 | "testing" 6 | ) 7 | 8 | func TestPoweredByMiddleware(t *testing.T) { 9 | 10 | api := NewApi() 11 | 12 | // the middleware to test 13 | api.Use(&PoweredByMiddleware{ 14 | XPoweredBy: "test", 15 | }) 16 | 17 | // a simple app 18 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 19 | w.WriteJson(map[string]string{"Id": "123"}) 20 | })) 21 | 22 | // wrap all 23 | handler := api.MakeHandler() 24 | 25 | req := test.MakeSimpleRequest("GET", "http://localhost/", nil) 26 | recorded := test.RunRequest(t, handler, req) 27 | recorded.CodeIs(200) 28 | recorded.ContentTypeIsJson() 29 | recorded.HeaderIs("X-Powered-By", "test") 30 | } 31 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/recover.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | "os" 9 | "runtime/debug" 10 | ) 11 | 12 | // RecoverMiddleware catches the panic errors that occur in the wrapped HandleFunc, 13 | // and convert them to 500 responses. 14 | type RecoverMiddleware struct { 15 | 16 | // Custom logger used for logging the panic errors, 17 | // optional, defaults to log.New(os.Stderr, "", 0) 18 | Logger *log.Logger 19 | 20 | // If true, the log records will be printed as JSON. Convenient for log parsing. 21 | EnableLogAsJson bool 22 | 23 | // If true, when a "panic" happens, the error string and the stack trace will be 24 | // printed in the 500 response body. 25 | EnableResponseStackTrace bool 26 | } 27 | 28 | // MiddlewareFunc makes RecoverMiddleware implement the Middleware interface. 29 | func (mw *RecoverMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { 30 | 31 | // set the default Logger 32 | if mw.Logger == nil { 33 | mw.Logger = log.New(os.Stderr, "", 0) 34 | } 35 | 36 | return func(w ResponseWriter, r *Request) { 37 | 38 | // catch user code's panic, and convert to http response 39 | defer func() { 40 | if reco := recover(); reco != nil { 41 | trace := debug.Stack() 42 | 43 | // log the trace 44 | message := fmt.Sprintf("%s\n%s", reco, trace) 45 | mw.logError(message) 46 | 47 | // write error response 48 | if mw.EnableResponseStackTrace { 49 | Error(w, message, http.StatusInternalServerError) 50 | } else { 51 | Error(w, "Internal Server Error", http.StatusInternalServerError) 52 | } 53 | } 54 | }() 55 | 56 | // call the handler 57 | h(w, r) 58 | } 59 | } 60 | 61 | func (mw *RecoverMiddleware) logError(message string) { 62 | if mw.EnableLogAsJson { 63 | record := map[string]string{ 64 | "error": message, 65 | } 66 | b, err := json.Marshal(&record) 67 | if err != nil { 68 | panic(err) 69 | } 70 | mw.Logger.Printf("%s", b) 71 | } else { 72 | mw.Logger.Print(message) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/recover_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "github.com/ant0ine/go-json-rest/rest/test" 5 | "io/ioutil" 6 | "log" 7 | "testing" 8 | ) 9 | 10 | func TestRecoverMiddleware(t *testing.T) { 11 | 12 | api := NewApi() 13 | 14 | // the middleware to test 15 | api.Use(&RecoverMiddleware{ 16 | Logger: log.New(ioutil.Discard, "", 0), 17 | EnableLogAsJson: false, 18 | EnableResponseStackTrace: true, 19 | }) 20 | 21 | // a simple app that fails 22 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 23 | panic("test") 24 | })) 25 | 26 | // wrap all 27 | handler := api.MakeHandler() 28 | 29 | req := test.MakeSimpleRequest("GET", "http://localhost/", nil) 30 | recorded := test.RunRequest(t, handler, req) 31 | recorded.CodeIs(500) 32 | recorded.ContentTypeIsJson() 33 | 34 | // payload 35 | payload := map[string]string{} 36 | err := recorded.DecodeJsonPayload(&payload) 37 | if err != nil { 38 | t.Fatal(err) 39 | } 40 | if payload["Error"] == "" { 41 | t.Errorf("Expected an error message, got: %v", payload) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/response_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ant0ine/go-json-rest/rest/test" 7 | ) 8 | 9 | func TestResponseNotIndent(t *testing.T) { 10 | 11 | writer := responseWriter{ 12 | nil, 13 | false, 14 | } 15 | 16 | got, err := writer.EncodeJson(map[string]bool{"test": true}) 17 | if err != nil { 18 | t.Error(err.Error()) 19 | } 20 | gotStr := string(got) 21 | expected := "{\"test\":true}" 22 | if gotStr != expected { 23 | t.Error(expected + " was the expected, but instead got " + gotStr) 24 | } 25 | } 26 | 27 | // The following tests could instantiate only the reponseWriter, 28 | // but using the Api object allows to use the rest/test utilities, 29 | // and make the tests easier to write. 30 | 31 | func TestWriteJsonResponse(t *testing.T) { 32 | 33 | api := NewApi() 34 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 35 | w.WriteJson(map[string]string{"Id": "123"}) 36 | })) 37 | 38 | recorded := test.RunRequest(t, api.MakeHandler(), test.MakeSimpleRequest("GET", "http://localhost/", nil)) 39 | recorded.CodeIs(200) 40 | recorded.ContentTypeIsJson() 41 | recorded.BodyIs("{\"Id\":\"123\"}") 42 | } 43 | 44 | func TestErrorResponse(t *testing.T) { 45 | 46 | api := NewApi() 47 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 48 | Error(w, "test", 500) 49 | })) 50 | 51 | recorded := test.RunRequest(t, api.MakeHandler(), test.MakeSimpleRequest("GET", "http://localhost/", nil)) 52 | recorded.CodeIs(500) 53 | recorded.ContentTypeIsJson() 54 | recorded.BodyIs("{\"Error\":\"test\"}") 55 | } 56 | 57 | func TestNotFoundResponse(t *testing.T) { 58 | 59 | api := NewApi() 60 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 61 | NotFound(w, r) 62 | })) 63 | 64 | recorded := test.RunRequest(t, api.MakeHandler(), test.MakeSimpleRequest("GET", "http://localhost/", nil)) 65 | recorded.CodeIs(404) 66 | recorded.ContentTypeIsJson() 67 | recorded.BodyIs("{\"Error\":\"Resource not found\"}") 68 | } 69 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/route_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestReverseRouteResolution(t *testing.T) { 8 | 9 | noParam := &Route{"GET", "/", nil} 10 | got := noParam.MakePath(nil) 11 | expected := "/" 12 | if got != expected { 13 | t.Errorf("expected %s, got %s", expected, got) 14 | } 15 | 16 | twoParams := &Route{"GET", "/:id.:format", nil} 17 | got = twoParams.MakePath( 18 | map[string]string{ 19 | "id": "123", 20 | "format": "json", 21 | }, 22 | ) 23 | expected = "/123.json" 24 | if got != expected { 25 | t.Errorf("expected %s, got %s", expected, got) 26 | } 27 | 28 | splatParam := &Route{"GET", "/:id.*format", nil} 29 | got = splatParam.MakePath( 30 | map[string]string{ 31 | "id": "123", 32 | "format": "tar.gz", 33 | }, 34 | ) 35 | expected = "/123.tar.gz" 36 | if got != expected { 37 | t.Errorf("expected %s, got %s", expected, got) 38 | } 39 | 40 | relaxedParam := &Route{"GET", "/#file", nil} 41 | got = relaxedParam.MakePath( 42 | map[string]string{ 43 | "file": "a.txt", 44 | }, 45 | ) 46 | expected = "/a.txt" 47 | if got != expected { 48 | t.Errorf("expected %s, got %s", expected, got) 49 | } 50 | } 51 | 52 | func TestShortcutMethods(t *testing.T) { 53 | 54 | r := Head("/", nil) 55 | if r.HttpMethod != "HEAD" { 56 | t.Errorf("expected HEAD, got %s", r.HttpMethod) 57 | } 58 | 59 | r = Get("/", nil) 60 | if r.HttpMethod != "GET" { 61 | t.Errorf("expected GET, got %s", r.HttpMethod) 62 | } 63 | 64 | r = Post("/", nil) 65 | if r.HttpMethod != "POST" { 66 | t.Errorf("expected POST, got %s", r.HttpMethod) 67 | } 68 | 69 | r = Put("/", nil) 70 | if r.HttpMethod != "PUT" { 71 | t.Errorf("expected PUT, got %s", r.HttpMethod) 72 | } 73 | 74 | r = Patch("/", nil) 75 | if r.HttpMethod != "PATCH" { 76 | t.Errorf("expected PATCH, got %s", r.HttpMethod) 77 | } 78 | 79 | r = Delete("/", nil) 80 | if r.HttpMethod != "DELETE" { 81 | t.Errorf("expected DELETE, got %s", r.HttpMethod) 82 | } 83 | 84 | r = Options("/", nil) 85 | if r.HttpMethod != "OPTIONS" { 86 | t.Errorf("expected OPTIONS, got %s", r.HttpMethod) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/status_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "github.com/ant0ine/go-json-rest/rest/test" 5 | "testing" 6 | ) 7 | 8 | func TestStatusMiddleware(t *testing.T) { 9 | 10 | api := NewApi() 11 | 12 | // the middlewares 13 | status := &StatusMiddleware{} 14 | api.Use(status) 15 | api.Use(&TimerMiddleware{}) 16 | api.Use(&RecorderMiddleware{}) 17 | 18 | // an app that return the Status 19 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 20 | w.WriteJson(status.GetStatus()) 21 | })) 22 | 23 | // wrap all 24 | handler := api.MakeHandler() 25 | 26 | // one request 27 | recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/1", nil)) 28 | recorded.CodeIs(200) 29 | recorded.ContentTypeIsJson() 30 | 31 | // another request 32 | recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/2", nil)) 33 | recorded.CodeIs(200) 34 | recorded.ContentTypeIsJson() 35 | 36 | // payload 37 | payload := map[string]interface{}{} 38 | err := recorded.DecodeJsonPayload(&payload) 39 | if err != nil { 40 | t.Fatal(err) 41 | } 42 | 43 | if payload["Pid"] == nil { 44 | t.Error("Expected a non nil Pid") 45 | } 46 | 47 | if payload["TotalCount"].(float64) != 1 { 48 | t.Errorf("TotalCount 1 Expected, got: %f", payload["TotalCount"].(float64)) 49 | } 50 | 51 | if payload["StatusCodeCount"].(map[string]interface{})["200"].(float64) != 1 { 52 | t.Errorf("StatusCodeCount 200 1 Expected, got: %f", payload["StatusCodeCount"].(map[string]interface{})["200"].(float64)) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/test/doc.go: -------------------------------------------------------------------------------- 1 | // Utility functions to help writing tests for a Go-Json-Rest app 2 | // 3 | // Go comes with net/http/httptest to help writing test for an http 4 | // server. When this http server implements a JSON REST API, some basic 5 | // checks end up to be always the same. This test package tries to save 6 | // some typing by providing helpers for this particular use case. 7 | // 8 | // package main 9 | // 10 | // import ( 11 | // "github.com/ant0ine/go-json-rest/rest" 12 | // "github.com/ant0ine/go-json-rest/rest/test" 13 | // "testing" 14 | // ) 15 | // 16 | // func TestSimpleRequest(t *testing.T) { 17 | // api := rest.NewApi() 18 | // api.Use(rest.DefaultDevStack...) 19 | // router, err := rest.MakeRouter( 20 | // rest.Get("/r", func(w rest.ResponseWriter, r *rest.Request) { 21 | // w.WriteJson(map[string]string{"Id": "123"}) 22 | // }), 23 | // ) 24 | // if err != nil { 25 | // log.Fatal(err) 26 | // } 27 | // api.SetApp(router) 28 | // recorded := test.RunRequest(t, api.MakeHandler(), 29 | // test.MakeSimpleRequest("GET", "http://1.2.3.4/r", nil)) 30 | // recorded.CodeIs(200) 31 | // recorded.ContentTypeIsJson() 32 | // } 33 | package test 34 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/timer.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // TimerMiddleware computes the elapsed time spent during the execution of the wrapped handler. 8 | // The result is available to the wrapping handlers as request.Env["ELAPSED_TIME"].(*time.Duration), 9 | // and as request.Env["START_TIME"].(*time.Time) 10 | type TimerMiddleware struct{} 11 | 12 | // MiddlewareFunc makes TimerMiddleware implement the Middleware interface. 13 | func (mw *TimerMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { 14 | return func(w ResponseWriter, r *Request) { 15 | 16 | start := time.Now() 17 | r.Env["START_TIME"] = &start 18 | 19 | // call the handler 20 | h(w, r) 21 | 22 | end := time.Now() 23 | elapsed := end.Sub(start) 24 | r.Env["ELAPSED_TIME"] = &elapsed 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/vendor/github.com/ant0ine/go-json-rest/rest/timer_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "github.com/ant0ine/go-json-rest/rest/test" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestTimerMiddleware(t *testing.T) { 10 | 11 | api := NewApi() 12 | 13 | // a middleware carrying the Env tests 14 | api.Use(MiddlewareSimple(func(handler HandlerFunc) HandlerFunc { 15 | return func(w ResponseWriter, r *Request) { 16 | 17 | handler(w, r) 18 | 19 | if r.Env["ELAPSED_TIME"] == nil { 20 | t.Error("ELAPSED_TIME is nil") 21 | } 22 | elapsedTime := r.Env["ELAPSED_TIME"].(*time.Duration) 23 | if elapsedTime.Nanoseconds() <= 0 { 24 | t.Errorf( 25 | "ELAPSED_TIME is expected to be at least 1 nanosecond %d", 26 | elapsedTime.Nanoseconds(), 27 | ) 28 | } 29 | 30 | if r.Env["START_TIME"] == nil { 31 | t.Error("START_TIME is nil") 32 | } 33 | start := r.Env["START_TIME"].(*time.Time) 34 | if start.After(time.Now()) { 35 | t.Errorf( 36 | "START_TIME is expected to be in the past %s", 37 | start.String(), 38 | ) 39 | } 40 | } 41 | })) 42 | 43 | // the middleware to test 44 | api.Use(&TimerMiddleware{}) 45 | 46 | // a simple app 47 | api.SetApp(AppSimple(func(w ResponseWriter, r *Request) { 48 | w.WriteJson(map[string]string{"Id": "123"}) 49 | })) 50 | 51 | // wrap all 52 | handler := api.MakeHandler() 53 | 54 | req := test.MakeSimpleRequest("GET", "http://localhost/", nil) 55 | recorded := test.RunRequest(t, handler, req) 56 | recorded.CodeIs(200) 57 | recorded.ContentTypeIsJson() 58 | } 59 | -------------------------------------------------------------------------------- /src/vendor/github.com/go-sql-driver/mysql/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: go 3 | go: 4 | - 1.2 5 | - 1.3 6 | - 1.4 7 | - 1.5 8 | - 1.6 9 | - tip 10 | 11 | before_script: 12 | - mysql -e 'create database gotest;' 13 | -------------------------------------------------------------------------------- /src/vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | ## Reporting Issues 4 | 5 | Before creating a new Issue, please check first if a similar Issue [already exists](https://github.com/go-sql-driver/mysql/issues?state=open) or was [recently closed](https://github.com/go-sql-driver/mysql/issues?direction=desc&page=1&sort=updated&state=closed). 6 | 7 | ## Contributing Code 8 | 9 | By contributing to this project, you share your code under the Mozilla Public License 2, as specified in the LICENSE file. 10 | Don't forget to add yourself to the AUTHORS file. 11 | 12 | ### Code Review 13 | 14 | Everyone is invited to review and comment on pull requests. 15 | If it looks fine to you, comment with "LGTM" (Looks good to me). 16 | 17 | If changes are required, notice the reviewers with "PTAL" (Please take another look) after committing the fixes. 18 | 19 | Before merging the Pull Request, at least one [team member](https://github.com/go-sql-driver?tab=members) must have commented with "LGTM". 20 | 21 | ## Development Ideas 22 | 23 | If you are looking for ideas for code contributions, please check our [Development Ideas](https://github.com/go-sql-driver/mysql/wiki/Development-Ideas) Wiki page. 24 | -------------------------------------------------------------------------------- /src/vendor/github.com/go-sql-driver/mysql/appengine.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | // +build appengine 10 | 11 | package mysql 12 | 13 | import ( 14 | "google.golang.org/appengine/cloudsql" 15 | ) 16 | 17 | func init() { 18 | RegisterDial("cloudsql", cloudsql.Dial) 19 | } 20 | -------------------------------------------------------------------------------- /src/vendor/github.com/go-sql-driver/mysql/connection_go18_test.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | // +build go1.8 10 | 11 | package mysql 12 | 13 | import ( 14 | "context" 15 | "database/sql/driver" 16 | "testing" 17 | ) 18 | 19 | func TestCheckNamedValue(t *testing.T) { 20 | value := driver.NamedValue{Value: ^uint64(0)} 21 | x := &mysqlConn{} 22 | err := x.CheckNamedValue(&value) 23 | 24 | if err != nil { 25 | t.Fatal("uint64 high-bit not convertible", err) 26 | } 27 | 28 | if value.Value != "18446744073709551615" { 29 | t.Fatalf("uint64 high-bit not converted, got %#v %T", value.Value, value.Value) 30 | } 31 | } 32 | 33 | // TestCleanCancel tests passed context is cancelled at start. 34 | // No packet should be sent. Connection should keep current status. 35 | func TestCleanCancel(t *testing.T) { 36 | mc := &mysqlConn{ 37 | closech: make(chan struct{}), 38 | } 39 | mc.startWatcher() 40 | defer mc.cleanup() 41 | 42 | ctx, cancel := context.WithCancel(context.Background()) 43 | cancel() 44 | 45 | for i := 0; i < 3; i++ { // Repeat same behavior 46 | err := mc.Ping(ctx) 47 | if err != context.Canceled { 48 | t.Errorf("expected context.Canceled, got %#v", err) 49 | } 50 | 51 | if mc.closed.IsSet() { 52 | t.Error("expected mc is not closed, closed actually") 53 | } 54 | 55 | if mc.watching { 56 | t.Error("expected watching is false, but true") 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/vendor/github.com/go-sql-driver/mysql/connection_test.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | import ( 12 | "database/sql/driver" 13 | "testing" 14 | ) 15 | 16 | func TestInterpolateParams(t *testing.T) { 17 | mc := &mysqlConn{ 18 | buf: newBuffer(nil), 19 | maxAllowedPacket: maxPacketSize, 20 | cfg: &Config{ 21 | InterpolateParams: true, 22 | }, 23 | } 24 | 25 | q, err := mc.interpolateParams("SELECT ?+?", []driver.Value{int64(42), "gopher"}) 26 | if err != nil { 27 | t.Errorf("Expected err=nil, got %#v", err) 28 | return 29 | } 30 | expected := `SELECT 42+'gopher'` 31 | if q != expected { 32 | t.Errorf("Expected: %q\nGot: %q", expected, q) 33 | } 34 | } 35 | 36 | func TestInterpolateParamsTooManyPlaceholders(t *testing.T) { 37 | mc := &mysqlConn{ 38 | buf: newBuffer(nil), 39 | maxAllowedPacket: maxPacketSize, 40 | cfg: &Config{ 41 | InterpolateParams: true, 42 | }, 43 | } 44 | 45 | q, err := mc.interpolateParams("SELECT ?+?", []driver.Value{int64(42)}) 46 | if err != driver.ErrSkip { 47 | t.Errorf("Expected err=driver.ErrSkip, got err=%#v, q=%#v", err, q) 48 | } 49 | } 50 | 51 | // We don't support placeholder in string literal for now. 52 | // https://github.com/go-sql-driver/mysql/pull/490 53 | func TestInterpolateParamsPlaceholderInString(t *testing.T) { 54 | mc := &mysqlConn{ 55 | buf: newBuffer(nil), 56 | maxAllowedPacket: maxPacketSize, 57 | cfg: &Config{ 58 | InterpolateParams: true, 59 | }, 60 | } 61 | 62 | q, err := mc.interpolateParams("SELECT 'abc?xyz',?", []driver.Value{int64(42)}) 63 | // When InterpolateParams support string literal, this should return `"SELECT 'abc?xyz', 42` 64 | if err != driver.ErrSkip { 65 | t.Errorf("Expected err=driver.ErrSkip, got err=%#v, q=%#v", err, q) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/vendor/github.com/go-sql-driver/mysql/errors_test.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | import ( 12 | "bytes" 13 | "log" 14 | "testing" 15 | ) 16 | 17 | func TestErrorsSetLogger(t *testing.T) { 18 | previous := errLog 19 | defer func() { 20 | errLog = previous 21 | }() 22 | 23 | // set up logger 24 | const expected = "prefix: test\n" 25 | buffer := bytes.NewBuffer(make([]byte, 0, 64)) 26 | logger := log.New(buffer, "prefix: ", 0) 27 | 28 | // print 29 | SetLogger(logger) 30 | errLog.Print("test") 31 | 32 | // check result 33 | if actual := buffer.String(); actual != expected { 34 | t.Errorf("expected %q, got %q", expected, actual) 35 | } 36 | } 37 | 38 | func TestErrorsStrictIgnoreNotes(t *testing.T) { 39 | runTests(t, dsn+"&sql_notes=false", func(dbt *DBTest) { 40 | dbt.mustExec("DROP TABLE IF EXISTS does_not_exist") 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /src/vendor/github.com/go-sql-driver/mysql/result.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | type mysqlResult struct { 12 | affectedRows int64 13 | insertId int64 14 | } 15 | 16 | func (res *mysqlResult) LastInsertId() (int64, error) { 17 | return res.insertId, nil 18 | } 19 | 20 | func (res *mysqlResult) RowsAffected() (int64, error) { 21 | return res.affectedRows, nil 22 | } 23 | -------------------------------------------------------------------------------- /src/vendor/github.com/go-sql-driver/mysql/transaction.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | type mysqlTx struct { 12 | mc *mysqlConn 13 | } 14 | 15 | func (tx *mysqlTx) Commit() (err error) { 16 | if tx.mc == nil || tx.mc.closed.IsSet() { 17 | return ErrInvalidConn 18 | } 19 | err = tx.mc.exec("COMMIT") 20 | tx.mc = nil 21 | return 22 | } 23 | 24 | func (tx *mysqlTx) Rollback() (err error) { 25 | if tx.mc == nil || tx.mc.closed.IsSet() { 26 | return ErrInvalidConn 27 | } 28 | err = tx.mc.exec("ROLLBACK") 29 | tx.mc = nil 30 | return 31 | } 32 | -------------------------------------------------------------------------------- /src/vendor/github.com/go-sql-driver/mysql/utils_go17.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | // +build go1.7 10 | // +build !go1.8 11 | 12 | package mysql 13 | 14 | import "crypto/tls" 15 | 16 | func cloneTLSConfig(c *tls.Config) *tls.Config { 17 | return &tls.Config{ 18 | Rand: c.Rand, 19 | Time: c.Time, 20 | Certificates: c.Certificates, 21 | NameToCertificate: c.NameToCertificate, 22 | GetCertificate: c.GetCertificate, 23 | RootCAs: c.RootCAs, 24 | NextProtos: c.NextProtos, 25 | ServerName: c.ServerName, 26 | ClientAuth: c.ClientAuth, 27 | ClientCAs: c.ClientCAs, 28 | InsecureSkipVerify: c.InsecureSkipVerify, 29 | CipherSuites: c.CipherSuites, 30 | PreferServerCipherSuites: c.PreferServerCipherSuites, 31 | SessionTicketsDisabled: c.SessionTicketsDisabled, 32 | SessionTicketKey: c.SessionTicketKey, 33 | ClientSessionCache: c.ClientSessionCache, 34 | MinVersion: c.MinVersion, 35 | MaxVersion: c.MaxVersion, 36 | CurvePreferences: c.CurvePreferences, 37 | DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, 38 | Renegotiation: c.Renegotiation, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/vendor/github.com/go-sql-driver/mysql/utils_go18.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | // +build go1.8 10 | 11 | package mysql 12 | 13 | import ( 14 | "crypto/tls" 15 | "database/sql" 16 | "database/sql/driver" 17 | "errors" 18 | "fmt" 19 | ) 20 | 21 | func cloneTLSConfig(c *tls.Config) *tls.Config { 22 | return c.Clone() 23 | } 24 | 25 | func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) { 26 | dargs := make([]driver.Value, len(named)) 27 | for n, param := range named { 28 | if len(param.Name) > 0 { 29 | // TODO: support the use of Named Parameters #561 30 | return nil, errors.New("mysql: driver does not support the use of Named Parameters") 31 | } 32 | dargs[n] = param.Value 33 | } 34 | return dargs, nil 35 | } 36 | 37 | func mapIsolationLevel(level driver.IsolationLevel) (string, error) { 38 | switch sql.IsolationLevel(level) { 39 | case sql.LevelRepeatableRead: 40 | return "REPEATABLE READ", nil 41 | case sql.LevelReadCommitted: 42 | return "READ COMMITTED", nil 43 | case sql.LevelReadUncommitted: 44 | return "READ UNCOMMITTED", nil 45 | case sql.LevelSerializable: 46 | return "SERIALIZABLE", nil 47 | default: 48 | return "", fmt.Errorf("mysql: unsupported isolation level: %v", level) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/vendor/github.com/go-sql-driver/mysql/utils_go18_test.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | // +build go1.8 10 | 11 | package mysql 12 | 13 | import ( 14 | "database/sql" 15 | "database/sql/driver" 16 | "testing" 17 | ) 18 | 19 | func TestIsolationLevelMapping(t *testing.T) { 20 | data := []struct { 21 | level driver.IsolationLevel 22 | expected string 23 | }{ 24 | { 25 | level: driver.IsolationLevel(sql.LevelReadCommitted), 26 | expected: "READ COMMITTED", 27 | }, 28 | { 29 | level: driver.IsolationLevel(sql.LevelRepeatableRead), 30 | expected: "REPEATABLE READ", 31 | }, 32 | { 33 | level: driver.IsolationLevel(sql.LevelReadUncommitted), 34 | expected: "READ UNCOMMITTED", 35 | }, 36 | { 37 | level: driver.IsolationLevel(sql.LevelSerializable), 38 | expected: "SERIALIZABLE", 39 | }, 40 | } 41 | 42 | for i, td := range data { 43 | if actual, err := mapIsolationLevel(td.level); actual != td.expected || err != nil { 44 | t.Fatal(i, td.expected, actual, err) 45 | } 46 | } 47 | 48 | // check unsupported mapping 49 | expectedErr := "mysql: unsupported isolation level: 7" 50 | actual, err := mapIsolationLevel(driver.IsolationLevel(sql.LevelLinearizable)) 51 | if actual != "" || err == nil { 52 | t.Fatal("Expected error on unsupported isolation level") 53 | } 54 | if err.Error() != expectedErr { 55 | t.Fatalf("Expected error to be %q, got %q", expectedErr, err) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/vendor/github.com/mattn/go-runewidth/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - tip 4 | before_install: 5 | - go get github.com/mattn/goveralls 6 | - go get golang.org/x/tools/cmd/cover 7 | script: 8 | - $HOME/gopath/bin/goveralls -repotoken lAKAWPzcGsD3A8yBX3BGGtRUdJ6CaGERL 9 | -------------------------------------------------------------------------------- /src/vendor/github.com/mattn/go-runewidth/README.mkd: -------------------------------------------------------------------------------- 1 | go-runewidth 2 | ============ 3 | 4 | [![Build Status](https://travis-ci.org/mattn/go-runewidth.png?branch=master)](https://travis-ci.org/mattn/go-runewidth) 5 | [![Coverage Status](https://coveralls.io/repos/mattn/go-runewidth/badge.png?branch=HEAD)](https://coveralls.io/r/mattn/go-runewidth?branch=HEAD) 6 | [![GoDoc](https://godoc.org/github.com/mattn/go-runewidth?status.svg)](http://godoc.org/github.com/mattn/go-runewidth) 7 | 8 | Provides functions to get fixed width of the character or string. 9 | 10 | Usage 11 | ----- 12 | 13 | ```go 14 | runewidth.StringWidth("つのだ☆HIRO") == 12 15 | ``` 16 | 17 | 18 | Author 19 | ------ 20 | 21 | Yasuhiro Matsumoto 22 | 23 | License 24 | ------- 25 | 26 | under the MIT License: http://mattn.mit-license.org/2013 27 | -------------------------------------------------------------------------------- /src/vendor/github.com/mattn/go-runewidth/runewidth_js.go: -------------------------------------------------------------------------------- 1 | // +build js 2 | 3 | package runewidth 4 | 5 | func IsEastAsian() bool { 6 | // TODO: Implement this for the web. Detect east asian in a compatible way, and return true. 7 | return false 8 | } 9 | -------------------------------------------------------------------------------- /src/vendor/github.com/mattn/go-runewidth/runewidth_posix.go: -------------------------------------------------------------------------------- 1 | // +build !windows,!js 2 | 3 | package runewidth 4 | 5 | import ( 6 | "os" 7 | "regexp" 8 | "strings" 9 | ) 10 | 11 | var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`) 12 | 13 | func IsEastAsian() bool { 14 | locale := os.Getenv("LC_CTYPE") 15 | if locale == "" { 16 | locale = os.Getenv("LANG") 17 | } 18 | 19 | // ignore C locale 20 | if locale == "POSIX" || locale == "C" { 21 | return false 22 | } 23 | if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') { 24 | return false 25 | } 26 | 27 | charset := strings.ToLower(locale) 28 | r := reLoc.FindStringSubmatch(locale) 29 | if len(r) == 2 { 30 | charset = strings.ToLower(r[1]) 31 | } 32 | 33 | if strings.HasSuffix(charset, "@cjk_narrow") { 34 | return false 35 | } 36 | 37 | for pos, b := range []byte(charset) { 38 | if b == '@' { 39 | charset = charset[:pos] 40 | break 41 | } 42 | } 43 | 44 | mbc_max := 1 45 | switch charset { 46 | case "utf-8", "utf8": 47 | mbc_max = 6 48 | case "jis": 49 | mbc_max = 8 50 | case "eucjp": 51 | mbc_max = 3 52 | case "euckr", "euccn": 53 | mbc_max = 2 54 | case "sjis", "cp932", "cp51932", "cp936", "cp949", "cp950": 55 | mbc_max = 2 56 | case "big5": 57 | mbc_max = 2 58 | case "gbk", "gb2312": 59 | mbc_max = 2 60 | } 61 | 62 | if mbc_max > 1 && (charset[0] != 'u' || 63 | strings.HasPrefix(locale, "ja") || 64 | strings.HasPrefix(locale, "ko") || 65 | strings.HasPrefix(locale, "zh")) { 66 | return true 67 | } 68 | return false 69 | } 70 | -------------------------------------------------------------------------------- /src/vendor/github.com/mattn/go-runewidth/runewidth_windows.go: -------------------------------------------------------------------------------- 1 | package runewidth 2 | 3 | import ( 4 | "syscall" 5 | ) 6 | 7 | var ( 8 | kernel32 = syscall.NewLazyDLL("kernel32") 9 | procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP") 10 | ) 11 | 12 | func IsEastAsian() bool { 13 | r1, _, _ := procGetConsoleOutputCP.Call() 14 | if r1 == 0 { 15 | return false 16 | } 17 | 18 | switch int(r1) { 19 | case 932, 51932, 936, 949, 950: 20 | return true 21 | } 22 | 23 | return false 24 | } 25 | -------------------------------------------------------------------------------- /src/vendor/github.com/olekukonko/tablewriter/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.1 5 | - 1.2 6 | - 1.3 7 | - 1.4 8 | - tip 9 | -------------------------------------------------------------------------------- /src/vendor/github.com/olekukonko/tablewriter/LICENCE.md: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 by Oleku Konko 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/vendor/github.com/olekukonko/tablewriter/csv.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Oleku Konko All rights reserved. 2 | // Use of this source code is governed by a MIT 3 | // license that can be found in the LICENSE file. 4 | 5 | // This module is a Table Writer API for the Go Programming Language. 6 | // The protocols were written in pure Go and works on windows and unix systems 7 | 8 | package tablewriter 9 | 10 | import ( 11 | "encoding/csv" 12 | "io" 13 | "os" 14 | ) 15 | 16 | // Start A new table by importing from a CSV file 17 | // Takes io.Writer and csv File name 18 | func NewCSV(writer io.Writer, fileName string, hasHeader bool) (*Table, error) { 19 | file, err := os.Open(fileName) 20 | if err != nil { 21 | return &Table{}, err 22 | } 23 | defer file.Close() 24 | csvReader := csv.NewReader(file) 25 | t, err := NewCSVReader(writer, csvReader, hasHeader) 26 | return t, err 27 | } 28 | 29 | // Start a New Table Writer with csv.Reader 30 | // This enables customisation such as reader.Comma = ';' 31 | // See http://golang.org/src/pkg/encoding/csv/reader.go?s=3213:3671#L94 32 | func NewCSVReader(writer io.Writer, csvReader *csv.Reader, hasHeader bool) (*Table, error) { 33 | t := NewWriter(writer) 34 | if hasHeader { 35 | // Read the first row 36 | headers, err := csvReader.Read() 37 | if err != nil { 38 | return &Table{}, err 39 | } 40 | t.SetHeader(headers) 41 | } 42 | for { 43 | record, err := csvReader.Read() 44 | if err == io.EOF { 45 | break 46 | } else if err != nil { 47 | return &Table{}, err 48 | } 49 | t.Append(record) 50 | } 51 | return t, nil 52 | } 53 | -------------------------------------------------------------------------------- /src/vendor/github.com/olekukonko/tablewriter/csv2table/README.md: -------------------------------------------------------------------------------- 1 | ASCII Table Writer Tool 2 | ========= 3 | 4 | Generate ASCII table on the fly via command line ... Installation is simple as 5 | 6 | #### Get Tool 7 | 8 | go get github.com/olekukonko/tablewriter/csv2table 9 | 10 | #### Install Tool 11 | 12 | go install github.com/olekukonko/tablewriter/csv2table 13 | 14 | 15 | #### Usage 16 | 17 | csv2table -f test.csv 18 | 19 | #### Support for Piping 20 | 21 | cat test.csv | csv2table -p=true 22 | 23 | #### Output 24 | 25 | ``` 26 | +------------+-----------+---------+ 27 | | FIRST NAME | LAST NAME | SSN | 28 | +------------+-----------+---------+ 29 | | John | Barry | 123456 | 30 | | Kathy | Smith | 687987 | 31 | | Bob | McCornick | 3979870 | 32 | +------------+-----------+---------+ 33 | ``` 34 | 35 | #### Another Piping with Header set to `false` 36 | 37 | echo dance,with,me | csv2table -p=true -h=false 38 | 39 | #### Output 40 | 41 | +-------+------+-----+ 42 | | dance | with | me | 43 | +-------+------+-----+ 44 | -------------------------------------------------------------------------------- /src/vendor/github.com/olekukonko/tablewriter/csv2table/csv2table.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/csv" 5 | "flag" 6 | "fmt" 7 | "github.com/olekukonko/tablewriter" 8 | "io" 9 | "os" 10 | "unicode/utf8" 11 | ) 12 | 13 | var ( 14 | fileName = flag.String("f", "", "Set file with eg. sample.csv") 15 | delimiter = flag.String("d", ",", "Set CSV File delimiter eg. ,|;|\t ") 16 | header = flag.Bool("h", true, "Set header options eg. true|false ") 17 | align = flag.String("a", "none", "Set aligmement with eg. none|left|right|center") 18 | pipe = flag.Bool("p", false, "Suport for Piping from STDIN") 19 | border = flag.Bool("b", true, "Enable / disable table border") 20 | ) 21 | 22 | func main() { 23 | flag.Parse() 24 | fmt.Println() 25 | if *pipe || hasArg("-p") { 26 | process(os.Stdin) 27 | } else { 28 | if *fileName == "" { 29 | fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) 30 | flag.PrintDefaults() 31 | fmt.Println() 32 | os.Exit(1) 33 | } 34 | processFile() 35 | } 36 | fmt.Println() 37 | } 38 | 39 | func hasArg(name string) bool { 40 | for _, v := range os.Args { 41 | if name == v { 42 | return true 43 | } 44 | } 45 | return false 46 | } 47 | func processFile() { 48 | r, err := os.Open(*fileName) 49 | if err != nil { 50 | exit(err) 51 | } 52 | defer r.Close() 53 | process(r) 54 | } 55 | func process(r io.Reader) { 56 | csvReader := csv.NewReader(r) 57 | rune, size := utf8.DecodeRuneInString(*delimiter) 58 | if size == 0 { 59 | rune = ',' 60 | } 61 | csvReader.Comma = rune 62 | 63 | table, err := tablewriter.NewCSVReader(os.Stdout, csvReader, *header) 64 | 65 | if err != nil { 66 | exit(err) 67 | } 68 | 69 | switch *align { 70 | case "left": 71 | table.SetAlignment(tablewriter.ALIGN_LEFT) 72 | case "right": 73 | table.SetAlignment(tablewriter.ALIGN_RIGHT) 74 | case "center": 75 | table.SetAlignment(tablewriter.ALIGN_CENTER) 76 | } 77 | table.SetBorder(*border) 78 | table.Render() 79 | } 80 | 81 | func exit(err error) { 82 | fmt.Fprintf(os.Stderr, "#Error : %s", err) 83 | os.Exit(1) 84 | } 85 | -------------------------------------------------------------------------------- /src/vendor/github.com/olekukonko/tablewriter/test.csv: -------------------------------------------------------------------------------- 1 | first_name,last_name,ssn 2 | John,Barry,123456 3 | Kathy,Smith,687987 4 | Bob,McCornick,3979870 -------------------------------------------------------------------------------- /src/vendor/github.com/olekukonko/tablewriter/test_info.csv: -------------------------------------------------------------------------------- 1 | Field,Type,Null,Key,Default,Extra 2 | user_id,smallint(5),NO,PRI,NULL,auto_increment 3 | username,varchar(10),NO,,NULL, 4 | password,varchar(100),NO,,NULL, -------------------------------------------------------------------------------- /src/vendor/github.com/olekukonko/tablewriter/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Oleku Konko All rights reserved. 2 | // Use of this source code is governed by a MIT 3 | // license that can be found in the LICENSE file. 4 | 5 | // This module is a Table Writer API for the Go Programming Language. 6 | // The protocols were written in pure Go and works on windows and unix systems 7 | 8 | package tablewriter 9 | 10 | import ( 11 | "math" 12 | "regexp" 13 | "strings" 14 | 15 | "github.com/mattn/go-runewidth" 16 | ) 17 | 18 | var ansi = regexp.MustCompile("\033\\[(?:[0-9]{1,3}(?:;[0-9]{1,3})*)?[m|K]") 19 | 20 | func DisplayWidth(str string) int { 21 | return runewidth.StringWidth(ansi.ReplaceAllLiteralString(str, "")) 22 | } 23 | 24 | // Simple Condition for string 25 | // Returns value based on condition 26 | func ConditionString(cond bool, valid, inValid string) string { 27 | if cond { 28 | return valid 29 | } 30 | return inValid 31 | } 32 | 33 | // Format Table Header 34 | // Replace _ , . and spaces 35 | func Title(name string) string { 36 | name = strings.Replace(name, "_", " ", -1) 37 | name = strings.Replace(name, ".", " ", -1) 38 | name = strings.TrimSpace(name) 39 | return strings.ToUpper(name) 40 | } 41 | 42 | // Pad String 43 | // Attempts to play string in the center 44 | func Pad(s, pad string, width int) string { 45 | gap := width - DisplayWidth(s) 46 | if gap > 0 { 47 | gapLeft := int(math.Ceil(float64(gap / 2))) 48 | gapRight := gap - gapLeft 49 | return strings.Repeat(string(pad), gapLeft) + s + strings.Repeat(string(pad), gapRight) 50 | } 51 | return s 52 | } 53 | 54 | // Pad String Right position 55 | // This would pace string at the left side fo the screen 56 | func PadRight(s, pad string, width int) string { 57 | gap := width - DisplayWidth(s) 58 | if gap > 0 { 59 | return s + strings.Repeat(string(pad), gap) 60 | } 61 | return s 62 | } 63 | 64 | // Pad String Left position 65 | // This would pace string at the right side fo the screen 66 | func PadLeft(s, pad string, width int) string { 67 | gap := width - DisplayWidth(s) 68 | if gap > 0 { 69 | return strings.Repeat(string(pad), gap) + s 70 | } 71 | return s 72 | } 73 | -------------------------------------------------------------------------------- /src/vendor/github.com/olekukonko/tablewriter/wrap_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Oleku Konko All rights reserved. 2 | // Use of this source code is governed by a MIT 3 | // license that can be found in the LICENSE file. 4 | 5 | // This module is a Table Writer API for the Go Programming Language. 6 | // The protocols were written in pure Go and works on windows and unix systems 7 | 8 | package tablewriter 9 | 10 | import ( 11 | "strings" 12 | "testing" 13 | ) 14 | 15 | var text = "The quick brown fox jumps over the lazy dog." 16 | 17 | func TestWrap(t *testing.T) { 18 | exp := []string{ 19 | "The", "quick", "brown", "fox", 20 | "jumps", "over", "the", "lazy", "dog."} 21 | 22 | got, _ := WrapString(text, 6) 23 | if len(exp) != len(got) { 24 | t.Fail() 25 | } 26 | } 27 | 28 | func TestWrapOneLine(t *testing.T) { 29 | exp := "The quick brown fox jumps over the lazy dog." 30 | words, _ := WrapString(text, 500) 31 | got := strings.Join(words, string(sp)) 32 | if exp != got { 33 | t.Fail() 34 | } 35 | } 36 | 37 | func TestUnicode(t *testing.T) { 38 | input := "Česká řeřicha" 39 | wordsUnicode, _ := WrapString(input, 13) 40 | // input contains 13 runes, so it fits on one line. 41 | if len(wordsUnicode) != 1 { 42 | t.Fail() 43 | } 44 | } 45 | 46 | func TestDisplayWidth(t *testing.T) { 47 | input := "Česká řeřicha" 48 | if n := DisplayWidth(input); n != 13 { 49 | t.Errorf("Wants: %d Got: %d", 13, n) 50 | } 51 | input = "\033[43;30m" + input + "\033[00m" 52 | if n := DisplayWidth(input); n != 13 { 53 | t.Errorf("Wants: %d Got: %d", 13, n) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/vendor/github.com/pierrre/gotestcover/.gitignore: -------------------------------------------------------------------------------- 1 | coverage.txt 2 | coverage.html -------------------------------------------------------------------------------- /src/vendor/github.com/pierrre/gotestcover/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | sudo: false 4 | 5 | go: 6 | - 1.6.2 7 | - tip 8 | 9 | before_install: 10 | # Redo the travis setup but with the pierre/gotestcover path. This is needed so the package path is correct 11 | - mkdir -p $HOME/gopath/src/github.com/pierrre/gotestcover 12 | - rsync -az ${TRAVIS_BUILD_DIR}/ $HOME/gopath/src/github.com/pierrre/gotestcover 13 | - export TRAVIS_BUILD_DIR=$HOME/gopath/src/github.com/pierrre/gotestcover 14 | - cd $HOME/gopath/src/github.com/pierrre/gotestcover 15 | 16 | install: make setup 17 | 18 | script: 19 | - make check 20 | - make coverage 21 | 22 | after_success: 23 | - bash <(curl -s https://codecov.io/bash) 24 | -------------------------------------------------------------------------------- /src/vendor/github.com/pierrre/gotestcover/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2015 Pierre Durand 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/vendor/github.com/pierrre/gotestcover/Makefile: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | setup: 4 | go get -u -v github.com/golang/lint/golint 5 | go get -v -t ./... 6 | 7 | check: 8 | gofmt -d . 9 | go tool vet . 10 | golint 11 | 12 | coverage: 13 | gotestcover -coverprofile=coverage.txt github.com/pierrre/gotestcover 14 | go tool cover -html=coverage.txt -o=coverage.html 15 | 16 | clean: 17 | -rm coverage.txt 18 | -rm coverage.html 19 | gofmt -w . -------------------------------------------------------------------------------- /src/vendor/github.com/pierrre/gotestcover/README.md: -------------------------------------------------------------------------------- 1 | # Go test cover with multiple packages support 2 | 3 | ## Deprecated 4 | Just use this script instead: 5 | ``` 6 | echo 'mode: atomic' > coverage.txt && go list ./... | xargs -n1 -I{} sh -c 'go test -covermode=atomic -coverprofile=coverage.tmp {} && tail -n +2 coverage.tmp >> coverage.txt' && rm coverage.tmp 7 | ``` 8 | It's easier to customize, gives you better control, and doesn't require to download a third-party tool. 9 | 10 | The repository will remain, but I will not update it anymore. 11 | If you want to add new features, create a new fork. 12 | 13 | ## Features 14 | - Coverage profile with multiple packages (`go test` doesn't support that) 15 | 16 | ## Install 17 | `go get github.com/pierrre/gotestcover` 18 | 19 | ## Usage 20 | ```sh 21 | gotestcover -coverprofile=cover.out mypackage 22 | go tool cover -html=cover.out -o=cover.html 23 | ``` 24 | 25 | Run on multiple package with: 26 | - `package1 package2` 27 | - `package/...` 28 | 29 | Some `go test / build` flags are available. 30 | -------------------------------------------------------------------------------- /src/vendor/github.com/pierrre/gotestcover/gotestcover_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | ) 7 | 8 | func TestParseFlags(t *testing.T) { 9 | os.Args = []string{"gotestcover", 10 | "-v", 11 | "-a", 12 | "-x", 13 | "-tags=foobar", 14 | "-race", 15 | "-cpu=4", 16 | "-parallel=2", 17 | "-run=abc", 18 | "-short", 19 | "-timeout=15s", 20 | "-covermode=atomic", 21 | "-parallelpackages=2", 22 | "-coverprofile=cover.out", 23 | "-gae", 24 | } 25 | 26 | err := parseFlags() 27 | 28 | if err != nil { 29 | t.Fatal(err) 30 | } 31 | 32 | if !flagV { 33 | t.Errorf("flagV should be set to true") 34 | } 35 | 36 | if !flagA { 37 | t.Errorf("flagA should be set to true") 38 | } 39 | 40 | if !flagX { 41 | t.Errorf("flagX should be set to true") 42 | } 43 | 44 | if flagTags != "foobar" { 45 | t.Errorf("flagCPU is not equal to foobar, got %s", flagTags) 46 | } 47 | 48 | if !flagRace { 49 | t.Errorf("flagRace should be set to true") 50 | } 51 | 52 | if flagCPU != "4" { 53 | t.Errorf("flagCPU is not equal to 4, got %s", flagCPU) 54 | } 55 | 56 | if flagParallel != "2" { 57 | t.Errorf("flagParallel is not equal to 2, got %s", flagParallel) 58 | } 59 | 60 | if flagRun != "abc" { 61 | t.Errorf("flagRun is not equal to 'abc', got %s", flagRun) 62 | } 63 | 64 | if !flagShort { 65 | t.Errorf("flagShort should be set to true") 66 | } 67 | 68 | if flagTimeout != "15s" { 69 | t.Errorf("flagTimeout is not equal to '15s', got %s", flagTimeout) 70 | } 71 | 72 | if flagCoverMode != "atomic" { 73 | t.Errorf("flagCoverMode is not equal to 'atomic', got %s", flagCoverMode) 74 | } 75 | 76 | if flagParallelPackages != 2 { 77 | t.Errorf("flagParallelPackages is not equal to '2', got %d", flagParallelPackages) 78 | } 79 | 80 | if flagCoverProfile != "cover.out" { 81 | t.Errorf("flagCoverProfile is not equal to 'cover.out', got %s", flagCoverProfile) 82 | } 83 | 84 | if !flagGoogleAppEngine { 85 | t.Errorf("flagGoogleAppEngine should be set to true") 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/vendor/github.com/pkg/errors/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /src/vendor/github.com/pkg/errors/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go_import_path: github.com/pkg/errors 3 | go: 4 | - 1.4.3 5 | - 1.5.4 6 | - 1.6.3 7 | - 1.7.3 8 | - tip 9 | 10 | script: 11 | - go test -v ./... 12 | -------------------------------------------------------------------------------- /src/vendor/github.com/pkg/errors/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Dave Cheney 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /src/vendor/github.com/pkg/errors/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: build-{build}.{branch} 2 | 3 | clone_folder: C:\gopath\src\github.com\pkg\errors 4 | shallow_clone: true # for startup speed 5 | 6 | environment: 7 | GOPATH: C:\gopath 8 | 9 | platform: 10 | - x64 11 | 12 | # http://www.appveyor.com/docs/installed-software 13 | install: 14 | # some helpful output for debugging builds 15 | - go version 16 | - go env 17 | # pre-installed MinGW at C:\MinGW is 32bit only 18 | # but MSYS2 at C:\msys64 has mingw64 19 | - set PATH=C:\msys64\mingw64\bin;%PATH% 20 | - gcc --version 21 | - g++ --version 22 | 23 | build_script: 24 | - go install -v ./... 25 | 26 | test_script: 27 | - set PATH=C:\gopath\bin;%PATH% 28 | - go test -v ./... 29 | 30 | #artifacts: 31 | # - path: '%GOPATH%\bin\*.exe' 32 | deploy: off 33 | -------------------------------------------------------------------------------- /src/vendor/github.com/pkg/errors/bench_test.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package errors 4 | 5 | import ( 6 | "fmt" 7 | "testing" 8 | 9 | stderrors "errors" 10 | ) 11 | 12 | func noErrors(at, depth int) error { 13 | if at >= depth { 14 | return stderrors.New("no error") 15 | } 16 | return noErrors(at+1, depth) 17 | } 18 | 19 | func yesErrors(at, depth int) error { 20 | if at >= depth { 21 | return New("ye error") 22 | } 23 | return yesErrors(at+1, depth) 24 | } 25 | 26 | func BenchmarkErrors(b *testing.B) { 27 | var toperr error 28 | type run struct { 29 | stack int 30 | std bool 31 | } 32 | runs := []run{ 33 | {10, false}, 34 | {10, true}, 35 | {100, false}, 36 | {100, true}, 37 | {1000, false}, 38 | {1000, true}, 39 | } 40 | for _, r := range runs { 41 | part := "pkg/errors" 42 | if r.std { 43 | part = "errors" 44 | } 45 | name := fmt.Sprintf("%s-stack-%d", part, r.stack) 46 | b.Run(name, func(b *testing.B) { 47 | var err error 48 | f := yesErrors 49 | if r.std { 50 | f = noErrors 51 | } 52 | b.ReportAllocs() 53 | for i := 0; i < b.N; i++ { 54 | err = f(0, r.stack) 55 | } 56 | b.StopTimer() 57 | toperr = err 58 | }) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/cobra/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | # Vim files https://github.com/github/gitignore/blob/master/Global/Vim.gitignore 23 | # swap 24 | [._]*.s[a-w][a-z] 25 | [._]s[a-w][a-z] 26 | # session 27 | Session.vim 28 | # temporary 29 | .netrwhist 30 | *~ 31 | # auto-generated tag files 32 | tags 33 | 34 | *.exe 35 | 36 | cobra.test 37 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/cobra/.mailmap: -------------------------------------------------------------------------------- 1 | Steve Francia 2 | Bjørn Erik Pedersen 3 | Fabiano Franz 4 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/cobra/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | matrix: 4 | include: 5 | - go: 1.4.3 6 | env: NOVET=true # No bundled vet. 7 | - go: 1.5.4 8 | - go: 1.6.3 9 | - go: 1.7 10 | - go: tip 11 | allow_failures: 12 | - go: tip 13 | 14 | before_install: 15 | - mkdir -p bin 16 | - curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.3/shellcheck 17 | - chmod +x bin/shellcheck 18 | script: 19 | - PATH=$PATH:$PWD/bin go test -v ./... 20 | - go build 21 | - diff -u <(echo -n) <(gofmt -d -s .) 22 | - if [ -z $NOVET ]; then 23 | diff -u <(echo -n) <(go tool vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint'); 24 | fi 25 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/cobra/cobra/cmd/helpers_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "testing" 8 | ) 9 | 10 | var _ = fmt.Println 11 | var _ = os.Stderr 12 | 13 | func checkGuess(t *testing.T, wd, input, expected string) { 14 | testWd = wd 15 | inputPath = input 16 | guessProjectPath() 17 | 18 | if projectPath != expected { 19 | t.Errorf("Unexpected Project Path. \n Got: %q\nExpected: %q\n", projectPath, expected) 20 | } 21 | 22 | reset() 23 | } 24 | 25 | func reset() { 26 | testWd = "" 27 | inputPath = "" 28 | projectPath = "" 29 | } 30 | 31 | func TestProjectPath(t *testing.T) { 32 | checkGuess(t, "", filepath.Join("github.com", "spf13", "hugo"), filepath.Join(getSrcPath(), "github.com", "spf13", "hugo")) 33 | checkGuess(t, "", filepath.Join("spf13", "hugo"), filepath.Join(getSrcPath(), "github.com", "spf13", "hugo")) 34 | checkGuess(t, "", filepath.Join("/", "bar", "foo"), filepath.Join("/", "bar", "foo")) 35 | checkGuess(t, "/bar/foo", "baz", filepath.Join("/", "bar", "foo", "baz")) 36 | checkGuess(t, "/bar/foo/cmd", "", filepath.Join("/", "bar", "foo")) 37 | checkGuess(t, "/bar/foo/command", "", filepath.Join("/", "bar", "foo")) 38 | checkGuess(t, "/bar/foo/commands", "", filepath.Join("/", "bar", "foo")) 39 | checkGuess(t, "github.com/spf13/hugo/../hugo", "", filepath.Join("github.com", "spf13", "hugo")) 40 | } 41 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/cobra/cobra/main.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2015 Steve Francia . 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 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import "github.com/spf13/cobra/cobra/cmd" 17 | 18 | func main() { 19 | cmd.Execute() 20 | } 21 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/cobra/command_notwin.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package cobra 4 | 5 | var preExecHookFn func(*Command) 6 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/cobra/command_win.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package cobra 4 | 5 | import ( 6 | "os" 7 | "time" 8 | 9 | "github.com/inconshreveable/mousetrap" 10 | ) 11 | 12 | var preExecHookFn = preExecHook 13 | 14 | // enables an information splash screen on Windows if the CLI is started from explorer.exe. 15 | var MousetrapHelpText string = `This is a command line tool 16 | 17 | You need to open cmd.exe and run it from there. 18 | ` 19 | 20 | func preExecHook(c *Command) { 21 | if mousetrap.StartedByExplorer() { 22 | c.Print(MousetrapHelpText) 23 | time.Sleep(5 * time.Second) 24 | os.Exit(1) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/cobra/doc/man_docs.md: -------------------------------------------------------------------------------- 1 | # Generating Man Pages For Your Own cobra.Command 2 | 3 | Generating man pages from a cobra command is incredibly easy. An example is as follows: 4 | 5 | ```go 6 | package main 7 | 8 | import ( 9 | "github.com/spf13/cobra" 10 | "github.com/spf13/cobra/doc" 11 | ) 12 | 13 | func main() { 14 | cmd := &cobra.Command{ 15 | Use: "test", 16 | Short: "my test program", 17 | } 18 | header := &cobra.GenManHeader{ 19 | Title: "MINE", 20 | Section: "3", 21 | } 22 | doc.GenManTree(cmd, header, "/tmp") 23 | } 24 | ``` 25 | 26 | That will get you a man page `/tmp/test.1` 27 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/cobra/doc/man_examples_test.go: -------------------------------------------------------------------------------- 1 | package doc_test 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | 7 | "github.com/spf13/cobra" 8 | "github.com/spf13/cobra/doc" 9 | ) 10 | 11 | func ExampleCommand_GenManTree() { 12 | cmd := &cobra.Command{ 13 | Use: "test", 14 | Short: "my test program", 15 | } 16 | header := &doc.GenManHeader{ 17 | Title: "MINE", 18 | Section: "3", 19 | } 20 | doc.GenManTree(cmd, header, "/tmp") 21 | } 22 | 23 | func ExampleCommand_GenMan() { 24 | cmd := &cobra.Command{ 25 | Use: "test", 26 | Short: "my test program", 27 | } 28 | header := &doc.GenManHeader{ 29 | Title: "MINE", 30 | Section: "3", 31 | } 32 | out := new(bytes.Buffer) 33 | doc.GenMan(cmd, header, out) 34 | fmt.Print(out.String()) 35 | } 36 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/cobra/doc/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Red Hat 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 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package doc 15 | 16 | import "github.com/spf13/cobra" 17 | 18 | // Test to see if we have a reason to print See Also information in docs 19 | // Basically this is a test for a parent commend or a subcommand which is 20 | // both not deprecated and not the autogenerated help command. 21 | func hasSeeAlso(cmd *cobra.Command) bool { 22 | if cmd.HasParent() { 23 | return true 24 | } 25 | for _, c := range cmd.Commands() { 26 | if !c.IsAvailableCommand() || c.IsHelpCommand() { 27 | continue 28 | } 29 | return true 30 | } 31 | return false 32 | } 33 | 34 | type byName []*cobra.Command 35 | 36 | func (s byName) Len() int { return len(s) } 37 | func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 38 | func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() } 39 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/pflag/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: go 4 | 5 | go: 6 | - 1.5.4 7 | - 1.6.3 8 | - 1.7 9 | - tip 10 | 11 | matrix: 12 | allow_failures: 13 | - go: tip 14 | install: 15 | - go get github.com/golang/lint/golint 16 | - export PATH=$GOPATH/bin:$PATH 17 | - go install ./... 18 | 19 | script: 20 | - verify/all.sh -v 21 | - go test ./... 22 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/pflag/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Alex Ogier. All rights reserved. 2 | Copyright (c) 2012 The Go Authors. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/pflag/count_test.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | ) 8 | 9 | var _ = fmt.Printf 10 | 11 | func setUpCount(c *int) *FlagSet { 12 | f := NewFlagSet("test", ContinueOnError) 13 | f.CountVarP(c, "verbose", "v", "a counter") 14 | return f 15 | } 16 | 17 | func TestCount(t *testing.T) { 18 | testCases := []struct { 19 | input []string 20 | success bool 21 | expected int 22 | }{ 23 | {[]string{"-vvv"}, true, 3}, 24 | {[]string{"-v", "-v", "-v"}, true, 3}, 25 | {[]string{"-v", "--verbose", "-v"}, true, 3}, 26 | {[]string{"-v=3", "-v"}, true, 4}, 27 | {[]string{"-v=a"}, false, 0}, 28 | } 29 | 30 | devnull, _ := os.Open(os.DevNull) 31 | os.Stderr = devnull 32 | for i := range testCases { 33 | var count int 34 | f := setUpCount(&count) 35 | 36 | tc := &testCases[i] 37 | 38 | err := f.Parse(tc.input) 39 | if err != nil && tc.success == true { 40 | t.Errorf("expected success, got %q", err) 41 | continue 42 | } else if err == nil && tc.success == false { 43 | t.Errorf("expected failure, got success") 44 | continue 45 | } else if tc.success { 46 | c, err := f.GetCount("verbose") 47 | if err != nil { 48 | t.Errorf("Got error trying to fetch the counter flag") 49 | } 50 | if c != tc.expected { 51 | t.Errorf("expected %q, got %q", tc.expected, c) 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/pflag/export_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pflag 6 | 7 | import ( 8 | "io/ioutil" 9 | "os" 10 | ) 11 | 12 | // Additional routines compiled into the package only during testing. 13 | 14 | // ResetForTesting clears all flag state and sets the usage function as directed. 15 | // After calling ResetForTesting, parse errors in flag handling will not 16 | // exit the program. 17 | func ResetForTesting(usage func()) { 18 | CommandLine = &FlagSet{ 19 | name: os.Args[0], 20 | errorHandling: ContinueOnError, 21 | output: ioutil.Discard, 22 | } 23 | Usage = usage 24 | } 25 | 26 | // GetCommandLine returns the default FlagSet. 27 | func GetCommandLine() *FlagSet { 28 | return CommandLine 29 | } 30 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/pflag/golangflag_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pflag 6 | 7 | import ( 8 | goflag "flag" 9 | "testing" 10 | ) 11 | 12 | func TestGoflags(t *testing.T) { 13 | goflag.String("stringFlag", "stringFlag", "stringFlag") 14 | goflag.Bool("boolFlag", false, "boolFlag") 15 | 16 | f := NewFlagSet("test", ContinueOnError) 17 | 18 | f.AddGoFlagSet(goflag.CommandLine) 19 | err := f.Parse([]string{"--stringFlag=bob", "--boolFlag"}) 20 | if err != nil { 21 | t.Fatal("expected no error; get", err) 22 | } 23 | 24 | getString, err := f.GetString("stringFlag") 25 | if err != nil { 26 | t.Fatal("expected no error; get", err) 27 | } 28 | if getString != "bob" { 29 | t.Fatalf("expected getString=bob but got getString=%s", getString) 30 | } 31 | 32 | getBool, err := f.GetBool("boolFlag") 33 | if err != nil { 34 | t.Fatal("expected no error; get", err) 35 | } 36 | if getBool != true { 37 | t.Fatalf("expected getBool=true but got getBool=%v", getBool) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/pflag/ip_test.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | "testing" 8 | ) 9 | 10 | func setUpIP(ip *net.IP) *FlagSet { 11 | f := NewFlagSet("test", ContinueOnError) 12 | f.IPVar(ip, "address", net.ParseIP("0.0.0.0"), "IP Address") 13 | return f 14 | } 15 | 16 | func TestIP(t *testing.T) { 17 | testCases := []struct { 18 | input string 19 | success bool 20 | expected string 21 | }{ 22 | {"0.0.0.0", true, "0.0.0.0"}, 23 | {" 0.0.0.0 ", true, "0.0.0.0"}, 24 | {"1.2.3.4", true, "1.2.3.4"}, 25 | {"127.0.0.1", true, "127.0.0.1"}, 26 | {"255.255.255.255", true, "255.255.255.255"}, 27 | {"", false, ""}, 28 | {"0", false, ""}, 29 | {"localhost", false, ""}, 30 | {"0.0.0", false, ""}, 31 | {"0.0.0.", false, ""}, 32 | {"0.0.0.0.", false, ""}, 33 | {"0.0.0.256", false, ""}, 34 | {"0 . 0 . 0 . 0", false, ""}, 35 | } 36 | 37 | devnull, _ := os.Open(os.DevNull) 38 | os.Stderr = devnull 39 | for i := range testCases { 40 | var addr net.IP 41 | f := setUpIP(&addr) 42 | 43 | tc := &testCases[i] 44 | 45 | arg := fmt.Sprintf("--address=%s", tc.input) 46 | err := f.Parse([]string{arg}) 47 | if err != nil && tc.success == true { 48 | t.Errorf("expected success, got %q", err) 49 | continue 50 | } else if err == nil && tc.success == false { 51 | t.Errorf("expected failure") 52 | continue 53 | } else if tc.success { 54 | ip, err := f.GetIP("address") 55 | if err != nil { 56 | t.Errorf("Got error trying to fetch the IP flag: %v", err) 57 | } 58 | if ip.String() != tc.expected { 59 | t.Errorf("expected %q, got %q", tc.expected, ip.String()) 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/pflag/ipnet_test.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | "testing" 8 | ) 9 | 10 | func setUpIPNet(ip *net.IPNet) *FlagSet { 11 | f := NewFlagSet("test", ContinueOnError) 12 | _, def, _ := net.ParseCIDR("0.0.0.0/0") 13 | f.IPNetVar(ip, "address", *def, "IP Address") 14 | return f 15 | } 16 | 17 | func TestIPNet(t *testing.T) { 18 | testCases := []struct { 19 | input string 20 | success bool 21 | expected string 22 | }{ 23 | {"0.0.0.0/0", true, "0.0.0.0/0"}, 24 | {" 0.0.0.0/0 ", true, "0.0.0.0/0"}, 25 | {"1.2.3.4/8", true, "1.0.0.0/8"}, 26 | {"127.0.0.1/16", true, "127.0.0.0/16"}, 27 | {"255.255.255.255/19", true, "255.255.224.0/19"}, 28 | {"255.255.255.255/32", true, "255.255.255.255/32"}, 29 | {"", false, ""}, 30 | {"/0", false, ""}, 31 | {"0", false, ""}, 32 | {"0/0", false, ""}, 33 | {"localhost/0", false, ""}, 34 | {"0.0.0/4", false, ""}, 35 | {"0.0.0./8", false, ""}, 36 | {"0.0.0.0./12", false, ""}, 37 | {"0.0.0.256/16", false, ""}, 38 | {"0.0.0.0 /20", false, ""}, 39 | {"0.0.0.0/ 24", false, ""}, 40 | {"0 . 0 . 0 . 0 / 28", false, ""}, 41 | {"0.0.0.0/33", false, ""}, 42 | } 43 | 44 | devnull, _ := os.Open(os.DevNull) 45 | os.Stderr = devnull 46 | for i := range testCases { 47 | var addr net.IPNet 48 | f := setUpIPNet(&addr) 49 | 50 | tc := &testCases[i] 51 | 52 | arg := fmt.Sprintf("--address=%s", tc.input) 53 | err := f.Parse([]string{arg}) 54 | if err != nil && tc.success == true { 55 | t.Errorf("expected success, got %q", err) 56 | continue 57 | } else if err == nil && tc.success == false { 58 | t.Errorf("expected failure") 59 | continue 60 | } else if tc.success { 61 | ip, err := f.GetIPNet("address") 62 | if err != nil { 63 | t.Errorf("Got error trying to fetch the IP flag: %v", err) 64 | } 65 | if ip.String() != tc.expected { 66 | t.Errorf("expected %q, got %q", tc.expected, ip.String()) 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/pflag/verify/all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | ROOT=$(dirname "${BASH_SOURCE}")/.. 8 | 9 | # Some useful colors. 10 | if [[ -z "${color_start-}" ]]; then 11 | declare -r color_start="\033[" 12 | declare -r color_red="${color_start}0;31m" 13 | declare -r color_yellow="${color_start}0;33m" 14 | declare -r color_green="${color_start}0;32m" 15 | declare -r color_norm="${color_start}0m" 16 | fi 17 | 18 | SILENT=true 19 | 20 | function is-excluded { 21 | for e in $EXCLUDE; do 22 | if [[ $1 -ef ${BASH_SOURCE} ]]; then 23 | return 24 | fi 25 | if [[ $1 -ef "$ROOT/hack/$e" ]]; then 26 | return 27 | fi 28 | done 29 | return 1 30 | } 31 | 32 | while getopts ":v" opt; do 33 | case $opt in 34 | v) 35 | SILENT=false 36 | ;; 37 | \?) 38 | echo "Invalid flag: -$OPTARG" >&2 39 | exit 1 40 | ;; 41 | esac 42 | done 43 | 44 | if $SILENT ; then 45 | echo "Running in the silent mode, run with -v if you want to see script logs." 46 | fi 47 | 48 | EXCLUDE="all.sh" 49 | 50 | ret=0 51 | for t in `ls $ROOT/verify/*.sh` 52 | do 53 | if is-excluded $t ; then 54 | echo "Skipping $t" 55 | continue 56 | fi 57 | if $SILENT ; then 58 | echo -e "Verifying $t" 59 | if bash "$t" &> /dev/null; then 60 | echo -e "${color_green}SUCCESS${color_norm}" 61 | else 62 | echo -e "${color_red}FAILED${color_norm}" 63 | ret=1 64 | fi 65 | else 66 | bash "$t" || ret=1 67 | fi 68 | done 69 | exit $ret 70 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/pflag/verify/gofmt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | ROOT=$(dirname "${BASH_SOURCE}")/.. 8 | 9 | pushd "${ROOT}" > /dev/null 10 | 11 | GOFMT=${GOFMT:-"gofmt"} 12 | bad_files=$(find . -name '*.go' | xargs $GOFMT -s -l) 13 | if [[ -n "${bad_files}" ]]; then 14 | echo "!!! '$GOFMT' needs to be run on the following files: " 15 | echo "${bad_files}" 16 | exit 1 17 | fi 18 | 19 | # ex: ts=2 sw=2 et filetype=sh 20 | -------------------------------------------------------------------------------- /src/vendor/github.com/spf13/pflag/verify/golint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ROOT=$(dirname "${BASH_SOURCE}")/.. 4 | GOLINT=${GOLINT:-"golint"} 5 | 6 | pushd "${ROOT}" > /dev/null 7 | bad_files=$($GOLINT -min_confidence=0.9 ./...) 8 | if [[ -n "${bad_files}" ]]; then 9 | echo "!!! '$GOLINT' problems: " 10 | echo "${bad_files}" 11 | exit 1 12 | fi 13 | popd > /dev/null 14 | 15 | # ex: ts=2 sw=2 et filetype=sh 16 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | 24 | .DS_Store 25 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | sudo: false 4 | 5 | go: 6 | - 1.1 7 | - 1.2 8 | - 1.3 9 | - 1.4 10 | - 1.5 11 | - 1.6 12 | - 1.7 13 | - tip 14 | 15 | script: 16 | - go test -v ./... 17 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/Godeps/Godeps.json: -------------------------------------------------------------------------------- 1 | { 2 | "ImportPath": "github.com/stretchr/testify", 3 | "GoVersion": "go1.5", 4 | "GodepVersion": "v74", 5 | "Packages": [ 6 | "./..." 7 | ], 8 | "Deps": [ 9 | { 10 | "ImportPath": "github.com/davecgh/go-spew/spew", 11 | "Comment": "v1.0.0-3-g6d21280", 12 | "Rev": "6d212800a42e8ab5c146b8ace3490ee17e5225f9" 13 | }, 14 | { 15 | "ImportPath": "github.com/pmezard/go-difflib/difflib", 16 | "Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d" 17 | }, 18 | { 19 | "ImportPath": "github.com/stretchr/objx", 20 | "Rev": "cbeaeb16a013161a98496fad62933b1d21786672" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/Godeps/Readme: -------------------------------------------------------------------------------- 1 | This directory tree is generated automatically by godep. 2 | 3 | Please do not edit. 4 | 5 | See https://github.com/tools/godep for more information. 6 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/LICENCE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell 2 | 3 | Please consider promoting this project if you find it useful. 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of the Software, 10 | and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 20 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 21 | OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 22 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell 2 | 3 | Please consider promoting this project if you find it useful. 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of the Software, 10 | and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 20 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 21 | OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 22 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { 3 | return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 4 | } 5 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/assert/doc.go: -------------------------------------------------------------------------------- 1 | // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. 2 | // 3 | // Example Usage 4 | // 5 | // The following is a complete example using assert in a standard test function: 6 | // import ( 7 | // "testing" 8 | // "github.com/stretchr/testify/assert" 9 | // ) 10 | // 11 | // func TestSomething(t *testing.T) { 12 | // 13 | // var a string = "Hello" 14 | // var b string = "Hello" 15 | // 16 | // assert.Equal(t, a, b, "The two words should be the same.") 17 | // 18 | // } 19 | // 20 | // if you assert many times, use the format below: 21 | // 22 | // import ( 23 | // "testing" 24 | // "github.com/stretchr/testify/assert" 25 | // ) 26 | // 27 | // func TestSomething(t *testing.T) { 28 | // assert := assert.New(t) 29 | // 30 | // var a string = "Hello" 31 | // var b string = "Hello" 32 | // 33 | // assert.Equal(a, b, "The two words should be the same.") 34 | // } 35 | // 36 | // Assertions 37 | // 38 | // Assertions allow you to easily write test code, and are global funcs in the `assert` package. 39 | // All assertion functions take, as the first argument, the `*testing.T` object provided by the 40 | // testing framework. This allows the assertion funcs to write the failings and other details to 41 | // the correct place. 42 | // 43 | // Every assertion function also takes an optional string message as the final argument, 44 | // allowing custom error messages to be appended to the message the assertion method outputs. 45 | package assert 46 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/assert/errors.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // AnError is an error instance useful for testing. If the code does not care 8 | // about error specifics, and only needs to return the error for example, this 9 | // error should be used to make the test code more readable. 10 | var AnError = errors.New("assert.AnError general error for testing") 11 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/assert/forward_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl 17 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/doc.go: -------------------------------------------------------------------------------- 1 | // Package testify is a set of packages that provide many tools for testifying that your code will behave as you intend. 2 | // 3 | // testify contains the following packages: 4 | // 5 | // The assert package provides a comprehensive set of assertion functions that tie in to the Go testing system. 6 | // 7 | // The http package contains tools to make it easier to test http activity using the Go testing system. 8 | // 9 | // The mock package provides a system by which it is possible to mock your objects and verify calls are happening as expected. 10 | // 11 | // The suite package provides a basic structure for using structs as testing suites, and methods on those structs as tests. It includes setup/teardown functionality in the way of interfaces. 12 | package testify 13 | 14 | // blank imports help docs. 15 | import ( 16 | // assert package 17 | _ "github.com/stretchr/testify/assert" 18 | // http package 19 | _ "github.com/stretchr/testify/http" 20 | // mock package 21 | _ "github.com/stretchr/testify/mock" 22 | ) 23 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/http/doc.go: -------------------------------------------------------------------------------- 1 | // Package http DEPRECATED USE net/http/httptest 2 | package http 3 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/http/test_response_writer.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | // TestResponseWriter DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead. 8 | type TestResponseWriter struct { 9 | 10 | // StatusCode is the last int written by the call to WriteHeader(int) 11 | StatusCode int 12 | 13 | // Output is a string containing the written bytes using the Write([]byte) func. 14 | Output string 15 | 16 | // header is the internal storage of the http.Header object 17 | header http.Header 18 | } 19 | 20 | // Header DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead. 21 | func (rw *TestResponseWriter) Header() http.Header { 22 | 23 | if rw.header == nil { 24 | rw.header = make(http.Header) 25 | } 26 | 27 | return rw.header 28 | } 29 | 30 | // Write DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead. 31 | func (rw *TestResponseWriter) Write(bytes []byte) (int, error) { 32 | 33 | // assume 200 success if no header has been set 34 | if rw.StatusCode == 0 { 35 | rw.WriteHeader(200) 36 | } 37 | 38 | // add these bytes to the output string 39 | rw.Output = rw.Output + string(bytes) 40 | 41 | // return normal values 42 | return 0, nil 43 | 44 | } 45 | 46 | // WriteHeader DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead. 47 | func (rw *TestResponseWriter) WriteHeader(i int) { 48 | rw.StatusCode = i 49 | } 50 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/http/test_round_tripper.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/stretchr/testify/mock" 5 | "net/http" 6 | ) 7 | 8 | // TestRoundTripper DEPRECATED USE net/http/httptest 9 | type TestRoundTripper struct { 10 | mock.Mock 11 | } 12 | 13 | // RoundTrip DEPRECATED USE net/http/httptest 14 | func (t *TestRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { 15 | args := t.Called(req) 16 | return args.Get(0).(*http.Response), args.Error(1) 17 | } 18 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/mock/doc.go: -------------------------------------------------------------------------------- 1 | // Package mock provides a system by which it is possible to mock your objects 2 | // and verify calls are happening as expected. 3 | // 4 | // Example Usage 5 | // 6 | // The mock package provides an object, Mock, that tracks activity on another object. It is usually 7 | // embedded into a test object as shown below: 8 | // 9 | // type MyTestObject struct { 10 | // // add a Mock object instance 11 | // mock.Mock 12 | // 13 | // // other fields go here as normal 14 | // } 15 | // 16 | // When implementing the methods of an interface, you wire your functions up 17 | // to call the Mock.Called(args...) method, and return the appropriate values. 18 | // 19 | // For example, to mock a method that saves the name and age of a person and returns 20 | // the year of their birth or an error, you might write this: 21 | // 22 | // func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) { 23 | // args := o.Called(firstname, lastname, age) 24 | // return args.Int(0), args.Error(1) 25 | // } 26 | // 27 | // The Int, Error and Bool methods are examples of strongly typed getters that take the argument 28 | // index position. Given this argument list: 29 | // 30 | // (12, true, "Something") 31 | // 32 | // You could read them out strongly typed like this: 33 | // 34 | // args.Int(0) 35 | // args.Bool(1) 36 | // args.String(2) 37 | // 38 | // For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion: 39 | // 40 | // return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine) 41 | // 42 | // This may cause a panic if the object you are getting is nil (the type assertion will fail), in those 43 | // cases you should check for nil first. 44 | package mock 45 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/package_test.go: -------------------------------------------------------------------------------- 1 | package testify 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | func TestImports(t *testing.T) { 9 | if assert.Equal(t, 1, 1) != true { 10 | t.Error("Something is wrong.") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/require/doc.go: -------------------------------------------------------------------------------- 1 | // Package require implements the same assertions as the `assert` package but 2 | // stops test execution when a test fails. 3 | // 4 | // Example Usage 5 | // 6 | // The following is a complete example using require in a standard test function: 7 | // import ( 8 | // "testing" 9 | // "github.com/stretchr/testify/require" 10 | // ) 11 | // 12 | // func TestSomething(t *testing.T) { 13 | // 14 | // var a string = "Hello" 15 | // var b string = "Hello" 16 | // 17 | // require.Equal(t, a, b, "The two words should be the same.") 18 | // 19 | // } 20 | // 21 | // Assertions 22 | // 23 | // The `require` package have same global functions as in the `assert` package, 24 | // but instead of returning a boolean result they call `t.FailNow()`. 25 | // 26 | // Every assertion function also takes an optional string message as the final argument, 27 | // allowing custom error messages to be appended to the message the assertion method outputs. 28 | package require 29 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/require/forward_requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl 17 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/require/require.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.Comment}} 2 | func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { 3 | if !assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { 4 | t.FailNow() 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { 3 | {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 4 | } 5 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/require/requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // TestingT is an interface wrapper around *testing.T 4 | type TestingT interface { 5 | Errorf(format string, args ...interface{}) 6 | FailNow() 7 | } 8 | 9 | //go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl 10 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/suite/interfaces.go: -------------------------------------------------------------------------------- 1 | package suite 2 | 3 | import "testing" 4 | 5 | // TestingSuite can store and return the current *testing.T context 6 | // generated by 'go test'. 7 | type TestingSuite interface { 8 | T() *testing.T 9 | SetT(*testing.T) 10 | } 11 | 12 | // SetupAllSuite has a SetupSuite method, which will run before the 13 | // tests in the suite are run. 14 | type SetupAllSuite interface { 15 | SetupSuite() 16 | } 17 | 18 | // SetupTestSuite has a SetupTest method, which will run before each 19 | // test in the suite. 20 | type SetupTestSuite interface { 21 | SetupTest() 22 | } 23 | 24 | // TearDownAllSuite has a TearDownSuite method, which will run after 25 | // all the tests in the suite have been run. 26 | type TearDownAllSuite interface { 27 | TearDownSuite() 28 | } 29 | 30 | // TearDownTestSuite has a TearDownTest method, which will run after 31 | // each test in the suite. 32 | type TearDownTestSuite interface { 33 | TearDownTest() 34 | } 35 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2012-2013 Dave Collins 4 | 5 | Permission to use, copy, modify, and distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is running on Google App Engine, compiled by GopherJS, or 17 | // "-tags safe" is added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build js appengine safe disableunsafe 20 | 21 | package spew 22 | 23 | import "reflect" 24 | 25 | const ( 26 | // UnsafeDisabled is a build-time constant which specifies whether or 27 | // not access to the unsafe package is available. 28 | UnsafeDisabled = true 29 | ) 30 | 31 | // unsafeReflectValue typically converts the passed reflect.Value into a one 32 | // that bypasses the typical safety restrictions preventing access to 33 | // unaddressable and unexported data. However, doing this relies on access to 34 | // the unsafe package. This is a stub version which simply returns the passed 35 | // reflect.Value when the unsafe package is not available. 36 | func unsafeReflectValue(v reflect.Value) reflect.Value { 37 | return v 38 | } 39 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Patrick Mezard 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | The names of its contributors may not be used to endorse or promote 14 | products derived from this software without specific prior written 15 | permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 18 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 20 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 23 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/LICENSE.md: -------------------------------------------------------------------------------- 1 | objx - by Mat Ryer and Tyler Bunnell 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2014 Stretchr, Inc. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/README.md: -------------------------------------------------------------------------------- 1 | # objx 2 | 3 | * Jump into the [API Documentation](http://godoc.org/github.com/stretchr/objx) 4 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/array-access.txt: -------------------------------------------------------------------------------- 1 | case []{1}: 2 | a := object.([]{1}) 3 | if isSet { 4 | a[index] = value.({1}) 5 | } else { 6 | if index >= len(a) { 7 | if panics { 8 | panic(fmt.Sprintf("objx: Index %d is out of range because the []{1} only contains %d items.", index, len(a))) 9 | } 10 | return nil 11 | } else { 12 | return a[index] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Codegen 5 | 6 | 17 | 18 | 19 | 20 |

21 | Template 22 |

23 |

24 | Use {x} as a placeholder for each argument. 25 |

26 | 27 | 28 |

29 | Arguments (comma separated) 30 |

31 |

32 | One block per line 33 |

34 | 35 | 36 |

37 | Output 38 |

39 | 40 | 41 | 42 | 43 | 44 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/types_list.txt: -------------------------------------------------------------------------------- 1 | Interface,interface{},"something",nil,Inter 2 | Map,map[string]interface{},map[string]interface{}{"name":"Tyler"},nil,MSI 3 | ObjxMap,(Map),New(1),New(nil),ObjxMap 4 | Bool,bool,true,false,Bool 5 | String,string,"hello","",Str 6 | Int,int,1,0,Int 7 | Int8,int8,1,0,Int8 8 | Int16,int16,1,0,Int16 9 | Int32,int32,1,0,Int32 10 | Int64,int64,1,0,Int64 11 | Uint,uint,1,0,Uint 12 | Uint8,uint8,1,0,Uint8 13 | Uint16,uint16,1,0,Uint16 14 | Uint32,uint32,1,0,Uint32 15 | Uint64,uint64,1,0,Uint64 16 | Uintptr,uintptr,1,0,Uintptr 17 | Float32,float32,1,0,Float32 18 | Float64,float64,1,0,Float64 19 | Complex64,complex64,1,0,Complex64 20 | Complex128,complex128,1,0,Complex128 21 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/constants.go: -------------------------------------------------------------------------------- 1 | package objx 2 | 3 | const ( 4 | // PathSeparator is the character used to separate the elements 5 | // of the keypath. 6 | // 7 | // For example, `location.address.city` 8 | PathSeparator string = "." 9 | 10 | // SignatureSeparator is the character that is used to 11 | // separate the Base64 string from the security signature. 12 | SignatureSeparator = "_" 13 | ) 14 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/security.go: -------------------------------------------------------------------------------- 1 | package objx 2 | 3 | import ( 4 | "crypto/sha1" 5 | "encoding/hex" 6 | ) 7 | 8 | // HashWithKey hashes the specified string using the security 9 | // key. 10 | func HashWithKey(data, key string) string { 11 | hash := sha1.New() 12 | hash.Write([]byte(data + ":" + key)) 13 | return hex.EncodeToString(hash.Sum(nil)) 14 | } 15 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/tests.go: -------------------------------------------------------------------------------- 1 | package objx 2 | 3 | // Has gets whether there is something at the specified selector 4 | // or not. 5 | // 6 | // If m is nil, Has will always return false. 7 | func (m Map) Has(selector string) bool { 8 | if m == nil { 9 | return false 10 | } 11 | return !m.Get(selector).IsNil() 12 | } 13 | 14 | // IsNil gets whether the data is nil or not. 15 | func (v *Value) IsNil() bool { 16 | return v == nil || v.data == nil 17 | } 18 | -------------------------------------------------------------------------------- /src/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/value.go: -------------------------------------------------------------------------------- 1 | package objx 2 | 3 | // Value provides methods for extracting interface{} data in various 4 | // types. 5 | type Value struct { 6 | // data contains the raw data being managed by this Value 7 | data interface{} 8 | } 9 | 10 | // Data returns the raw data contained by this Value 11 | func (v *Value) Data() interface{} { 12 | return v.data 13 | } 14 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/.gitignore: -------------------------------------------------------------------------------- 1 | /examples/blog/blog 2 | /examples/orders/orders 3 | /examples/basic/basic 4 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.2 5 | - 1.3 6 | - 1.4 7 | - 1.5 8 | - 1.6 9 | - tip 10 | 11 | script: go test -race 12 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/LICENSE: -------------------------------------------------------------------------------- 1 | The three clause BSD license (http://en.wikipedia.org/wiki/BSD_licenses) 2 | 3 | Copyright (c) 2013-2016, DATA-DOG team 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * The name DataDog.lt may not be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, 23 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 26 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 28 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/argument.go: -------------------------------------------------------------------------------- 1 | package sqlmock 2 | 3 | import "database/sql/driver" 4 | 5 | // Argument interface allows to match 6 | // any argument in specific way when used with 7 | // ExpectedQuery and ExpectedExec expectations. 8 | type Argument interface { 9 | Match(driver.Value) bool 10 | } 11 | 12 | // AnyArg will return an Argument which can 13 | // match any kind of arguments. 14 | // 15 | // Useful for time.Time or similar kinds of arguments. 16 | func AnyArg() Argument { 17 | return anyArgument{} 18 | } 19 | 20 | type anyArgument struct{} 21 | 22 | func (a anyArgument) Match(_ driver.Value) bool { 23 | return true 24 | } 25 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/argument_test.go: -------------------------------------------------------------------------------- 1 | package sqlmock 2 | 3 | import ( 4 | "database/sql/driver" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | type AnyTime struct{} 10 | 11 | // Match satisfies sqlmock.Argument interface 12 | func (a AnyTime) Match(v driver.Value) bool { 13 | _, ok := v.(time.Time) 14 | return ok 15 | } 16 | 17 | func TestAnyTimeArgument(t *testing.T) { 18 | t.Parallel() 19 | db, mock, err := New() 20 | if err != nil { 21 | t.Errorf("an error '%s' was not expected when opening a stub database connection", err) 22 | } 23 | defer db.Close() 24 | 25 | mock.ExpectExec("INSERT INTO users"). 26 | WithArgs("john", AnyTime{}). 27 | WillReturnResult(NewResult(1, 1)) 28 | 29 | _, err = db.Exec("INSERT INTO users(name, created_at) VALUES (?, ?)", "john", time.Now()) 30 | if err != nil { 31 | t.Errorf("error '%s' was not expected, while inserting a row", err) 32 | } 33 | 34 | if err := mock.ExpectationsWereMet(); err != nil { 35 | t.Errorf("there were unfulfilled expections: %s", err) 36 | } 37 | } 38 | 39 | func TestByteSliceArgument(t *testing.T) { 40 | t.Parallel() 41 | db, mock, err := New() 42 | if err != nil { 43 | t.Errorf("an error '%s' was not expected when opening a stub database connection", err) 44 | } 45 | defer db.Close() 46 | 47 | username := []byte("user") 48 | mock.ExpectExec("INSERT INTO users").WithArgs(username).WillReturnResult(NewResult(1, 1)) 49 | 50 | _, err = db.Exec("INSERT INTO users(username) VALUES (?)", username) 51 | if err != nil { 52 | t.Errorf("error '%s' was not expected, while inserting a row", err) 53 | } 54 | 55 | if err := mock.ExpectationsWereMet(); err != nil { 56 | t.Errorf("there were unfulfilled expections: %s", err) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/driver.go: -------------------------------------------------------------------------------- 1 | package sqlmock 2 | 3 | import ( 4 | "database/sql" 5 | "database/sql/driver" 6 | "fmt" 7 | "sync" 8 | ) 9 | 10 | var pool *mockDriver 11 | 12 | func init() { 13 | pool = &mockDriver{ 14 | conns: make(map[string]*sqlmock), 15 | } 16 | sql.Register("sqlmock", pool) 17 | } 18 | 19 | type mockDriver struct { 20 | sync.Mutex 21 | counter int 22 | conns map[string]*sqlmock 23 | } 24 | 25 | func (d *mockDriver) Open(dsn string) (driver.Conn, error) { 26 | d.Lock() 27 | defer d.Unlock() 28 | 29 | c, ok := d.conns[dsn] 30 | if !ok { 31 | return c, fmt.Errorf("expected a connection to be available, but it is not") 32 | } 33 | 34 | c.opened++ 35 | return c, nil 36 | } 37 | 38 | // New creates sqlmock database connection 39 | // and a mock to manage expectations. 40 | // Pings db so that all expectations could be 41 | // asserted. 42 | func New() (*sql.DB, Sqlmock, error) { 43 | pool.Lock() 44 | dsn := fmt.Sprintf("sqlmock_db_%d", pool.counter) 45 | pool.counter++ 46 | 47 | smock := &sqlmock{dsn: dsn, drv: pool, ordered: true} 48 | pool.conns[dsn] = smock 49 | pool.Unlock() 50 | 51 | return smock.open() 52 | } 53 | 54 | // NewWithDSN creates sqlmock database connection 55 | // with a specific DSN and a mock to manage expectations. 56 | // Pings db so that all expectations could be asserted. 57 | // 58 | // This method is introduced because of sql abstraction 59 | // libraries, which do not provide a way to initialize 60 | // with sql.DB instance. For example GORM library. 61 | // 62 | // Note, it will error if attempted to create with an 63 | // already used dsn 64 | // 65 | // It is not recommended to use this method, unless you 66 | // really need it and there is no other way around. 67 | func NewWithDSN(dsn string) (*sql.DB, Sqlmock, error) { 68 | pool.Lock() 69 | if _, ok := pool.conns[dsn]; ok { 70 | pool.Unlock() 71 | return nil, nil, fmt.Errorf("cannot create a new mock database with the same dsn: %s", dsn) 72 | } 73 | smock := &sqlmock{dsn: dsn, drv: pool, ordered: true} 74 | pool.conns[dsn] = smock 75 | pool.Unlock() 76 | 77 | return smock.open() 78 | } 79 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/examples/basic/basic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "database/sql" 4 | 5 | func recordStats(db *sql.DB, userID, productID int64) (err error) { 6 | tx, err := db.Begin() 7 | if err != nil { 8 | return 9 | } 10 | 11 | defer func() { 12 | switch err { 13 | case nil: 14 | err = tx.Commit() 15 | default: 16 | tx.Rollback() 17 | } 18 | }() 19 | 20 | if _, err = tx.Exec("UPDATE products SET views = views + 1"); err != nil { 21 | return 22 | } 23 | if _, err = tx.Exec("INSERT INTO product_viewers (user_id, product_id) VALUES (?, ?)", userID, productID); err != nil { 24 | return 25 | } 26 | return 27 | } 28 | 29 | func main() { 30 | // @NOTE: the real connection is not required for tests 31 | db, err := sql.Open("mysql", "root@/blog") 32 | if err != nil { 33 | panic(err) 34 | } 35 | defer db.Close() 36 | 37 | if err = recordStats(db, 1 /*some user id*/, 5 /*some product id*/); err != nil { 38 | panic(err) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/examples/basic/basic_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/DATA-DOG/go-sqlmock" 8 | ) 9 | 10 | // a successful case 11 | func TestShouldUpdateStats(t *testing.T) { 12 | db, mock, err := sqlmock.New() 13 | if err != nil { 14 | t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) 15 | } 16 | defer db.Close() 17 | 18 | mock.ExpectBegin() 19 | mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1)) 20 | mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnResult(sqlmock.NewResult(1, 1)) 21 | mock.ExpectCommit() 22 | 23 | // now we execute our method 24 | if err = recordStats(db, 2, 3); err != nil { 25 | t.Errorf("error was not expected while updating stats: %s", err) 26 | } 27 | 28 | // we make sure that all expectations were met 29 | if err := mock.ExpectationsWereMet(); err != nil { 30 | t.Errorf("there were unfulfilled expections: %s", err) 31 | } 32 | } 33 | 34 | // a failing test case 35 | func TestShouldRollbackStatUpdatesOnFailure(t *testing.T) { 36 | db, mock, err := sqlmock.New() 37 | if err != nil { 38 | t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) 39 | } 40 | defer db.Close() 41 | 42 | mock.ExpectBegin() 43 | mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1)) 44 | mock.ExpectExec("INSERT INTO product_viewers"). 45 | WithArgs(2, 3). 46 | WillReturnError(fmt.Errorf("some error")) 47 | mock.ExpectRollback() 48 | 49 | // now we execute our method 50 | if err = recordStats(db, 2, 3); err == nil { 51 | t.Errorf("was expecting an error, but there was none") 52 | } 53 | 54 | // we make sure that all expectations were met 55 | if err := mock.ExpectationsWereMet(); err != nil { 56 | t.Errorf("there were unfulfilled expections: %s", err) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/examples/blog/blog.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "encoding/json" 6 | "net/http" 7 | ) 8 | 9 | type api struct { 10 | db *sql.DB 11 | } 12 | 13 | type post struct { 14 | ID int 15 | Title string 16 | Body string 17 | } 18 | 19 | func (a *api) posts(w http.ResponseWriter, r *http.Request) { 20 | rows, err := a.db.Query("SELECT id, title, body FROM posts") 21 | if err != nil { 22 | a.fail(w, "failed to fetch posts: "+err.Error(), 500) 23 | return 24 | } 25 | defer rows.Close() 26 | 27 | var posts []*post 28 | for rows.Next() { 29 | p := &post{} 30 | if err := rows.Scan(&p.ID, &p.Title, &p.Body); err != nil { 31 | a.fail(w, "failed to scan post: "+err.Error(), 500) 32 | return 33 | } 34 | posts = append(posts, p) 35 | } 36 | if rows.Err() != nil { 37 | a.fail(w, "failed to read all posts: "+rows.Err().Error(), 500) 38 | return 39 | } 40 | 41 | data := struct { 42 | Posts []*post 43 | }{posts} 44 | 45 | a.ok(w, data) 46 | } 47 | 48 | func main() { 49 | // @NOTE: the real connection is not required for tests 50 | db, err := sql.Open("mysql", "root@/blog") 51 | if err != nil { 52 | panic(err) 53 | } 54 | app := &api{db: db} 55 | http.HandleFunc("/posts", app.posts) 56 | http.ListenAndServe(":8080", nil) 57 | } 58 | 59 | func (a *api) fail(w http.ResponseWriter, msg string, status int) { 60 | w.Header().Set("Content-Type", "application/json") 61 | 62 | data := struct { 63 | Error string 64 | }{Error: msg} 65 | 66 | resp, _ := json.Marshal(data) 67 | w.WriteHeader(status) 68 | w.Write(resp) 69 | } 70 | 71 | func (a *api) ok(w http.ResponseWriter, data interface{}) { 72 | w.Header().Set("Content-Type", "application/json") 73 | 74 | resp, err := json.Marshal(data) 75 | if err != nil { 76 | w.WriteHeader(http.StatusInternalServerError) 77 | a.fail(w, "oops something evil has happened", 500) 78 | return 79 | } 80 | w.Write(resp) 81 | } 82 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/examples/doc.go: -------------------------------------------------------------------------------- 1 | package examples 2 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/result.go: -------------------------------------------------------------------------------- 1 | package sqlmock 2 | 3 | import ( 4 | "database/sql/driver" 5 | ) 6 | 7 | // Result satisfies sql driver Result, which 8 | // holds last insert id and rows affected 9 | // by Exec queries 10 | type result struct { 11 | insertID int64 12 | rowsAffected int64 13 | err error 14 | } 15 | 16 | // NewResult creates a new sql driver Result 17 | // for Exec based query mocks. 18 | func NewResult(lastInsertID int64, rowsAffected int64) driver.Result { 19 | return &result{ 20 | insertID: lastInsertID, 21 | rowsAffected: rowsAffected, 22 | } 23 | } 24 | 25 | // NewErrorResult creates a new sql driver Result 26 | // which returns an error given for both interface methods 27 | func NewErrorResult(err error) driver.Result { 28 | return &result{ 29 | err: err, 30 | } 31 | } 32 | 33 | func (r *result) LastInsertId() (int64, error) { 34 | return r.insertID, r.err 35 | } 36 | 37 | func (r *result) RowsAffected() (int64, error) { 38 | return r.rowsAffected, r.err 39 | } 40 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/result_test.go: -------------------------------------------------------------------------------- 1 | package sqlmock 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | // used for examples 9 | var mock = &sqlmock{} 10 | 11 | func ExampleNewErrorResult() { 12 | db, mock, _ := New() 13 | result := NewErrorResult(fmt.Errorf("some error")) 14 | mock.ExpectExec("^INSERT (.+)").WillReturnResult(result) 15 | res, _ := db.Exec("INSERT something") 16 | _, err := res.LastInsertId() 17 | fmt.Println(err) 18 | // Output: some error 19 | } 20 | 21 | func ExampleNewResult() { 22 | var lastInsertID, affected int64 23 | result := NewResult(lastInsertID, affected) 24 | mock.ExpectExec("^INSERT (.+)").WillReturnResult(result) 25 | fmt.Println(mock.ExpectationsWereMet()) 26 | // Output: there is a remaining expectation which was not matched: ExpectedExec => expecting Exec which: 27 | // - matches sql: '^INSERT (.+)' 28 | // - is without arguments 29 | // - should return Result having: 30 | // LastInsertId: 0 31 | // RowsAffected: 0 32 | } 33 | 34 | func TestShouldReturnValidSqlDriverResult(t *testing.T) { 35 | result := NewResult(1, 2) 36 | id, err := result.LastInsertId() 37 | if 1 != id { 38 | t.Errorf("Expected last insert id to be 1, but got: %d", id) 39 | } 40 | if err != nil { 41 | t.Errorf("expected no error, but got: %s", err) 42 | } 43 | affected, err := result.RowsAffected() 44 | if 2 != affected { 45 | t.Errorf("Expected affected rows to be 2, but got: %d", affected) 46 | } 47 | if err != nil { 48 | t.Errorf("expected no error, but got: %s", err) 49 | } 50 | } 51 | 52 | func TestShouldReturnErroeSqlDriverResult(t *testing.T) { 53 | result := NewErrorResult(fmt.Errorf("some error")) 54 | _, err := result.LastInsertId() 55 | if err == nil { 56 | t.Error("expected error, but got none") 57 | } 58 | _, err = result.RowsAffected() 59 | if err == nil { 60 | t.Error("expected error, but got none") 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/statement.go: -------------------------------------------------------------------------------- 1 | package sqlmock 2 | 3 | import ( 4 | "database/sql/driver" 5 | ) 6 | 7 | type statement struct { 8 | conn *sqlmock 9 | query string 10 | err error 11 | } 12 | 13 | func (stmt *statement) Close() error { 14 | return stmt.err 15 | } 16 | 17 | func (stmt *statement) NumInput() int { 18 | return -1 19 | } 20 | 21 | func (stmt *statement) Exec(args []driver.Value) (driver.Result, error) { 22 | return stmt.conn.Exec(stmt.query, args) 23 | } 24 | 25 | func (stmt *statement) Query(args []driver.Value) (driver.Rows, error) { 26 | return stmt.conn.Query(stmt.query, args) 27 | } 28 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/statement_test.go: -------------------------------------------------------------------------------- 1 | // +build go1.6 2 | 3 | package sqlmock 4 | 5 | import ( 6 | "errors" 7 | "testing" 8 | ) 9 | 10 | func TestExpectedPreparedStatemtCloseError(t *testing.T) { 11 | conn, mock, err := New() 12 | if err != nil { 13 | t.Fatal("failed to open sqlmock database:", err) 14 | } 15 | 16 | mock.ExpectBegin() 17 | want := errors.New("STMT ERROR") 18 | mock.ExpectPrepare("SELECT").WillReturnCloseError(want) 19 | 20 | txn, err := conn.Begin() 21 | if err != nil { 22 | t.Fatal("unexpected error while opening transaction:", err) 23 | } 24 | 25 | stmt, err := txn.Prepare("SELECT") 26 | if err != nil { 27 | t.Fatal("unexpected error while preparing a statement:", err) 28 | } 29 | 30 | if err := stmt.Close(); err != want { 31 | t.Fatalf("Got = %v, want = %v", err, want) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/stubs_test.go: -------------------------------------------------------------------------------- 1 | package sqlmock 2 | 3 | import ( 4 | "database/sql/driver" 5 | "fmt" 6 | "strconv" 7 | "time" 8 | ) 9 | 10 | type NullTime struct { 11 | Time time.Time 12 | Valid bool // Valid is true if Time is not NULL 13 | } 14 | 15 | type NullInt struct { 16 | Integer int 17 | Valid bool 18 | } 19 | 20 | // Satisfy sql.Scanner interface 21 | func (ni *NullInt) Scan(value interface{}) (err error) { 22 | if value == nil { 23 | ni.Integer, ni.Valid = 0, false 24 | return 25 | } 26 | 27 | switch v := value.(type) { 28 | case int, int8, int16, int32, int64: 29 | ni.Integer, ni.Valid = v.(int), true 30 | return 31 | case []byte: 32 | ni.Integer, err = strconv.Atoi(string(v)) 33 | ni.Valid = (err == nil) 34 | return 35 | case string: 36 | ni.Integer, err = strconv.Atoi(v) 37 | ni.Valid = (err == nil) 38 | return 39 | } 40 | 41 | ni.Valid = false 42 | return fmt.Errorf("Can't convert %T to integer", value) 43 | } 44 | 45 | // Satisfy sql.Valuer interface. 46 | func (ni NullInt) Value() (driver.Value, error) { 47 | if !ni.Valid { 48 | return nil, nil 49 | } 50 | return ni.Integer, nil 51 | } 52 | 53 | // Satisfy sql.Scanner interface 54 | func (nt *NullTime) Scan(value interface{}) (err error) { 55 | if value == nil { 56 | nt.Time, nt.Valid = time.Time{}, false 57 | return 58 | } 59 | 60 | switch v := value.(type) { 61 | case time.Time: 62 | nt.Time, nt.Valid = v, true 63 | return 64 | } 65 | 66 | nt.Valid = false 67 | return fmt.Errorf("Can't convert %T to time.Time", value) 68 | } 69 | 70 | // Satisfy sql.Valuer interface. 71 | func (nt NullTime) Value() (driver.Value, error) { 72 | if !nt.Valid { 73 | return nil, nil 74 | } 75 | return nt.Time, nil 76 | } 77 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/util.go: -------------------------------------------------------------------------------- 1 | package sqlmock 2 | 3 | import ( 4 | "regexp" 5 | "strings" 6 | ) 7 | 8 | var re = regexp.MustCompile("\\s+") 9 | 10 | // strip out new lines and trim spaces 11 | func stripQuery(q string) (s string) { 12 | return strings.TrimSpace(re.ReplaceAllString(q, " ")) 13 | } 14 | -------------------------------------------------------------------------------- /src/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/util_test.go: -------------------------------------------------------------------------------- 1 | package sqlmock 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestQueryStringStripping(t *testing.T) { 8 | assert := func(actual, expected string) { 9 | if res := stripQuery(actual); res != expected { 10 | t.Errorf("Expected '%s' to be '%s', but got '%s'", actual, expected, res) 11 | } 12 | } 13 | 14 | assert(" SELECT 1", "SELECT 1") 15 | assert("SELECT 1 FROM d", "SELECT 1 FROM d") 16 | assert(` 17 | SELECT c 18 | FROM D 19 | `, "SELECT c FROM D") 20 | assert("UPDATE (.+) SET ", "UPDATE (.+) SET") 21 | } 22 | -------------------------------------------------------------------------------- /src/xbase/common/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package common 10 | 11 | import ( 12 | "math/rand" 13 | "time" 14 | ) 15 | 16 | func RandomTimeout(min int) *time.Timer { 17 | var max int 18 | if min <= 5 { 19 | max = min * 2 20 | } else if min <= 20 { 21 | max = min + min/2 22 | } else { 23 | max = min + 10 24 | } 25 | rand := rand.New(rand.NewSource(time.Now().UnixNano())) 26 | d, delta := min, (max - min) 27 | if delta > 0 { 28 | d += rand.Intn(int(delta)) 29 | } 30 | return time.NewTimer(time.Duration(d) * time.Millisecond) 31 | } 32 | 33 | func RandomPort(min int, max int) int { 34 | rand := rand.New(rand.NewSource(time.Now().UnixNano())) 35 | d, delta := min, (max - min) 36 | if delta > 0 { 37 | d += rand.Intn(int(delta)) 38 | } 39 | return d 40 | } 41 | 42 | func NormalTimeout(d int) *time.Timer { 43 | return time.NewTimer(time.Duration(d) * time.Millisecond) 44 | } 45 | 46 | func NormalTimerRelaese(t *time.Timer) { 47 | if t == nil { 48 | return 49 | } 50 | 51 | if !t.Stop() { 52 | select { 53 | case <-t.C: 54 | default: 55 | } 56 | } 57 | } 58 | 59 | func NormalTicker(d int) *time.Ticker { 60 | return time.NewTicker(time.Duration(d) * time.Millisecond) 61 | } 62 | -------------------------------------------------------------------------------- /src/xbase/common/common_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package common 10 | 11 | import ( 12 | "fmt" 13 | "sync/atomic" 14 | "testing" 15 | "time" 16 | 17 | "github.com/stretchr/testify/assert" 18 | ) 19 | 20 | func TestRandomProt(t *testing.T) { 21 | for i := 0; i < 10; i++ { 22 | fmt.Printf("%v\n", RandomPort(8000, 9000)) 23 | } 24 | } 25 | 26 | func TestRandomTimeout(t *testing.T) { 27 | var fired int32 28 | var want int32 29 | 30 | tick := RandomTimeout(100) 31 | go func() { 32 | for range tick.C { 33 | atomic.AddInt32(&fired, 1) 34 | } 35 | }() 36 | 37 | time.Sleep(210 * time.Millisecond) 38 | want = 1 39 | got := atomic.LoadInt32(&fired) 40 | assert.Equal(t, want, got) 41 | } 42 | 43 | func TestNormalTimeout(t *testing.T) { 44 | var fired int32 45 | var want int32 46 | 47 | tick := NormalTimeout(100) 48 | go func() { 49 | for range tick.C { 50 | atomic.AddInt32(&fired, 1) 51 | } 52 | }() 53 | 54 | { 55 | time.Sleep(150 * time.Millisecond) 56 | want = 1 57 | got := atomic.LoadInt32(&fired) 58 | assert.Equal(t, want, got) 59 | } 60 | 61 | { 62 | NormalTimerRelaese(tick) 63 | tick = NormalTimeout(100) 64 | time.Sleep(150 * time.Millisecond) 65 | want = 1 66 | got := atomic.LoadInt32(&fired) 67 | assert.Equal(t, want, got) 68 | } 69 | } 70 | 71 | func TestNormalTicker(t *testing.T) { 72 | var fired int32 73 | var want int32 74 | 75 | tick := NormalTicker(100) 76 | go func() { 77 | for range tick.C { 78 | atomic.AddInt32(&fired, 1) 79 | } 80 | }() 81 | 82 | time.Sleep(110 * time.Millisecond) 83 | want = 1 84 | got := atomic.LoadInt32(&fired) 85 | assert.Equal(t, want, got) 86 | } 87 | -------------------------------------------------------------------------------- /src/xbase/common/handler.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package common 10 | 11 | type Command interface { 12 | Run(string, []string) error 13 | Scan(string, int) error 14 | Kill() error 15 | RunCommand(string, []string) (string, error) 16 | RunCommandWithTimeout(int, string, []string) (string, error) 17 | } 18 | -------------------------------------------------------------------------------- /src/xbase/common/linux_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package common 10 | 11 | import ( 12 | "runtime" 13 | "testing" 14 | "xbase/xlog" 15 | 16 | "github.com/stretchr/testify/assert" 17 | ) 18 | 19 | // TEST EFFECTS: 20 | // test linux api 21 | // 22 | // TEST PROCESSES: 23 | // 1. run ls -l 24 | // 2. run sleep 2 25 | func TestRunCommandWithTimeout(t *testing.T) { 26 | log := xlog.NewStdLog(xlog.Level(xlog.PANIC)) 27 | timeout := 5 * 1000 28 | cmds := "ls" 29 | args := []string{ 30 | "-l", 31 | } 32 | _, err := runCommandWithTimeout(log, timeout, cmds, args...) 33 | assert.Nil(t, err) 34 | 35 | timeout = 1 * 1000 36 | cmds = "sleep" 37 | args = []string{ 38 | "2", 39 | } 40 | _, err = runCommandWithTimeout(log, timeout, cmds, args...) 41 | assert.NotNil(t, err) 42 | } 43 | 44 | func TestRunCommand(t *testing.T) { 45 | cmds := "ls" 46 | args := []string{ 47 | "-l", 48 | } 49 | _, err := RunCommand(cmds, args...) 50 | assert.Nil(t, err) 51 | } 52 | 53 | func TestCommand(t *testing.T) { 54 | log := xlog.NewStdLog(xlog.Level(xlog.PANIC)) 55 | cmds := "bash" 56 | args := []string{"-c", "sleep"} 57 | cmd := NewLinuxCommand(log) 58 | err := cmd.Run(cmds, args) 59 | assert.Nil(t, err) 60 | 61 | // For different systems, cmd "sleep" will return different result. 62 | sysType := runtime.GOOS 63 | if sysType == "linux" { 64 | err = cmd.Scan("sleep: missing operand", 1) 65 | } else if sysType == "darwin" { 66 | err = cmd.Scan("usage: sleep seconds", 1) 67 | } 68 | assert.Nil(t, err) 69 | 70 | args = []string{"-c", "sleep 30"} 71 | err = cmd.Run(cmds, args) 72 | assert.Nil(t, err) 73 | cmd.Kill() 74 | err = cmd.Scan("sleep: missing operand", 0) 75 | assert.Nil(t, err) 76 | 77 | args = []string{"-c", "ls -l"} 78 | err = cmd.Run(cmds, args) 79 | assert.Nil(t, err) 80 | err = cmd.Scan("sleep: missing operand", 0) 81 | assert.Nil(t, err) 82 | 83 | args = []string{"-c", "ls -l"} 84 | _, err = cmd.RunCommand(cmds, args) 85 | assert.Nil(t, err) 86 | 87 | args = []string{"-c", "ls -l"} 88 | _, err = cmd.RunCommandWithTimeout(100, cmds, args) 89 | assert.Nil(t, err) 90 | 91 | args = []string{"-c", "sleep 1000"} 92 | _, err = cmd.RunCommandWithTimeout(1, cmds, args) 93 | assert.NotNil(t, err) 94 | } 95 | -------------------------------------------------------------------------------- /src/xbase/xlog/options.go: -------------------------------------------------------------------------------- 1 | /* 2 | * go-mysqlstack 3 | * xelabs.org 4 | * 5 | * Copyright (c) XeLabs 6 | * GPL License 7 | * 8 | */ 9 | 10 | package xlog 11 | 12 | var ( 13 | defaultName = " " 14 | defaultLevel = DEBUG 15 | ) 16 | 17 | // Options used for the options of the xlog. 18 | type Options struct { 19 | Name string 20 | Level LogLevel 21 | } 22 | 23 | // Option func. 24 | type Option func(*Options) 25 | 26 | func newOptions(opts ...Option) *Options { 27 | opt := &Options{} 28 | for _, o := range opts { 29 | o(opt) 30 | } 31 | 32 | if len(opt.Name) == 0 { 33 | opt.Name = defaultName 34 | } 35 | 36 | if opt.Level == 0 { 37 | opt.Level = defaultLevel 38 | } 39 | return opt 40 | } 41 | 42 | // Name used to set the name. 43 | func Name(v string) Option { 44 | return func(o *Options) { 45 | o.Name = v 46 | } 47 | } 48 | 49 | // Level used to set the log level. 50 | func Level(v LogLevel) Option { 51 | return func(o *Options) { 52 | o.Level = v 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/xbase/xrpc/options.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package xrpc 10 | 11 | import ( 12 | "xbase/xlog" 13 | ) 14 | 15 | var ( 16 | DefaultConnectionStr = ":8080" 17 | DefaultLog = xlog.NewStdLog() 18 | ) 19 | 20 | type Options struct { 21 | ConnectionStr string 22 | Log *xlog.Log 23 | } 24 | 25 | type Option func(*Options) 26 | 27 | func newOptions(opts ...Option) *Options { 28 | opt := &Options{} 29 | for _, o := range opts { 30 | o(opt) 31 | } 32 | 33 | if opt.Log == nil { 34 | panic("xrpc.log.handler.is.nil") 35 | } 36 | 37 | if len(opt.ConnectionStr) == 0 { 38 | opt.ConnectionStr = DefaultConnectionStr 39 | } 40 | return opt 41 | } 42 | 43 | // ConnectionStr: 44 | // server connection string 45 | func ConnectionStr(v string) Option { 46 | return func(o *Options) { 47 | o.ConnectionStr = v 48 | } 49 | } 50 | 51 | // Log: 52 | // server log 53 | func Log(v *xlog.Log) Option { 54 | return func(o *Options) { 55 | o.Log = v 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/xenon/xenon.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Xenon 3 | * 4 | * Copyright 2018 The Xenon Authors. 5 | * Code is licensed under the GPLv3. 6 | * 7 | */ 8 | 9 | package main 10 | 11 | import ( 12 | "build" 13 | "config" 14 | "ctl" 15 | "flag" 16 | "fmt" 17 | _ "net/http/pprof" 18 | "os" 19 | "raft" 20 | "server" 21 | "xbase/xlog" 22 | ) 23 | 24 | var ( 25 | flag_conf string 26 | flag_role string 27 | ) 28 | 29 | func init() { 30 | flag.StringVar(&flag_conf, "c", "", "xenon config file") 31 | flag.StringVar(&flag_conf, "config", "", "xenon config file") 32 | flag.StringVar(&flag_role, "r", "", "role type:[LEADER|FOLLOWER|IDLE]") 33 | flag.StringVar(&flag_role, "role", "", "role type:[LEADER|FOLLOWER|IDLE]") 34 | } 35 | 36 | func main() { 37 | log := xlog.NewStdLog(xlog.Level(xlog.DEBUG)) 38 | var state raft.State 39 | flag.Parse() 40 | 41 | build := build.GetInfo() 42 | fmt.Printf("xenon:[%+v]\n", build) 43 | if flag_conf == "" { 44 | fmt.Printf("usage: %s [-c|--config ]\nxenon:[%+v]\n", 45 | os.Args[0], build) 46 | os.Exit(1) 47 | } 48 | 49 | // config 50 | conf, err := config.LoadConfig(flag_conf) 51 | if err != nil { 52 | log.Panic("xenon.loadconfig.error[%v]", err) 53 | } 54 | 55 | // set log level 56 | log.SetLevel(conf.Log.Level) 57 | 58 | // set the initialization state 59 | switch flag_role { 60 | case "LEADER": 61 | state = raft.LEADER 62 | case "FOLLOWER": 63 | state = raft.FOLLOWER 64 | case "IDLE": 65 | state = raft.IDLE 66 | default: 67 | state = raft.UNKNOW 68 | } 69 | 70 | // build 71 | log.Info("main: tag=[%s], git=[%s], goversion=[%s], builddate=[%s]", 72 | build.Tag, build.Git, build.GoVersion, build.Time) 73 | log.Warning("xenon.conf.raft:[%+v]", conf.Raft) 74 | log.Warning("xenon.conf.mysql:[%+v]", conf.Mysql) 75 | log.Warning("xenon.conf.mysqld:[%+v]", conf.Backup) 76 | 77 | // server 78 | server := server.NewServer(conf, log, state) 79 | server.Init() 80 | server.Start() 81 | log.Info("xenon.start.success...") 82 | 83 | if conf.Server.EnableAPIs { 84 | // Admin portal. 85 | admin := ctl.NewAdmin(log, server) 86 | admin.Start() 87 | defer admin.Stop() 88 | } 89 | 90 | server.Wait() 91 | 92 | log.Info("xenon.shutdown.complete...") 93 | } 94 | --------------------------------------------------------------------------------