Skip to content

Commit

Permalink
Creating setuphandler to allow in-game set up to be queried via API (#…
Browse files Browse the repository at this point in the history
…274)

* Updating draft handler.

* Update handler with test function.

* Tested working endpoint and golang test function for happy case.

* Updating, removing comment.
  • Loading branch information
pwdel authored Aug 25, 2024
1 parent 07255a5 commit e5a74d0
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README/TESTING/TESTING_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ A `setup.yaml` file is used to configure custom conditions and fees for the game

### Testing Guidelines

- **General Golang Style Guidelines** Style guidelines can be found within the Golang language specification for the version and question as well as [here](https://google.github.io/styleguide/go/best-practices) for best practices.

- **Pre-deployment Testing:** The goal is to ensure that all tests pass before deploying new software changes. This is particularly important when custom, non-standard conditions are introduced, as these could potentially cause issues that existing tests do not cover. If such conditions arise, it's important to document them so that administrators are aware of potential risks.

- **Infinity Avoidance:** One of the specific test conditions that have been identified is the need to avoid infinity in market calculations. An example of such a test is available [here](https://github.com/openpredictionmarkets/socialpredict/blob/main/backend/tests/market_math/marketvolume_test.go).
Expand Down
22 changes: 22 additions & 0 deletions backend/handlers/setup/setuphandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package setup

import (
"encoding/json"
"net/http"
"socialpredict/setup"
)

func GetSetupHandler(w http.ResponseWriter, r *http.Request) {

appConfig, err := setup.LoadEconomicsConfig()
if err != nil {
http.Error(w, "Failed to load economic config", http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(appConfig.Economics)
if err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
}
}
90 changes: 90 additions & 0 deletions backend/handlers/setup/setuphandler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package setup

import (
"encoding/json"
"net/http"
"net/http/httptest"
"socialpredict/setup"
"strings"
"testing"
)

var loadEconomicsConfig = setup.LoadEconomicsConfig

func TestGetSetupHandler(t *testing.T) {
tests := []struct {
Name string
MockConfigLoader func() (*setup.EconomicConfig, error)
ExpectedStatus int
ExpectedResponse string
IsJSONResponse bool
}{
{
Name: "successful load",
MockConfigLoader: func() (*setup.EconomicConfig, error) {
return setup.LoadEconomicsConfig()
},
ExpectedStatus: http.StatusOK,
ExpectedResponse: `{
"MarketCreation":{"InitialMarketProbability":0.5,"InitialMarketSubsidization":10,"InitialMarketYes":0,"InitialMarketNo":0},
"MarketIncentives":{"CreateMarketCost":10,"TraderBonus":1},
"User":{"InitialAccountBalance":0,"MaximumDebtAllowed":500},
"Betting":{"MinimumBet":1,"BetFees":{"InitialBetFee":1,"EachBetFee":0,"SellSharesFee":0}}}`,
IsJSONResponse: true,
},
}

for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
// Replace the actual loader function with the mock
loadEconomicsConfig = test.MockConfigLoader
defer func() { loadEconomicsConfig = setup.LoadEconomicsConfig }()

req, err := http.NewRequest("GET", "/setup", nil)
if err != nil {
t.Fatal(err)
}

rr := httptest.NewRecorder()
handler := http.HandlerFunc(GetSetupHandler)

handler.ServeHTTP(rr, req)

if status := rr.Code; status != test.ExpectedStatus {
t.Errorf("%s: handler returned wrong status code: got %v want %v",
test.Name, status, test.ExpectedStatus)
}

if test.IsJSONResponse {
var expectedjson, actualjson map[string]interface{}
if err := json.Unmarshal([]byte(test.ExpectedResponse), &expectedjson); err != nil {
t.Fatalf("%s: error parsing expected response JSON: %v", test.Name, err)
}
if err := json.Unmarshal(rr.Body.Bytes(), &actualjson); err != nil {
t.Fatalf("%s: error parsing actual response JSON: %v", test.Name, err)
}

if !jsonEqual(expectedjson, actualjson) {
t.Errorf("%s: handler returned unexpected body: got %v want %v",
test.Name, rr.Body.String(), test.ExpectedResponse)
}
} else {
if strings.TrimSpace(rr.Body.String()) != strings.TrimSpace(test.ExpectedResponse) {
t.Errorf("%s: handler returned unexpected body: got %v want %v",
test.Name, rr.Body.String(), test.ExpectedResponse)
}
}
})
}
}

// jsonEqual compares two JSON objects for equality
func jsonEqual(a, b map[string]interface{}) bool {
return jsonString(a) == jsonString(b)
}

// jsonString converts a JSON object to a sorted string
func jsonString(v interface{}) string {
bytes, _ := json.Marshal(v)
return string(bytes)
}
5 changes: 4 additions & 1 deletion backend/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import (
adminhandlers "socialpredict/handlers/admin"
betshandlers "socialpredict/handlers/bets"
marketshandlers "socialpredict/handlers/markets"
"socialpredict/handlers/positions"
positions "socialpredict/handlers/positions"
setuphandlers "socialpredict/handlers/setup"
usershandlers "socialpredict/handlers/users"
"socialpredict/middleware"

Expand All @@ -34,6 +35,8 @@ func Start() {
router.HandleFunc("/v0/home", handlers.HomeHandler)
router.HandleFunc("/v0/login", middleware.LoginHandler)

// application setup information
router.HandleFunc("/v0/setup", setuphandlers.GetSetupHandler).Methods("GET")
// markets display, market information
router.HandleFunc("/v0/markets", marketshandlers.ListMarketsHandler).Methods("GET")
router.HandleFunc("/v0/markets/{marketId}", marketshandlers.MarketDetailsHandler).Methods("GET")
Expand Down

0 comments on commit e5a74d0

Please sign in to comment.