From a022f35784b1fd564c4af8fab7c1e21482171375 Mon Sep 17 00:00:00 2001 From: Tobias Schottdorf Date: Thu, 23 Apr 2015 09:19:32 -0400 Subject: [PATCH] provide and use compiled in test certs (only) in tests this allows tests to run without external dependencies, while avoiding compiled-in testdata in the main build. --- client/main_test.go | 27 ++++++++++++++++++ kv/main_test.go | 27 ++++++++++++++++++ rpc/main_test.go | 27 ++++++++++++++++++ rpc/testing.go | 2 +- security/certs_test.go | 7 +++++ security/main_test.go | 30 ++++++++++++++++++++ security/tls.go | 62 ++++++++++++----------------------------- security/tls_test.go | 2 +- server/cli/cli_test.go | 5 ++-- server/cli/main_test.go | 27 ++++++++++++++++++ server/main_test.go | 27 ++++++++++++++++++ server/node_test.go | 5 +++- server/server_test.go | 3 +- server/testserver.go | 9 ++++-- storage/main_test.go | 6 ++++ 15 files changed, 212 insertions(+), 54 deletions(-) create mode 100644 client/main_test.go create mode 100644 kv/main_test.go create mode 100644 rpc/main_test.go create mode 100644 security/main_test.go create mode 100644 server/cli/main_test.go create mode 100644 server/main_test.go diff --git a/client/main_test.go b/client/main_test.go new file mode 100644 index 000000000000..cd52ce49384b --- /dev/null +++ b/client/main_test.go @@ -0,0 +1,27 @@ +// Copyright 2015 The Cockroach Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. See the AUTHORS file +// for names of contributors. +// +// Author: Tobias Schottdorf (tobias.schottdorf@gmail.com) + +package client + +import ( + "github.com/cockroachdb/cockroach/security" + "github.com/cockroachdb/cockroach/security/securitytest" +) + +func init() { + security.SetReadFileFn(securitytest.Asset) +} diff --git a/kv/main_test.go b/kv/main_test.go new file mode 100644 index 000000000000..e09a2a584e5e --- /dev/null +++ b/kv/main_test.go @@ -0,0 +1,27 @@ +// Copyright 2015 The Cockroach Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. See the AUTHORS file +// for names of contributors. +// +// Author: Tobias Schottdorf (tobias.schottdorf@gmail.com) + +package kv + +import ( + "github.com/cockroachdb/cockroach/security" + "github.com/cockroachdb/cockroach/security/securitytest" +) + +func init() { + security.SetReadFileFn(securitytest.Asset) +} diff --git a/rpc/main_test.go b/rpc/main_test.go new file mode 100644 index 000000000000..2f8af3b248fc --- /dev/null +++ b/rpc/main_test.go @@ -0,0 +1,27 @@ +// Copyright 2015 The Cockroach Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. See the AUTHORS file +// for names of contributors. +// +// Author: Tobias Schottdorf (tobias.schottdorf@gmail.com) + +package rpc + +import ( + "github.com/cockroachdb/cockroach/security" + "github.com/cockroachdb/cockroach/security/securitytest" +) + +func init() { + security.SetReadFileFn(securitytest.Asset) +} diff --git a/rpc/testing.go b/rpc/testing.go index 07235df37f87..2b599551b5b2 100644 --- a/rpc/testing.go +++ b/rpc/testing.go @@ -26,7 +26,7 @@ import ( // NewTestContext returns a rpc.Context for testing. func NewTestContext(t *testing.T) *Context { - tlsConfig, err := security.LoadTLSConfigFromDir(security.EmbeddedPrefix + "test_certs") + tlsConfig, err := security.LoadTLSConfigFromDir("test_certs") if err != nil { t.Fatal(err) } diff --git a/security/certs_test.go b/security/certs_test.go index 6a0ee04ec2e2..8812be08698f 100644 --- a/security/certs_test.go +++ b/security/certs_test.go @@ -29,6 +29,10 @@ import ( // This is just the mechanics of certs generation. func TestGenerateCerts(t *testing.T) { + // Do not mock cert access for this test. + security.ResetReadFileFn() + defer security.ResetTest() + certsDir := util.CreateTempDir(t, "certs_test") defer util.CleanupDir(certsDir) @@ -63,6 +67,9 @@ func TestGenerateCerts(t *testing.T) { // This is a fairly high-level test of CA and node certificates. // We construct SSL server and clients and use the generated certs. func TestUseCerts(t *testing.T) { + // Do not mock cert access for this test. + security.ResetReadFileFn() + defer security.ResetTest() certsDir := util.CreateTempDir(t, "certs_test") defer util.CleanupDir(certsDir) diff --git a/security/main_test.go b/security/main_test.go new file mode 100644 index 000000000000..1722f6843422 --- /dev/null +++ b/security/main_test.go @@ -0,0 +1,30 @@ +// Copyright 2015 The Cockroach Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. See the AUTHORS file +// for names of contributors. +// +// Author: Tobias Schottdorf (tobias.schottdorf@gmail.com) + +package security + +import "github.com/cockroachdb/cockroach/security/securitytest" + +func init() { + ResetTest() +} + +// ResetTest sets up the test environment. In particular, it embeds the +// test_certs folder and makes the tls package load from there. +func ResetTest() { + SetReadFileFn(securitytest.Asset) +} diff --git a/security/tls.go b/security/tls.go index 1595b5bcc0eb..82851f7c7b65 100644 --- a/security/tls.go +++ b/security/tls.go @@ -25,17 +25,25 @@ import ( "crypto/x509" "io/ioutil" "path" - "strings" "sync" - "github.com/cockroachdb/cockroach/security/securitytest" "github.com/cockroachdb/cockroach/util" ) -const ( - // EmbeddedPrefix is the prefix to the -certs arg that indicates embedded certs. - EmbeddedPrefix = "embedded=" -) +// readFileFn is used to mock out file system access during tests. +var readFileFn = ioutil.ReadFile + +// SetReadFileFn allows to switch out ioutil.ReadFile by a mock +// for testing purposes. +func SetReadFileFn(f func(string) ([]byte, error)) { + readFileFn = f +} + +// ResetReadFileFn is the counterpart to SetReadFileFn, restoring the +// original behaviour for loading certificate related data from disk. +func ResetReadFileFn() { + readFileFn = ioutil.ReadFile +} // TLSConfig contains the TLS settings for a Cockroach node. Currently it's // just a wrapper for tls.Config. If config is nil, we don't use TLS. @@ -62,36 +70,15 @@ func (c *TLSConfig) Config() *tls.Config { // - node.key -- the private key of this node // If the path is prefixed with "embedded=", load the embedded certs. func LoadTLSConfigFromDir(certDir string) (*TLSConfig, error) { - if strings.HasPrefix(certDir, EmbeddedPrefix) { - return LoadTestTLSConfig(certDir[len(EmbeddedPrefix):]) - } - certPEM, err := ioutil.ReadFile(path.Join(certDir, "node.crt")) + certPEM, err := readFileFn(path.Join(certDir, "node.crt")) if err != nil { return nil, err } - keyPEM, err := ioutil.ReadFile(path.Join(certDir, "node.key")) + keyPEM, err := readFileFn(path.Join(certDir, "node.key")) if err != nil { return nil, err } - caPEM, err := ioutil.ReadFile(path.Join(certDir, "ca.crt")) - if err != nil { - return nil, err - } - return LoadTLSConfig(certPEM, keyPEM, caPEM) -} - -// LoadTestTLSConfig loads the embedded certs. This is only called from -// LoadTLSConfigFromDir when the certdir path starts with "embedded=". -func LoadTestTLSConfig(certDir string) (*TLSConfig, error) { - certPEM, err := securitytest.Asset(path.Join(certDir, "node.crt")) - if err != nil { - return nil, err - } - keyPEM, err := securitytest.Asset(path.Join(certDir, "node.key")) - if err != nil { - return nil, err - } - caPEM, err := securitytest.Asset(path.Join(certDir, "ca.crt")) + caPEM, err := readFileFn(path.Join(certDir, "ca.crt")) if err != nil { return nil, err } @@ -147,20 +134,7 @@ func LoadInsecureTLSConfig() *TLSConfig { // LoadClientTLSConfigFromDir creates a client TLSConfig by loading the root CA certs from the // specified directory. The directory must contain ca.crt. func LoadClientTLSConfigFromDir(certDir string) (*TLSConfig, error) { - if strings.HasPrefix(certDir, EmbeddedPrefix) { - return LoadTestClientTLSConfig(certDir[len(EmbeddedPrefix):]) - } - caPEM, err := ioutil.ReadFile(path.Join(certDir, "ca.crt")) - if err != nil { - return nil, err - } - return LoadClientTLSConfig(caPEM) -} - -// LoadTestClientTLSConfig loads the embedded certs. This is only called from -// LoadClientTLSConfigFromDir when the certdir path starts with "embedded=". -func LoadTestClientTLSConfig(certDir string) (*TLSConfig, error) { - caPEM, err := securitytest.Asset(path.Join(certDir, "ca.crt")) + caPEM, err := readFileFn(path.Join(certDir, "ca.crt")) if err != nil { return nil, err } diff --git a/security/tls_test.go b/security/tls_test.go index fb05eb961212..d50b78609407 100644 --- a/security/tls_test.go +++ b/security/tls_test.go @@ -23,7 +23,7 @@ import ( ) func TestLoadTLSConfig(t *testing.T) { - wrapperConfig, err := LoadTLSConfigFromDir(EmbeddedPrefix + "test_certs") + wrapperConfig, err := LoadTLSConfigFromDir("test_certs") if err != nil { t.Fatalf("Failed to load TLS config: %v", err) } diff --git a/server/cli/cli_test.go b/server/cli/cli_test.go index 3aead1750971..fb0ed400a8bb 100644 --- a/server/cli/cli_test.go +++ b/server/cli/cli_test.go @@ -23,7 +23,6 @@ import ( "os" "strings" - "github.com/cockroachdb/cockroach/security" "github.com/cockroachdb/cockroach/server" ) @@ -49,8 +48,8 @@ func (c cliTest) Run(line string) { var args []string args = append(args, a[0]) args = append(args, fmt.Sprintf("-addr=%s", c.ServingAddr())) - // Always load server certs. Not sure if this path is a good assumption though. - args = append(args, fmt.Sprintf("-certs=%s", security.EmbeddedPrefix+"test_certs")) + // Always load test certs. + args = append(args, fmt.Sprintf("-certs=%s", "test_certs")) args = append(args, a[1:]...) fmt.Printf("%s\n", line) diff --git a/server/cli/main_test.go b/server/cli/main_test.go new file mode 100644 index 000000000000..889ad036ce60 --- /dev/null +++ b/server/cli/main_test.go @@ -0,0 +1,27 @@ +// Copyright 2015 The Cockroach Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. See the AUTHORS file +// for names of contributors. +// +// Author: Tobias Schottdorf (tobias.schottdorf@gmail.com) + +package cli + +import ( + "github.com/cockroachdb/cockroach/security" + "github.com/cockroachdb/cockroach/security/securitytest" +) + +func init() { + security.SetReadFileFn(securitytest.Asset) +} diff --git a/server/main_test.go b/server/main_test.go new file mode 100644 index 000000000000..2b9c85cc8cb1 --- /dev/null +++ b/server/main_test.go @@ -0,0 +1,27 @@ +// Copyright 2015 The Cockroach Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. See the AUTHORS file +// for names of contributors. +// +// Author: Tobias Schottdorf (tobias.schottdorf@gmail.com) + +package server + +import ( + "github.com/cockroachdb/cockroach/security" + "github.com/cockroachdb/cockroach/security/securitytest" +) + +func init() { + security.SetReadFileFn(securitytest.Asset) +} diff --git a/server/node_test.go b/server/node_test.go index 4f33e71e55a6..a1eacb7d5a6c 100644 --- a/server/node_test.go +++ b/server/node_test.go @@ -46,7 +46,10 @@ import ( // not nil, the gossip bootstrap address is set to gossipBS. func createTestNode(addr net.Addr, engines []engine.Engine, gossipBS net.Addr, t *testing.T) ( *rpc.Server, *hlc.Clock, *Node, *util.Stopper) { - tlsConfig, err := security.LoadTLSConfigFromDir(security.EmbeddedPrefix + "test_certs") + // Load the TLS config from our test certs. They're embedded in the + // test binary and calls to the file system have been mocked out, + // see main_test.go. + tlsConfig, err := security.LoadTLSConfigFromDir("test_certs") if err != nil { t.Fatal(err) } diff --git a/server/server_test.go b/server/server_test.go index 6d9c457933f3..99aaa3928bf5 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -40,7 +40,8 @@ import ( func newTestContext() *Context { newContext := NewContext() - newContext.Certs = security.EmbeddedPrefix + "test_certs" + // The certs are compiled in, see main_test.go. + newContext.Certs = "test_certs" return newContext } diff --git a/server/testserver.go b/server/testserver.go index 4c62090c8730..f9c1f710ae31 100644 --- a/server/testserver.go +++ b/server/testserver.go @@ -22,7 +22,6 @@ import ( "github.com/cockroachdb/cockroach/gossip" "github.com/cockroachdb/cockroach/proto" - "github.com/cockroachdb/cockroach/security" "github.com/cockroachdb/cockroach/storage" "github.com/cockroachdb/cockroach/storage/engine" "github.com/cockroachdb/cockroach/util" @@ -55,8 +54,12 @@ func NewTestContext() *Context { // uncertainty intervals. ctx.MaxOffset = 0 - // Load certs from embedded files. - ctx.Certs = security.EmbeddedPrefix + "test_certs" + // Load test certs. In addition, the tests requiring certs + // need to call security.SetReadFileFn(securitytest.Asset) + // in their init to mock out the file system calls for calls to AssetFS, + // which has the test certs compiled in. Typically this is done + // once per package, in main_test.go. + ctx.Certs = "test_certs" // Addr defaults to localhost with port set at time of call to // Start() to an available port. // Call TestServer.ServingAddr() for the full address (including bound port). diff --git a/storage/main_test.go b/storage/main_test.go index e8c18bac77bb..6cf09aeaced2 100644 --- a/storage/main_test.go +++ b/storage/main_test.go @@ -20,11 +20,17 @@ package storage import ( "testing" + "github.com/cockroachdb/cockroach/security" + "github.com/cockroachdb/cockroach/security/securitytest" "github.com/cockroachdb/cockroach/util/leaktest" ) //go:generate ../util/leaktest/add-leaktest.sh *_test.go +func init() { + security.SetReadFileFn(securitytest.Asset) +} + func TestMain(m *testing.M) { leaktest.TestMainWithLeakCheck(m) }