Simplify provider tests (#862)
This commit is contained in:
parent
90f79e585c
commit
d8df4b5f6b
@ -25,6 +25,19 @@ func NewIdentities(list ...*provider.FullIdentity) *Identities {
|
||||
}
|
||||
}
|
||||
|
||||
// PregeneratedIdentity returns a pregenerated identity from a list
|
||||
func PregeneratedIdentity(index int) (*provider.FullIdentity, error) {
|
||||
if pregeneratedIdentities.next >= len(pregeneratedIdentities.list) {
|
||||
return nil, errors.New("out of pregenerated identities")
|
||||
}
|
||||
return pregeneratedIdentities.list[index], nil
|
||||
}
|
||||
|
||||
// NewPregeneratedIdentities retruns a new table from provided identities.
|
||||
func NewPregeneratedIdentities() *Identities {
|
||||
return pregeneratedIdentities.Clone()
|
||||
}
|
||||
|
||||
// Clone creates a shallow clone of the table.
|
||||
func (identities *Identities) Clone() *Identities {
|
||||
return NewIdentities(identities.list...)
|
||||
|
@ -58,7 +58,7 @@ func New(t zaptest.TestingT, satelliteCount, storageNodeCount, uplinkCount int)
|
||||
|
||||
planet := &Planet{
|
||||
log: log,
|
||||
identities: pregeneratedIdentities.Clone(),
|
||||
identities: NewPregeneratedIdentities(),
|
||||
}
|
||||
|
||||
var err error
|
||||
|
@ -150,6 +150,13 @@ func WriteChain(w io.Writer, chain ...*x509.Certificate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChainBytes returns bytes of the certificate chain (leaf-first) to the writer, PEM-encoded.
|
||||
func ChainBytes(chain ...*x509.Certificate) ([]byte, error) {
|
||||
var data bytes.Buffer
|
||||
err := WriteChain(&data, chain...)
|
||||
return data.Bytes(), err
|
||||
}
|
||||
|
||||
// WriteKey writes the private key to the writer, PEM-encoded.
|
||||
func WriteKey(w io.Writer, key crypto.PrivateKey) error {
|
||||
var (
|
||||
@ -173,6 +180,13 @@ func WriteKey(w io.Writer, key crypto.PrivateKey) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// KeyBytes returns bytes of the private key to the writer, PEM-encoded.
|
||||
func KeyBytes(key crypto.PrivateKey) ([]byte, error) {
|
||||
var data bytes.Buffer
|
||||
err := WriteKey(&data, key)
|
||||
return data.Bytes(), err
|
||||
}
|
||||
|
||||
// NewCert returns a new x509 certificate using the provided templates and key,
|
||||
// signed by the parent cert if provided; otherwise, self-signed.
|
||||
func NewCert(key, parentKey crypto.PrivateKey, template, parent *x509.Certificate) (*x509.Certificate, error) {
|
||||
|
@ -5,21 +5,14 @@ package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// newTestCA returns a ca with a default difficulty and concurrency for use in tests
|
||||
func newTestCA(ctx context.Context) (*FullCertificateAuthority, error) {
|
||||
return NewCA(ctx, NewCAOptions{
|
||||
Difficulty: 12,
|
||||
Concurrency: 4,
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewCA(t *testing.T) {
|
||||
expectedDifficulty := uint16(4)
|
||||
const expectedDifficulty = 4
|
||||
|
||||
ca, err := NewCA(context.Background(), NewCAOptions{
|
||||
Difficulty: expectedDifficulty,
|
||||
@ -34,16 +27,21 @@ func TestNewCA(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFullCertificateAuthority_NewIdentity(t *testing.T) {
|
||||
check := func(err error, v interface{}) {
|
||||
if !assert.NoError(t, err) || !assert.NotEmpty(t, v) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
ca, err := NewCA(context.Background(), NewCAOptions{
|
||||
Difficulty: 12,
|
||||
Concurrency: 4,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NotEmpty(t, ca)
|
||||
|
||||
ca, err := newTestCA(context.Background())
|
||||
check(err, ca)
|
||||
fi, err := ca.NewIdentity()
|
||||
check(err, fi)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NotEmpty(t, fi)
|
||||
|
||||
assert.Equal(t, ca.Cert, fi.CA)
|
||||
assert.Equal(t, ca.ID, fi.ID)
|
||||
@ -54,27 +52,19 @@ func TestFullCertificateAuthority_NewIdentity(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func NewCABenchmark(b *testing.B, difficulty uint16, concurrency uint) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = NewCA(context.Background(), NewCAOptions{
|
||||
Difficulty: difficulty,
|
||||
Concurrency: concurrency,
|
||||
})
|
||||
func BenchmarkNewCA(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
for _, difficulty := range []uint16{8, 12} {
|
||||
for _, concurrency := range []uint{1, 2, 5, 10} {
|
||||
test := fmt.Sprintf("%d/%d", difficulty, concurrency)
|
||||
b.Run(test, func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = NewCA(ctx, NewCAOptions{
|
||||
Difficulty: difficulty,
|
||||
Concurrency: concurrency,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNewCA_Difficulty8_Concurrency1(b *testing.B) {
|
||||
NewCABenchmark(b, 8, 1)
|
||||
}
|
||||
|
||||
func BenchmarkNewCA_Difficulty8_Concurrency2(b *testing.B) {
|
||||
NewCABenchmark(b, 8, 2)
|
||||
}
|
||||
|
||||
func BenchmarkNewCA_Difficulty8_Concurrency5(b *testing.B) {
|
||||
NewCABenchmark(b, 8, 5)
|
||||
}
|
||||
|
||||
func BenchmarkNewCA_Difficulty8_Concurrency10(b *testing.B) {
|
||||
NewCABenchmark(b, 8, 10)
|
||||
}
|
||||
|
@ -125,6 +125,7 @@ func FullIdentityFromPEM(chainPEM, keyPEM []byte) (*FullIdentity, error) {
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err)
|
||||
}
|
||||
|
||||
i, err := NodeIDFromKey(ch[1].PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (C) 2018 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package provider
|
||||
package provider_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -11,14 +11,15 @@ import (
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"storj.io/storj/internal/testcontext"
|
||||
"storj.io/storj/pkg/peertls"
|
||||
"storj.io/storj/pkg/provider"
|
||||
)
|
||||
|
||||
func TestPeerIdentityFromCertChain(t *testing.T) {
|
||||
@ -40,7 +41,7 @@ func TestPeerIdentityFromCertChain(t *testing.T) {
|
||||
leafCert, err := peertls.NewCert(leafKey, caKey, leafTemplate, caTemplate)
|
||||
assert.NoError(t, err)
|
||||
|
||||
peerIdent, err := PeerIdentityFromCerts(leafCert, caCert, nil)
|
||||
peerIdent, err := provider.PeerIdentityFromCerts(leafCert, caCert, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, caCert, peerIdent.CA)
|
||||
assert.Equal(t, leafCert, peerIdent.Leaf)
|
||||
@ -84,7 +85,7 @@ func TestFullIdentityFromPEM(t *testing.T) {
|
||||
keyPEM := bytes.NewBuffer([]byte{})
|
||||
assert.NoError(t, pem.Encode(keyPEM, peertls.NewKeyBlock(leafKeyBytes)))
|
||||
|
||||
fullIdent, err := FullIdentityFromPEM(chainPEM.Bytes(), keyPEM.Bytes())
|
||||
fullIdent, err := provider.FullIdentityFromPEM(chainPEM.Bytes(), keyPEM.Bytes())
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, leafCert.Raw, fullIdent.Leaf.Raw)
|
||||
assert.Equal(t, caCert.Raw, fullIdent.CA.Raw)
|
||||
@ -92,8 +93,14 @@ func TestFullIdentityFromPEM(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIdentityConfig_SaveIdentity(t *testing.T) {
|
||||
done, ic, fi, _ := tempIdentity(t)
|
||||
defer done()
|
||||
ctx := testcontext.New(t)
|
||||
defer ctx.Cleanup()
|
||||
|
||||
ic := &provider.IdentityConfig{
|
||||
CertPath: ctx.File("chain.pem"),
|
||||
KeyPath: ctx.File("key.pem"),
|
||||
}
|
||||
fi := pregeneratedIdentity(t)
|
||||
|
||||
chainPEM := bytes.NewBuffer([]byte{})
|
||||
assert.NoError(t, pem.Encode(chainPEM, peertls.NewCertBlock(fi.Leaf.Raw)))
|
||||
@ -110,152 +117,112 @@ func TestIdentityConfig_SaveIdentity(t *testing.T) {
|
||||
keyPEM := bytes.NewBuffer([]byte{})
|
||||
assert.NoError(t, pem.Encode(keyPEM, peertls.NewKeyBlock(keyBytes)))
|
||||
|
||||
err = ic.Save(fi)
|
||||
assert.NoError(t, err)
|
||||
{ // test saving
|
||||
err = ic.Save(fi)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
// TODO (windows): ignoring for windows due to different default permissions
|
||||
certInfo, err := os.Stat(ic.CertPath)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, os.FileMode(0644), certInfo.Mode())
|
||||
|
||||
keyInfo, err := os.Stat(ic.KeyPath)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, os.FileMode(0600), keyInfo.Mode())
|
||||
}
|
||||
|
||||
savedChainPEM, err := ioutil.ReadFile(ic.CertPath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
savedKeyPEM, err := ioutil.ReadFile(ic.KeyPath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, chainPEM.Bytes(), savedChainPEM)
|
||||
assert.Equal(t, keyPEM.Bytes(), savedKeyPEM)
|
||||
}
|
||||
|
||||
func TestIdentityConfig_LoadIdentity(t *testing.T) {
|
||||
done, ic, expectedFI, _ := tempIdentity(t)
|
||||
defer done()
|
||||
|
||||
err := ic.Save(expectedFI)
|
||||
assert.NoError(t, err)
|
||||
|
||||
fi, err := ic.Load()
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, fi)
|
||||
assert.NotEmpty(t, fi.Key)
|
||||
assert.NotEmpty(t, fi.Leaf)
|
||||
assert.NotEmpty(t, fi.CA)
|
||||
assert.NotEmpty(t, fi.ID.Bytes())
|
||||
|
||||
assert.Equal(t, expectedFI.Key, fi.Key)
|
||||
assert.Equal(t, expectedFI.Leaf, fi.Leaf)
|
||||
assert.Equal(t, expectedFI.CA, fi.CA)
|
||||
assert.Equal(t, expectedFI.ID.Bytes(), fi.ID.Bytes())
|
||||
}
|
||||
|
||||
func TestNodeID_Difficulty(t *testing.T) {
|
||||
done, _, fi, knownDifficulty := tempIdentity(t)
|
||||
defer done()
|
||||
|
||||
difficulty, err := fi.ID.Difficulty()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, difficulty >= knownDifficulty)
|
||||
}
|
||||
|
||||
func TestVerifyPeer(t *testing.T) {
|
||||
check := func(e error) {
|
||||
if !assert.NoError(t, e) {
|
||||
t.Fail()
|
||||
// TODO (windows): ignoring for windows due to different default permissions
|
||||
if runtime.GOOS != "windows" {
|
||||
assert.Equal(t, os.FileMode(0644), certInfo.Mode())
|
||||
assert.Equal(t, os.FileMode(0600), keyInfo.Mode())
|
||||
}
|
||||
}
|
||||
|
||||
ca, err := newTestCA(context.Background())
|
||||
check(err)
|
||||
{ // test loading
|
||||
loadedFi, err := ic.Load()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, fi.Key, loadedFi.Key)
|
||||
assert.Equal(t, fi.Leaf, loadedFi.Leaf)
|
||||
assert.Equal(t, fi.CA, loadedFi.CA)
|
||||
assert.Equal(t, fi.ID, loadedFi.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyPeer(t *testing.T) {
|
||||
ca, err := provider.NewCA(context.Background(), provider.NewCAOptions{
|
||||
Difficulty: 12,
|
||||
Concurrency: 4,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
fi, err := ca.NewIdentity()
|
||||
check(err)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = peertls.VerifyPeerFunc(peertls.VerifyPeerCertChains)([][]byte{fi.Leaf.Raw, fi.CA.Raw}, nil)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestNewServerOptions(t *testing.T) {
|
||||
done, _, fi, _ := tempIdentity(t)
|
||||
defer done()
|
||||
ctx := testcontext.New(t)
|
||||
defer ctx.Cleanup()
|
||||
|
||||
tmp, err := ioutil.TempDir("", "TestNewServerOptions")
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
defer func() { _ = os.RemoveAll(tmp) }()
|
||||
fi := pregeneratedIdentity(t)
|
||||
|
||||
whitelistPath := filepath.Join(tmp, "whitelist.pem")
|
||||
w, err := os.Create(whitelistPath)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
err = peertls.WriteChain(w, fi.CA)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
whitelistPath := ctx.File("whitelist.pem")
|
||||
|
||||
chainData, err := peertls.ChainBytes(fi.CA)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = ioutil.WriteFile(whitelistPath, chainData, 0644)
|
||||
assert.NoError(t, err)
|
||||
|
||||
cases := []struct {
|
||||
testID string
|
||||
config ServerConfig
|
||||
config provider.ServerConfig
|
||||
pcvFuncsLen int
|
||||
}{
|
||||
{
|
||||
"default",
|
||||
ServerConfig{},
|
||||
provider.ServerConfig{},
|
||||
0,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
"revocation processing",
|
||||
ServerConfig{
|
||||
RevocationDBURL: "bolt://" + filepath.Join(tmp, "revocation1.db"),
|
||||
provider.ServerConfig{
|
||||
RevocationDBURL: "bolt://" + ctx.File("revocation1.db"),
|
||||
Extensions: peertls.TLSExtConfig{
|
||||
Revocation: true,
|
||||
},
|
||||
},
|
||||
2,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
"ca whitelist verification",
|
||||
ServerConfig{
|
||||
provider.ServerConfig{
|
||||
PeerCAWhitelistPath: whitelistPath,
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
"ca whitelist verification and whitelist signed leaf verification",
|
||||
ServerConfig{
|
||||
provider.ServerConfig{
|
||||
// NB: file doesn't actually exist
|
||||
PeerCAWhitelistPath: filepath.Join(tmp, "whitelist.pem"),
|
||||
PeerCAWhitelistPath: whitelistPath,
|
||||
Extensions: peertls.TLSExtConfig{
|
||||
WhitelistSignedLeaf: true,
|
||||
},
|
||||
},
|
||||
2,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
"revocation processing and whitelist verification",
|
||||
ServerConfig{
|
||||
provider.ServerConfig{
|
||||
// NB: file doesn't actually exist
|
||||
PeerCAWhitelistPath: whitelistPath,
|
||||
RevocationDBURL: "bolt://" + filepath.Join(tmp, "revocation2.db"),
|
||||
RevocationDBURL: "bolt://" + ctx.File("revocation2.db"),
|
||||
Extensions: peertls.TLSExtConfig{
|
||||
Revocation: true,
|
||||
},
|
||||
},
|
||||
3,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
"revocation processing, whitelist, and signed leaf verification",
|
||||
ServerConfig{
|
||||
provider.ServerConfig{
|
||||
// NB: file doesn't actually exist
|
||||
PeerCAWhitelistPath: whitelistPath,
|
||||
RevocationDBURL: "bolt://" + filepath.Join(tmp, "revocation3.db"),
|
||||
RevocationDBURL: "bolt://" + ctx.File("revocation3.db"),
|
||||
Extensions: peertls.TLSExtConfig{
|
||||
Revocation: true,
|
||||
WhitelistSignedLeaf: true,
|
||||
@ -266,35 +233,17 @@ func TestNewServerOptions(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.testID, func(t *testing.T) {
|
||||
opts, err := NewServerOptions(fi, c.config)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, reflect.DeepEqual(fi, opts.Ident))
|
||||
assert.Equal(t, c.config, opts.Config)
|
||||
assert.Len(t, opts.PCVFuncs, c.pcvFuncsLen)
|
||||
})
|
||||
t.Log(c.testID)
|
||||
opts, err := provider.NewServerOptions(fi, c.config)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, reflect.DeepEqual(fi, opts.Ident))
|
||||
assert.Equal(t, c.config, opts.Config)
|
||||
assert.Len(t, opts.PCVFuncs, c.pcvFuncsLen)
|
||||
}
|
||||
}
|
||||
|
||||
func tempIdentityConfig() (*IdentityConfig, func(), error) {
|
||||
tmpDir, err := ioutil.TempDir("", "storj-identity")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
cleanup := func() { _ = os.RemoveAll(tmpDir) }
|
||||
|
||||
return &IdentityConfig{
|
||||
CertPath: filepath.Join(tmpDir, "chain.pem"),
|
||||
KeyPath: filepath.Join(tmpDir, "key.pem"),
|
||||
}, cleanup, nil
|
||||
}
|
||||
|
||||
func tempIdentity(t *testing.T) (func(), *IdentityConfig, *FullIdentity, uint16) {
|
||||
// NB: known difficulty
|
||||
difficulty := uint16(12)
|
||||
|
||||
chain := `-----BEGIN CERTIFICATE-----
|
||||
func pregeneratedIdentity(t *testing.T) *provider.FullIdentity {
|
||||
const chain = `-----BEGIN CERTIFICATE-----
|
||||
MIIBQDCB56ADAgECAhB+u3d03qyW/ROgwy/ZsPccMAoGCCqGSM49BAMCMAAwIhgP
|
||||
MDAwMTAxMDEwMDAwMDBaGA8wMDAxMDEwMTAwMDAwMFowADBZMBMGByqGSM49AgEG
|
||||
CCqGSM49AwEHA0IABIZrEPV/ExEkF0qUF0fJ3qSeGt5oFUX231v02NSUywcQ/Ve0
|
||||
@ -313,17 +262,14 @@ BAMCA0cAMEQCIGAZfPT1qvlnkTacojTtP20ZWf6XbnSztJHIKlUw6AE+AiB5Vcjj
|
||||
awRaC5l1KBPGqiKB0coVXDwhW+K70l326MPUcg==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
key := `-----BEGIN EC PRIVATE KEY-----
|
||||
const key = `-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIKGjEetrxKrzl+AL1E5LXke+1ElyAdjAmr88/1Kx09+doAoGCCqGSM49
|
||||
AwEHoUQDQgAEoLy/0hs5deTXZunRumsMkiHpF0g8wAc58aXANmr7Mxx9tzoIYFnx
|
||||
0YN4VDKdCtUJa29yA6TIz1MiIDUAcB5YCA==
|
||||
-----END EC PRIVATE KEY-----`
|
||||
|
||||
ic, cleanup, err := tempIdentityConfig()
|
||||
fi, err := provider.FullIdentityFromPEM([]byte(chain), []byte(key))
|
||||
assert.NoError(t, err)
|
||||
|
||||
fi, err := FullIdentityFromPEM([]byte(chain), []byte(key))
|
||||
assert.NoError(t, err)
|
||||
|
||||
return cleanup, ic, fi, difficulty
|
||||
return fi
|
||||
}
|
||||
|
25
pkg/storj/node_test.go
Normal file
25
pkg/storj/node_test.go
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright (C) 2018 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package storj_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"storj.io/storj/pkg/storj"
|
||||
)
|
||||
|
||||
func TestNodeID_Difficulty(t *testing.T) {
|
||||
invalidID := storj.NodeID{}
|
||||
difficulty, err := invalidID.Difficulty()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, uint16(0), difficulty)
|
||||
|
||||
// node id with difficulty 13
|
||||
node13 := storj.NodeID{253, 160, 157, 107, 237, 151, 13, 122, 56, 254, 115, 137, 205, 43, 27, 150, 32, 207, 14, 161, 252, 218, 36, 4, 211, 83, 195, 250, 17, 61, 224, 0}
|
||||
difficulty, err = node13.Difficulty()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, uint16(13), difficulty)
|
||||
}
|
Loading…
Reference in New Issue
Block a user