Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: internal/accounts.go #15

Merged
merged 10 commits into from
Oct 29, 2024
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ require (
github.com/oapi-codegen/runtime v1.1.1
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0
)

require gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)

require (
github.com/algorand/go-algorand-sdk/v2 v2.6.0
Expand Down
4 changes: 4 additions & 0 deletions internal/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ func getAccountOnlineStatus(client *api.ClientWithResponses, address string) (st
return "N/A", errors.New(fmt.Sprintf("Failed to get account information. Received error code: %d", r.StatusCode()))
}

if r.JSON200 == nil {
return "N/A", errors.New("Failed to get account information. JSON200 is nil")
}

return r.JSON200.Status, nil
}

Expand Down
177 changes: 177 additions & 0 deletions internal/accounts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package internal

import (
"context"
"encoding/json"
"io"
"net/http"
"testing"
"time"

"github.com/algorandfoundation/hack-tui/api"
"github.com/oapi-codegen/oapi-codegen/v2/pkg/securityprovider"
"github.com/stretchr/testify/assert"
)

func getAddressesFromGenesis(t *testing.T) ([]string, string, string) {
HashMapsData2Value marked this conversation as resolved.
Show resolved Hide resolved

// TODO: replace with calls to GetGenesis

resp, err := http.Get("http://localhost:8080/genesis")
PhearZero marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()

// Check the response status code
assert.Equal(t, 200, resp.StatusCode)

// Read the response body
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}

// Unmarshal the JSON response into a map
var jsonResponse map[string]interface{}
err = json.Unmarshal(body, &jsonResponse)
if err != nil {
t.Fatal(err)
}

// Two special addresses
rewardsPool := "7777777777777777777777777777777777777777777777777774MSJUVU"
feeSink := "A7NMWS3NT3IUDMLVO26ULGXGIIOUQ3ND2TXSER6EBGRZNOBOUIQXHIBGDE"
rewardsPoolIncluded := false
feeSinkIncluded := false

// Loop over each entry in the "alloc" list and collect the "addr" values
var addresses []string
if allocList, ok := jsonResponse["alloc"].([]interface{}); ok {
for _, entry := range allocList {
if entryMap, ok := entry.(map[string]interface{}); ok {
if addr, ok := entryMap["addr"].(string); ok {
if addr == rewardsPool {
rewardsPoolIncluded = true
} else if addr == feeSink {
feeSinkIncluded = true
} else {
addresses = append(addresses, addr)
}
} else {
t.Logf("Address not found in entry: %+v", entry)
}
} else {
t.Logf("Entry is not a map: %+v", entry)
}
}
} else {
t.Fatal("alloc is not a list")
}

if !rewardsPoolIncluded || !feeSinkIncluded {

t.Fatalf("Expected RewardsPool and/or FeeSink addresses NOT found in genesis file")
}

return addresses, rewardsPool, feeSink
}

func isValidStatus(status string) bool {
validStatuses := map[string]bool{
"Online": true,
"Offline": true,
"Not Participating": true,
}
return validStatuses[status]
}

func Test_AccountsFromState(t *testing.T) {

// Setup elevated client
apiToken, err := securityprovider.NewSecurityProviderApiKey("header", "X-Algo-API-Token", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
if err != nil {
t.Fatal(err)
}
client, err := api.NewClientWithResponses("http://localhost:8080", api.WithRequestEditorFn(apiToken.Intercept))

addresses, rewardsPool, feeSink := getAddressesFromGenesis(t)

// Test getAccountOnlineStatus

var mapAddressOnlineStatus = make(map[string]string)

for _, address := range addresses {
status, err := getAccountOnlineStatus(client, address)
if err != nil {
t.Fatal(err)
}

assert.True(t, status == "Online" || status == "Offline")
mapAddressOnlineStatus[address] = status
}

status, err := getAccountOnlineStatus(client, rewardsPool)
if err != nil {
t.Fatal(err)
}
if status != "Not Participating" {
t.Fatalf("Expected RewardsPool to be 'Not Participating', got %s", status)
}

status, err = getAccountOnlineStatus(client, feeSink)
if err != nil {
t.Fatal(err)
}
if status != "Not Participating" {
t.Fatalf("Expected FeeSink to be 'Not Participating', got %s", status)
}

_, err = getAccountOnlineStatus(client, "invalid_address")
if err == nil {
t.Fatal("Expected error for invalid address")
}

// Test AccountFromState

params := api.GenerateParticipationKeysParams{
Dilution: nil,
First: 0,
Last: 10000,
}

// Generate ParticipationKeys for all addresses
var participationKeys []api.ParticipationKey
for _, address := range addresses {
key, err := GenerateKeyPair(context.Background(), client, address, &params)
if err != nil {
t.Fatal(err)
}
participationKeys = append(participationKeys, *key)
}

// Mock StateModel
state := &StateModel{
ParticipationKeys: &participationKeys,
}

// Call AccountsFromState
accounts := AccountsFromState(state, client)

// Create expectedAccounts dynamically
expectedAccounts := make(map[string]Account)
for _, address := range addresses {
expectedAccounts[address] = Account{
Address: address,
Status: mapAddressOnlineStatus[address],
Balance: 0,
Expires: time.Unix(0, 0),
Keys: 1,
LastModified: 0,
}
}

// Assert results
assert.Equal(t, expectedAccounts, accounts)

}
2 changes: 1 addition & 1 deletion ui/pages/transaction/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (m *ViewModel) UpdateTxnURLAndQRCode() error {
isOnline = true
case "Offline":
isOnline = false
case "NotParticipating": // This status means the account can never participate in consensus
case "Not Participating": // This status means the account can never participate in consensus
m.urlTxn = ""
m.asciiQR = ""
m.hint = fmt.Sprintf("%s is NotParticipating. Cannot register key.", m.Data.Address)
Expand Down
Loading