diff --git a/.vscode/launch.json b/.vscode/launch.json index 7f8a1c51..a35389c0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,7 +22,7 @@ "-test.timeout", "30m", "-test.run", - "TestRouterTestSuite/TestGetOptimalQuote_Cache_Overwrites", + "TestRouterTestSuite/TestOverwriteRoutes", "-test.v" ], }, diff --git a/app/sidecar_query_server.go b/app/sidecar_query_server.go index 472a2144..8f29792c 100644 --- a/app/sidecar_query_server.go +++ b/app/sidecar_query_server.go @@ -57,6 +57,12 @@ type sideCarQueryServer struct { logger log.Logger } +const ( + // This is a directory path where the overwrite routes are backed up in case of failure. + // On restart, the overwrite routes are restored from this directory. + overwriteRoutesPath = "overwrite_routes" +) + // GetTokensUseCase implements SideCarQueryServer. func (sqs *sideCarQueryServer) GetTokensUseCase() domain.TokensUsecase { return sqs.tokensUseCase @@ -147,7 +153,7 @@ func NewSideCarQueryServer(appCodec codec.Codec, routerConfig domain.RouterConfi // Initialize router repository, usecase and HTTP handler routerRepository := routerredisrepo.New(redisTxManager, routerConfig.RouteCacheExpirySeconds) - routerUsecase := routerUseCase.NewRouterUsecase(timeoutContext, routerRepository, poolsUseCase, routerConfig, logger, cache.New(), routesOverwrite) + routerUsecase := routerUseCase.WithOverwriteRoutesPath(routerUseCase.NewRouterUsecase(timeoutContext, routerRepository, poolsUseCase, routerConfig, logger, cache.New(), routesOverwrite), overwriteRoutesPath) routerHttpDelivery.NewRouterHandler(e, routerUsecase, logger) // Initialize system handler diff --git a/domain/mvc/router.go b/domain/mvc/router.go index 0b3dca2e..c5585de0 100644 --- a/domain/mvc/router.go +++ b/domain/mvc/router.go @@ -29,4 +29,12 @@ type RouterUsecase interface { GetCachedCandidateRoutes(ctx context.Context, tokenInDenom, tokenOutDenom string) (sqsdomain.CandidateRoutes, error) // StoreRoutes stores all router state in the files locally. Used for debugging. StoreRouterStateFiles(ctx context.Context) error + // OverwriteRoutes overwrites the routes for the given tokenIn and tokenOutDenom with the given candidateRoutes. + // Returns error if: + // - The routes are invalid + // * No pool exists + // * Denom mismatch in route + // * Denom does not exist in pool + // * Token out mismatch across routes + OverwriteRoutes(ctx context.Context, tokeinInDenom string, candidateRoutes []sqsdomain.CandidateRoute) error } diff --git a/router/delivery/http/router_handler.go b/router/delivery/http/router_handler.go index ceaf0170..85dd5dfc 100644 --- a/router/delivery/http/router_handler.go +++ b/router/delivery/http/router_handler.go @@ -2,6 +2,7 @@ package http import ( "errors" + "io" "net/http" "strconv" "strings" @@ -14,6 +15,8 @@ import ( "github.com/osmosis-labs/sqs/domain" "github.com/osmosis-labs/sqs/domain/mvc" "github.com/osmosis-labs/sqs/log" + "github.com/osmosis-labs/sqs/sqsdomain" + "github.com/osmosis-labs/sqs/sqsdomain/json" ) // ResponseError represent the response error struct @@ -46,6 +49,7 @@ func NewRouterHandler(e *echo.Echo, us mvc.RouterUsecase, logger log.Logger) { e.GET(formatRouterResource("/custom-quote"), handler.GetCustomQuote) e.GET(formatRouterResource("/taker-fee-pool/:id"), handler.GetTakerFee) e.POST(formatRouterResource("/store-state"), handler.StoreRouterStateInFiles) + e.POST(formatRouterResource("/overwrite-route"), handler.OverwriteRoute) } // GetOptimalQuote will determine the optimal quote for a given tokenIn and tokenOutDenom @@ -189,6 +193,35 @@ func (a *RouterHandler) StoreRouterStateInFiles(c echo.Context) error { return c.JSON(http.StatusOK, "Router state stored in files") } +// TODO: authentication for the endpoint and enable only in dev mode. +func (a *RouterHandler) OverwriteRoute(c echo.Context) error { + ctx := c.Request().Context() + + // Get the tokenInDenom denom string + tokenInDenom, err := getValidTokenInStr(c) + if err != nil { + return c.JSON(getStatusCode(err), ResponseError{Message: err.Error()}) + } + + // Read the request body + body, err := io.ReadAll(c.Request().Body) + if err != nil { + return c.String(http.StatusInternalServerError, "Error reading request body") + } + + // Parse the request body + var routes []sqsdomain.CandidateRoute + if err := json.Unmarshal(body, &routes); err != nil { + return c.String(http.StatusInternalServerError, "Error parsing request body") + } + + if err := a.RUsecase.OverwriteRoutes(ctx, tokenInDenom, routes); err != nil { + return c.JSON(getStatusCode(err), ResponseError{Message: err.Error()}) + } + + return c.JSON(http.StatusOK, "Router state stored in files") +} + func getStatusCode(err error) int { if err == nil { return http.StatusOK @@ -222,14 +255,24 @@ func getValidRoutingParameters(c echo.Context) (string, sdk.Coin, error) { return tokenOutStr, tokenIn, nil } -func getValidTokenInTokenOutStr(c echo.Context) (tokenOutStr, tokenInStr string, err error) { - tokenInStr = c.QueryParam("tokenIn") - tokenOutStr = c.QueryParam("tokenOutDenom") +func getValidTokenInStr(c echo.Context) (string, error) { + tokenInStr := c.QueryParam("tokenIn") if len(tokenInStr) == 0 { - return "", "", errors.New("tokenIn is required") + return "", errors.New("tokenIn is required") + } + + return tokenInStr, nil +} + +func getValidTokenInTokenOutStr(c echo.Context) (tokenOutStr, tokenInStr string, err error) { + tokenInStr, err = getValidTokenInStr(c) + if err != nil { + return "", "", err } + tokenOutStr = c.QueryParam("tokenOutDenom") + if len(tokenOutStr) == 0 { return "", "", errors.New("tokenOutDenom is required") } diff --git a/router/usecase/optimized_routes_test.go b/router/usecase/optimized_routes_test.go index dffa3a32..ab2459e7 100644 --- a/router/usecase/optimized_routes_test.go +++ b/router/usecase/optimized_routes_test.go @@ -664,7 +664,7 @@ func (s *RouterTestSuite) TestGetOptimalQuote_Mainnet() { router, tickMap, takerFeeMap := s.setupMainnetRouter(config) // Mock router use case. - routerUsecase, _ := s.setupRouterAndPoolsUsecase(router, tc.tokenInDenom, tc.tokenOutDenom, tickMap, takerFeeMap, cache.New(), cache.NewNoOpRoutesOverwrite()) + routerUsecase, _ := s.setupRouterAndPoolsUsecase(router, tickMap, takerFeeMap, cache.New(), cache.NewNoOpRoutesOverwrite()) // System under test quote, err := routerUsecase.GetOptimalQuote(context.Background(), sdk.NewCoin(tc.tokenInDenom, tc.amountIn), tc.tokenOutDenom) @@ -738,7 +738,7 @@ func (s *RouterTestSuite) TestGetCustomQuote_Mainnet_UOSMOUION() { // - converting candidate routes to routes with all the necessary data. // COTRACT: router is initialized with setupMainnetRouter(...) or setupDefaultMainnetRouter(...) func (s *RouterTestSuite) constructRoutesFromMainnetPools(router *routerusecase.Router, tokenInDenom, tokenOutDenom string, tickMap map[uint64]sqsdomain.TickModel, takerFeeMap sqsdomain.TakerFeeMap) []route.RouteImpl { - _, poolsUsecase := s.setupRouterAndPoolsUsecase(router, tokenInDenom, tokenOutDenom, tickMap, takerFeeMap, cache.New(), cache.NewNoOpRoutesOverwrite()) + _, poolsUsecase := s.setupRouterAndPoolsUsecase(router, tickMap, takerFeeMap, cache.New(), cache.NewNoOpRoutesOverwrite()) candidateRoutes, err := router.GetCandidateRoutes(tokenInDenom, tokenOutDenom) s.Require().NoError(err) @@ -751,7 +751,7 @@ func (s *RouterTestSuite) constructRoutesFromMainnetPools(router *routerusecase. // Sets up and returns usecases for router and pools by mocking the mainnet data // from json files. -func (s *RouterTestSuite) setupRouterAndPoolsUsecase(router *routerusecase.Router, tokenInDenom, tokenOutDenom string, tickMap map[uint64]sqsdomain.TickModel, takerFeeMap sqsdomain.TakerFeeMap, rankedRoutesCache *cache.Cache, routesOverwrite *cache.RoutesOverwrite) (mvc.RouterUsecase, mvc.PoolsUsecase) { +func (s *RouterTestSuite) setupRouterAndPoolsUsecase(router *routerusecase.Router, tickMap map[uint64]sqsdomain.TickModel, takerFeeMap sqsdomain.TakerFeeMap, rankedRoutesCache *cache.Cache, routesOverwrite *cache.RoutesOverwrite) (mvc.RouterUsecase, mvc.PoolsUsecase) { // Setup router repository mock routerRepositoryMock := sqsdomainmocks.RedisRouterRepositoryMock{} routerusecase.WithRouterRepository(router, &routerRepositoryMock) diff --git a/router/usecase/router_usecase.go b/router/usecase/router_usecase.go index cabd0679..a2fc2314 100644 --- a/router/usecase/router_usecase.go +++ b/router/usecase/router_usecase.go @@ -2,8 +2,10 @@ package usecase import ( "context" + "encoding/json" "errors" "fmt" + "net/url" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,6 +13,7 @@ import ( "go.uber.org/zap" "github.com/osmosis-labs/osmosis/osmomath" + "github.com/osmosis-labs/osmosis/osmoutils" poolmanagertypes "github.com/osmosis-labs/osmosis/v21/x/poolmanager/types" "github.com/osmosis-labs/sqs/domain" "github.com/osmosis-labs/sqs/domain/cache" @@ -20,6 +23,7 @@ import ( "github.com/osmosis-labs/sqs/router/usecase/routertesting/parsing" "github.com/osmosis-labs/sqs/sqsdomain" routerredisrepo "github.com/osmosis-labs/sqs/sqsdomain/repository/redis/router" + "github.com/osmosis-labs/sqs/sqsutil" ) var _ mvc.RouterUsecase = &routerUseCaseImpl{} @@ -34,6 +38,11 @@ type routerUseCaseImpl struct { routesOverwrite *cache.RoutesOverwrite rankedRouteCache *cache.Cache + + // This is a path where the overwrite routes are stored as backup in case of failure. + // On restart, the routes are loaded from this path. + // It is defined on the use case for testability (s.t. we can set a temp path in tests) + overwriteRoutesPath string } const ( @@ -77,6 +86,12 @@ func NewRouterUsecase(timeout time.Duration, routerRepository routerredisrepo.Ro } } +// WithOverwriteRoutesPath sets the overwrite routes path on the router use case. +func WithOverwriteRoutesPath(routerUsecase mvc.RouterUsecase, overwriteRoutesPath string) mvc.RouterUsecase { + routerUsecase.(*routerUseCaseImpl).overwriteRoutesPath = overwriteRoutesPath + return routerUsecase +} + // GetOptimalQuote returns the optimal quote by estimating the optimal route(s) through pools // on the osmosis network. // Uses caching strategies for optimal performance. @@ -573,6 +588,78 @@ func (r *routerUseCaseImpl) StoreRouterStateFiles(ctx context.Context) error { return nil } +// OverwriteRoutes implements mvc.RouterUsecase. +func (r *routerUseCaseImpl) OverwriteRoutes(ctx context.Context, tokeinInDenom string, routes []sqsdomain.CandidateRoute) error { + if len(routes) == 0 { + return errors.New("routes cannot be empty") + } + + // Find the unique pool IDs + uniquePoolIDs := make(map[uint64]struct{}) + + var ( + // The token out denom that we expect to be the same for all routes + // We initialize it to token out denom of the first route and then validate + // that it equals for all other routes. + expectedTokenOutDenom string + // The token out denom of the previous pool + // For the first pool in route, assumed to be tokenInDenom + previousPoolsTokenOutDenom = tokeinInDenom + ) + for i, route := range routes { + for _, pool := range route.Pools { + // Validate that token in is present in the first pool + poolData, err := r.poolsUsecase.GetPool(ctx, pool.ID) + if err != nil { + return err + } + + poolDenoms := poolData.GetPoolDenoms() + if !osmoutils.Contains(poolDenoms, previousPoolsTokenOutDenom) { + return fmt.Errorf("token in denom %s not found in pool %d of route with index %d", tokeinInDenom, pool.ID, i) + } + + // Persist unique pool ID + uniquePoolIDs[pool.ID] = struct{}{} + + previousPoolsTokenOutDenom = pool.TokenOutDenom + } + + // Make sure that the token out denom of the previous route is the same as for current route + // That is, all routes have the same token out denom + if i != 0 { + if expectedTokenOutDenom != previousPoolsTokenOutDenom { + return fmt.Errorf("token out denom %s does not match expected token out denom %s for route with index %d", previousPoolsTokenOutDenom, expectedTokenOutDenom, i) + } + } + expectedTokenOutDenom = previousPoolsTokenOutDenom + } + + // Create the overwrite data structure that we save in cache + candidateRoutes := sqsdomain.CandidateRoutes{ + Routes: routes, + UniquePoolIDs: uniquePoolIDs, + } + + // Note that we only persist overwrite in one direction (tokenInDenom -> tokenOutDenom) + // For other directions, we must resubmit the request with denoms inversed. + overwriteKey := formatRouteCacheKey(tokeinInDenom, expectedTokenOutDenom) + r.routesOverwrite.Set(overwriteKey, candidateRoutes) + + // Also save this thing to a file for crash recovery + bz, err := json.Marshal(candidateRoutes) + if err != nil { + return err + } + + err = sqsutil.WriteBytes(r.overwriteRoutesPath, url.PathEscape(overwriteKey), bz) + if err != nil { + return err + } + + return nil +} + // formatRouteCacheKey formats the given token in and token out denoms to a string. func formatRouteCacheKey(tokenInDenom string, tokenOutDenom string) string { return fmt.Sprintf("%s/%s", tokenInDenom, tokenOutDenom) diff --git a/router/usecase/router_usecase_test.go b/router/usecase/router_usecase_test.go index 8008ed69..6b5015e3 100644 --- a/router/usecase/router_usecase_test.go +++ b/router/usecase/router_usecase_test.go @@ -2,6 +2,7 @@ package usecase_test import ( "context" + "os" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -19,6 +20,58 @@ import ( "github.com/osmosis-labs/osmosis/v21/x/gamm/pool-models/balancer" ) +const ( + // See description of: + // - TestGetOptimalQuote_Cache_Overwrites + // - TestOverwriteRoutes + // for details. + poolIDOneBalancer = uint64(1) + poolID1135Concentrated = uint64(1135) + poolID1265Concentrated = uint64(1265) +) + +var ( + // For the purposes of testing cache, we focus on a small amount of token in (1_000_000 uosmo), expecting pool 1265 to be returned. + // Search for tests that reference this value and read test description for details. + defaultAmountInCache = osmomath.NewInt(1_000_000) + + // See description of: + // - TestGetOptimalQuote_Cache_Overwrites + // - TestOverwriteRoutes + // for details. + poolIDOneRoute = sqsdomain.CandidateRoutes{ + Routes: []sqsdomain.CandidateRoute{ + { + Pools: []sqsdomain.CandidatePool{ + { + ID: poolIDOneBalancer, + TokenOutDenom: ATOM, + }, + }, + }, + }, + UniquePoolIDs: map[uint64]struct{}{ + poolIDOneBalancer: {}, + }, + } + + poolID1135Route = sqsdomain.CandidateRoutes{ + Routes: []sqsdomain.CandidateRoute{ + { + Pools: []sqsdomain.CandidatePool{ + { + ID: poolID1135Concentrated, + TokenOutDenom: ATOM, + }, + }, + }, + }, + UniquePoolIDs: map[uint64]struct{}{ + poolID1135Concentrated: {}, + }, + } +) + // Tests the call to handleRoutes by mocking the router repository and pools use case // with relevant data. func (s *RouterTestSuite) TestHandleRoutes() { @@ -441,16 +494,6 @@ func (s *RouterTestSuite) TestGetOptimalQuote_Cache_Overwrites() { const ( defaultTokenInDenom = UOSMO defaultTokenOutDenom = ATOM - - // See test description above for details about - // the pools. - poolIDOneBalancer = uint64(1) - poolID1135Concentrated = uint64(1135) - poolID1265Concentrated = uint64(1265) - ) - - var ( - defaultAmountIn = osmomath.NewInt(1_000_000) ) tests := map[string]struct { @@ -465,32 +508,18 @@ func (s *RouterTestSuite) TestGetOptimalQuote_Cache_Overwrites() { expectedRoutePoolID uint64 }{ "cache is not set, computes routes": { - amountIn: defaultAmountIn, + amountIn: defaultAmountInCache, // For the default amount in, we expect pool 1265 to be returned. // See test description above for details. expectedRoutePoolID: poolID1265Concentrated, }, "cache is set to balancer - overwrites computed": { - amountIn: defaultAmountIn, + amountIn: defaultAmountInCache, - preCachedRoutes: sqsdomain.CandidateRoutes{ - Routes: []sqsdomain.CandidateRoute{ - { - Pools: []sqsdomain.CandidatePool{ - { - ID: poolIDOneBalancer, - TokenOutDenom: ATOM, - }, - }, - }, - }, - UniquePoolIDs: map[uint64]struct{}{ - poolIDOneBalancer: {}, - }, - }, + preCachedRoutes: poolIDOneRoute, - cacheOrderOfMagnitudeTokenIn: osmomath.OrderOfMagnitude(defaultAmountIn.ToLegacyDec()), + cacheOrderOfMagnitudeTokenIn: osmomath.OrderOfMagnitude(defaultAmountInCache.ToLegacyDec()), cacheExpiryDuration: time.Hour, @@ -498,26 +527,12 @@ func (s *RouterTestSuite) TestGetOptimalQuote_Cache_Overwrites() { expectedRoutePoolID: poolIDOneBalancer, }, "cache is set to balancer but for a different order of magnitude - computes new routes": { - amountIn: defaultAmountIn, + amountIn: defaultAmountInCache, - preCachedRoutes: sqsdomain.CandidateRoutes{ - Routes: []sqsdomain.CandidateRoute{ - { - Pools: []sqsdomain.CandidatePool{ - { - ID: poolIDOneBalancer, - TokenOutDenom: ATOM, - }, - }, - }, - }, - UniquePoolIDs: map[uint64]struct{}{ - poolIDOneBalancer: {}, - }, - }, + preCachedRoutes: poolIDOneRoute, // Note that we multiply the order of magnitude by 10 so cache is not applied for this amount in. - cacheOrderOfMagnitudeTokenIn: osmomath.OrderOfMagnitude(defaultAmountIn.ToLegacyDec().MulInt64(10)), + cacheOrderOfMagnitudeTokenIn: osmomath.OrderOfMagnitude(defaultAmountInCache.ToLegacyDec().MulInt64(10)), cacheExpiryDuration: time.Hour, @@ -525,25 +540,11 @@ func (s *RouterTestSuite) TestGetOptimalQuote_Cache_Overwrites() { expectedRoutePoolID: poolID1265Concentrated, }, "cache is expired - overwrites computed": { - amountIn: defaultAmountIn, + amountIn: defaultAmountInCache, - preCachedRoutes: sqsdomain.CandidateRoutes{ - Routes: []sqsdomain.CandidateRoute{ - { - Pools: []sqsdomain.CandidatePool{ - { - ID: poolIDOneBalancer, - TokenOutDenom: ATOM, - }, - }, - }, - }, - UniquePoolIDs: map[uint64]struct{}{ - poolIDOneBalancer: {}, - }, - }, + preCachedRoutes: poolIDOneRoute, - cacheOrderOfMagnitudeTokenIn: osmomath.OrderOfMagnitude(defaultAmountIn.ToLegacyDec()), + cacheOrderOfMagnitudeTokenIn: osmomath.OrderOfMagnitude(defaultAmountInCache.ToLegacyDec()), // Note: we rely on the fact that the it takes more than 1 nanosecond from the test set up to // test execution. @@ -553,62 +554,20 @@ func (s *RouterTestSuite) TestGetOptimalQuote_Cache_Overwrites() { expectedRoutePoolID: poolID1265Concentrated, }, "cache is not set, overwrites set, routes taken from overwrites (not computed)": { - amountIn: defaultAmountIn, + amountIn: defaultAmountInCache, - overwriteRoutes: sqsdomain.CandidateRoutes{ - Routes: []sqsdomain.CandidateRoute{ - { - Pools: []sqsdomain.CandidatePool{ - { - ID: poolIDOneBalancer, - TokenOutDenom: ATOM, - }, - }, - }, - }, - UniquePoolIDs: map[uint64]struct{}{ - poolIDOneBalancer: {}, - }, - }, + overwriteRoutes: poolIDOneRoute, // For the default amount in, we expect pool 1265 to be returned. // However, we overwrite the routes with pool of ID 1. expectedRoutePoolID: poolIDOneBalancer, }, "cache is set, overwrites set, routes taken from overwrites (not computed and not cache)": { - amountIn: defaultAmountIn, + amountIn: defaultAmountInCache, - overwriteRoutes: sqsdomain.CandidateRoutes{ - Routes: []sqsdomain.CandidateRoute{ - { - Pools: []sqsdomain.CandidatePool{ - { - ID: poolIDOneBalancer, - TokenOutDenom: ATOM, - }, - }, - }, - }, - UniquePoolIDs: map[uint64]struct{}{ - poolIDOneBalancer: {}, - }, - }, + overwriteRoutes: poolIDOneRoute, - preCachedRoutes: sqsdomain.CandidateRoutes{ - Routes: []sqsdomain.CandidateRoute{ - { - Pools: []sqsdomain.CandidatePool{ - { - ID: poolID1135Concentrated, - TokenOutDenom: ATOM, - }, - }, - }, - }, - UniquePoolIDs: map[uint64]struct{}{ - poolID1135Concentrated: {}, - }, - }, + preCachedRoutes: poolID1135Route, // For the default amount in, we expect pool 1265 to be returned. // However, we overwrite the routes (or cache) with pool of ID 1. @@ -639,7 +598,7 @@ func (s *RouterTestSuite) TestGetOptimalQuote_Cache_Overwrites() { } // Mock router use case. - routerUsecase, _ := s.setupRouterAndPoolsUsecase(router, defaultTokenInDenom, defaultTokenOutDenom, tickMap, takerFeeMap, rankedRouteCache, routesOverwrite) + routerUsecase, _ := s.setupRouterAndPoolsUsecase(router, tickMap, takerFeeMap, rankedRouteCache, routesOverwrite) // System under test quote, err := routerUsecase.GetOptimalQuote(context.Background(), sdk.NewCoin(defaultTokenInDenom, tc.amountIn), defaultTokenOutDenom) @@ -663,3 +622,65 @@ func (s *RouterTestSuite) TestGetOptimalQuote_Cache_Overwrites() { }) } } + +// Basic happy path test for OverwriteRoutes. +// +// Similar to TestGetOptimalQuote_Cache_Overwrites, this test is set up by focusing on ATOM / OSMO mainnet state pool. +// We restrict the number of routes via config. +// +// As of today there are 3 major ATOM / OSMO pools: +// Pool ID 1: https://app.osmosis.zone/pool/1 (balancer) 0.2% spread factor and 20M of liquidity to date +// Pool ID 1135: https://app.osmosis.zone/pool/1135 (concentrated) 0.2% spread factor and 14M of liquidity to date +// Pool ID 1265: https://app.osmosis.zone/pool/1265 (concentrated) 0.05% spread factor and 224K of liquidity to date +func (s *RouterTestSuite) TestOverwriteRoutes() { + const tempPath = "temp" + + s.Setup() + + // Setup router config + config := defaultRouterConfig + // Note that we set one max route for ease of testing caching specifically. + config.MaxRoutes = 1 + + // Setup mainnet router + router, tickMap, takerFeeMap := s.setupMainnetRouter(config) + + // Mock router use case. + routerUsecase, _ := s.setupRouterAndPoolsUsecase(router, tickMap, takerFeeMap, cache.New(), cache.NewRoutesOverwrite()) + + routerUsecase = usecase.WithOverwriteRoutesPath(routerUsecase, tempPath) + + // Get quote without overwrite + quote, err := routerUsecase.GetOptimalQuote(context.Background(), sdk.NewCoin(UOSMO, defaultAmountInCache), ATOM) + s.Require().NoError(err) + + // Without overwrite this is the pool ID we expect given the amount in. + s.Require().Equal(poolID1265Concentrated, quote.GetRoute()[0].GetPools()[0].GetId()) + + defer func() { + // Clean up + os.RemoveAll(tempPath) + }() + + // System under test #1 + err = routerUsecase.OverwriteRoutes(context.Background(), UOSMO, poolIDOneRoute.Routes) + s.Require().NoError(err) + + // Get quote with overwrite + quote, err = routerUsecase.GetOptimalQuote(context.Background(), sdk.NewCoin(UOSMO, defaultAmountInCache), ATOM) + s.Require().NoError(err) + + // With overwrite this is the pool ID we expect given the amount in. + s.Require().Equal(poolIDOneBalancer, quote.GetRoute()[0].GetPools()[0].GetId()) + + // Validate that the overwrite can be modified + // System under test #2 + err = routerUsecase.OverwriteRoutes(context.Background(), UOSMO, poolID1135Route.Routes) + s.Require().NoError(err) + + quote, err = routerUsecase.GetOptimalQuote(context.Background(), sdk.NewCoin(UOSMO, defaultAmountInCache), ATOM) + s.Require().NoError(err) + + // With overwrite this is the pool ID we expect given the amount in. + s.Require().Equal(poolID1135Concentrated, quote.GetRoute()[0].GetPools()[0].GetId()) +} diff --git a/sqs.log b/sqs.log deleted file mode 100644 index 8ac08ff0..00000000 --- a/sqs.log +++ /dev/null @@ -1,252 +0,0 @@ -{"level":"info","ts":1704682211.2188835,"msg":"log level","is_debug":false,"log_level":"info"} -{"level":"info","ts":1704682211.2189429,"msg":"Starting sidecar query server"} -{"level":"info","ts":1704682211.2189825,"msg":"Pinging redis","redis_address":"localhost:6379"} -{"level":"info","ts":1704682211.2302728,"msg":"Starting sidecar query server","address":":9092"} -{"level":"info","ts":1704682211.231136,"msg":"Starting profiling server"} -{"level":"info","ts":1704682243.7789152,"msg":"pool count in router ","pool_count":245} -{"level":"info","ts":1704682243.779023,"msg":"pool","index":0,"pool":1212,"rate":"181020166867126","tvl":"373154929597","tvl_error":""} -{"level":"info","ts":1704682243.7790427,"msg":"pool","index":1,"pool":1135,"rate":"68281019641450","tvl":"7267790444007","tvl_error":""} -{"level":"info","ts":1704682243.7790573,"msg":"pool","index":2,"pool":1134,"rate":"64753540036886","tvl":"3740310839443","tvl_error":""} -{"level":"info","ts":1704682243.7790713,"msg":"pool","index":3,"pool":1093,"rate":"63584195336438","tvl":"2570966138995","tvl_error":""} -{"level":"info","ts":1704682243.7790847,"msg":"pool","index":4,"pool":1319,"rate":"63224053970299","tvl":"2210824772856","tvl_error":""} -{"level":"info","ts":1704682243.7790978,"msg":"pool","index":5,"pool":1220,"rate":"62990776895081","tvl":"1977547697638","tvl_error":""} -{"level":"info","ts":1704682243.7791114,"msg":"pool","index":6,"pool":1133,"rate":"62713896527554","tvl":"1700667330111","tvl_error":""} -{"level":"info","ts":1704682243.7791247,"msg":"pool","index":7,"pool":1090,"rate":"62680139113530","tvl":"1666909916087","tvl_error":""} -{"level":"info","ts":1704682243.779138,"msg":"pool","index":8,"pool":1314,"rate":"62295567434434","tvl":"1282338236991","tvl_error":""} -{"level":"info","ts":1704682243.7791529,"msg":"pool","index":9,"pool":1221,"rate":"62141580038227","tvl":"1128350840784","tvl_error":""} -{"level":"info","ts":1704682243.7791662,"msg":"pool","index":10,"pool":1248,"rate":"62132907014952","tvl":"1119677817509","tvl_error":""} -{"level":"info","ts":1704682243.7791798,"msg":"pool","index":11,"pool":1251,"rate":"61901210039845","tvl":"887980842402","tvl_error":""} -{"level":"info","ts":1704682243.7791932,"msg":"pool","index":12,"pool":1096,"rate":"61753632478359","tvl":"740403280916","tvl_error":""} -{"level":"info","ts":1704682243.7792068,"msg":"pool","index":13,"pool":1265,"rate":"61721396312443","tvl":"708167115000","tvl_error":""} -{"level":"info","ts":1704682243.7792199,"msg":"pool","index":14,"pool":1097,"rate":"61559096440036","tvl":"545867242593","tvl_error":""} -{"level":"info","ts":1704682243.7792335,"msg":"pool","index":15,"pool":1150,"rate":"61533453422659","tvl":"520224225216","tvl_error":""} -{"level":"info","ts":1704682243.779247,"msg":"pool","index":16,"pool":1094,"rate":"61532766634710","tvl":"519537437267","tvl_error":""} -{"level":"info","ts":1704682243.7792604,"msg":"pool","index":17,"pool":1223,"rate":"61527928499403","tvl":"514699301960","tvl_error":""} -{"level":"info","ts":1704682243.7792735,"msg":"pool","index":18,"pool":1281,"rate":"61443551629442","tvl":"430322431999","tvl_error":""} -{"level":"info","ts":1704682243.779287,"msg":"pool","index":19,"pool":1263,"rate":"61411615059303","tvl":"398385861860","tvl_error":""} -{"level":"info","ts":1704682243.7793005,"msg":"pool","index":20,"pool":1264,"rate":"61395931670923","tvl":"382702473480","tvl_error":""} -{"level":"info","ts":1704682243.7793136,"msg":"pool","index":21,"pool":1325,"rate":"61390506790334","tvl":"377277592891","tvl_error":""} -{"level":"info","ts":1704682243.779327,"msg":"pool","index":22,"pool":1092,"rate":"61378935125551","tvl":"365705928108","tvl_error":""} -{"level":"info","ts":1704682243.7793403,"msg":"pool","index":23,"pool":1098,"rate":"61370309048321","tvl":"357079850878","tvl_error":""} -{"level":"info","ts":1704682243.7793539,"msg":"pool","index":24,"pool":1110,"rate":"61364148466864","tvl":"350919269421","tvl_error":""} -{"level":"info","ts":1704682243.779367,"msg":"pool","index":25,"pool":1066,"rate":"61359783896508","tvl":"346554699065","tvl_error":""} -{"level":"info","ts":1704682243.77938,"msg":"pool","index":26,"pool":1247,"rate":"61307871156884","tvl":"294641959441","tvl_error":""} -{"level":"info","ts":1704682243.7794018,"msg":"pool","index":27,"pool":1103,"rate":"61298166953296","tvl":"284937755853","tvl_error":""} -{"level":"info","ts":1704682243.7794154,"msg":"pool","index":28,"pool":1099,"rate":"61290645066623","tvl":"277415869180","tvl_error":""} -{"level":"info","ts":1704682243.7794282,"msg":"pool","index":29,"pool":1104,"rate":"61259957516230","tvl":"246728318787","tvl_error":""} -{"level":"info","ts":1704682243.7794416,"msg":"pool","index":30,"pool":1246,"rate":"61250967293158","tvl":"237738095715","tvl_error":""} -{"level":"info","ts":1704682243.7794547,"msg":"pool","index":31,"pool":1095,"rate":"61220613756591","tvl":"207384559148","tvl_error":""} -{"level":"info","ts":1704682243.779466,"msg":"pool","index":32,"pool":1170,"rate":"61196524711519","tvl":"183295514076","tvl_error":""} -{"level":"info","ts":1704682243.77948,"msg":"pool","index":33,"pool":1215,"rate":"61194294321952","tvl":"181065124509","tvl_error":""} -{"level":"info","ts":1704682243.779495,"msg":"pool","index":34,"pool":1301,"rate":"61187661103959","tvl":"174431906516","tvl_error":""} -{"level":"info","ts":1704682243.7795086,"msg":"pool","index":35,"pool":1205,"rate":"61175991403385","tvl":"162762205942","tvl_error":""} -{"level":"info","ts":1704682243.779522,"msg":"pool","index":36,"pool":1077,"rate":"61157183401770","tvl":"143954204327","tvl_error":""} -{"level":"info","ts":1704682243.7795358,"msg":"pool","index":37,"pool":1324,"rate":"61151682222658","tvl":"138453025215","tvl_error":""} -{"level":"info","ts":1704682243.7795491,"msg":"pool","index":38,"pool":1114,"rate":"61148344035004","tvl":"135114837561","tvl_error":""} -{"level":"info","ts":1704682243.7795627,"msg":"pool","index":39,"pool":1297,"rate":"61144223536791","tvl":"130994339348","tvl_error":""} -{"level":"info","ts":1704682243.779576,"msg":"pool","index":40,"pool":1111,"rate":"61139476772442","tvl":"126247574999","tvl_error":""} -{"level":"info","ts":1704682243.7795892,"msg":"pool","index":41,"pool":1252,"rate":"61136405590239","tvl":"123176392796","tvl_error":""} -{"level":"info","ts":1704682243.7796025,"msg":"pool","index":42,"pool":1106,"rate":"61120528261882","tvl":"107299064439","tvl_error":""} -{"level":"info","ts":1704682243.7796237,"msg":"pool","index":43,"pool":1277,"rate":"61118575324616","tvl":"105346127173","tvl_error":""} -{"level":"info","ts":1704682243.7796376,"msg":"pool","index":44,"pool":1108,"rate":"61113154372370","tvl":"99925174927","tvl_error":""} -{"level":"info","ts":1704682243.7796512,"msg":"pool","index":45,"pool":1101,"rate":"61112099367159","tvl":"98870169716","tvl_error":""} -{"level":"info","ts":1704682243.779664,"msg":"pool","index":46,"pool":1224,"rate":"61108808520887","tvl":"95579323444","tvl_error":""} -{"level":"info","ts":1704682243.7796774,"msg":"pool","index":47,"pool":1091,"rate":"61106970707317","tvl":"93741509874","tvl_error":""} -{"level":"info","ts":1704682243.779691,"msg":"pool","index":48,"pool":1100,"rate":"61102709256495","tvl":"89480059052","tvl_error":""} -{"level":"info","ts":1704682243.7797043,"msg":"pool","index":49,"pool":1318,"rate":"61093854235426","tvl":"80625037983","tvl_error":""} -{"level":"info","ts":1704682243.7797256,"msg":"pool","index":50,"pool":1321,"rate":"61090013283026","tvl":"76784085583","tvl_error":""} -{"level":"info","ts":1704682243.779739,"msg":"pool","index":51,"pool":1273,"rate":"61088204051986","tvl":"74974854543","tvl_error":""} -{"level":"info","ts":1704682243.779753,"msg":"pool","index":52,"pool":1260,"rate":"61079735166101","tvl":"66505968658","tvl_error":""} -{"level":"info","ts":1704682243.7797663,"msg":"pool","index":53,"pool":1161,"rate":"61071162280937","tvl":"57933083494","tvl_error":""} -{"level":"info","ts":1704682243.7797797,"msg":"pool","index":54,"pool":1337,"rate":"61071013352796","tvl":"57784155353","tvl_error":""} -{"level":"info","ts":1704682243.7797928,"msg":"pool","index":55,"pool":1081,"rate":"61068579908349","tvl":"55350710906","tvl_error":""} -{"level":"info","ts":1704682243.7798064,"msg":"pool","index":56,"pool":1282,"rate":"61067210781694","tvl":"53981584251","tvl_error":""} -{"level":"info","ts":1704682243.7798233,"msg":"pool","index":57,"pool":1109,"rate":"61063837208226","tvl":"50608010783","tvl_error":""} -{"level":"info","ts":1704682243.779837,"msg":"pool","index":58,"pool":1088,"rate":"61062680413985","tvl":"49451216542","tvl_error":""} -{"level":"info","ts":1704682243.7798512,"msg":"pool","index":59,"pool":1261,"rate":"61060867234785","tvl":"47638037342","tvl_error":""} -{"level":"info","ts":1704682243.7798645,"msg":"pool","index":60,"pool":1334,"rate":"61060668608876","tvl":"47439411433","tvl_error":""} -{"level":"info","ts":1704682243.779878,"msg":"pool","index":61,"pool":1323,"rate":"61060545897587","tvl":"47316700144","tvl_error":""} -{"level":"info","ts":1704682243.7798913,"msg":"pool","index":62,"pool":1105,"rate":"61059601570554","tvl":"46372373111","tvl_error":""} -{"level":"info","ts":1704682243.7799046,"msg":"pool","index":63,"pool":1158,"rate":"61053905977119","tvl":"40676779676","tvl_error":""} -{"level":"info","ts":1704682243.7799227,"msg":"pool","index":64,"pool":1078,"rate":"61047643107811","tvl":"34413910368","tvl_error":""} -{"level":"info","ts":1704682243.779936,"msg":"pool","index":65,"pool":1268,"rate":"61040253198618","tvl":"27024001175","tvl_error":""} -{"level":"info","ts":1704682243.7799497,"msg":"pool","index":66,"pool":1361,"rate":"61032073859501","tvl":"18844662058","tvl_error":""} -{"level":"info","ts":1704682243.7799628,"msg":"pool","index":67,"pool":1243,"rate":"61030536831541","tvl":"17307634098","tvl_error":""} -{"level":"info","ts":1704682243.7799761,"msg":"pool","index":68,"pool":1267,"rate":"61029896154543","tvl":"16666957100","tvl_error":""} -{"level":"info","ts":1704682243.7799895,"msg":"pool","index":69,"pool":1113,"rate":"61029240573532","tvl":"16011376089","tvl_error":""} -{"level":"info","ts":1704682243.780003,"msg":"pool","index":70,"pool":1107,"rate":"61024449738234","tvl":"11220540791","tvl_error":""} -{"level":"info","ts":1704682243.7800164,"msg":"pool","index":71,"pool":1274,"rate":"61024026111273","tvl":"10796913830","tvl_error":""} -{"level":"info","ts":1704682243.78003,"msg":"pool","index":72,"pool":1136,"rate":"60669581548630","tvl":"852690178587","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/C140AFD542AE77BD7DCC83F13FDD8C5E5BB8C4929785E6EC2F4C636F98F17901 not found"} -{"level":"info","ts":1704682243.7800484,"msg":"pool","index":73,"pool":1283,"rate":"60606898927580","tvl":"790007557537","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/C140AFD542AE77BD7DCC83F13FDD8C5E5BB8C4929785E6EC2F4C636F98F17901 not found"} -{"level":"info","ts":1704682243.7800665,"msg":"pool","index":74,"pool":1335,"rate":"60578374179510","tvl":"761482809467","tvl_error":"highest liquidity pool between base uosmo and match denom factory/osmo1f5vfcph2dvfeqcqkhetwv75fda69z7e5c2dldm3kvgj23crkv6wqcn47a0/umilkTIA not found"} -{"level":"info","ts":1704682243.7800817,"msg":"pool","index":75,"pool":1213,"rate":"60102778536377","tvl":"285887166334","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/FBB3FEF80ED2344D821D4F95C31DBFD33E4E31D5324CAD94EF756E67B749F668 not found"} -{"level":"info","ts":1704682243.7800968,"msg":"pool","index":76,"pool":1227,"rate":"60026052036163","tvl":"209160666120","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/B66CE615C600ED0A8B5AF425ECFE0D57BE2377587F66C45934A76886F34DC9B7 not found"} -{"level":"info","ts":1704682243.7801287,"msg":"pool","index":77,"pool":1230,"rate":"59854711301260","tvl":"37819931217","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/01D2F0C4739C871BFBEE7E786709E6904A55559DC1483DD92ED392EF12247862 not found"} -{"level":"info","ts":1704682243.7801466,"msg":"pool","index":78,"pool":1294,"rate":"59836474720778","tvl":"19583350735","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/1E43D59E565D41FB4E54CA639B838FFD5BCFC20003D330A56CB1396231AA1CBA not found"} -{"level":"info","ts":1704682243.780165,"msg":"pool","index":79,"pool":1305,"rate":"59830759312710","tvl":"13867942667","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/6928AFA9EA721938FED13B051F9DBF1272B16393D20C49EA5E4901BB76D94A90 not found"} -{"level":"info","ts":1704682243.7801864,"msg":"pool","index":80,"pool":833,"rate":"26153897736556","tvl":"24957559909156","tvl_error":""} -{"level":"info","ts":1704682243.7802,"msg":"pool","index":81,"pool":1,"rate":"14034098697334","tvl":"12837760869934","tvl_error":""} -{"level":"info","ts":1704682243.780214,"msg":"pool","index":82,"pool":704,"rate":"4978560583948","tvl":"3782222756548","tvl_error":""} -{"level":"info","ts":1704682243.7802277,"msg":"pool","index":83,"pool":803,"rate":"3639459710798","tvl":"3639459710798","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/C140AFD542AE77BD7DCC83F13FDD8C5E5BB8C4929785E6EC2F4C636F98F17901 not found"} -{"level":"info","ts":1704682243.7802498,"msg":"pool","index":84,"pool":1057,"rate":"3550068491921","tvl":"2353730664521","tvl_error":""} -{"level":"info","ts":1704682243.7802644,"msg":"pool","index":85,"pool":712,"rate":"3526391319196","tvl":"2330053491796","tvl_error":""} -{"level":"info","ts":1704682243.780281,"msg":"pool","index":86,"pool":678,"rate":"3122139718014","tvl":"1925801890614","tvl_error":""} -{"level":"info","ts":1704682243.7802942,"msg":"pool","index":87,"pool":812,"rate":"3053976495397","tvl":"1857638667997","tvl_error":""} -{"level":"info","ts":1704682243.7803073,"msg":"pool","index":88,"pool":725,"rate":"2813717741515","tvl":"1617379914115","tvl_error":""} -{"level":"info","ts":1704682243.7803202,"msg":"pool","index":89,"pool":796,"rate":"2618382524951","tvl":"1422044697551","tvl_error":""} -{"level":"info","ts":1704682243.7803335,"msg":"pool","index":90,"pool":722,"rate":"2560113259175","tvl":"1363775431775","tvl_error":""} -{"level":"info","ts":1704682243.7803473,"msg":"pool","index":91,"pool":604,"rate":"2164979243157","tvl":"968641415757","tvl_error":""} -{"level":"info","ts":1704682243.7803612,"msg":"pool","index":92,"pool":3,"rate":"2111638079710","tvl":"915300252310","tvl_error":""} -{"level":"info","ts":1704682243.7803743,"msg":"pool","index":93,"pool":681,"rate":"1936841162196","tvl":"740503334796","tvl_error":""} -{"level":"info","ts":1704682243.7803879,"msg":"pool","index":94,"pool":1241,"rate":"1931644782499","tvl":"735306955099","tvl_error":""} -{"level":"info","ts":1704682243.7804015,"msg":"pool","index":95,"pool":9,"rate":"1854241580702","tvl":"657903753302","tvl_error":""} -{"level":"info","ts":1704682243.7804146,"msg":"pool","index":96,"pool":832,"rate":"1841208458657","tvl":"644870631257","tvl_error":""} -{"level":"info","ts":1704682243.7804277,"msg":"pool","index":97,"pool":4,"rate":"1771465141192","tvl":"575127313792","tvl_error":""} -{"level":"info","ts":1704682243.7804415,"msg":"pool","index":98,"pool":806,"rate":"1752960798363","tvl":"556622970963","tvl_error":""} -{"level":"info","ts":1704682243.7804546,"msg":"pool","index":99,"pool":840,"rate":"1750322957744","tvl":"553985130344","tvl_error":""} -{"level":"info","ts":1704682243.7804725,"msg":"pool","index":100,"pool":1244,"rate":"1746437305486","tvl":"550099478086","tvl_error":""} -{"level":"info","ts":1704682243.7804859,"msg":"pool","index":101,"pool":1233,"rate":"1687579686102","tvl":"491241858702","tvl_error":""} -{"level":"info","ts":1704682243.7804992,"msg":"pool","index":102,"pool":1173,"rate":"1627326439283","tvl":"430988611883","tvl_error":""} -{"level":"info","ts":1704682243.7805128,"msg":"pool","index":103,"pool":497,"rate":"1621295894377","tvl":"424958066977","tvl_error":""} -{"level":"info","ts":1704682243.780526,"msg":"pool","index":104,"pool":1225,"rate":"1592670096375","tvl":"396332268975","tvl_error":""} -{"level":"info","ts":1704682243.7805393,"msg":"pool","index":105,"pool":584,"rate":"1587887209998","tvl":"391549382598","tvl_error":""} -{"level":"info","ts":1704682243.7805529,"msg":"pool","index":106,"pool":1041,"rate":"1568093952885","tvl":"371756125485","tvl_error":""} -{"level":"info","ts":1704682243.7805665,"msg":"pool","index":107,"pool":674,"rate":"1560386481172","tvl":"364048653772","tvl_error":""} -{"level":"info","ts":1704682243.7805831,"msg":"pool","index":108,"pool":611,"rate":"1509833919194","tvl":"313496091794","tvl_error":""} -{"level":"info","ts":1704682243.7805977,"msg":"pool","index":109,"pool":799,"rate":"1503130335920","tvl":"306792508520","tvl_error":""} -{"level":"info","ts":1704682243.7806113,"msg":"pool","index":110,"pool":1226,"rate":"1485516879856","tvl":"289179052456","tvl_error":""} -{"level":"info","ts":1704682243.7806246,"msg":"pool","index":111,"pool":560,"rate":"1484047175445","tvl":"287709348045","tvl_error":""} -{"level":"info","ts":1704682243.7806377,"msg":"pool","index":112,"pool":789,"rate":"1453964734196","tvl":"257626906796","tvl_error":""} -{"level":"info","ts":1704682243.780651,"msg":"pool","index":113,"pool":608,"rate":"1452466532610","tvl":"256128705210","tvl_error":""} -{"level":"info","ts":1704682243.7806642,"msg":"pool","index":114,"pool":571,"rate":"1449051373525","tvl":"252713546125","tvl_error":""} -{"level":"info","ts":1704682243.7806785,"msg":"pool","index":115,"pool":498,"rate":"1443316554242","tvl":"246978726842","tvl_error":""} -{"level":"info","ts":1704682243.7806916,"msg":"pool","index":116,"pool":2,"rate":"1435481645357","tvl":"239143817957","tvl_error":""} -{"level":"info","ts":1704682243.7807052,"msg":"pool","index":117,"pool":586,"rate":"1429890534935","tvl":"233552707535","tvl_error":""} -{"level":"info","ts":1704682243.7807186,"msg":"pool","index":118,"pool":463,"rate":"1420504104573","tvl":"224166277173","tvl_error":""} -{"level":"info","ts":1704682243.7807324,"msg":"pool","index":119,"pool":744,"rate":"1413331099904","tvl":"216993272504","tvl_error":""} -{"level":"info","ts":1704682243.7807457,"msg":"pool","index":120,"pool":899,"rate":"1399348350352","tvl":"203010522952","tvl_error":""} -{"level":"info","ts":1704682243.7807593,"msg":"pool","index":121,"pool":5,"rate":"1397135805470","tvl":"200797978070","tvl_error":""} -{"level":"info","ts":1704682243.780773,"msg":"pool","index":122,"pool":42,"rate":"1394388376141","tvl":"198050548741","tvl_error":""} -{"level":"info","ts":1704682243.7807863,"msg":"pool","index":123,"pool":6,"rate":"1393832482435","tvl":"197494655035","tvl_error":""} -{"level":"info","ts":1704682243.7807994,"msg":"pool","index":124,"pool":1046,"rate":"1388822374831","tvl":"192484547431","tvl_error":""} -{"level":"info","ts":1704682243.780813,"msg":"pool","index":125,"pool":1075,"rate":"1385999059914","tvl":"189661232514","tvl_error":""} -{"level":"info","ts":1704682243.7808266,"msg":"pool","index":126,"pool":992,"rate":"1385226902049","tvl":"188889074649","tvl_error":""} -{"level":"info","ts":1704682243.7808402,"msg":"pool","index":127,"pool":605,"rate":"1383716412882","tvl":"187378585482","tvl_error":""} -{"level":"info","ts":1704682243.78086,"msg":"pool","index":128,"pool":907,"rate":"1381320014419","tvl":"184982187019","tvl_error":""} -{"level":"info","ts":1704682243.796009,"msg":"pool","index":129,"pool":587,"rate":"1379770279669","tvl":"183432452269","tvl_error":""} -{"level":"info","ts":1704682243.7960274,"msg":"pool","index":130,"pool":1249,"rate":"1378573673599","tvl":"182235846199","tvl_error":""} -{"level":"info","ts":1704682243.7960422,"msg":"pool","index":131,"pool":572,"rate":"1376538482409","tvl":"180200655009","tvl_error":""} -{"level":"info","ts":1704682243.7960565,"msg":"pool","index":132,"pool":1320,"rate":"1370444448453","tvl":"174106621053","tvl_error":""} -{"level":"info","ts":1704682243.7960715,"msg":"pool","index":133,"pool":816,"rate":"1369312699329","tvl":"172974871929","tvl_error":""} -{"level":"info","ts":1704682243.7960916,"msg":"pool","index":134,"pool":10,"rate":"1358191851164","tvl":"161854023764","tvl_error":""} -{"level":"info","ts":1704682243.7961063,"msg":"pool","index":135,"pool":627,"rate":"1346940861309","tvl":"150603033909","tvl_error":""} -{"level":"info","ts":1704682243.7961235,"msg":"pool","index":136,"pool":481,"rate":"1342994487501","tvl":"146656660101","tvl_error":""} -{"level":"info","ts":1704682243.796138,"msg":"pool","index":137,"pool":1036,"rate":"1338163028715","tvl":"141825201315","tvl_error":""} -{"level":"info","ts":1704682243.7961607,"msg":"pool","index":138,"pool":585,"rate":"1323845455337","tvl":"127507627937","tvl_error":""} -{"level":"info","ts":1704682243.7961748,"msg":"pool","index":139,"pool":1121,"rate":"1312100322192","tvl":"115762494792","tvl_error":""} -{"level":"info","ts":1704682243.7961895,"msg":"pool","index":140,"pool":777,"rate":"1297788294542","tvl":"101450467142","tvl_error":""} -{"level":"info","ts":1704682243.7962039,"msg":"pool","index":141,"pool":15,"rate":"1292383847543","tvl":"96046020143","tvl_error":""} -{"level":"info","ts":1704682243.7962184,"msg":"pool","index":142,"pool":952,"rate":"1291336688720","tvl":"94998861320","tvl_error":""} -{"level":"info","ts":1704682243.7962327,"msg":"pool","index":143,"pool":602,"rate":"1287672863870","tvl":"91335036470","tvl_error":""} -{"level":"info","ts":1704682243.796247,"msg":"pool","index":144,"pool":773,"rate":"1286858012519","tvl":"90520185119","tvl_error":""} -{"level":"info","ts":1704682243.7962613,"msg":"pool","index":145,"pool":1020,"rate":"1284565653057","tvl":"88227825657","tvl_error":""} -{"level":"info","ts":1704682243.7962763,"msg":"pool","index":146,"pool":629,"rate":"1281812478783","tvl":"85474651383","tvl_error":""} -{"level":"info","ts":1704682243.796291,"msg":"pool","index":147,"pool":1180,"rate":"1272443226387","tvl":"76105398987","tvl_error":""} -{"level":"info","ts":1704682243.7963052,"msg":"pool","index":148,"pool":928,"rate":"1271277351997","tvl":"74939524597","tvl_error":""} -{"level":"info","ts":1704682243.7963207,"msg":"pool","index":149,"pool":606,"rate":"1270769157085","tvl":"74431329685","tvl_error":""} -{"level":"info","ts":1704682243.7963347,"msg":"pool","index":150,"pool":1179,"rate":"1269118208340","tvl":"72780380940","tvl_error":""} -{"level":"info","ts":1704682243.7963488,"msg":"pool","index":151,"pool":732,"rate":"1268791084111","tvl":"72453256711","tvl_error":""} -{"level":"info","ts":1704682243.7963634,"msg":"pool","index":152,"pool":924,"rate":"1267217469394","tvl":"70879641994","tvl_error":""} -{"level":"info","ts":1704682243.7963774,"msg":"pool","index":153,"pool":648,"rate":"1264646782104","tvl":"68308954704","tvl_error":""} -{"level":"info","ts":1704682243.796392,"msg":"pool","index":154,"pool":900,"rate":"1264583513828","tvl":"68245686428","tvl_error":""} -{"level":"info","ts":1704682243.7964065,"msg":"pool","index":155,"pool":8,"rate":"1263214161125","tvl":"66876333725","tvl_error":""} -{"level":"info","ts":1704682243.7964213,"msg":"pool","index":156,"pool":601,"rate":"1262986316681","tvl":"66648489281","tvl_error":""} -{"level":"info","ts":1704682243.796435,"msg":"pool","index":157,"pool":1019,"rate":"1260227807205","tvl":"63889979805","tvl_error":""} -{"level":"info","ts":1704682243.796449,"msg":"pool","index":158,"pool":626,"rate":"1256329821069","tvl":"59991993669","tvl_error":""} -{"level":"info","ts":1704682243.7964642,"msg":"pool","index":159,"pool":574,"rate":"1255850348463","tvl":"59512521063","tvl_error":""} -{"level":"info","ts":1704682243.7964785,"msg":"pool","index":160,"pool":731,"rate":"1253372969123","tvl":"57035141723","tvl_error":""} -{"level":"info","ts":1704682243.7964897,"msg":"pool","index":161,"pool":877,"rate":"1252923991375","tvl":"56586163975","tvl_error":""} -{"level":"info","ts":1704682243.796504,"msg":"pool","index":162,"pool":482,"rate":"1252071639181","tvl":"55733811781","tvl_error":""} -{"level":"info","ts":1704682243.7965178,"msg":"pool","index":163,"pool":972,"rate":"1252024600460","tvl":"55686773060","tvl_error":""} -{"level":"info","ts":1704682243.7965317,"msg":"pool","index":164,"pool":1065,"rate":"1249915517810","tvl":"53577690410","tvl_error":""} -{"level":"info","ts":1704682243.796546,"msg":"pool","index":165,"pool":917,"rate":"1249307124892","tvl":"52969297492","tvl_error":""} -{"level":"info","ts":1704682243.7965603,"msg":"pool","index":166,"pool":7,"rate":"1242760208915","tvl":"46422381515","tvl_error":""} -{"level":"info","ts":1704682243.7965744,"msg":"pool","index":167,"pool":641,"rate":"1242110906970","tvl":"45773079570","tvl_error":""} -{"level":"info","ts":1704682243.7965982,"msg":"pool","index":168,"pool":13,"rate":"1241982069183","tvl":"45644241783","tvl_error":""} -{"level":"info","ts":1704682243.796613,"msg":"pool","index":169,"pool":644,"rate":"1241502950154","tvl":"45165122754","tvl_error":""} -{"level":"info","ts":1704682243.7966278,"msg":"pool","index":170,"pool":930,"rate":"1240821864947","tvl":"44484037547","tvl_error":""} -{"level":"info","ts":1704682243.7966418,"msg":"pool","index":171,"pool":600,"rate":"1240758205342","tvl":"44420377942","tvl_error":""} -{"level":"info","ts":1704682243.7966561,"msg":"pool","index":172,"pool":929,"rate":"1239129809170","tvl":"42791981770","tvl_error":""} -{"level":"info","ts":1704682243.7966702,"msg":"pool","index":173,"pool":956,"rate":"1238164125144","tvl":"41826297744","tvl_error":""} -{"level":"info","ts":1704682243.7966845,"msg":"pool","index":174,"pool":619,"rate":"1237680868654","tvl":"41343041254","tvl_error":""} -{"level":"info","ts":1704682243.7966988,"msg":"pool","index":175,"pool":686,"rate":"1236134528622","tvl":"39796701222","tvl_error":""} -{"level":"info","ts":1704682243.7967122,"msg":"pool","index":176,"pool":914,"rate":"1234859398538","tvl":"38521571138","tvl_error":""} -{"level":"info","ts":1704682243.796726,"msg":"pool","index":177,"pool":651,"rate":"1234504790056","tvl":"38166962656","tvl_error":""} -{"level":"info","ts":1704682243.7967403,"msg":"pool","index":178,"pool":1011,"rate":"1234208995252","tvl":"37871167852","tvl_error":""} -{"level":"info","ts":1704682243.7967544,"msg":"pool","index":179,"pool":573,"rate":"1233318620538","tvl":"36980793138","tvl_error":""} -{"level":"info","ts":1704682243.7967682,"msg":"pool","index":180,"pool":800,"rate":"1232623654566","tvl":"36285827166","tvl_error":""} -{"level":"info","ts":1704682243.7967827,"msg":"pool","index":181,"pool":826,"rate":"1231462270439","tvl":"35124443039","tvl_error":""} -{"level":"info","ts":1704682243.7967973,"msg":"pool","index":182,"pool":625,"rate":"1230867271695","tvl":"34529444295","tvl_error":""} -{"level":"info","ts":1704682243.796811,"msg":"pool","index":183,"pool":577,"rate":"1230292564445","tvl":"33954737045","tvl_error":""} -{"level":"info","ts":1704682243.7968278,"msg":"pool","index":184,"pool":898,"rate":"1229368685528","tvl":"33030858128","tvl_error":""} -{"level":"info","ts":1704682243.796842,"msg":"pool","index":185,"pool":778,"rate":"1229216428426","tvl":"32878601026","tvl_error":""} -{"level":"info","ts":1704682243.7968564,"msg":"pool","index":186,"pool":915,"rate":"1228232331343","tvl":"31894503943","tvl_error":""} -{"level":"info","ts":1704682243.79689,"msg":"pool","index":187,"pool":831,"rate":"1228047113316","tvl":"31709285916","tvl_error":""} -{"level":"info","ts":1704682243.7969046,"msg":"pool","index":188,"pool":1239,"rate":"1227833577164","tvl":"31495749764","tvl_error":""} -{"level":"info","ts":1704682243.7969193,"msg":"pool","index":189,"pool":960,"rate":"1227422693392","tvl":"31084865992","tvl_error":""} -{"level":"info","ts":1704682243.796933,"msg":"pool","index":190,"pool":1218,"rate":"1227188265472","tvl":"30850438072","tvl_error":""} -{"level":"info","ts":1704682243.7969475,"msg":"pool","index":191,"pool":1232,"rate":"1227029150497","tvl":"30691323097","tvl_error":""} -{"level":"info","ts":1704682243.7969615,"msg":"pool","index":192,"pool":616,"rate":"1226596094154","tvl":"30258266754","tvl_error":""} -{"level":"info","ts":1704682243.7969759,"msg":"pool","index":193,"pool":631,"rate":"1224955470952","tvl":"28617643552","tvl_error":""} -{"level":"info","ts":1704682243.7969897,"msg":"pool","index":194,"pool":1061,"rate":"1224408673764","tvl":"28070846364","tvl_error":""} -{"level":"info","ts":1704682243.7970035,"msg":"pool","index":195,"pool":553,"rate":"1223670683612","tvl":"27332856212","tvl_error":""} -{"level":"info","ts":1704682243.7970176,"msg":"pool","index":196,"pool":882,"rate":"1223211304364","tvl":"26873476964","tvl_error":""} -{"level":"info","ts":1704682243.7970314,"msg":"pool","index":197,"pool":918,"rate":"1222811756616","tvl":"26473929216","tvl_error":""} -{"level":"info","ts":1704682243.797045,"msg":"pool","index":198,"pool":769,"rate":"1222400877899","tvl":"26063050499","tvl_error":""} -{"level":"info","ts":1704682243.7970629,"msg":"pool","index":199,"pool":617,"rate":"1221489867834","tvl":"25152040434","tvl_error":""} -{"level":"info","ts":1704682243.7970772,"msg":"pool","index":200,"pool":1013,"rate":"1218340617076","tvl":"22002789676","tvl_error":""} -{"level":"info","ts":1704682243.797091,"msg":"pool","index":201,"pool":662,"rate":"1217241964230","tvl":"20904136830","tvl_error":""} -{"level":"info","ts":1704682243.7971048,"msg":"pool","index":202,"pool":790,"rate":"1217199724121","tvl":"20861896721","tvl_error":""} -{"level":"info","ts":1704682243.797119,"msg":"pool","index":203,"pool":837,"rate":"1216586644900","tvl":"20248817500","tvl_error":""} -{"level":"info","ts":1704682243.797133,"msg":"pool","index":204,"pool":1238,"rate":"1214884445411","tvl":"18546618011","tvl_error":""} -{"level":"info","ts":1704682243.7971463,"msg":"pool","index":205,"pool":618,"rate":"1214612117498","tvl":"18274290098","tvl_error":""} -{"level":"info","ts":1704682243.7971601,"msg":"pool","index":206,"pool":561,"rate":"1214611251384","tvl":"18273423984","tvl_error":""} -{"level":"info","ts":1704682243.7971737,"msg":"pool","index":207,"pool":738,"rate":"1214161868034","tvl":"17824040634","tvl_error":""} -{"level":"info","ts":1704682243.7971878,"msg":"pool","index":208,"pool":813,"rate":"1212524308736","tvl":"16186481336","tvl_error":""} -{"level":"info","ts":1704682243.7972028,"msg":"pool","index":209,"pool":730,"rate":"1211826988994","tvl":"15489161594","tvl_error":""} -{"level":"info","ts":1704682243.7972167,"msg":"pool","index":210,"pool":562,"rate":"1211725041750","tvl":"15387214350","tvl_error":""} -{"level":"info","ts":1704682243.797231,"msg":"pool","index":211,"pool":1023,"rate":"1210648765906","tvl":"14310938506","tvl_error":""} -{"level":"info","ts":1704682243.797245,"msg":"pool","index":212,"pool":621,"rate":"1209229262725","tvl":"12891435325","tvl_error":""} -{"level":"info","ts":1704682243.7972589,"msg":"pool","index":213,"pool":613,"rate":"1208823575575","tvl":"12485748175","tvl_error":""} -{"level":"info","ts":1704682243.797273,"msg":"pool","index":214,"pool":637,"rate":"1208804364327","tvl":"12466536927","tvl_error":""} -{"level":"info","ts":1704682243.797287,"msg":"pool","index":215,"pool":555,"rate":"1208646742863","tvl":"12308915463","tvl_error":""} -{"level":"info","ts":1704682243.7973008,"msg":"pool","index":216,"pool":634,"rate":"1208432405755","tvl":"12094578355","tvl_error":""} -{"level":"info","ts":1704682243.797315,"msg":"pool","index":217,"pool":22,"rate":"1208311173958","tvl":"11973346558","tvl_error":""} -{"level":"info","ts":1704682243.7973287,"msg":"pool","index":218,"pool":795,"rate":"1208149256498","tvl":"11811429098","tvl_error":""} -{"level":"info","ts":1704682243.7973425,"msg":"pool","index":219,"pool":643,"rate":"1207903465619","tvl":"11565638219","tvl_error":""} -{"level":"info","ts":1704682243.797356,"msg":"pool","index":220,"pool":1039,"rate":"1207402043787","tvl":"11064216387","tvl_error":""} -{"level":"info","ts":1704682243.7973692,"msg":"pool","index":221,"pool":558,"rate":"1206598604528","tvl":"10260777128","tvl_error":""} -{"level":"info","ts":1704682243.797383,"msg":"pool","index":222,"pool":1242,"rate":"1206547004523","tvl":"10209177123","tvl_error":""} -{"level":"info","ts":1704682243.7973979,"msg":"pool","index":223,"pool":1240,"rate":"1206422764462","tvl":"10084937062","tvl_error":""} -{"level":"info","ts":1704682243.797412,"msg":"pool","index":224,"pool":817,"rate":"493825023479","tvl":"493825023479","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/84502A75BCA4A5F68D464C00B3F610CE2585847D59B52E5FFB7C3C9D2DDCD3FE not found"} -{"level":"info","ts":1704682243.7974277,"msg":"pool","index":225,"pool":944,"rate":"342153811767","tvl":"342153811767","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/FA602364BEC305A696CBDF987058E99D8B479F0318E47314C49173E8838C5BAC not found"} -{"level":"info","ts":1704682243.79745,"msg":"pool","index":226,"pool":810,"rate":"206114921859","tvl":"206114921859","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/5DD1F95ED336014D00CE2520977EC71566D282F9749170ADC83A392E0EA7426A not found"} -{"level":"info","ts":1704682243.7974691,"msg":"pool","index":227,"pool":1137,"rate":"100153232839","tvl":"100153232839","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/208B2F137CDE510B44C41947C045CFDC27F996A9D990EA64460BDD5B3DBEB2ED not found"} -{"level":"info","ts":1704682243.7974846,"msg":"pool","index":228,"pool":1120,"rate":"79615432089","tvl":"79615432089","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/5A0060579D24FBE5268BEA74C3281E7FE533D361C41A99307B4998FEC611E46B not found"} -{"level":"info","ts":1704682243.7975037,"msg":"pool","index":229,"pool":912,"rate":"47521888008","tvl":"47521888008","tvl_error":"error getting token precision ibc/FE2CD1E6828EC0FAB8AF39BAC45BC25B965BA67CCBC50C13A14BD610B0D1E2C4"} -{"level":"info","ts":1704682243.797522,"msg":"pool","index":230,"pool":1035,"rate":"40493244275","tvl":"40493244275","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/02F196DA6FD0917DD5FEA249EE61880F4D941EE9059E7964C5C9B50AF103800F not found"} -{"level":"info","ts":1704682243.7975378,"msg":"pool","index":231,"pool":1087,"rate":"32161372273","tvl":"32161372273","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/EAF76AD1EEF7B16D167D87711FB26ABE881AC7D9F7E6D0CF313D5FA530417208 not found"} -{"level":"info","ts":1704682243.797553,"msg":"pool","index":232,"pool":903,"rate":"22707656789","tvl":"22707656789","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/46C83BB054E12E189882B5284542DB605D94C99827E367C9192CF0579CD5BC83 not found"} -{"level":"info","ts":1704682243.7975724,"msg":"pool","index":233,"pool":1284,"rate":"20887197371","tvl":"20887197371","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/75345531D87BD90BF108BE7240BD721CB2CB0A1F16D4EBA71B09EC3C43E15C8F not found"} -{"level":"info","ts":1704682243.797588,"msg":"pool","index":234,"pool":597,"rate":"18223806444","tvl":"18223806444","tvl_error":"error getting token precision ibc/FE2CD1E6828EC0FAB8AF39BAC45BC25B965BA67CCBC50C13A14BD610B0D1E2C4"} -{"level":"info","ts":1704682243.7976038,"msg":"pool","index":235,"pool":886,"rate":"17036115777","tvl":"17036115777","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/CAA179E40F0266B0B29FB5EAA288FB9212E628822265D4141EBD1C47C3CBFCBC not found"} -{"level":"info","ts":1704682243.7976186,"msg":"pool","index":236,"pool":1254,"rate":"17019022596","tvl":"17019022596","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/D3B574938631B0A1BA704879020C696E514CFADAA7643CDE4BD5EB010BDE327B not found"} -{"level":"info","ts":1704682243.79764,"msg":"pool","index":237,"pool":1311,"rate":"15551693007","tvl":"15551693007","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/E7905742CE2EA4EA5D592527DC89220C59B617DE803939FE7293805A64B484D7 not found"} -{"level":"info","ts":1704682243.7976637,"msg":"pool","index":238,"pool":1356,"rate":"14272196663","tvl":"14272196663","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/2FFE07C4B4EFC0DDA099A16C6AF3C9CCA653CC56077E87217A585D48794B0BC7 not found"} -{"level":"info","ts":1704682243.79768,"msg":"pool","index":239,"pool":922,"rate":"13852018021","tvl":"13852018021","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/C5579A9595790017C600DD726276D978B9BF314CF82406CE342720A9C7911A01 not found"} -{"level":"info","ts":1704682243.797695,"msg":"pool","index":240,"pool":1255,"rate":"13572315101","tvl":"13572315101","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/D3B574938631B0A1BA704879020C696E514CFADAA7643CDE4BD5EB010BDE327B not found"} -{"level":"info","ts":1704682243.7977104,"msg":"pool","index":241,"pool":695,"rate":"12616355692","tvl":"12616355692","tvl_error":"error getting token precision ibc/52E12CF5CA2BB903D84F5298B4BFD725D66CAB95E09AA4FC75B2904CA5485FEB"} -{"level":"info","ts":1704682243.797729,"msg":"pool","index":242,"pool":1007,"rate":"11237175709","tvl":"11237175709","tvl_error":"highest liquidity pool between base uosmo and match denom ibc/63CDD51098FD99E04E5F5610A3882CBE7614C441607BA6FCD7F3A3C1CD5325F8 not found"} -{"level":"info","ts":1704682243.7977476,"msg":"pool","index":243,"pool":596,"rate":"10519973150","tvl":"10519973150","tvl_error":"error getting token precision ibc/FE2CD1E6828EC0FAB8AF39BAC45BC25B965BA67CCBC50C13A14BD610B0D1E2C4"} -{"level":"info","ts":1704682243.7977626,"msg":"pool","index":244,"pool":751,"rate":"10205152373","tvl":"10205152373","tvl_error":"error getting token precision ibc/7ABF696369EFB3387DF22B6A24204459FE5EFD010220E8E5618DC49DB877047B"} -{"level":"info","ts":1704682243.8254836,"msg":"calculated routes","num_routes":3} diff --git a/sqsutil/os.go b/sqsutil/os.go new file mode 100644 index 00000000..9659419c --- /dev/null +++ b/sqsutil/os.go @@ -0,0 +1,30 @@ +package sqsutil + +import "os" + +const separator = "/" + +// WriteBytes writes the given bytes to the given file in the given directory. +// If the directory does not exist, it is created. +// If the file already exists, it is overwritten. +// Returns an error if any. +func WriteBytes(directory, fileName string, bz []byte) error { + // Create a directory if not exists + err := os.MkdirAll(directory, os.ModePerm) + if err != nil { + return err + } + + // Write the bytes to file + file, err := os.Create(directory + separator + fileName) + if err != nil { + return err + } + defer file.Close() + + _, err = file.Write(bz) + if err != nil { + return err + } + return nil +} diff --git a/sqsutil/os_test.go b/sqsutil/os_test.go new file mode 100644 index 00000000..51c0e402 --- /dev/null +++ b/sqsutil/os_test.go @@ -0,0 +1,205 @@ +package sqsutil_test + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/osmosis-labs/sqs/sqsutil" +) + +// This test is ChatGPT generated with the following prompt: +// +// Please generate table driven unit tests for this function. +// +// Make sure to test: +// - New file is written without issues +// - The contents of the file are overwritten if previously exist +// - If directory exists, no error returned +// - If directory does not exist, it is created and no error returned +// - Ability to write twice to the same file without permission issues +func TestWriteBytes(t *testing.T) { + tests := []struct { + name string + directory string + fileName string + data []byte + setup func() // setup function for any required preconditions + assert func() // assert function for validating the result + cleanup func() // cleanup function for any necessary cleanup after the test + }{ + { + name: "New file is written without issues", + directory: "testdata/test1", + fileName: "file1.txt", + data: []byte("Hello, World!"), + setup: func() { + // No setup required for this test case + }, + assert: func() { + // Check if the file was created + fileContent, err := os.ReadFile("testdata/test1/file1.txt") + if err != nil { + t.Errorf("Error reading file: %v", err) + } + expectedContent := "Hello, World!" + if string(fileContent) != expectedContent { + t.Errorf("Unexpected file content. Expected: %s, Actual: %s", expectedContent, fileContent) + } + }, + cleanup: func() { + // Cleanup: Remove the directory and its contents + os.RemoveAll("testdata/test1") + }, + }, + { + name: "Contents of the file are overwritten if previously exist", + directory: "testdata/test2", + fileName: "file2.txt", + data: []byte("Hello, World!"), + setup: func() { + // Create the directory + err := os.MkdirAll("testdata/test2", os.ModePerm) + if err != nil { + t.Fatalf("Setup error: %v", err) + } + + // Create a file with initial content + err = os.WriteFile("testdata/test2/file2.txt", []byte("Initial Content"), 0644) + if err != nil { + t.Fatalf("Setup error: %v", err) + } + }, + assert: func() { + // Check if the file was overwritten + fileContent, err := os.ReadFile("testdata/test2/file2.txt") + if err != nil { + t.Errorf("Error reading file: %v", err) + } + expectedContent := "Hello, World!" + if string(fileContent) != expectedContent { + t.Errorf("Unexpected file content. Expected: %s, Actual: %s", expectedContent, fileContent) + } + }, + cleanup: func() { + // Cleanup: Remove the directory and its contents + os.RemoveAll("testdata/test2") + }, + }, + { + name: "If directory exists, no error returned", + directory: "testdata/test3", + fileName: "file3.txt", + data: []byte("Hello, World!"), + setup: func() { + // Create the directory + err := os.MkdirAll("testdata/test3", os.ModePerm) + if err != nil { + t.Fatalf("Setup error: %v", err) + } + }, + assert: func() { + // Check if the file was created + fileContent, err := os.ReadFile("testdata/test3/file3.txt") + if err != nil { + t.Errorf("Error reading file: %v", err) + } + expectedContent := "Hello, World!" + if string(fileContent) != expectedContent { + t.Errorf("Unexpected file content. Expected: %s, Actual: %s", expectedContent, fileContent) + } + }, + cleanup: func() { + // Cleanup: Remove the directory and its contents + os.RemoveAll("testdata/test3") + }, + }, + { + name: "If directory does not exist, it is created and no error returned", + directory: "testdata/test4", + fileName: "file4.txt", + data: []byte("Hello, World!"), + setup: func() { + // No setup required for this test case + }, + assert: func() { + // Check if the file was created + fileContent, err := os.ReadFile("testdata/test4/file4.txt") + if err != nil { + t.Errorf("Error reading file: %v", err) + } + expectedContent := "Hello, World!" + if string(fileContent) != expectedContent { + t.Errorf("Unexpected file content. Expected: %s, Actual: %s", expectedContent, fileContent) + } + }, + cleanup: func() { + // Cleanup: Remove the directory and its contents + os.RemoveAll("testdata/test4") + }, + }, + { + name: "Ability to write twice to the same file without permission issues", + directory: "testdata/test5", + fileName: "file5.txt", + data: []byte("Hello, World!"), + setup: func() { + // No setup required for this test case + }, + assert: func() { + // Check if the file was created + fileContent, err := ioutil.ReadFile("testdata/test5/file5.txt") + if err != nil { + t.Errorf("Error reading file: %v", err) + } + expectedContent := "Hello, World!" + if string(fileContent) != expectedContent { + t.Errorf("Unexpected file content. Expected: %s, Actual: %s", expectedContent, fileContent) + } + + // Write to the same file again + err = sqsutil.WriteBytes("testdata/test5", "file5.txt", []byte("New Content")) + if err != nil { + t.Errorf("Error writing to the same file: %v", err) + } + + // Check if the file was overwritten + fileContent, err = ioutil.ReadFile("testdata/test5/file5.txt") + if err != nil { + t.Errorf("Error reading file: %v", err) + } + expectedContent = "New Content" + if string(fileContent) != expectedContent { + t.Errorf("Unexpected file content. Expected: %s, Actual: %s", expectedContent, fileContent) + } + }, + cleanup: func() { + // Cleanup: Remove the directory and its contents + os.RemoveAll("testdata/test5") + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Run the setup function + if tt.setup != nil { + tt.setup() + } + + // Run the function being tested + err := sqsutil.WriteBytes(tt.directory, tt.fileName, tt.data) + if err != nil { + t.Fatalf("Error writing bytes to file: %v", err) + } + + // Run the assert function + tt.assert() + + // Run the cleanup function + if tt.cleanup != nil { + tt.cleanup() + } + }) + } +}