Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions client/eth/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package eth_test

import (
"context"
"os"
"testing"
"time"

"github.com/berachain/offchain-sdk/client/eth"
"github.com/berachain/offchain-sdk/config/env"
"github.com/stretchr/testify/assert"

"github.com/ethereum/go-ethereum"
Expand All @@ -29,21 +29,29 @@ const (
TestModeEither
)

// setupClientTest loads environment variables and performs any necessary test setup.
func setupClientTest(t *testing.T) {
t.Helper()
err := env.Load()
assert.NoError(t, err)
}

// NOTE: requires Ethereum chain rpc url at env var `ETH_RPC_URL` or `ETH_RPC_URL_WS`.
func setUp(testMode int, t *testing.T) (*eth.ExtendedEthClient, error) {
setupClientTest(t)
rpcTimeout := 5 * time.Second
ctxWithTimeout, cancel := context.WithTimeout(context.Background(), rpcTimeout)
defer cancel()

var ethRPC string
switch testMode {
case TestModeWS:
ethRPC = os.Getenv("ETH_RPC_URL_WS")
ethRPC = env.GetEthWSURL()
case TestModeHTTP:
ethRPC = os.Getenv("ETH_RPC_URL")
ethRPC = env.GetEthRPCURL()
case TestModeEither:
if ethRPC = os.Getenv("ETH_RPC_URL_WS"); ethRPC == "" {
ethRPC = os.Getenv("ETH_RPC_URL")
if ethRPC = env.GetEthWSURL(); ethRPC == "" {
ethRPC = env.GetEthRPCURL()
}
default:
panic("invalid test mode")
Expand Down Expand Up @@ -130,7 +138,7 @@ func TestTxPoolContentFrom(t *testing.T) {
assert.NoError(t, err)

ctx := context.Background()
addrStr := os.Getenv("ETH_ADDR")
addrStr := env.GetAddressToListen()
if addrStr == "" {
t.Skipf("Skipping test: no eth address provided")
}
Expand Down
40 changes: 22 additions & 18 deletions client/eth/connection_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,26 @@ package eth_test
import (
"bytes"
"io"
"os"
"testing"

"github.com/berachain/offchain-sdk/client/eth"
"github.com/berachain/offchain-sdk/config/env"
"github.com/berachain/offchain-sdk/log"
"github.com/stretchr/testify/require"
)

var (
HTTPURL = os.Getenv("ETH_HTTP_URL")
WSURL = os.Getenv("ETH_WS_URL")
)

/******************************* HELPER FUNCTIONS ***************************************/
// setupTest loads environment variables and performs any necessary test setup.
func setupTest(t *testing.T) {
t.Helper()
err := env.Load()
require.NoError(t, err)
}

// NOTE: requires chain rpc url at env var `ETH_HTTP_URL` and `ETH_WS_URL`.
// NOTE: requires chain rpc url at env var `ETH_RPC_URL` and `ETH_WS_URL`.
func checkEnv(t *testing.T) {
ethHTTPRPC := os.Getenv("ETH_HTTP_URL")
ethWSRPC := os.Getenv("ETH_WS_URL")
if ethHTTPRPC == "" || ethWSRPC == "" {
ethRPC := env.GetEthRPCURL()
ethWS := env.GetEthWSURL()
if ethRPC == "" || ethWS == "" {
t.Skipf("Skipping test: no eth rpc url provided")
}
}
Expand Down Expand Up @@ -58,7 +58,7 @@ func TestNewConnectionPoolImpl_MissingURLs(t *testing.T) {
// TestNewConnectionPoolImpl_MissingWSURLs tests the case when the WS URLs are missing.
func TestNewConnectionPoolImpl_MissingWSURLs(t *testing.T) {
cfg := eth.ConnectionPoolConfig{
EthHTTPURLs: []string{HTTPURL},
EthHTTPURLs: []string{env.GetEthRPCURL()},
}
var logBuffer bytes.Buffer
pool, err := Init(cfg, &logBuffer, t)
Expand All @@ -71,9 +71,10 @@ func TestNewConnectionPoolImpl_MissingWSURLs(t *testing.T) {
// TestNewConnectionPoolImpl tests the case when the URLs are provided.
// It should the expected behavior.
func TestNewConnectionPoolImpl(t *testing.T) {
setupTest(t)
cfg := eth.ConnectionPoolConfig{
EthHTTPURLs: []string{HTTPURL},
EthWSURLs: []string{WSURL},
EthHTTPURLs: []string{env.GetEthRPCURL()},
EthWSURLs: []string{env.GetEthWSURL()},
}
var logBuffer bytes.Buffer
pool, err := Init(cfg, &logBuffer, t)
Expand All @@ -86,8 +87,9 @@ func TestNewConnectionPoolImpl(t *testing.T) {
// TestGetHTTP tests the retrieval of the HTTP client when it
// has been set and the connection has been established.
func TestGetHTTP(t *testing.T) {
setupTest(t)
cfg := eth.ConnectionPoolConfig{
EthHTTPURLs: []string{HTTPURL},
EthHTTPURLs: []string{env.GetEthRPCURL()},
}
var logBuffer bytes.Buffer
pool, _ := Init(cfg, &logBuffer, t)
Expand All @@ -102,9 +104,10 @@ func TestGetHTTP(t *testing.T) {
// TestGetWS tests the retrieval of the HTTP client when it
// has been set and the connection has been established.
func TestGetWS(t *testing.T) {
setupTest(t)
cfg := eth.ConnectionPoolConfig{
EthHTTPURLs: []string{HTTPURL},
EthWSURLs: []string{WSURL},
EthHTTPURLs: []string{env.GetEthRPCURL()},
EthWSURLs: []string{env.GetEthWSURL()},
}
var logBuffer bytes.Buffer
pool, _ := Init(cfg, &logBuffer, t)
Expand All @@ -120,8 +123,9 @@ func TestGetWS(t *testing.T) {
// TestGetWS_WhenItIsNotSet tests the retrieval of the WS client when
// no WS URLs have been provided.
func TestGetWS_WhenItIsNotSet(t *testing.T) {
setupTest(t)
cfg := eth.ConnectionPoolConfig{
EthHTTPURLs: []string{HTTPURL},
EthHTTPURLs: []string{env.GetEthRPCURL()},
}
var logBuffer bytes.Buffer
pool, _ := Init(cfg, &logBuffer, t)
Expand Down
81 changes: 80 additions & 1 deletion config/env/env.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,82 @@
package env

// TODO support reading .env
import (
"os"
"path/filepath"

"github.com/joho/godotenv"
)

const (
// Ethereum RPC URLs.
EnvEthRPCURL = "ETH_RPC_URL"
EnvEthWSURL = "ETH_WS_URL"
EnvEthRPCURLWS = "ETH_RPC_URL_WS" // Alternative WS URL used in some tests

// Event listening configuration.
EnvEventName = "EVENT_NAME"
EnvAddressListen = "ADDRESS_TO_LISTEN"
)

// Loads environment variables from .env file.
func Load() error {
// Try loading from current directory first
err := godotenv.Load()
if err == nil {
return nil
}

// Then If that fails, try to find .env in
// parent directories.
dir, err := os.Getwd()
if err != nil {
return err
}

for {
envPath := filepath.Join(dir, ".env")
if _, statErr := os.Stat(envPath); statErr == nil {
return godotenv.Load(envPath)
}

parent := filepath.Dir(dir)
if parent == dir {
break
}
dir = parent
}

// If we get here, we couldn't find the .env file
// But we don't return an error because the env vars
// might be actually set in the system in which case
// we don't need the .env file.
return nil
}

// Loads environment variables from the specified file.
func LoadFile(filename string) error {
return godotenv.Load(filename)
}

// Returns the Ethereum RPC URL.
func GetEthRPCURL() string {
return os.Getenv(EnvEthRPCURL)
}

// Returns the Ethereum WebSocket URL.
func GetEthWSURL() string {
if url := os.Getenv(EnvEthRPCURLWS); url != "" {
return url
}
return os.Getenv(EnvEthWSURL)
}

// Returns the event name to listen for.
func GetEventName() string {
return os.Getenv(EnvEventName)
}

// Returns the contract address to listen to.
func GetAddressToListen() string {
return os.Getenv(EnvAddressListen)
}
60 changes: 60 additions & 0 deletions config/env/env_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package env

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
)

func TestEnv(t *testing.T) {
t.Run("test loading from .env file", func(t *testing.T) {
// Creating a temporary .env file for this test
dir := t.TempDir()
envFile := filepath.Join(dir, ".env")
err := os.WriteFile(envFile, []byte(`
ETH_RPC_URL=http://localhost:8545
ETH_WS_URL=ws://localhost:8546
ETH_RPC_URL_WS=ws://localhost:8547
EVENT_NAME=NumberChanged(uint256)
ADDRESS_TO_LISTEN=0x5793a71D3eF074f71dCC21216Dbfd5C0e780132c
`), 0644)
require.NoError(t, err)

// Loading the env file
err = LoadFile(envFile)
require.NoError(t, err)

// Testing each getter
require.Equal(t, "http://localhost:8545", GetEthRPCURL())
require.Equal(t, "ws://localhost:8547", GetEthWSURL(), "should prefer ETH_RPC_URL_WS")

// Clearing ETH_RPC_URL_WS and verifying fallback to ETH_WS_URL
os.Unsetenv(EnvEthRPCURLWS)
require.Equal(t, "ws://localhost:8546", GetEthWSURL(), "should fallback to ETH_WS_URL")

require.Equal(t, "NumberChanged(uint256)", GetEventName())
require.Equal(t, "0x5793a71D3eF074f71dCC21216Dbfd5C0e780132c", GetAddressToListen())
})

t.Run("test loading non-existent file", func(t *testing.T) {
err := LoadFile("non-existent.env")
require.Error(t, err)
})

t.Run("test loading with missing values", func(t *testing.T) {
// Clearing all env vars first
os.Unsetenv(EnvEthRPCURL)
os.Unsetenv(EnvEthWSURL)
os.Unsetenv(EnvEthRPCURLWS)
os.Unsetenv(EnvEventName)
os.Unsetenv(EnvAddressListen)

// Testing empty values
require.Empty(t, GetEthRPCURL())
require.Empty(t, GetEthWSURL())
require.Empty(t, GetEventName())
require.Empty(t, GetAddressToListen())
})
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/holiman/uint256 v1.2.4
github.com/huandu/skiplist v1.2.0
github.com/jellydator/ttlcache/v2 v2.11.1
github.com/joho/godotenv v1.5.1
github.com/prometheus/client_golang v1.17.0
github.com/redis/go-redis/v9 v9.5.1
github.com/rs/zerolog v1.31.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pk
github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
Expand Down