Skip to content

Commit

Permalink
Add unit test for backup execution
Browse files Browse the repository at this point in the history
  • Loading branch information
zivkovicmilos committed Oct 3, 2023
1 parent f0d8327 commit 16be3b2
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 28 deletions.
37 changes: 30 additions & 7 deletions backup/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package backup

import (
"encoding/json"
"errors"
"fmt"
"os"

Expand Down Expand Up @@ -64,16 +65,27 @@ func ExecuteBackup(
return fmt.Errorf("unable to fetch block data, %w", blockDataErr)
}

// Marshal the response
blockDataRaw, marshalErr := json.Marshal(blockData)
// Prepare the archive
metadata, metadataErr := generateMetadata(blockData)
if metadataErr != nil {
return fmt.Errorf("unable to generate metadata, %w", metadataErr)
}

archive := &types.Archive{
BlockData: blockData,
Metadata: metadata,
}

// Marshal the archive data
archiveRaw, marshalErr := json.Marshal(archive)
if marshalErr != nil {
return fmt.Errorf("unable to marshal block data JSON, %w", marshalErr)
return fmt.Errorf("unable to marshal archive JSON, %w", marshalErr)
}

// Write the chain data to a file
_, writeErr := outputFile.Write(blockDataRaw)
// Write the archive data to a file
_, writeErr := outputFile.Write(archiveRaw)
if writeErr != nil {
return fmt.Errorf("unable to write block data JSON, %w", writeErr)
return fmt.Errorf("unable to write archive JSON, %w", writeErr)
}

return nil
Expand Down Expand Up @@ -110,7 +122,7 @@ func getBlockData(
) ([]*types.BlockData, error) {
blockData := make([]*types.BlockData, 0, to-from+1)

for block := from; block < to; block++ {
for block := from; block <= to; block++ {
txs, txErr := client.GetBlockTransactions(block)
if txErr != nil {
return nil, fmt.Errorf("unable to fetch block transactions, %w", txErr)
Expand Down Expand Up @@ -143,3 +155,14 @@ func logProgress(logger log.Logger, from, to, current uint64) {
"status", fmt.Sprintf("%.2f%%", status),
)
}

func generateMetadata(blockData []*types.BlockData) (*types.Metadata, error) {
if len(blockData) == 0 {
return nil, errors.New("unable to generate metadata, no block data")
}

return &types.Metadata{
EarliestBlockHeight: blockData[0].BlockNum,
LatestBlockHeight: blockData[len(blockData)-1].BlockNum,
}, nil
}
73 changes: 73 additions & 0 deletions backup/backup_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package backup

import (
"encoding/json"
"errors"
"os"
"testing"

"github.com/gnolang/gno/tm2/pkg/std"
"github.com/gnolang/tx-archive/log/noop"
"github.com/gnolang/tx-archive/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -71,3 +76,71 @@ func TestBackup_DetermineRightBound(t *testing.T) {
assert.Equal(t, requestedTo, rightBound)
})
}

func TestBackup_ExecuteBackup(t *testing.T) {
t.Parallel()

var (
tempFile = createTempFile(t)

fromBlock uint64 = 10
toBlock = fromBlock + 10

exampleTx = std.Tx{
Memo: "example transaction",
}

cfg = DefaultConfig()

mockClient = &mockClient{
getLatestBlockNumberFn: func() (uint64, error) {
return toBlock, nil
},
getBlockTransactionsFn: func(blockNum uint64) ([]std.Tx, error) {
// Sanity check
if blockNum < fromBlock && blockNum > toBlock {
t.Fatal("invalid block number requested")
}

return []std.Tx{exampleTx}, nil
},
}
)

// Temp file cleanup
t.Cleanup(func() {
require.NoError(t, tempFile.Close())
require.NoError(t, os.Remove(tempFile.Name()))
})

// Set the config
cfg.FromBlock = fromBlock
cfg.ToBlock = &toBlock
cfg.OutputFile = tempFile.Name()
cfg.Overwrite = true

// Run the backup procedure
require.NoError(t, ExecuteBackup(mockClient, noop.New(), cfg))

// Read the output file
archiveRaw, err := os.ReadFile(tempFile.Name())
require.NoError(t, err)

// Unmarshal the raw archive output
var archive types.Archive

require.NoError(t, json.Unmarshal(archiveRaw, &archive))

// Validate the archive
assert.Equal(t, fromBlock, archive.Metadata.EarliestBlockHeight)
assert.Equal(t, toBlock, archive.Metadata.LatestBlockHeight)
assert.Equal(t, int(toBlock-fromBlock+1), len(archive.BlockData))

for index, block := range archive.BlockData {
assert.Equal(t, uint64(index)+fromBlock, block.BlockNum)

for _, tx := range block.Txs {
assert.Equal(t, exampleTx, tx)
}
}
}
28 changes: 13 additions & 15 deletions backup/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,20 @@ import (
"github.com/stretchr/testify/require"
)

func TestConfig_ValidateConfig(t *testing.T) {
t.Parallel()
// createTempFile creates a temporary file
func createTempFile(t *testing.T) *os.File {
t.Helper()

// Helper for creating a temporary file
createTempFile := func() *os.File {
f, err := os.CreateTemp("", "temp-")
if err != nil {
t.Fatalf("unable to create temporary file, %v", err)
}
f, err := os.CreateTemp("", "temp-")
if err != nil {
t.Fatalf("unable to create temporary file, %v", err)
}

if _, err := f.WriteString("random data"); err != nil {
t.Fatalf("unable to write dummy data, %v", err)
}
return f
}

return f
}
func TestConfig_ValidateConfig(t *testing.T) {
t.Parallel()

t.Run("invalid output file", func(t *testing.T) {
t.Parallel()
Expand All @@ -38,7 +36,7 @@ func TestConfig_ValidateConfig(t *testing.T) {
t.Parallel()

// Create temp file
tempFile := createTempFile()
tempFile := createTempFile(t)

t.Cleanup(func() {
require.NoError(t, tempFile.Close())
Expand All @@ -56,7 +54,7 @@ func TestConfig_ValidateConfig(t *testing.T) {
t.Parallel()

// Create temp file
tempFile := createTempFile()
tempFile := createTempFile(t)

t.Cleanup(func() {
require.NoError(t, tempFile.Close())
Expand Down
9 changes: 3 additions & 6 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@ import "github.com/gnolang/gno/tm2/pkg/std"

// Archive wraps the backed-up chain data
type Archive struct {
ChainData BlockData `json:"chainData"`
Metadata Metadata `json:"metadata"`
Metadata *Metadata `json:"metadata"`
BlockData []*BlockData `json:"blockData"`
}

// Metadata contains contextual information about the archive
type Metadata struct {
EarliestBlockHeight uint64 `json:"earliestBlockHeight"`
EarliestTxHash uint64 `json:"earliestTxHash"`

LatestBlockHeight uint64 `json:"latestBlockHeight"`
LatestTxHash uint64 `json:"latestTxHash"`
LatestBlockHeight uint64 `json:"latestBlockHeight"`
}

// BlockData contains the historical transaction data
Expand Down

0 comments on commit 16be3b2

Please sign in to comment.