forked from grassrootseconomics/visedriver
		
	Merge branch 'master' into tests-refactor
This commit is contained in:
		
						commit
						2b34b3a75c
					
				| @ -12,6 +12,7 @@ DB_SSLMODE=disable | ||||
| DB_TIMEZONE=Africa/Nairobi | ||||
| 
 | ||||
| #External API Calls | ||||
| CREATE_ACCOUNT_URL=https://custodial.sarafu.africa/api/account/create | ||||
| CREATE_ACCOUNT_URL=http://localhost:5003/api/v2/account/create | ||||
| TRACK_STATUS_URL=https://custodial.sarafu.africa/api/track/ | ||||
| BALANCE_URL=https://custodial.sarafu.africa/api/account/status/ | ||||
| TRACK_URL=http://localhost:5003/api/v2/account/status | ||||
|  | ||||
| @ -6,11 +6,13 @@ var ( | ||||
| 	CreateAccountURL string | ||||
| 	TrackStatusURL   string | ||||
| 	BalanceURL       string | ||||
|     TrackURL         string | ||||
| ) | ||||
| 
 | ||||
| // LoadConfig initializes the configuration values after environment variables are loaded.
 | ||||
| func LoadConfig() { | ||||
| 	CreateAccountURL = initializers.GetEnv("CREATE_ACCOUNT_URL", "https://custodial.sarafu.africa/api/account/create") | ||||
| 	CreateAccountURL = initializers.GetEnv("CREATE_ACCOUNT_URL", "http://localhost:5003/api/v2/account/create") | ||||
| 	TrackStatusURL = initializers.GetEnv("TRACK_STATUS_URL", "https://custodial.sarafu.africa/api/track/") | ||||
| 	BalanceURL = initializers.GetEnv("BALANCE_URL", "https://custodial.sarafu.africa/api/account/status/") | ||||
|     TrackURL = initializers.GetEnv("TRACK_URL", "http://localhost:5003/api/v2/account/status") | ||||
| } | ||||
|  | ||||
							
								
								
									
										20
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								go.mod
									
									
									
									
									
								
							| @ -1,20 +1,25 @@ | ||||
| module git.grassecon.net/urdt/ussd | ||||
| 
 | ||||
| go 1.22.6 | ||||
| go 1.23.0 | ||||
| 
 | ||||
| toolchain go1.23.2 | ||||
| 
 | ||||
| require ( | ||||
| 	git.defalsify.org/vise.git v0.2.1-0.20241017112704-307fa6fcdc6b | ||||
| 	github.com/alecthomas/assert/v2 v2.2.2 | ||||
| 	github.com/peteole/testdata-loader v0.3.0 | ||||
| 	gopkg.in/leonelquinteros/gotext.v1 v1.3.1 | ||||
| 
 | ||||
| ) | ||||
| 
 | ||||
| require github.com/joho/godotenv v1.5.1 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/grassrootseconomics/eth-custodial v1.3.0-beta | ||||
| 	github.com/jackc/pgpassfile v1.0.0 // indirect | ||||
| 	github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect | ||||
| 	github.com/jackc/pgx/v5 v5.7.0 // indirect | ||||
| 	github.com/jackc/puddle/v2 v2.2.1 // indirect | ||||
| 	github.com/joho/godotenv v1.5.1 | ||||
| 	github.com/jackc/pgx/v5 v5.7.1 // indirect | ||||
| 	github.com/jackc/puddle/v2 v2.2.2 // indirect | ||||
| 	github.com/kr/text v0.2.0 // indirect | ||||
| 	github.com/rogpeppe/go-internal v1.13.1 // indirect | ||||
| 	golang.org/x/crypto v0.27.0 // indirect | ||||
| @ -26,15 +31,18 @@ require ( | ||||
| 	github.com/alecthomas/participle/v2 v2.0.0 // indirect | ||||
| 	github.com/alecthomas/repr v0.2.0 // indirect | ||||
| 	github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect | ||||
| 	github.com/davecgh/go-spew v1.1.1 // indirect | ||||
| 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect | ||||
| 	github.com/fxamacker/cbor/v2 v2.4.0 // indirect | ||||
| 	github.com/gofrs/uuid v4.4.0+incompatible | ||||
| 	github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 // indirect | ||||
| 	github.com/hexops/gotextdiff v1.0.3 // indirect | ||||
| 	github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect | ||||
| 	github.com/stretchr/objx v0.5.2 // indirect | ||||
| 	github.com/stretchr/testify v1.9.0 | ||||
| 	github.com/x448/float16 v0.8.4 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| 
 | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										17
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								go.sum
									
									
									
									
									
								
							| @ -10,12 +10,14 @@ github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YV | ||||
| github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U= | ||||
| github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | ||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= | ||||
| github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= | ||||
| github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= | ||||
| github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= | ||||
| github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= | ||||
| github.com/grassrootseconomics/eth-custodial v1.3.0-beta h1:twrMBhl89GqDUL9PlkzQxMP/6OST1BByrNDj+rqXDmU= | ||||
| github.com/grassrootseconomics/eth-custodial v1.3.0-beta/go.mod h1:7uhRcdnJplX4t6GKCEFkbeDhhjlcaGJeJqevbcvGLZo= | ||||
| github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo= | ||||
| github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y= | ||||
| github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= | ||||
| @ -24,10 +26,10 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI | ||||
| github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= | ||||
| github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= | ||||
| github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= | ||||
| github.com/jackc/pgx/v5 v5.7.0 h1:FG6VLIdzvAPhnYqP14sQ2xhFLkiUQHCs6ySqO91kF4g= | ||||
| github.com/jackc/pgx/v5 v5.7.0/go.mod h1:awP1KNnjylvpxHuHP63gzjhnGkI1iw+PMoIwvoleN/8= | ||||
| github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= | ||||
| github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= | ||||
| github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= | ||||
| github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= | ||||
| github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= | ||||
| github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= | ||||
| github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= | ||||
| github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= | ||||
| github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= | ||||
| @ -40,8 +42,9 @@ github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNL | ||||
| github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= | ||||
| github.com/peteole/testdata-loader v0.3.0 h1:8jckE9KcyNHgyv/VPoaljvKZE0Rqr8+dPVYH6rfNr9I= | ||||
| github.com/peteole/testdata-loader v0.3.0/go.mod h1:Mt0ZbRtb56u8SLJpNP+BnQbENljMorYBpqlvt3cS83U= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= | ||||
| github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= | ||||
| github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= | ||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
|  | ||||
| @ -1,25 +1,36 @@ | ||||
| package server | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"git.grassecon.net/urdt/ussd/config" | ||||
| 	"git.grassecon.net/urdt/ussd/internal/models" | ||||
| 	"github.com/grassrootseconomics/eth-custodial/pkg/api" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	okResponse  api.OKResponse | ||||
| 	errResponse api.ErrResponse | ||||
| ) | ||||
| 
 | ||||
