storj/internal/testrand/rand.go
2019-11-06 11:04:12 -05:00

207 lines
4.7 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
// Package testrand implements generating random base types for testing.
package testrand
import (
"io"
"math/rand"
"github.com/skyrings/skyring-common/tools/uuid"
"storj.io/storj/internal/memory"
"storj.io/storj/pkg/storj"
)
// Intn returns, as an int, a non-negative pseudo-random number in [0,n)
// from the default Source.
// It panics if n <= 0.
func Intn(n int) int { return rand.Intn(n) }
// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n)
// from the default Source.
// It panics if n <= 0.
func Int63n(n int64) int64 {
return rand.Int63n(n)
}
// Float64n returns floating point pseudo-random number in [-n,0] || [0,n]
// based on the sign of the input
func Float64n(n int64) float64 {
return rand.Float64() * float64(n)
}
// Read reads pseudo-random data into data.
func Read(data []byte) {
const newSourceThreshold = 64
if len(data) < newSourceThreshold {
_, _ = rand.Read(data)
return
}
src := rand.NewSource(rand.Int63())
r := rand.New(src)
_, _ = r.Read(data)
}
// Bytes generates size amount of random data.
func Bytes(size memory.Size) []byte {
data := make([]byte, size.Int())
Read(data)
return data
}
// BytesInt generates size amount of random data.
func BytesInt(size int) []byte {
return Bytes(memory.Size(size))
}
// Reader creates a new random data reader.
func Reader() io.Reader {
return rand.New(rand.NewSource(rand.Int63()))
}
// NodeID creates a random node id.
func NodeID() storj.NodeID {
var id storj.NodeID
Read(id[:])
// set version to 0
id[len(id)-1] = 0
return id
}
// PieceID creates a random piece id.
func PieceID() storj.PieceID {
var id storj.PieceID
Read(id[:])
return id
}
// Key creates a random test key.
func Key() storj.Key {
var key storj.Key
Read(key[:])
return key
}
// Nonce creates a random test nonce.
func Nonce() storj.Nonce {
var nonce storj.Nonce
Read(nonce[:])
return nonce
}
// SerialNumber creates a random serial number.
func SerialNumber() storj.SerialNumber {
var serial storj.SerialNumber
Read(serial[:])
return serial
}
// StreamID creates a random stream ID
func StreamID(size int) storj.StreamID {
return storj.StreamID(BytesInt(size))
}
// SegmentID creates a random segment ID
func SegmentID(size int) storj.SegmentID {
return storj.SegmentID(BytesInt(size))
}
// UUID creates a random uuid.
func UUID() uuid.UUID {
var uuid uuid.UUID
Read(uuid[:])
return uuid
}
// BucketName creates a random bucket name mostly confirming to the
// restrictions of S3:
// https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html
//
// NOTE: This may not generate values that cover all valid values (for Storj or
// S3). This is a best effort to cover most cases we believe our design
// requires and will need to be revisited when a more explicit design spec is
// created.
func BucketName() string {
const (
edges = "abcdefghijklmnopqrstuvwxyz0123456789"
body = "abcdefghijklmnopqrstuvwxyz0123456789-"
min = 3
max = 63
)
size := rand.Intn(max-min) + min
b := make([]byte, size)
for i := range b {
switch i {
case 0:
fallthrough
case size - 1:
b[i] = edges[rand.Intn(len(edges))]
default:
b[i] = body[rand.Intn(len(body))]
}
}
return string(b)
}
// Metadata creates random metadata mostly conforming to the restrictions of S3:
// https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#object-metadata
//
// NOTE: This may not generate values that cover all valid values (for Storj or
// S3). This is a best effort to cover most cases we believe our design
// requires and will need to be revisited when a more explicit design spec is
// created.
func Metadata() map[string]string {
const (
max = 2 * 1024
)
total := rand.Intn(max)
metadata := make(map[string]string)
for used := 0; total-used > 1; {
keySize := rand.Intn(total-(used+1)) + 1
key := BytesInt(keySize)
used += len(key)
valueSize := rand.Intn(total - used)
value := BytesInt(valueSize)
used += len(value)
metadata[string(key)] = string(value)
}
return metadata
}
// Path creates a random path mostly conforming to the retrictions of S3:
// https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#object-keys
//
// NOTE: This may not generate values that cover all valid values (for Storj or
// S3). This is a best effort to cover most cases we believe our design
// requires and will need to be revisited when a more explicit design spec is
// created.
func Path() string {
const (
max = 1 * 1024
)
total := rand.Intn(max)
path := ""
for used := 0; len(path) < total; {
if used != 0 {
path += "/"
}
path += SegmentID(rand.Intn(total - used)).String()
}
return path[:total]
}