2018-08-17 18:40:15 +01:00
|
|
|
// Copyright (C) 2018 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package psdb
|
|
|
|
|
|
|
|
import (
|
2018-09-08 16:34:55 +01:00
|
|
|
"bytes"
|
2018-10-30 16:43:09 +00:00
|
|
|
"context"
|
2018-08-17 18:40:15 +01:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2018-09-08 16:34:55 +01:00
|
|
|
"strconv"
|
2018-08-17 18:40:15 +01:00
|
|
|
"testing"
|
2018-10-10 15:04:42 +01:00
|
|
|
"time"
|
2018-08-17 18:40:15 +01:00
|
|
|
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
2018-10-16 12:43:44 +01:00
|
|
|
|
2018-11-29 18:39:27 +00:00
|
|
|
"storj.io/storj/internal/teststorj"
|
2018-10-16 12:43:44 +01:00
|
|
|
"storj.io/storj/pkg/pb"
|
2018-11-30 13:40:13 +00:00
|
|
|
"storj.io/storj/pkg/storj"
|
2018-08-17 18:40:15 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
var ctx = context.Background()
|
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
const concurrency = 10
|
2018-08-17 18:40:15 +01:00
|
|
|
|
2018-10-30 16:43:09 +00:00
|
|
|
func newDB(t testing.TB) (*DB, func()) {
|
2018-09-08 16:34:55 +01:00
|
|
|
tmpdir, err := ioutil.TempDir("", "storj-psdb")
|
2018-08-17 18:40:15 +01:00
|
|
|
if err != nil {
|
2018-09-08 16:34:55 +01:00
|
|
|
t.Fatal(err)
|
2018-08-17 18:40:15 +01:00
|
|
|
}
|
2018-09-08 16:34:55 +01:00
|
|
|
dbpath := filepath.Join(tmpdir, "psdb.db")
|
2018-08-17 18:40:15 +01:00
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
db, err := Open(ctx, "", dbpath)
|
2018-08-17 18:40:15 +01:00
|
|
|
if err != nil {
|
2018-09-08 16:34:55 +01:00
|
|
|
t.Fatal(err)
|
2018-08-17 18:40:15 +01:00
|
|
|
}
|
2018-09-11 14:13:25 +01:00
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
return db, func() {
|
|
|
|
err := db.Close()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-08-17 18:40:15 +01:00
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
err = os.RemoveAll(tmpdir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
2018-08-17 18:40:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-30 16:43:09 +00:00
|
|
|
func TestNewInmemory(t *testing.T) {
|
|
|
|
db, err := OpenInMemory(context.Background(), "")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := db.Close(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
func TestHappyPath(t *testing.T) {
|
2018-10-30 16:43:09 +00:00
|
|
|
db, cleanup := newDB(t)
|
2018-09-08 16:34:55 +01:00
|
|
|
defer cleanup()
|
2018-08-17 18:40:15 +01:00
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
type TTL struct {
|
|
|
|
ID string
|
|
|
|
Expiration int64
|
2018-08-17 18:40:15 +01:00
|
|
|
}
|
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
tests := []TTL{
|
|
|
|
{ID: "", Expiration: 0},
|
|
|
|
{ID: "\x00", Expiration: ^int64(0)},
|
|
|
|
{ID: "test", Expiration: 666},
|
2018-08-17 18:40:15 +01:00
|
|
|
}
|
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
t.Run("Add", func(t *testing.T) {
|
|
|
|
for P := 0; P < concurrency; P++ {
|
|
|
|
t.Run("#"+strconv.Itoa(P), func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
for _, ttl := range tests {
|
2018-09-13 15:30:45 +01:00
|
|
|
err := db.AddTTL(ttl.ID, ttl.Expiration, 0)
|
2018-09-08 16:34:55 +01:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-08-17 18:40:15 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2018-09-08 16:34:55 +01:00
|
|
|
})
|
2018-08-17 18:40:15 +01:00
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
t.Run("Get", func(t *testing.T) {
|
|
|
|
for P := 0; P < concurrency; P++ {
|
|
|
|
t.Run("#"+strconv.Itoa(P), func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
for _, ttl := range tests {
|
|
|
|
expiration, err := db.GetTTLByID(ttl.ID)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if ttl.Expiration != expiration {
|
|
|
|
t.Fatalf("expected %d got %d", ttl.Expiration, expiration)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
2018-08-17 18:40:15 +01:00
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
t.Run("Delete", func(t *testing.T) {
|
|
|
|
for P := 0; P < concurrency; P++ {
|
|
|
|
t.Run("Delete", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
for _, ttl := range tests {
|
|
|
|
err := db.DeleteTTLByID(ttl.ID)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-08-17 18:40:15 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2018-09-08 16:34:55 +01:00
|
|
|
})
|
2018-08-17 18:40:15 +01:00
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
t.Run("Get Deleted", func(t *testing.T) {
|
|
|
|
for P := 0; P < concurrency; P++ {
|
|
|
|
t.Run("#"+strconv.Itoa(P), func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
for _, ttl := range tests {
|
|
|
|
expiration, err := db.GetTTLByID(ttl.ID)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if expiration != 0 {
|
|
|
|
t.Fatalf("expected expiration 0 got %d", expiration)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2018-08-17 18:40:15 +01:00
|
|
|
})
|
|
|
|
|
2018-11-29 18:39:27 +00:00
|
|
|
bandwidthAllocation := func(satelliteID storj.NodeID, total int64) []byte {
|
2018-09-08 16:34:55 +01:00
|
|
|
return serialize(t, &pb.RenterBandwidthAllocation_Data{
|
2018-11-01 16:40:26 +00:00
|
|
|
PayerAllocation: &pb.PayerBandwidthAllocation{
|
|
|
|
Data: serialize(t, &pb.PayerBandwidthAllocation_Data{
|
2018-11-29 18:39:27 +00:00
|
|
|
SatelliteId: satelliteID,
|
2018-11-01 16:40:26 +00:00
|
|
|
}),
|
|
|
|
},
|
|
|
|
Total: total,
|
2018-09-08 16:34:55 +01:00
|
|
|
})
|
|
|
|
}
|
2018-08-17 18:40:15 +01:00
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
//TODO: use better data
|
2018-11-29 18:39:27 +00:00
|
|
|
nodeIDAB := teststorj.NodeIDFromString("AB")
|
2018-09-08 16:34:55 +01:00
|
|
|
allocationTests := []*pb.RenterBandwidthAllocation{
|
2018-08-17 18:40:15 +01:00
|
|
|
{
|
2018-09-08 16:34:55 +01:00
|
|
|
Signature: []byte("signed by test"),
|
2018-11-29 18:39:27 +00:00
|
|
|
Data: bandwidthAllocation(nodeIDAB, 0),
|
2018-09-08 16:34:55 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
Signature: []byte("signed by sigma"),
|
2018-11-29 18:39:27 +00:00
|
|
|
Data: bandwidthAllocation(nodeIDAB, 10),
|
2018-09-08 16:34:55 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
Signature: []byte("signed by sigma"),
|
2018-11-29 18:39:27 +00:00
|
|
|
Data: bandwidthAllocation(nodeIDAB, 98),
|
2018-09-08 16:34:55 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
Signature: []byte("signed by test"),
|
2018-11-29 18:39:27 +00:00
|
|
|
Data: bandwidthAllocation(nodeIDAB, 3),
|
2018-08-17 18:40:15 +01:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
t.Run("Bandwidth Allocation", func(t *testing.T) {
|
|
|
|
for P := 0; P < concurrency; P++ {
|
|
|
|
t.Run("#"+strconv.Itoa(P), func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
for _, test := range allocationTests {
|
|
|
|
err := db.WriteBandwidthAllocToDB(test)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
agreements, err := db.GetBandwidthAllocationBySignature(test.Signature)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
found := false
|
|
|
|
for _, agreement := range agreements {
|
|
|
|
if bytes.Equal(agreement, test.Data) {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !found {
|
|
|
|
t.Fatal("did not find added bandwidth allocation")
|
|
|
|
}
|
2018-08-17 18:40:15 +01:00
|
|
|
}
|
2018-11-01 16:40:26 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Get all Bandwidth Allocations", func(t *testing.T) {
|
|
|
|
for P := 0; P < concurrency; P++ {
|
|
|
|
t.Run("#"+strconv.Itoa(P), func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
agreementGroups, err := db.GetBandwidthAllocations()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
found := false
|
|
|
|
for _, agreements := range agreementGroups {
|
|
|
|
for _, agreement := range agreements {
|
|
|
|
for _, test := range allocationTests {
|
|
|
|
if bytes.Equal(agreement.Agreement, test.Data) {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !found {
|
|
|
|
t.Fatal("did not find added bandwidth allocation")
|
|
|
|
}
|
2018-09-08 16:34:55 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2018-08-17 18:40:15 +01:00
|
|
|
|
2018-10-10 15:04:42 +01:00
|
|
|
func TestBandwidthUsage(t *testing.T) {
|
2018-10-30 16:43:09 +00:00
|
|
|
db, cleanup := newDB(t)
|
2018-10-10 15:04:42 +01:00
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
type BWUSAGE struct {
|
|
|
|
size int64
|
|
|
|
timenow time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
bwtests := []BWUSAGE{
|
|
|
|
{size: 1000, timenow: time.Now()},
|
|
|
|
}
|
|
|
|
|
|
|
|
var bwTotal int64
|
|
|
|
t.Run("AddBandwidthUsed", func(t *testing.T) {
|
|
|
|
for P := 0; P < concurrency; P++ {
|
|
|
|
bwTotal = bwTotal + bwtests[0].size
|
|
|
|
t.Run("#"+strconv.Itoa(P), func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
for _, bw := range bwtests {
|
|
|
|
err := db.AddBandwidthUsed(bw.size)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("GetTotalBandwidthBetween", func(t *testing.T) {
|
|
|
|
for P := 0; P < concurrency; P++ {
|
|
|
|
t.Run("#"+strconv.Itoa(P), func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
for _, bw := range bwtests {
|
|
|
|
size, err := db.GetTotalBandwidthBetween(bw.timenow, bw.timenow)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if bwTotal != size {
|
|
|
|
t.Fatalf("expected %d got %d", bw.size, size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("GetBandwidthUsedByDay", func(t *testing.T) {
|
|
|
|
for P := 0; P < concurrency; P++ {
|
|
|
|
t.Run("#"+strconv.Itoa(P), func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
for _, bw := range bwtests {
|
|
|
|
size, err := db.GetBandwidthUsedByDay(bw.timenow)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if bwTotal != size {
|
|
|
|
t.Fatalf("expected %d got %d", bw.size, size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
func BenchmarkWriteBandwidthAllocation(b *testing.B) {
|
2018-10-30 16:43:09 +00:00
|
|
|
db, cleanup := newDB(b)
|
2018-09-08 16:34:55 +01:00
|
|
|
defer cleanup()
|
2018-08-17 18:40:15 +01:00
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
const WritesPerLoop = 10
|
2018-08-17 18:40:15 +01:00
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
data := serialize(b, &pb.RenterBandwidthAllocation_Data{
|
|
|
|
PayerAllocation: &pb.PayerBandwidthAllocation{},
|
|
|
|
Total: 156,
|
|
|
|
})
|
2018-08-17 18:40:15 +01:00
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
b.RunParallel(func(b *testing.PB) {
|
|
|
|
for b.Next() {
|
|
|
|
for i := 0; i < WritesPerLoop; i++ {
|
|
|
|
_ = db.WriteBandwidthAllocToDB(&pb.RenterBandwidthAllocation{
|
|
|
|
Signature: []byte("signed by test"),
|
|
|
|
Data: data,
|
|
|
|
})
|
|
|
|
}
|
2018-08-17 18:40:15 +01:00
|
|
|
}
|
2018-09-08 16:34:55 +01:00
|
|
|
})
|
2018-08-17 18:40:15 +01:00
|
|
|
}
|
|
|
|
|
2018-09-08 16:34:55 +01:00
|
|
|
func serialize(t testing.TB, v proto.Message) []byte {
|
|
|
|
data, err := proto.Marshal(v)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-08-17 18:40:15 +01:00
|
|
|
return data
|
|
|
|
}
|