| type AccountServiceInterface interface { | ||||
| 	CheckBalance(publicKey string) (*models.BalanceResponse, error) | ||||
| 	CreateAccount() (*models.AccountResponse, error) | ||||
| 	CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) | ||||
| 	CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) | ||||
| 	CreateAccount(ctx context.Context) (*api.OKResponse, error) | ||||
| 	CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) | ||||
| 	TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) | ||||
| } | ||||
| 
 | ||||
| type AccountService struct { | ||||
| } | ||||
| 
 | ||||
| // CheckAccountStatus retrieves the status of an account transaction based on the provided tracking ID.
 | ||||
| //
 | ||||
| type TestAccountService struct { | ||||
| } | ||||
| 
 | ||||
| // Parameters:
 | ||||
| //   - trackingId: A unique identifier for the account.This should be obtained from a previous call to
 | ||||
| //     CreateAccount or a similar function that returns an AccountResponse. The `trackingId` field in the
 | ||||
| @ -28,9 +39,9 @@ type AccountService struct { | ||||
| // Returns:
 | ||||
| //   - string: The status of the transaction as a string. If there is an error during the request or processing, this will be an empty string.
 | ||||
| //   - error: An error if any occurred during the HTTP request, reading the response, or unmarshalling the JSON data.
 | ||||
| //     If no error occurs, this will be nil.
 | ||||
| func (as *AccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { | ||||
| 	resp, err := http.Get(config.TrackStatusURL + trackingId) | ||||
| //     If no error occurs, this will be nil
 | ||||
| func (as *AccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) { | ||||
| 	resp, err := http.Get(config.BalanceURL + trackingId) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @ -40,18 +51,61 @@ func (as *AccountService) CheckAccountStatus(trackingId string) (*models.TrackSt | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var trackResp models.TrackStatusResponse | ||||
| 	err = json.Unmarshal(body, &trackResp) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &trackResp, nil | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) { | ||||
| 	var err error | ||||
| 	// Construct the URL with the path parameter
 | ||||
| 	url := fmt.Sprintf("%s/%s", config.TrackURL, publicKey) | ||||
| 	req, err := http.NewRequest("GET", url, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	req.Header.Set("Content-Type", "application/json") | ||||
| 	req.Header.Set("X-GE-KEY", "xd") | ||||
| 
 | ||||
| 	resp, err := http.DefaultClient.Do(req) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 
 | ||||
| 	body, err := io.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		errResponse.Description = err.Error() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if resp.StatusCode >= http.StatusBadRequest { | ||||
| 		err := json.Unmarshal([]byte(body), &errResponse) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return nil, errors.New(errResponse.Description) | ||||
| 	} | ||||
| 	err = json.Unmarshal([]byte(body), &okResponse) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if len(okResponse.Result) == 0 { | ||||
| 		return nil, errors.New("Empty api result") | ||||
| 	} | ||||
| 	return &okResponse, nil | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // CheckBalance retrieves the balance for a given public key from the custodial balance API endpoint.
 | ||||
| // Parameters:
 | ||||
| //   - publicKey: The public key associated with the account whose balance needs to be checked.
 | ||||
| func (as *AccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { | ||||
| func (as *AccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) { | ||||
| 	resp, err := http.Get(config.BalanceURL + publicKey) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| @ -75,20 +129,98 @@ func (as *AccountService) CheckBalance(publicKey string) (*models.BalanceRespons | ||||
| //     If there is an error during the request or processing, this will be nil.
 | ||||
| //   - error: An error if any occurred during the HTTP request, reading the response, or unmarshalling the JSON data.
 | ||||
| //     If no error occurs, this will be nil.
 | ||||
| func (as *AccountService) CreateAccount() (*models.AccountResponse, error) { | ||||
| 	resp, err := http.Post(config.CreateAccountURL, "application/json", nil) | ||||
| func (as *AccountService) CreateAccount(ctx context.Context) (*api.OKResponse, error) { | ||||
| 	var err error | ||||
| 
 | ||||
| 	// Create a new request
 | ||||
| 	req, err := http.NewRequest("POST", config.CreateAccountURL, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	req.Header.Set("Content-Type", "application/json") | ||||
| 	req.Header.Set("X-GE-KEY", "xd") | ||||
| 
 | ||||
| 	resp, err := http.DefaultClient.Do(req) | ||||
| 	if err != nil { | ||||
| 		errResponse.Description = err.Error() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 
 | ||||
| 	body, err := io.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var accountResp models.AccountResponse | ||||
| 	err = json.Unmarshal(body, &accountResp) | ||||
| 	if resp.StatusCode >= http.StatusBadRequest { | ||||
| 		err := json.Unmarshal([]byte(body), &errResponse) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return nil, errors.New(errResponse.Description) | ||||
| 	} | ||||
| 	err = json.Unmarshal([]byte(body), &okResponse) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &accountResp, nil | ||||
| 	if len(okResponse.Result) == 0 { | ||||
| 		return nil, errors.New("Empty api result") | ||||
| 	} | ||||
| 	return &okResponse, nil | ||||
| } | ||||
| 
 | ||||
| func (tas *TestAccountService) CreateAccount(ctx context.Context) (*api.OKResponse, error) { | ||||
| 	return &api.OKResponse{ | ||||
| 		Ok:          true, | ||||
| 		Description: "Account creation request received successfully", | ||||
| 		Result:      map[string]any{"publicKey": "0x48ADca309b5085852207FAaf2816eD72B52F527C", "trackingId": "28ebe84d-b925-472c-87ae-bbdfa1fb97be"}, | ||||
| 	}, nil | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func (tas *TestAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) { | ||||
| 	balanceResponse := &models.BalanceResponse{ | ||||
| 		Ok: true, | ||||
| 		Result: struct { | ||||
| 			Balance string      `json:"balance"` | ||||
| 			Nonce   json.Number `json:"nonce"` | ||||
| 		}{ | ||||
| 			Balance: "0.003 CELO", | ||||
| 			Nonce:   json.Number("0"), | ||||
| 		}, | ||||
| 	} | ||||
| 	return balanceResponse, nil | ||||
| } | ||||
| 
 | ||||
| func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) { | ||||
| 	return &api.OKResponse{ | ||||
| 		Ok:          true, | ||||
| 		Description: "Account creation succeeded", | ||||
| 		Result: map[string]any{ | ||||
| 			"active": true, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func (tas *TestAccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) { | ||||
| 	trackResponse := &models.TrackStatusResponse{ | ||||
| 		Ok: true, | ||||
| 		Result: struct { | ||||
| 			Transaction struct { | ||||
| 				CreatedAt     time.Time   "json:\"createdAt\"" | ||||
| 				Status        string      "json:\"status\"" | ||||
| 				TransferValue json.Number "json:\"transferValue\"" | ||||
| 				TxHash        string      "json:\"txHash\"" | ||||
| 				TxType        string      "json:\"txType\"" | ||||
| 			} | ||||
| 		}{ | ||||
| 			Transaction: models.Transaction{ | ||||
| 				CreatedAt:     time.Now(), | ||||
| 				Status:        "SUCCESS", | ||||
| 				TransferValue: json.Number("0.5"), | ||||
| 				TxHash:        "0x123abc456def", | ||||
| 				TxType:        "transfer", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	return trackResponse, nil | ||||
| } | ||||
|  | ||||
| @ -10,6 +10,7 @@ import ( | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"git.defalsify.org/vise.git/asm" | ||||
| 	"github.com/grassrootseconomics/eth-custodial/pkg/api" | ||||
| 
 | ||||
| 	"git.defalsify.org/vise.git/cache" | ||||
| 	"git.defalsify.org/vise.git/db" | ||||
| @ -27,6 +28,8 @@ var ( | ||||
| 	logg           = logging.NewVanilla().WithDomain("ussdmenuhandler") | ||||
| 	scriptDir      = path.Join("services", "registration") | ||||
| 	translationDir = path.Join(scriptDir, "locale") | ||||
| 	okResponse     *api.OKResponse | ||||
| 	errResponse    *api.ErrResponse | ||||
| 	backOption     = []byte("0") | ||||
| ) | ||||
| 
 | ||||
| @ -137,13 +140,18 @@ func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (r | ||||
| } | ||||
| 
 | ||||
| func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, res *resource.Result) error { | ||||
| 	accountResp, err := h.accountService.CreateAccount() | ||||
| 	data := map[utils.DataTyp]string{ | ||||
| 		utils.DATA_TRACKING_ID:  accountResp.Result.TrackingId, | ||||
| 		utils.DATA_PUBLIC_KEY:   accountResp.Result.PublicKey, | ||||
| 		utils.DATA_CUSTODIAL_ID: accountResp.Result.CustodialId.String(), | ||||
| 	flag_account_created, _ := h.flagManager.GetFlag("flag_account_created") | ||||
| 	okResponse, err := h.accountService.CreateAccount(ctx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	trackingId := okResponse.Result["trackingId"].(string) | ||||
| 	publicKey := okResponse.Result["publicKey"].(string) | ||||
| 
 | ||||
| 	data := map[utils.DataTyp]string{ | ||||
| 		utils.DATA_TRACKING_ID: trackingId, | ||||
| 		utils.DATA_PUBLIC_KEY:  publicKey, | ||||
| 	} | ||||
| 	for key, value := range data { | ||||
| 		store := h.userdataStore | ||||
| 		err := store.WriteEntry(ctx, sessionId, key, []byte(value)) | ||||
| @ -151,9 +159,8 @@ func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, r | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	flag_account_created, _ := h.flagManager.GetFlag("flag_account_created") | ||||
| 	res.FlagSet = append(res.FlagSet, flag_account_created) | ||||
| 	return err | ||||
| 	return nil | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| @ -192,7 +199,6 @@ func (h *Handlers) SavePin(ctx context.Context, sym string, input []byte) (resou | ||||
| 	} | ||||
| 
 | ||||
| 	flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin") | ||||
| 
 | ||||
| 	accountPIN := string(input) | ||||
| 	// Validate that the PIN is a 4-digit number
 | ||||
| 	if !isValidPIN(accountPIN) { | ||||
| @ -374,7 +380,6 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou | ||||
| 	if !ok { | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 
 | ||||
| 	if len(input) == 4 { | ||||
| 		yob := string(input) | ||||
| 		store := h.userdataStore | ||||
| @ -440,7 +445,6 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) | ||||
| 	if !ok { | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 
 | ||||
| 	if len(input) > 0 { | ||||
| 		offerings := string(input) | ||||
| 		store := h.userdataStore | ||||
| @ -466,7 +470,6 @@ func (h *Handlers) ResetAllowUpdate(ctx context.Context, sym string, input []byt | ||||
| // ResetAccountAuthorized resets the account authorization flag after a successful PIN entry.
 | ||||
| func (h *Handlers) ResetAccountAuthorized(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| 	var res resource.Result | ||||
| 
 | ||||
| 	flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") | ||||
| 
 | ||||
| 	res.FlagReset = append(res.FlagReset, flag_account_authorized) | ||||
| @ -476,12 +479,10 @@ func (h *Handlers) ResetAccountAuthorized(ctx context.Context, sym string, input | ||||
| // CheckIdentifier retrieves the PublicKey from the JSON data file.
 | ||||
| func (h *Handlers) CheckIdentifier(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| 	var res resource.Result | ||||
| 
 | ||||
| 	sessionId, ok := ctx.Value("SessionId").(string) | ||||
| 	if !ok { | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 
 | ||||
| 	store := h.userdataStore | ||||
| 	publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) | ||||
| 
 | ||||
| @ -495,12 +496,10 @@ func (h *Handlers) CheckIdentifier(ctx context.Context, sym string, input []byte | ||||
| func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| 	var res resource.Result | ||||
| 	var err error | ||||
| 
 | ||||
| 	sessionId, ok := ctx.Value("SessionId").(string) | ||||
| 	if !ok { | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 
 | ||||
| 	flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin") | ||||
| 	flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") | ||||
| 	flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") | ||||
| @ -552,28 +551,21 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 	store := h.userdataStore | ||||
| 	trackingId, err := store.ReadEntry(ctx, sessionId, utils.DATA_TRACKING_ID) | ||||
| 	publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) | ||||
| 	if err != nil { | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	accountStatus, err := h.accountService.CheckAccountStatus(string(trackingId)) | ||||
| 	okResponse, err = h.accountService.TrackAccountStatus(ctx, string(publicKey)) | ||||
| 	if err != nil { | ||||
| 		fmt.Println("Error checking account status:", err) | ||||
| 		return res, err | ||||
| 	} | ||||
| 	if !accountStatus.Ok { | ||||
| 		res.FlagSet = append(res.FlagSet, flag_api_error) | ||||
| 		return res, err | ||||
| 	} | ||||
| 	res.FlagReset = append(res.FlagReset, flag_api_error) | ||||
| 	status := accountStatus.Result.Transaction.Status | ||||
| 
 | ||||
| 	err = store.WriteEntry(ctx, sessionId, utils.DATA_ACCOUNT_STATUS, []byte(status)) | ||||
| 	if err != nil { | ||||
| 		return res, nil | ||||
| 	isActive := okResponse.Result["active"].(bool) | ||||
| 	if !ok { | ||||
| 		return res, err | ||||
| 	} | ||||
| 	if accountStatus.Result.Transaction.Status == "SUCCESS" { | ||||
| 	if isActive { | ||||
| 		res.FlagSet = append(res.FlagSet, flag_account_success) | ||||
| 		res.FlagReset = append(res.FlagReset, flag_account_pending) | ||||
| 	} else { | ||||
| @ -660,13 +652,17 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 
 | ||||
| 	code := codeFromCtx(ctx) | ||||
| 	l := gotext.NewLocale(translationDir, code) | ||||
| 	l.AddDomain("default") | ||||
| 
 | ||||
| 	store := h.userdataStore | ||||
| 	publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) | ||||
| 	if err != nil { | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	balanceResponse, err := h.accountService.CheckBalance(string(publicKey)) | ||||
| 	balanceResponse, err := h.accountService.CheckBalance(ctx, string(publicKey)) | ||||
| 	if err != nil { | ||||
| 		return res, nil | ||||
| 	} | ||||
| @ -676,7 +672,8 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( | ||||
| 	} | ||||
| 	res.FlagReset = append(res.FlagReset, flag_api_error) | ||||
| 	balance := balanceResponse.Result.Balance | ||||
| 	res.Content = balance | ||||
| 
 | ||||
| 	res.Content = l.Get("Balance: %s\n", balance) | ||||
| 
 | ||||
| 	return res, nil | ||||
| } | ||||
| @ -698,7 +695,7 @@ func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	balanceResponse, err := h.accountService.CheckBalance(string(publicKey)) | ||||
| 	balanceResponse, err := h.accountService.CheckBalance(ctx, string(publicKey)) | ||||
| 	if err != nil { | ||||
| 		return res, nil | ||||
| 	} | ||||
| @ -816,7 +813,7 @@ func (h *Handlers) MaxAmount(ctx context.Context, sym string, input []byte) (res | ||||
| 	store := h.userdataStore | ||||
| 	publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) | ||||
| 
 | ||||
| 	balanceResp, err := h.accountService.CheckBalance(string(publicKey)) | ||||
| 	balanceResp, err := h.accountService.CheckBalance(ctx, string(publicKey)) | ||||
| 	if err != nil { | ||||
| 		return res, nil | ||||
| 	} | ||||
| @ -846,7 +843,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) | ||||
| 
 | ||||
| 	amountStr := string(input) | ||||
| 
 | ||||
| 	balanceRes, err := h.accountService.CheckBalance(string(publicKey)) | ||||
| 	balanceRes, err := h.accountService.CheckBalance(ctx, string(publicKey)) | ||||
| 	balanceStr := balanceRes.Result.Balance | ||||
| 
 | ||||
| 	if !balanceRes.Ok { | ||||
| @ -916,7 +913,7 @@ func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) ( | ||||
| 	return res, nil | ||||
| } | ||||
| 
 | ||||
| // GetSender retrieves the public key from the Gdbm Db
 | ||||
| // GetSender returns the sessionId (phoneNumber)
 | ||||
| func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| 	var res resource.Result | ||||
| 
 | ||||
| @ -925,10 +922,7 @@ func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (res | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 
 | ||||
| 	store := h.userdataStore | ||||
| 	publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) | ||||
| 
 | ||||
| 	res.Content = string(publicKey) | ||||
| 	res.Content = string(sessionId) | ||||
| 
 | ||||
| 	return res, nil | ||||
| } | ||||
| @ -965,13 +959,12 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] | ||||
| 	// TODO
 | ||||
| 	// Use the amount, recipient and sender to call the API and initialize the transaction
 | ||||
| 	store := h.userdataStore | ||||
| 	publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) | ||||
| 
 | ||||
| 	amount, _ := store.ReadEntry(ctx, sessionId, utils.DATA_AMOUNT) | ||||
| 
 | ||||
| 	recipient, _ := store.ReadEntry(ctx, sessionId, utils.DATA_RECIPIENT) | ||||
| 
 | ||||
| 	res.Content = l.Get("Your request has been sent. %s will receive %s from %s.", string(recipient), string(amount), string(publicKey)) | ||||
| 	res.Content = l.Get("Your request has been sent. %s will receive %s from %s.", string(recipient), string(amount), string(sessionId)) | ||||
| 
 | ||||
| 	account_authorized_flag, err := h.flagManager.GetFlag("flag_account_authorized") | ||||
| 	if err != nil { | ||||
|  | ||||
| @ -21,6 +21,7 @@ import ( | ||||
| 
 | ||||
| 	"git.grassecon.net/urdt/ussd/internal/utils" | ||||
| 	"github.com/alecthomas/assert/v2" | ||||
| 	"github.com/grassrootseconomics/eth-custodial/pkg/api" | ||||
| 	testdataloader "github.com/peteole/testdata-loader" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
| @ -73,68 +74,74 @@ func TestCreateAccount(t *testing.T) { | ||||
| 	if err != nil { | ||||
| 		t.Logf(err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	// Create required mocks
 | ||||
| 	mockDataStore := new(mocks.MockUserDataStore) | ||||
| 	mockCreateAccountService := new(mocks.MockAccountService) | ||||
| 	expectedResult := resource.Result{} | ||||
| 	accountCreatedFlag, err := fm.GetFlag("flag_account_created") | ||||
| 
 | ||||
| 	flag_account_created, err := fm.GetFlag("flag_account_created") | ||||
| 	if err != nil { | ||||
| 		t.Logf(err.Error()) | ||||
| 	} | ||||
| 	expectedResult.FlagSet = append(expectedResult.FlagSet, accountCreatedFlag) | ||||
| 
 | ||||
| 	// Define session ID and mock data
 | ||||
| 	sessionId := "session123" | ||||
| 	typ := utils.DATA_ACCOUNT_CREATED | ||||
| 	fakeError := db.ErrNotFound{} | ||||
| 	// Create context with session ID
 | ||||
| 	notFoundErr := db.ErrNotFound{} | ||||
| 	ctx := context.WithValue(context.Background(), "SessionId", sessionId) | ||||
| 
 | ||||
| 	// Define expected interactions with the mock
 | ||||
| 	mockDataStore.On("ReadEntry", ctx, sessionId, typ).Return([]byte("123"), fakeError) | ||||
| 	expectedAccountResp := &models.AccountResponse{ | ||||
| 		Ok: true, | ||||
| 		Result: struct { | ||||
| 			CustodialId json.Number `json:"custodialId"` | ||||
| 			PublicKey   string      `json:"publicKey"` | ||||
| 			TrackingId  string      `json:"trackingId"` | ||||
| 		}{ | ||||
| 			CustodialId: "12", | ||||
| 			PublicKey:   "0x8E0XSCSVA", | ||||
| 			TrackingId:  "d95a7e83-196c-4fd0-866fSGAGA", | ||||
| 	tests := []struct { | ||||
| 		name           string | ||||
| 		serverResponse *api.OKResponse | ||||
| 		expectedResult resource.Result | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "Test account creation success", | ||||
| 			serverResponse: &api.OKResponse{ | ||||
| 				Ok:          true, | ||||
| 				Description: "Account creation successed", | ||||
| 				Result: map[string]any{ | ||||
| 					"trackingId": "1234567890", | ||||
| 					"publicKey":  "1235QERYU", | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectedResult: resource.Result{ | ||||
| 				FlagSet: []uint32{flag_account_created}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	mockCreateAccountService.On("CreateAccount").Return(expectedAccountResp, nil) | ||||
| 	data := map[utils.DataTyp]string{ | ||||
| 		utils.DATA_TRACKING_ID:  expectedAccountResp.Result.TrackingId, | ||||
| 		utils.DATA_PUBLIC_KEY:   expectedAccountResp.Result.PublicKey, | ||||
| 		utils.DATA_CUSTODIAL_ID: expectedAccountResp.Result.CustodialId.String(), | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 
 | ||||
| 			mockDataStore := new(mocks.MockUserDataStore) | ||||
| 			mockCreateAccountService := new(mocks.MockAccountService) | ||||
| 
 | ||||
| 			// Create a Handlers instance with the mock data store
 | ||||
| 			h := &Handlers{ | ||||
| 				userdataStore:  mockDataStore, | ||||
| 				accountService: mockCreateAccountService, | ||||
| 				flagManager:    fm.parser, | ||||
| 			} | ||||
| 
 | ||||
| 			data := map[utils.DataTyp]string{ | ||||
| 				utils.DATA_TRACKING_ID: tt.serverResponse.Result["trackingId"].(string), | ||||
| 				utils.DATA_PUBLIC_KEY:  tt.serverResponse.Result["publicKey"].(string), | ||||
| 			} | ||||
| 
 | ||||
| 			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACCOUNT_CREATED).Return([]byte(""), notFoundErr) | ||||
| 			mockCreateAccountService.On("CreateAccount").Return(tt.serverResponse, nil) | ||||
| 
 | ||||
| 			for key, value := range data { | ||||
| 				mockDataStore.On("WriteEntry", ctx, sessionId, key, []byte(value)).Return(nil) | ||||
| 			} | ||||
| 
 | ||||
| 			// Call the method you want to test
 | ||||
| 			res, err := h.CreateAccount(ctx, "create_account", []byte("some-input")) | ||||
| 
 | ||||
| 			// Assert that no errors occurred
 | ||||
| 			assert.NoError(t, err) | ||||
| 
 | ||||
| 			// Assert that the account created flag has been set to the result
 | ||||
| 			assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") | ||||
| 
 | ||||
| 			// Assert that expectations were met
 | ||||
| 			mockDataStore.AssertExpectations(t) | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	for key, value := range data { | ||||
| 		mockDataStore.On("WriteEntry", ctx, sessionId, key, []byte(value)).Return(nil) | ||||
| 	} | ||||
| 
 | ||||
| 	// Create a Handlers instance with the mock data store
 | ||||
| 	h := &Handlers{ | ||||
| 		userdataStore:  mockDataStore, | ||||
| 		accountService: mockCreateAccountService, | ||||
| 		flagManager:    fm.parser, | ||||
| 	} | ||||
| 
 | ||||
| 	// Call the method you want to test
 | ||||
| 	res, err := h.CreateAccount(ctx, "create_account", []byte("some-input")) | ||||
| 
 | ||||
| 	// Assert that no errors occurred
 | ||||
| 	assert.NoError(t, err) | ||||
| 
 | ||||
| 	//Assert that the account created flag has been set to the result
 | ||||
| 	assert.Equal(t, res, expectedResult, "Expected result should be equal to the actual result") | ||||
| 
 | ||||
| 	// Assert that expectations were met
 | ||||
| 	mockDataStore.AssertExpectations(t) | ||||
| } | ||||
| 
 | ||||
| func TestWithPersister(t *testing.T) { | ||||
| @ -510,12 +517,8 @@ func TestGetSender(t *testing.T) { | ||||
| 	mockStore := new(mocks.MockUserDataStore) | ||||
| 
 | ||||
| 	// Define test data
 | ||||
| 	sessionId := "session123" | ||||
| 	sessionId := "254712345678" | ||||
| 	ctx := context.WithValue(context.Background(), "SessionId", sessionId) | ||||
| 	publicKey := "0xcasgatweksalw1018221" | ||||
| 
 | ||||
| 	// Set up the expected behavior of the mock
 | ||||
| 	mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) | ||||
| 
 | ||||
| 	// Create the Handlers instance with the mock store
 | ||||
| 	h := &Handlers{ | ||||
| @ -523,11 +526,10 @@ func TestGetSender(t *testing.T) { | ||||
| 	} | ||||
| 
 | ||||
| 	// Call the method
 | ||||
| 	res, _ := h.GetSender(ctx, "max_amount", []byte("check_balance")) | ||||
| 
 | ||||
| 	//Assert that the public key from readentry operation  is what was set as the result content.
 | ||||
| 	assert.Equal(t, publicKey, res.Content) | ||||
| 	res, _ := h.GetSender(ctx, "get_sender", []byte("")) | ||||
| 
 | ||||
| 	//Assert that the sessionId is what was set as the result content.
 | ||||
| 	assert.Equal(t, sessionId, res.Content) | ||||
| } | ||||
| 
 | ||||
| func TestGetAmount(t *testing.T) { | ||||
| @ -1067,12 +1069,20 @@ func TestCheckAccountStatus(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name           string | ||||
| 		input          []byte | ||||
| 		serverResponse *api.OKResponse | ||||
| 		response       *models.TrackStatusResponse | ||||
| 		expectedResult resource.Result | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:  "Test when account status is Success", | ||||
| 			name:  "Test when account is on the Sarafu network", | ||||
| 			input: []byte("TrackingId1234"), | ||||
| 			serverResponse: &api.OKResponse{ | ||||
| 				Ok:          true, | ||||
| 				Description: "Account creation succeeded", | ||||
| 				Result: map[string]any{ | ||||
| 					"active": true, | ||||
| 				}, | ||||
| 			}, | ||||
| 			response: &models.TrackStatusResponse{ | ||||
| 				Ok: true, | ||||
| 				Result: struct { | ||||
| @ -1099,17 +1109,7 @@ func TestCheckAccountStatus(t *testing.T) { | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "Test when fetching  account status is not  Success", | ||||
| 			input: []byte("TrackingId1234"), | ||||
| 			response: &models.TrackStatusResponse{ | ||||
| 				Ok: false, | ||||
| 			}, | ||||
| 			expectedResult: resource.Result{ | ||||
| 				FlagSet: []uint32{flag_api_error}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "Test when checking account status api call is a SUCCESS but an account is not yet ready", | ||||
| 			name:  "Test when the account is not  yet on the sarafu network", | ||||
| 			input: []byte("TrackingId1234"), | ||||
| 			response: &models.TrackStatusResponse{ | ||||
| 				Ok: true, | ||||
| @ -1124,13 +1124,20 @@ func TestCheckAccountStatus(t *testing.T) { | ||||
| 				}{ | ||||
| 					Transaction: models.Transaction{ | ||||
| 						CreatedAt:     time.Now(), | ||||
| 						Status:        "IN_NETWORK", | ||||
| 						Status:        "SUCCESS", | ||||
| 						TransferValue: json.Number("0.5"), | ||||
| 						TxHash:        "0x123abc456def", | ||||
| 						TxType:        "transfer", | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			serverResponse: &api.OKResponse{ | ||||
| 				Ok:          true, | ||||
| 				Description: "Account creation succeeded", | ||||
| 				Result: map[string]any{ | ||||
| 					"active": false, | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectedResult: resource.Result{ | ||||
| 				FlagSet:   []uint32{flag_account_pending}, | ||||
| 				FlagReset: []uint32{flag_api_error, flag_account_success}, | ||||
| @ -1150,9 +1157,10 @@ func TestCheckAccountStatus(t *testing.T) { | ||||
| 
 | ||||
| 			status := tt.response.Result.Transaction.Status | ||||
| 			// Define expected interactions with the mock
 | ||||
| 			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TRACKING_ID).Return(tt.input, nil) | ||||
| 			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.input, nil) | ||||
| 
 | ||||
| 			mockCreateAccountService.On("CheckAccountStatus", string(tt.input)).Return(tt.response, nil) | ||||
| 			mockCreateAccountService.On("TrackAccountStatus", string(tt.input)).Return(tt.serverResponse, nil) | ||||
| 			mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_STATUS, []byte(status)).Return(nil).Maybe() | ||||
| 
 | ||||
| 			// Call the method under test
 | ||||
| @ -1285,7 +1293,7 @@ func TestResetInvalidAmount(t *testing.T) { | ||||
| } | ||||
| 
 | ||||
| func TestInitiateTransaction(t *testing.T) { | ||||
| 	sessionId := "session123" | ||||
| 	sessionId := "254712345678" | ||||
| 
 | ||||
| 	fm, err := NewFlagManager(flagsPath) | ||||
| 
 | ||||
| @ -1308,30 +1316,26 @@ func TestInitiateTransaction(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name           string | ||||
| 		input          []byte | ||||
| 		PublicKey      []byte | ||||
| 		Recipient      []byte | ||||
| 		Amount         []byte | ||||
| 		status         string | ||||
| 		expectedResult resource.Result | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:      "Test amount reset", | ||||
| 			PublicKey: []byte("0x1241527192"), | ||||
| 			Amount:    []byte("0.002CELO"), | ||||
| 			name:      "Test initiate transaction", | ||||
| 			Amount:    []byte("0.002 CELO"), | ||||
| 			Recipient: []byte("0x12415ass27192"), | ||||
| 			expectedResult: resource.Result{ | ||||
| 				FlagReset: []uint32{account_authorized_flag}, | ||||
| 				Content:   "Your request has been sent. 0x12415ass27192 will receive 0.002CELO from 0x1241527192.", | ||||
| 				Content:   "Your request has been sent. 0x12415ass27192 will receive 0.002 CELO from 254712345678.", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 			// Define expected interactions with the mock
 | ||||
| 			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.PublicKey, nil) | ||||
| 			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return(tt.Amount, nil) | ||||
| 			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_RECIPIENT).Return(tt.Recipient, nil) | ||||
| 			//mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, []byte("")).Return(nil)
 | ||||
| 
 | ||||
| 			// Call the method under test
 | ||||
| 			res, _ := h.InitiateTransaction(ctx, "transaction_reset_amount", tt.input) | ||||
| @ -1344,10 +1348,8 @@ func TestInitiateTransaction(t *testing.T) { | ||||
| 
 | ||||
| 			// Assert that expectations were met
 | ||||
| 			mockDataStore.AssertExpectations(t) | ||||
| 
 | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func TestQuit(t *testing.T) { | ||||
| @ -1626,7 +1628,6 @@ func TestValidateRecipient(t *testing.T) { | ||||
| } | ||||
| 
 | ||||
| func TestCheckBalance(t *testing.T) { | ||||
| 
 | ||||
| 	sessionId := "session123" | ||||
| 	publicKey := "0X13242618721" | ||||
| 	fm, _ := NewFlagManager(flagsPath) | ||||
| @ -1656,7 +1657,7 @@ func TestCheckBalance(t *testing.T) { | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "Test when checking a  balance is a success", | ||||
| 			name: "Test when checking a balance is a success", | ||||
| 			balanceResonse: &models.BalanceResponse{ | ||||
| 				Ok: true, | ||||
| 				Result: struct { | ||||
| @ -1668,7 +1669,7 @@ func TestCheckBalance(t *testing.T) { | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectedResult: resource.Result{ | ||||
| 				Content:   "0.003 CELO", | ||||
| 				Content:   "Balance: 0.003 CELO\n", | ||||
| 				FlagReset: []uint32{flag_api_error}, | ||||
| 			}, | ||||
| 		}, | ||||
| @ -1701,10 +1702,8 @@ func TestCheckBalance(t *testing.T) { | ||||
| 
 | ||||
| 			//Assert that the result set to content is what was expected
 | ||||
| 			assert.Equal(t, res, tt.expectedResult, "Result should contain flags set according to user input") | ||||
| 
 | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func TestGetProfile(t *testing.T) { | ||||
|  | ||||
| @ -1,15 +1,10 @@ | ||||
| package models | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 
 | ||||
| ) | ||||
| 
 | ||||
| type AccountResponse struct { | ||||
| 	Ok     bool `json:"ok"` | ||||
| 	Result struct { | ||||
| 		CustodialId json.Number `json:"custodialId"` | ||||
| 		PublicKey   string      `json:"publicKey"` | ||||
| 		TrackingId  string      `json:"trackingId"` | ||||
| 	Ok          bool   `json:"ok"` | ||||
| 	Description string `json:"description"` // Include the description field
 | ||||
| 	Result      struct { | ||||
| 		PublicKey  string `json:"publicKey"` | ||||
| 		TrackingId string `json:"trackingId"` | ||||
| 	} `json:"result"` | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -4,7 +4,6 @@ import ( | ||||
| 	"encoding/json" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| type Transaction struct { | ||||
| 	CreatedAt     time.Time   `json:"createdAt"` | ||||
| 	Status        string      `json:"status"` | ||||
|  | ||||
| @ -1,7 +1,10 @@ | ||||
| package mocks | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 
 | ||||
| 	"git.grassecon.net/urdt/ussd/internal/models" | ||||
| 	"github.com/grassrootseconomics/eth-custodial/pkg/api" | ||||
| 	"github.com/stretchr/testify/mock" | ||||
| ) | ||||
| 
 | ||||
| @ -10,17 +13,22 @@ type MockAccountService struct { | ||||
| 	mock.Mock | ||||
| } | ||||
| 
 | ||||
| func (m *MockAccountService) CreateAccount() (*models.AccountResponse, error) { | ||||
| func (m *MockAccountService) CreateAccount(ctx context.Context) (*api.OKResponse, error) { | ||||
| 	args := m.Called() | ||||
| 	return args.Get(0).(*models.AccountResponse), args.Error(1) | ||||
| 	return args.Get(0).(*api.OKResponse), args.Error(1) | ||||
| } | ||||
| 
 | ||||
| func (m *MockAccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { | ||||
| func (m *MockAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) { | ||||
| 	args := m.Called(publicKey) | ||||
| 	return args.Get(0).(*models.BalanceResponse), args.Error(1) | ||||
| } | ||||
| 
 | ||||
| func (m *MockAccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { | ||||
| func (m *MockAccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) { | ||||
| 	args := m.Called(trackingId) | ||||
| 	return args.Get(0).(*models.TrackStatusResponse), args.Error(1) | ||||
| } | ||||
| } | ||||
| 
 | ||||
| func (m *MockAccountService) TrackAccountStatus(ctx context.Context,publicKey string) (*api.OKResponse, error) { | ||||
| 	args := m.Called(publicKey) | ||||
| 	return args.Get(0).(*api.OKResponse), args.Error(1) | ||||
| } | ||||
|  | ||||
| @ -7,6 +7,8 @@ msgstr "Ombi lako limetumwa. %s atapokea %s kutoka kwa %s." | ||||
| msgid "Thank you for using Sarafu. Goodbye!" | ||||
| msgstr "Asante kwa kutumia huduma ya Sarafu. Kwaheri!" | ||||
| 
 | ||||
| 
 | ||||
| msgid "For more help,please call: 0757628885" | ||||
| msgstr "Kwa usaidizi zaidi,piga: 0757628885" | ||||
| 
 | ||||
| msgid "Balance: %s\n" | ||||
| msgstr "Salio: %s\n" | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Balance: {{.check_balance}} | ||||
| {{.check_balance}} | ||||
| @ -1 +1 @@ | ||||
| Salio: {{.check_balance}} | ||||
| {{.check_balance}} | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user