Skip to content

Commit

Permalink
Add fuzz tests (#137)
Browse files Browse the repository at this point in the history
  • Loading branch information
anupsv authored Dec 19, 2024
1 parent 89cfdd7 commit d89658b
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 4 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/fuzz-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: fuzz-tests

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
go-test:
outputs:
COVERAGE: ${{ steps.unit.outputs.coverage }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.21

- name: Install project dependencies
run: |
go mod download
- name: Run E2E Fuzz Tests
run: |
make e2e-fuzz-test
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ LDFLAGSSTRING +=-X main.Date=$(BUILD_TIME)
LDFLAGSSTRING +=-X main.Version=$(GIT_TAG)
LDFLAGS := -ldflags "$(LDFLAGSSTRING)"

E2EFUZZTEST = FUZZ=true go test ./e2e -fuzz -v -fuzztime=15m

.PHONY: eigenda-proxy
eigenda-proxy:
env GO111MODULE=on GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -v $(LDFLAGS) -o ./bin/eigenda-proxy ./cmd/server
Expand All @@ -35,6 +37,9 @@ test:
e2e-test:
INTEGRATION=true go test -timeout 1m ./e2e -parallel 4

e2e-fuzz-test:
$(E2EFUZZTEST)

holesky-test:
TESTNET=true go test -timeout 50m ./e2e -parallel 4

Expand Down
4 changes: 2 additions & 2 deletions e2e/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ import (
var (
runTestnetIntegrationTests bool // holesky tests
runIntegrationTests bool // memstore tests
runFuzzTests bool // fuzz tests
)

// ParseEnv ... reads testing cfg fields. Go test flags don't work for this library due to the dependency on Optimism's E2E framework
// which initializes test flags per init function which is called before an init in this package.
func ParseEnv() {
runIntegrationTests = os.Getenv("INTEGRATION") == "true" || os.Getenv("INTEGRATION") == "1"
runTestnetIntegrationTests = os.Getenv("TESTNET") == "true" || os.Getenv("TESTNET") == "1"
runFuzzTests = os.Getenv("FUZZ") == "true" || os.Getenv("FUZZ") == "1"
if runIntegrationTests && runTestnetIntegrationTests {
panic("only one of INTEGRATION=true or TESTNET=true env var can be set")
}
Expand Down
46 changes: 46 additions & 0 deletions e2e/server_fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package e2e_test

import (
"github.com/stretchr/testify/assert"

"testing"
"unicode"

"github.com/Layr-Labs/eigenda-proxy/client"
"github.com/Layr-Labs/eigenda-proxy/e2e"
)

// FuzzProxyClientServerIntegrationAndOpClientKeccak256MalformedInputs will fuzz the proxy client server integration
// and op client keccak256 with malformed inputs. This is never meant to be fuzzed with EigenDA.
func FuzzProxyClientServerIntegration(f *testing.F) {
if !runFuzzTests {
f.Skip("Skipping test as FUZZ env var not set")
}

tsConfig := e2e.TestSuiteConfig(e2e.TestConfig(useMemory()))
ts, kill := e2e.CreateTestSuite(tsConfig)

for r := rune(0); r <= unicode.MaxRune; r++ {
if unicode.IsPrint(r) {
f.Add([]byte(string(r))) // Add each printable Unicode character as a seed
}
}

cfg := &client.Config{
URL: ts.Address(),
}

daClient := client.New(cfg)

// seed and data are expected. `seed` value is seed: {rune} and data is the one with the random byte(s)
f.Fuzz(func(t *testing.T, data []byte) {
_, err := daClient.SetData(ts.Ctx, data)
assert.NoError(t, err)
if err != nil {
t.Errorf("Failed to set data: %v", err)
}
})

f.Cleanup(kill)

}
105 changes: 103 additions & 2 deletions e2e/server_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package e2e_test

import (
"strings"
"testing"
"time"

"github.com/Layr-Labs/eigenda-proxy/client"
"github.com/Layr-Labs/eigenda-proxy/commitments"
"github.com/Layr-Labs/eigenda-proxy/common"
"github.com/stretchr/testify/require"

"github.com/Layr-Labs/eigenda-proxy/e2e"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func useMemory() bool {
Expand All @@ -29,6 +30,7 @@ func TestOptimismClientWithKeccak256Commitment(t *testing.T) {
tsConfig := e2e.TestSuiteConfig(testCfg)
ts, kill := e2e.CreateTestSuite(tsConfig)
defer kill()

requireOPClientSetGet(t, ts, e2e.RandBytes(100), true)
}

Expand All @@ -52,6 +54,105 @@ func TestOptimismClientWithGenericCommitment(t *testing.T) {
requireDispersalRetrievalEigenDA(t, ts.Metrics.HTTPServerRequestsTotal, commitments.OptimismGeneric)
}

// TestProxyClientServerIntegration tests the proxy client and server integration by setting the data as a single byte,
// many unicode characters, single unicode character and an empty preimage. It then tries to get the data from the
// proxy server with empty byte, single byte and random string.
func TestProxyClientServerIntegration(t *testing.T) {
t.Parallel()

if !runIntegrationTests && !runTestnetIntegrationTests {
t.Skip("Skipping test as INTEGRATION or TESTNET env var not set")
}

tsConfig := e2e.TestSuiteConfig(e2e.TestConfig(useMemory()))
ts, kill := e2e.CreateTestSuite(tsConfig)
t.Cleanup(kill)

cfg := &client.Config{
URL: ts.Address(),
}
daClient := client.New(cfg)

t.Run("single byte preimage set data case", func(t *testing.T) {
t.Parallel()
testPreimage := []byte{1} // single byte preimage
t.Log("Setting input data on proxy server...")
_, err := daClient.SetData(ts.Ctx, testPreimage)
require.NoError(t, err)
})

t.Run("unicode preimage set data case", func(t *testing.T) {
t.Parallel()
testPreimage := []byte("§§©ˆªªˆ˙√ç®∂§∞¶§ƒ¥√¨¥√¨¥ƒƒ©˙˜ø˜˜˜∫˙∫¥∫√†®®√稈¨˙ï") // many unicode characters
t.Log("Setting input data on proxy server...")
_, err := daClient.SetData(ts.Ctx, testPreimage)
require.NoError(t, err)

testPreimage = []byte("§") // single unicode character
t.Log("Setting input data on proxy server...")
_, err = daClient.SetData(ts.Ctx, testPreimage)
require.NoError(t, err)

})

t.Run("empty preimage set data case", func(t *testing.T) {
t.Parallel()
testPreimage := []byte("") // Empty preimage
t.Log("Setting input data on proxy server...")
_, err := daClient.SetData(ts.Ctx, testPreimage)
require.NoError(t, err)
})

t.Run("get data edge cases", func(t *testing.T) {
t.Parallel()
testCert := []byte("")
_, err := daClient.GetData(ts.Ctx, testCert)
require.Error(t, err)
assert.True(t, strings.Contains(err.Error(),
"404") && !isNilPtrDerefPanic(err.Error()))

testCert = []byte{1}
_, err = daClient.GetData(ts.Ctx, testCert)
require.Error(t, err)
assert.True(t, strings.Contains(err.Error(),
"400") && !isNilPtrDerefPanic(err.Error()))

testCert = e2e.RandBytes(10000)
_, err = daClient.GetData(ts.Ctx, testCert)
require.Error(t, err)
assert.True(t, strings.Contains(err.Error(), "400") && !isNilPtrDerefPanic(err.Error()))
})

}

func TestProxyClient(t *testing.T) {
if !runIntegrationTests && !runTestnetIntegrationTests {
t.Skip("Skipping test as INTEGRATION or TESTNET env var not set")
}

t.Parallel()

tsConfig := e2e.TestSuiteConfig(e2e.TestConfig(useMemory()))
ts, kill := e2e.CreateTestSuite(tsConfig)
defer kill()

cfg := &client.Config{
URL: ts.Address(),
}
daClient := client.New(cfg)

testPreimage := e2e.RandBytes(100)

t.Log("Setting input data on proxy server...")
blobInfo, err := daClient.SetData(ts.Ctx, testPreimage)
require.NoError(t, err)

t.Log("Getting input data from proxy server...")
preimage, err := daClient.GetData(ts.Ctx, blobInfo)
require.NoError(t, err)
require.Equal(t, testPreimage, preimage)
}

func TestProxyClientWriteRead(t *testing.T) {
if !runIntegrationTests && !runTestnetIntegrationTests {
t.Skip("Skipping test as INTEGRATION or TESTNET env var not set")
Expand Down

0 comments on commit d89658b

Please sign in to comment.