2023-07-11 22:20:09 +00:00
|
|
|
package itests
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/sha256"
|
|
|
|
"encoding/hex"
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/filecoin-project/lotus/itests/kit"
|
|
|
|
"github.com/filecoin-project/lotus/lib/sturdy/clusterdb"
|
|
|
|
"github.com/filecoin-project/lotus/node"
|
2023-07-12 16:02:23 +00:00
|
|
|
"github.com/filecoin-project/lotus/node/impl"
|
2023-07-11 22:20:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func withSetup(t *testing.T, f func(*kit.TestMiner)) {
|
|
|
|
_, miner, _ := kit.EnsembleMinimal(t,
|
|
|
|
kit.LatestActorsAt(-1),
|
|
|
|
kit.MockProofs(),
|
|
|
|
kit.ConstructorOpts(
|
2023-07-12 16:02:23 +00:00
|
|
|
node.Override(new(clusterdb.ITestID), func() clusterdb.ITestID {
|
|
|
|
return clusterdb.ITestNewID()
|
|
|
|
}),
|
2023-07-11 22:20:09 +00:00
|
|
|
),
|
|
|
|
)
|
|
|
|
|
2023-07-12 16:02:23 +00:00
|
|
|
defer miner.BaseAPI.(*impl.StorageMinerAPI).ClusterDB.ITestDeleteAll()
|
2023-07-11 22:20:09 +00:00
|
|
|
f(miner)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCrud(t *testing.T) {
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
withSetup(t, func(miner *kit.TestMiner) {
|
2023-07-12 16:02:23 +00:00
|
|
|
cdb := miner.BaseAPI.(*impl.StorageMinerAPI).ClusterDB
|
|
|
|
err := cdb.Exec(ctx, `
|
2023-07-11 22:20:09 +00:00
|
|
|
INSERT INTO
|
|
|
|
itest_scratch (some_int, content)
|
|
|
|
VALUES
|
|
|
|
(11, 'cows'),
|
|
|
|
(5, 'cats')
|
|
|
|
`)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal("Could not insert: ", err)
|
|
|
|
}
|
|
|
|
var ints []struct {
|
|
|
|
Count int `db:"some_int"`
|
|
|
|
Animal string `db:"content"`
|
|
|
|
Unpopulated int
|
|
|
|
}
|
2023-07-12 16:02:23 +00:00
|
|
|
err = cdb.Select(ctx, &ints, "SELECT content, some_int FROM itest_scratch")
|
2023-07-11 22:20:09 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal("Could not select: ", err)
|
|
|
|
}
|
|
|
|
if len(ints) != 2 {
|
|
|
|
t.Fatal("unexpected count of returns. Want 2, Got ", len(ints))
|
|
|
|
}
|
|
|
|
if ints[0].Count != 11 || ints[1].Count != 5 {
|
|
|
|
t.Fatal("expected [11,5] got ", ints)
|
|
|
|
}
|
|
|
|
if ints[0].Animal != "cows" || ints[1].Animal != "cats" {
|
|
|
|
t.Fatal("expected, [cows, cats] ", ints)
|
|
|
|
}
|
|
|
|
fmt.Println("test completed")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTransaction(t *testing.T) {
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
withSetup(t, func(miner *kit.TestMiner) {
|
2023-07-12 16:02:23 +00:00
|
|
|
cdb := miner.BaseAPI.(*impl.StorageMinerAPI).ClusterDB
|
|
|
|
if err := cdb.Exec(ctx, "INSERT INTO itest_scratch (some_int) VALUES (4), (5), (6)"); err != nil {
|
2023-07-11 22:20:09 +00:00
|
|
|
t.Fatal("E0", err)
|
|
|
|
}
|
2023-07-12 16:02:23 +00:00
|
|
|
cdb.BeginTransaction(ctx, func(tx *clusterdb.Transaction) (commit bool) {
|
2023-07-11 22:20:09 +00:00
|
|
|
if err := tx.Exec(ctx, "INSERT INTO itest_scratch (some_int) VALUES (7), (8), (9)"); err != nil {
|
|
|
|
t.Fatal("E1", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// sum1 is read from OUTSIDE the transaction so it's the old value
|
|
|
|
var sum1 int
|
2023-07-12 16:02:23 +00:00
|
|
|
if err := cdb.QueryRow(ctx, "SELECT SUM(some_int) FROM itest_scratch").Scan(&sum1); err != nil {
|
2023-07-11 22:20:09 +00:00
|
|
|
t.Fatal("E2", err)
|
|
|
|
}
|
|
|
|
if sum1 != 4+5+6 {
|
|
|
|
t.Fatal("Expected 15, got ", sum1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// sum2 is from INSIDE the transaction, so the updated value.
|
|
|
|
var sum2 int
|
|
|
|
if err := tx.QueryRow(ctx, "SELECT SUM(some_int) FROM itest_scratch").Scan(&sum2); err != nil {
|
|
|
|
t.Fatal("E3", err)
|
|
|
|
}
|
|
|
|
if sum2 != 4+5+6+7+8+9 {
|
|
|
|
t.Fatal("Expected 39, got ", sum2)
|
|
|
|
}
|
|
|
|
return false // rollback
|
|
|
|
})
|
|
|
|
|
|
|
|
var sum2 int
|
|
|
|
// Query() example (yes, QueryRow would be preferred here)
|
2023-07-12 16:02:23 +00:00
|
|
|
q, err := cdb.Query(ctx, "SELECT SUM(some_int) FROM itest_scratch")
|
2023-07-11 22:20:09 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal("E4", err)
|
|
|
|
}
|
|
|
|
defer q.Close()
|
|
|
|
var rowCt int
|
|
|
|
for q.Next() {
|
|
|
|
q.Scan(&sum2)
|
|
|
|
rowCt++
|
|
|
|
}
|
|
|
|
if sum2 != 4+5+6 {
|
|
|
|
t.Fatal("Expected 15, got ", sum2)
|
|
|
|
}
|
|
|
|
if rowCt != 1 {
|
|
|
|
t.Fatal("unexpected count of rows")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPartialWalk(t *testing.T) {
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
withSetup(t, func(miner *kit.TestMiner) {
|
2023-07-12 16:02:23 +00:00
|
|
|
cdb := miner.BaseAPI.(*impl.StorageMinerAPI).ClusterDB
|
|
|
|
if err := cdb.Exec(ctx, `
|
2023-07-11 22:20:09 +00:00
|
|
|
INSERT INTO
|
|
|
|
itest_scratch (content, some_int)
|
|
|
|
VALUES
|
|
|
|
('andy was here', 5),
|
|
|
|
('lotus is awesome', 6),
|
|
|
|
('hello world', 7),
|
|
|
|
('3rd integration test', 8),
|
|
|
|
('fiddlesticks', 9)
|
|
|
|
`); err != nil {
|
|
|
|
t.Fatal("e1", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TASK: FIND THE ID of the string with a specific SHA256
|
|
|
|
needle := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
|
2023-07-12 16:02:23 +00:00
|
|
|
q, err := cdb.Query(ctx, `SELECT id, content FROM itest_scratch`)
|
2023-07-11 22:20:09 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal("e2", err)
|
|
|
|
}
|
|
|
|
defer q.Close()
|
|
|
|
|
|
|
|
var tmp struct {
|
|
|
|
Src string `db:"content"`
|
|
|
|
ID int
|
|
|
|
}
|
|
|
|
|
|
|
|
var done bool
|
|
|
|
for q.Next() {
|
|
|
|
|
|
|
|
if err := q.StructScan(&tmp); err != nil {
|
2023-07-12 16:02:23 +00:00
|
|
|
t.Fatal("structscan err " + err.Error())
|
2023-07-11 22:20:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bSha := sha256.Sum256([]byte(tmp.Src))
|
|
|
|
if hex.EncodeToString(bSha[:]) == needle {
|
|
|
|
done = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !done {
|
|
|
|
t.Fatal("We didn't find it.")
|
|
|
|
}
|
|
|
|
// Answer: tmp.ID
|
|
|
|
})
|
|
|
|
}
|