forked from grassrootseconomics/visedriver
		
	Merge pull request 'menu-api-errors' (#112) from menu-api-errors into master
Reviewed-on: urdt/ussd#112
This commit is contained in:
		
						commit
						e986eaa538
					
				| @ -87,7 +87,7 @@ func main() { | ||||
| 	cfg := engine.Config{ | ||||
| 		Root:       "root", | ||||
| 		OutputSize: uint32(size), | ||||
| 		FlagCount:  uint32(16), | ||||
| 		FlagCount:  uint32(128), | ||||
| 	} | ||||
| 
 | ||||
| 	if engineDebug { | ||||
|  | ||||
| @ -60,7 +60,7 @@ func main() { | ||||
| 	cfg := engine.Config{ | ||||
| 		Root:       "root", | ||||
| 		OutputSize: uint32(size), | ||||
| 		FlagCount:  uint32(16), | ||||
| 		FlagCount:  uint32(128), | ||||
| 	} | ||||
| 
 | ||||
| 	if engineDebug { | ||||
|  | ||||
| @ -48,7 +48,7 @@ func main() { | ||||
| 	cfg := engine.Config{ | ||||
| 		Root:       "root", | ||||
| 		OutputSize: uint32(size), | ||||
| 		FlagCount:  uint32(16), | ||||
| 		FlagCount:  uint32(128), | ||||
| 	} | ||||
| 
 | ||||
| 	if engineDebug { | ||||
|  | ||||
| @ -40,7 +40,7 @@ func main() { | ||||
| 		Root:       "root", | ||||
| 		SessionId:  sessionId, | ||||
| 		OutputSize: uint32(size), | ||||
| 		FlagCount:  uint32(16), | ||||
| 		FlagCount:  uint32(128), | ||||
| 	} | ||||
| 
 | ||||
| 	resourceDir := scriptDir | ||||
|  | ||||
| @ -82,7 +82,6 @@ func (ls *LocalHandlerService) GetHandler() (*ussd.Handlers, error) { | ||||
| 	ls.DbRs.AddLocalFunc("save_location", ussdHandlers.SaveLocation) | ||||
| 	ls.DbRs.AddLocalFunc("save_yob", ussdHandlers.SaveYob) | ||||
| 	ls.DbRs.AddLocalFunc("save_offerings", ussdHandlers.SaveOfferings) | ||||
| 	ls.DbRs.AddLocalFunc("quit_with_balance", ussdHandlers.QuitWithBalance) | ||||
| 	ls.DbRs.AddLocalFunc("reset_account_authorized", ussdHandlers.ResetAccountAuthorized) | ||||
| 	ls.DbRs.AddLocalFunc("reset_allow_update", ussdHandlers.ResetAllowUpdate) | ||||
| 	ls.DbRs.AddLocalFunc("get_profile_info", ussdHandlers.GetProfileInfo) | ||||
| @ -93,6 +92,7 @@ func (ls *LocalHandlerService) GetHandler() (*ussd.Handlers, error) { | ||||
| 	ls.DbRs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin) | ||||
| 	ls.DbRs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange) | ||||
| 	ls.DbRs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp) | ||||
| 	ls.DbRs.AddLocalFunc("fetch_custodial_balances", ussdHandlers.FetchCustodialBalances) | ||||
| 
 | ||||
| 	return ussdHandlers, nil | ||||
| } | ||||
|  | ||||
| @ -10,16 +10,14 @@ import ( | ||||
| ) | ||||
| 
 | ||||
| type AccountServiceInterface interface { | ||||
| 	CheckBalance(publicKey string) (string, error) | ||||
| 	CheckBalance(publicKey string) (*models.BalanceResponse, error) | ||||
| 	CreateAccount() (*models.AccountResponse, error) | ||||
| 	CheckAccountStatus(trackingId string) (string, error) | ||||
| 	CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) | ||||
| } | ||||
| 
 | ||||
| type AccountService struct { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // CheckAccountStatus retrieves the status of an account transaction based on the provided tracking ID.
 | ||||
| //
 | ||||
| // Parameters:
 | ||||
| @ -27,64 +25,51 @@ type AccountService struct { | ||||
| //     CreateAccount or a similar function that returns an AccountResponse. The `trackingId` field in the
 | ||||
| //     AccountResponse struct can be used here to check the account status during a transaction.
 | ||||
| //
 | ||||
| //
 | ||||
| // 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) (string, error) { | ||||
| func (as *AccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { | ||||
| 	resp, err := http.Get(config.TrackStatusURL + trackingId) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 
 | ||||
| 	body, err := io.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var trackResp models.TrackStatusResponse | ||||
| 	err = json.Unmarshal(body, &trackResp) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	status := trackResp.Result.Transaction.Status | ||||
| 
 | ||||
| 	return status, nil | ||||
| 	return &trackResp, 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) (string, error) { | ||||
| 
 | ||||
| func (as *AccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { | ||||
| 	resp, err := http.Get(config.BalanceURL + publicKey) | ||||
| 	if err != nil { | ||||
| 		return "0.0", err | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 
 | ||||
| 	body, err := io.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		return "0.0", err | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var balanceResp models.BalanceResponse | ||||
| 	err = json.Unmarshal(body, &balanceResp) | ||||
| 	if err != nil { | ||||
| 		return "0.0", err | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	balance := balanceResp.Result.Balance | ||||
| 	return balance, nil | ||||
| 	return &balanceResp, nil | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //CreateAccount creates a new account in the custodial system.
 | ||||
| // CreateAccount creates a new account in the custodial system.
 | ||||
| // Returns:
 | ||||
| //   - *models.AccountResponse: A pointer to an AccountResponse struct containing the details of the created account.
 | ||||
| //     If there is an error during the request or processing, this will be nil.
 | ||||
| @ -96,17 +81,14 @@ func (as *AccountService) CreateAccount() (*models.AccountResponse, 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 err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return &accountResp, nil | ||||
| } | ||||
|  | ||||
| @ -290,8 +290,6 @@ func (h *Handlers) VerifyPin(ctx context.Context, sym string, input []byte) (res | ||||
| 	if !ok { | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 
 | ||||
| 	//AccountPin, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_PIN)
 | ||||
| 	store := h.userdataStore | ||||
| 	AccountPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN) | ||||
| 	if err != nil { | ||||
| @ -525,9 +523,7 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res | ||||
| // ResetIncorrectPin resets the incorrect pin flag  after a new PIN attempt.
 | ||||
| func (h *Handlers) ResetIncorrectPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| 	var res resource.Result | ||||
| 
 | ||||
| 	flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin") | ||||
| 
 | ||||
| 	res.FlagReset = append(res.FlagReset, flag_incorrect_pin) | ||||
| 	return res, nil | ||||
| } | ||||
| @ -539,6 +535,7 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b | ||||
| 
 | ||||
| 	flag_account_success, _ := h.flagManager.GetFlag("flag_account_success") | ||||
| 	flag_account_pending, _ := h.flagManager.GetFlag("flag_account_pending") | ||||
| 	flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") | ||||
| 
 | ||||
| 	sessionId, ok := ctx.Value("SessionId").(string) | ||||
| 	if !ok { | ||||
| @ -550,18 +547,23 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	status, err := h.accountService.CheckAccountStatus(string(trackingId)) | ||||
| 	accountStatus, err := h.accountService.CheckAccountStatus(string(trackingId)) | ||||
| 	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 | ||||
| 	} | ||||
| 
 | ||||
| 	if status == "SUCCESS" { | ||||
| 	if accountStatus.Result.Transaction.Status == "SUCCESS" { | ||||
| 		res.FlagSet = append(res.FlagSet, flag_account_success) | ||||
| 		res.FlagReset = append(res.FlagReset, flag_account_pending) | ||||
| 	} else { | ||||
| @ -641,6 +643,8 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( | ||||
| 	var res resource.Result | ||||
| 	var err error | ||||
| 
 | ||||
| 	flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") | ||||
| 
 | ||||
| 	sessionId, ok := ctx.Value("SessionId").(string) | ||||
| 	if !ok { | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| @ -652,15 +656,60 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	balance, err := h.accountService.CheckBalance(string(publicKey)) | ||||
| 	balanceResponse, err := h.accountService.CheckBalance(string(publicKey)) | ||||
| 	if err != nil { | ||||
| 		return res, nil | ||||
| 	} | ||||
| 	if !balanceResponse.Ok { | ||||
| 		res.FlagSet = append(res.FlagSet, flag_api_error) | ||||
| 		return res, nil | ||||
| 	} | ||||
| 	res.FlagReset = append(res.FlagReset, flag_api_error) | ||||
| 	balance := balanceResponse.Result.Balance | ||||
| 	res.Content = balance | ||||
| 
 | ||||
| 	return res, nil | ||||
| } | ||||
| 
 | ||||
| func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| 	var res resource.Result | ||||
| 	flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") | ||||
| 
 | ||||
| 	sessionId, ok := ctx.Value("SessionId").(string) | ||||
| 	if !ok { | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 	symbol, _ := h.st.Where() | ||||
| 	balanceType := strings.Split(symbol, "_")[0] | ||||
| 
 | ||||
| 	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)) | ||||
| 	if err != nil { | ||||
| 		return res, nil | ||||
| 	} | ||||
| 	if !balanceResponse.Ok { | ||||
| 		res.FlagSet = append(res.FlagSet, flag_api_error) | ||||
| 		return res, nil | ||||
| 	} | ||||
| 	res.FlagReset = append(res.FlagReset, flag_api_error) | ||||
| 	balance := balanceResponse.Result.Balance | ||||
| 
 | ||||
| 	switch balanceType { | ||||
| 	case "my": | ||||
| 		res.Content = fmt.Sprintf("Your balance is %s", balance) | ||||
| 	case "community": | ||||
| 		res.Content = fmt.Sprintf("Your community balance is %s", balance) | ||||
| 	default: | ||||
| 		break | ||||
| 	} | ||||
| 	return res, nil | ||||
| } | ||||
| 
 | ||||
| // ValidateRecipient validates that the given input is a valid phone number.
 | ||||
| func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| 	var res resource.Result | ||||
| @ -757,10 +806,11 @@ func (h *Handlers) MaxAmount(ctx context.Context, sym string, input []byte) (res | ||||
| 	store := h.userdataStore | ||||
| 	publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) | ||||
| 
 | ||||
| 	balance, err := h.accountService.CheckBalance(string(publicKey)) | ||||
| 	balanceResp, err := h.accountService.CheckBalance(string(publicKey)) | ||||
| 	if err != nil { | ||||
| 		return res, nil | ||||
| 	} | ||||
| 	balance := balanceResp.Result.Balance | ||||
| 
 | ||||
| 	res.Content = balance | ||||
| 
 | ||||
| @ -779,18 +829,25 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) | ||||
| 	} | ||||
| 
 | ||||
| 	flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") | ||||
| 	flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") | ||||
| 
 | ||||
| 	store := h.userdataStore | ||||
| 	publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) | ||||
| 
 | ||||
| 	amountStr := string(input) | ||||
| 
 | ||||
| 	balanceStr, err := h.accountService.CheckBalance(string(publicKey)) | ||||
| 	balanceRes, err := h.accountService.CheckBalance(string(publicKey)) | ||||
| 	balanceStr := balanceRes.Result.Balance | ||||
| 
 | ||||
| 	if !balanceRes.Ok { | ||||
| 		res.FlagSet = append(res.FlagSet, flag_api_error) | ||||
| 		return res, nil | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return res, err | ||||
| 	} | ||||
| 	res.Content = balanceStr | ||||
| 	res.FlagReset = append(res.FlagReset, flag_api_error) | ||||
| 
 | ||||
| 	// Parse the balance
 | ||||
| 	balanceParts := strings.Split(balanceStr, " ") | ||||
| @ -882,36 +939,6 @@ func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (res | ||||
| 	return res, nil | ||||
| } | ||||
| 
 | ||||
| // QuickWithBalance retrieves the balance for a given public key from the custodial balance API endpoint before
 | ||||
| // gracefully exiting the session.
 | ||||
| func (h *Handlers) QuitWithBalance(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_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") | ||||
| 
 | ||||
| 	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 | ||||
| 	} | ||||
| 	balance, err := h.accountService.CheckBalance(string(publicKey)) | ||||
| 	if err != nil { | ||||
| 		return res, nil | ||||
| 	} | ||||
| 	res.Content = l.Get("Your account balance is %s", balance) | ||||
| 	res.FlagReset = append(res.FlagReset, flag_account_authorized) | ||||
| 	return res, nil | ||||
| } | ||||
| 
 | ||||
| // InitiateTransaction returns a confirmation and resets the transaction data
 | ||||
| // on the gdbm store.
 | ||||
| func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| @ -945,16 +972,23 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] | ||||
| 	return res, nil | ||||
| } | ||||
| 
 | ||||
| // GetProfileInfo retrieves and formats the profile information of a user from a Gdbm backed storage.
 | ||||
| func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| 	var res resource.Result | ||||
| 	var defaultValue string | ||||
| 	sessionId, ok := ctx.Value("SessionId").(string) | ||||
| 	if !ok { | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 
 | ||||
| 	// Default value when an entry is not found
 | ||||
| 	defaultValue := "Not Provided" | ||||
| 	language, ok := ctx.Value("Language").(lang.Language) | ||||
| 	if !ok { | ||||
| 		return res, fmt.Errorf("value for 'Language' is not of type lang.Language") | ||||
| 	} | ||||
| 	code := language.Code | ||||
| 	if code == "swa" { | ||||
| 		defaultValue = "Haipo" | ||||
| 	} else { | ||||
| 		defaultValue = "Not Provided" | ||||
| 	} | ||||
| 
 | ||||
| 	// Helper function to handle nil byte slices and convert them to string
 | ||||
| 	getEntryOrDefault := func(entry []byte, err error) string { | ||||
| @ -991,12 +1025,23 @@ func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) | ||||
| 			return res, fmt.Errorf("invalid year of birth: %v", err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Format the result
 | ||||
| 	res.Content = fmt.Sprintf( | ||||
| 		"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", | ||||
| 		name, gender, age, location, offerings, | ||||
| 	) | ||||
| 	switch language.Code { | ||||
| 	case "eng": | ||||
| 		res.Content = fmt.Sprintf( | ||||
| 			"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", | ||||
| 			name, gender, age, location, offerings, | ||||
| 		) | ||||
| 	case "swa": | ||||
| 		res.Content = fmt.Sprintf( | ||||
| 			"Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\n", | ||||
| 			name, gender, age, location, offerings, | ||||
| 		) | ||||
| 	default: | ||||
| 		res.Content = fmt.Sprintf( | ||||
| 			"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", | ||||
| 			name, gender, age, location, offerings, | ||||
| 		) | ||||
| 	} | ||||
| 
 | ||||
| 	return res, nil | ||||
| } | ||||
|  | ||||
| @ -7,8 +7,11 @@ import ( | ||||
| 	"log" | ||||
| 	"path" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"git.defalsify.org/vise.git/asm" | ||||
| 	"git.defalsify.org/vise.git/db" | ||||
| 	"git.defalsify.org/vise.git/lang" | ||||
| 	"git.defalsify.org/vise.git/persist" | ||||
| 	"git.defalsify.org/vise.git/resource" | ||||
| 	"git.defalsify.org/vise.git/state" | ||||
| @ -25,10 +28,53 @@ var ( | ||||
| 	flagsPath = path.Join(baseDir, "services", "registration", "pp.csv") | ||||
| ) | ||||
| 
 | ||||
| func TestCreateAccount(t *testing.T) { | ||||
| type Transaction struct { | ||||
| 	CreatedAt     time.Time   `json:"createdAt"` | ||||
| 	Status        string      `json:"status"` | ||||
| 	TransferValue json.Number `json:"transferValue"` | ||||
| 	TxHash        string      `json:"txHash"` | ||||
| 	TxType        string      `json:"txType"` | ||||
| } | ||||
| 
 | ||||
| func TestNewHandlers(t *testing.T) { | ||||
| 	fm, err := NewFlagManager(flagsPath) | ||||
| 	if err != nil { | ||||
| 		t.Logf(err.Error()) | ||||
| 	} | ||||
| 	t.Run("Valid UserDataStore", func(t *testing.T) { | ||||
| 		mockStore := &mocks.MockUserDataStore{} | ||||
| 		handlers, err := NewHandlers(fm.parser, mockStore) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("expected no error, got %v", err) | ||||
| 		} | ||||
| 		if handlers == nil { | ||||
| 			t.Fatal("expected handlers to be non-nil") | ||||
| 		} | ||||
| 		if handlers.userdataStore == nil { | ||||
| 			t.Fatal("expected userdataStore to be set in handlers") | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	// Test case for nil userdataStore
 | ||||
| 	t.Run("Nil UserDataStore", func(t *testing.T) { | ||||
| 		appFlags := &asm.FlagParser{} | ||||
| 
 | ||||
| 		handlers, err := NewHandlers(appFlags, nil) | ||||
| 
 | ||||
| 		if err == nil { | ||||
| 			t.Fatal("expected an error, got none") | ||||
| 		} | ||||
| 		if handlers != nil { | ||||
| 			t.Fatal("expected handlers to be nil") | ||||
| 		} | ||||
| 		if err.Error() != "cannot create handler with nil userdata store" { | ||||
| 			t.Fatalf("expected specific error, got %v", err) | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestCreateAccount(t *testing.T) { | ||||
| 	fm, err := NewFlagManager(flagsPath) | ||||
| 	if err != nil { | ||||
| 		t.Logf(err.Error()) | ||||
| 	} | ||||
| @ -442,7 +488,10 @@ func TestMaxAmount(t *testing.T) { | ||||
| 	sessionId := "session123" | ||||
| 	ctx := context.WithValue(context.Background(), "SessionId", sessionId) | ||||
| 	publicKey := "0xcasgatweksalw1018221" | ||||
| 	expectedBalance := "0.003CELO" | ||||
| 
 | ||||
| 	expectedBalance := &models.BalanceResponse{ | ||||
| 		Ok: true, | ||||
| 	} | ||||
| 
 | ||||
| 	// Set up the expected behavior of the mock
 | ||||
| 	mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) | ||||
| @ -458,7 +507,7 @@ func TestMaxAmount(t *testing.T) { | ||||
| 	res, _ := h.MaxAmount(ctx, "max_amount", []byte("check_balance")) | ||||
| 
 | ||||
| 	//Assert that the balance that was set as the result content is what was returned by  Check Balance
 | ||||
| 	assert.Equal(t, expectedBalance, res.Content) | ||||
| 	assert.Equal(t, expectedBalance.Result.Balance, res.Content) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| @ -537,12 +586,10 @@ func TestGetRecipient(t *testing.T) { | ||||
| func TestGetFlag(t *testing.T) { | ||||
| 	fm, err := NewFlagManager(flagsPath) | ||||
| 	expectedFlag := uint32(9) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		t.Logf(err.Error()) | ||||
| 	} | ||||
| 	flag, err := fm.GetFlag("flag_account_created") | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		t.Logf(err.Error()) | ||||
| 	} | ||||
| @ -1012,53 +1059,109 @@ func TestVerifyPin(t *testing.T) { | ||||
| 
 | ||||
| func TestCheckAccountStatus(t *testing.T) { | ||||
| 	fm, err := NewFlagManager(flagsPath) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		t.Logf(err.Error()) | ||||
| 	} | ||||
| 	mockDataStore := new(mocks.MockUserDataStore) | ||||
| 	mockCreateAccountService := new(mocks.MockAccountService) | ||||
| 
 | ||||
| 	sessionId := "session123" | ||||
| 	flag_account_success, _ := fm.GetFlag("flag_account_success") | ||||
| 	flag_account_pending, _ := fm.GetFlag("flag_account_pending") | ||||
| 	flag_api_error, _ := fm.GetFlag("flag_api_call_error") | ||||
| 
 | ||||
| 	ctx := context.WithValue(context.Background(), "SessionId", sessionId) | ||||
| 
 | ||||
| 	h := &Handlers{ | ||||
| 		userdataStore:  mockDataStore, | ||||
| 		accountService: mockCreateAccountService, | ||||
| 		flagManager:    fm.parser, | ||||
| 	} | ||||
| 	tests := []struct { | ||||
| 		name           string | ||||
| 		input          []byte | ||||
| 		status         string | ||||
| 		response       *models.TrackStatusResponse | ||||
| 		expectedResult resource.Result | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:   "Test when account status is Success", | ||||
| 			input:  []byte("TrackingId1234"), | ||||
| 			status: "SUCCESS", | ||||
| 			name:  "Test when account status is Success", | ||||
| 			input: []byte("TrackingId1234"), | ||||
| 			response: &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: Transaction{ | ||||
| 						CreatedAt:     time.Now(), | ||||
| 						Status:        "SUCCESS", | ||||
| 						TransferValue: json.Number("0.5"), | ||||
| 						TxHash:        "0x123abc456def", | ||||
| 						TxType:        "transfer", | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectedResult: resource.Result{ | ||||
| 				FlagSet:   []uint32{flag_account_success}, | ||||
| 				FlagReset: []uint32{flag_account_pending}, | ||||
| 				FlagReset: []uint32{flag_api_error, flag_account_pending}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			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", | ||||
| 			input: []byte("TrackingId1234"), | ||||
| 			response: &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: Transaction{ | ||||
| 						CreatedAt:     time.Now(), | ||||
| 						Status:        "IN_NETWORK", | ||||
| 						TransferValue: json.Number("0.5"), | ||||
| 						TxHash:        "0x123abc456def", | ||||
| 						TxType:        "transfer", | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectedResult: resource.Result{ | ||||
| 				FlagSet:   []uint32{flag_account_pending}, | ||||
| 				FlagReset: []uint32{flag_api_error, flag_account_success}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	typ := utils.DATA_TRACKING_ID | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 			mockDataStore := new(mocks.MockUserDataStore) | ||||
| 			mockCreateAccountService := new(mocks.MockAccountService) | ||||
| 
 | ||||
| 			h := &Handlers{ | ||||
| 				userdataStore:  mockDataStore, | ||||
| 				accountService: mockCreateAccountService, | ||||
| 				flagManager:    fm.parser, | ||||
| 			} | ||||
| 
 | ||||
| 			status := tt.response.Result.Transaction.Status | ||||
| 			// Define expected interactions with the mock
 | ||||
| 			mockDataStore.On("ReadEntry", ctx, sessionId, typ).Return(tt.input, nil) | ||||
| 			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TRACKING_ID).Return(tt.input, nil) | ||||
| 
 | ||||
| 			mockCreateAccountService.On("CheckAccountStatus", string(tt.input)).Return(tt.status, nil) | ||||
| 			mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_STATUS, []byte(tt.status)).Return(nil) | ||||
| 			mockCreateAccountService.On("CheckAccountStatus", string(tt.input)).Return(tt.response, nil) | ||||
| 			mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_STATUS, []byte(status)).Return(nil).Maybe() | ||||
| 
 | ||||
| 			// Call the method under test
 | ||||
| 			res, _ := h.CheckAccountStatus(ctx, "check_status", tt.input) | ||||
| 			res, _ := h.CheckAccountStatus(ctx, "check_account_status", tt.input) | ||||
| 
 | ||||
| 			// Assert that no errors occurred
 | ||||
| 			assert.NoError(t, err) | ||||
| @ -1358,66 +1461,6 @@ func TestIsValidPIN(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestQuitWithBalance(t *testing.T) { | ||||
| 	fm, err := NewFlagManager(flagsPath) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		t.Logf(err.Error()) | ||||
| 	} | ||||
| 	flag_account_authorized, _ := fm.parser.GetFlag("flag_account_authorized") | ||||
| 
 | ||||
| 	mockDataStore := new(mocks.MockUserDataStore) | ||||
| 	mockCreateAccountService := new(mocks.MockAccountService) | ||||
| 
 | ||||
| 	sessionId := "session123" | ||||
| 
 | ||||
| 	ctx := context.WithValue(context.Background(), "SessionId", sessionId) | ||||
| 
 | ||||
| 	h := &Handlers{ | ||||
| 		userdataStore:  mockDataStore, | ||||
| 		accountService: mockCreateAccountService, | ||||
| 		flagManager:    fm.parser, | ||||
| 	} | ||||
| 	tests := []struct { | ||||
| 		name           string | ||||
| 		input          []byte | ||||
| 		publicKey      []byte | ||||
| 		balance        string | ||||
| 		expectedResult resource.Result | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:      "Test quit with balance", | ||||
| 			balance:   "0.02CELO", | ||||
| 			publicKey: []byte("0xrqeqrequuq"), | ||||
| 			expectedResult: resource.Result{ | ||||
| 				FlagReset: []uint32{flag_account_authorized}, | ||||
| 				Content:   fmt.Sprintf("Your account balance is %s", "0.02CELO"), | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 
 | ||||
| 			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.publicKey, nil) | ||||
| 			mockCreateAccountService.On("CheckBalance", string(tt.publicKey)).Return(tt.balance, nil) | ||||
| 
 | ||||
| 			// Call the method under test
 | ||||
| 			res, _ := h.QuitWithBalance(ctx, "test_quit_with_balance", tt.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) | ||||
| 
 | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestValidateAmount(t *testing.T) { | ||||
| 	fm, err := NewFlagManager(flagsPath) | ||||
| 
 | ||||
| @ -1425,6 +1468,7 @@ func TestValidateAmount(t *testing.T) { | ||||
| 		t.Logf(err.Error()) | ||||
| 	} | ||||
| 	flag_invalid_amount, _ := fm.parser.GetFlag("flag_invalid_amount") | ||||
| 	flag_api_error, _ := fm.GetFlag("flag_api_call_error") | ||||
| 	mockDataStore := new(mocks.MockUserDataStore) | ||||
| 	mockCreateAccountService := new(mocks.MockAccountService) | ||||
| 
 | ||||
| @ -1438,39 +1482,69 @@ func TestValidateAmount(t *testing.T) { | ||||
| 		flagManager:    fm.parser, | ||||
| 	} | ||||
| 	tests := []struct { | ||||
| 		name           string | ||||
| 		input          []byte | ||||
| 		publicKey      []byte | ||||
| 		balance        string | ||||
| 		expectedResult resource.Result | ||||
| 		name            string | ||||
| 		input           []byte | ||||
| 		publicKey       []byte | ||||
| 		balanceResponse *models.BalanceResponse | ||||
| 		expectedResult  resource.Result | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:      "Test with valid amount", | ||||
| 			input:     []byte("0.001"), | ||||
| 			balance:   "0.003 CELO", | ||||
| 			name:  "Test with valid amount", | ||||
| 			input: []byte("0.001"), | ||||
| 			balanceResponse: &models.BalanceResponse{ | ||||
| 				Ok: true, | ||||
| 				Result: struct { | ||||
| 					Balance string      `json:"balance"` | ||||
| 					Nonce   json.Number `json:"nonce"` | ||||
| 				}{ | ||||
| 					Balance: "0.003 CELO", | ||||
| 					Nonce:   json.Number("0"), | ||||
| 				}, | ||||
| 			}, | ||||
| 			publicKey: []byte("0xrqeqrequuq"), | ||||
| 			expectedResult: resource.Result{ | ||||
| 				Content: "0.001", | ||||
| 				Content:   "0.001", | ||||
| 				FlagReset: []uint32{flag_api_error}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "Test with amount larger than balance", | ||||
| 			input:     []byte("0.02"), | ||||
| 			balance:   "0.003 CELO", | ||||
| 			name:  "Test with amount larger than balance", | ||||
| 			input: []byte("0.02"), | ||||
| 			balanceResponse: &models.BalanceResponse{ | ||||
| 				Ok: true, | ||||
| 				Result: struct { | ||||
| 					Balance string      `json:"balance"` | ||||
| 					Nonce   json.Number `json:"nonce"` | ||||
| 				}{ | ||||
| 					Balance: "0.003 CELO", | ||||
| 					Nonce:   json.Number("0"), | ||||
| 				}, | ||||
| 			}, | ||||
| 			publicKey: []byte("0xrqeqrequuq"), | ||||
| 			expectedResult: resource.Result{ | ||||
| 				FlagSet: []uint32{flag_invalid_amount}, | ||||
| 				Content: "0.02", | ||||
| 				FlagSet:   []uint32{flag_invalid_amount}, | ||||
| 				FlagReset: []uint32{flag_api_error}, | ||||
| 				Content:   "0.02", | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "Test with invalid amount", | ||||
| 			input:     []byte("0.02ms"), | ||||
| 			balance:   "0.003 CELO", | ||||
| 			name:  "Test with invalid amount", | ||||
| 			input: []byte("0.02ms"), | ||||
| 			balanceResponse: &models.BalanceResponse{ | ||||
| 				Ok: true, | ||||
| 				Result: struct { | ||||
| 					Balance string      `json:"balance"` | ||||
| 					Nonce   json.Number `json:"nonce"` | ||||
| 				}{ | ||||
| 					Balance: "0.003 CELO", | ||||
| 					Nonce:   json.Number("0"), | ||||
| 				}, | ||||
| 			}, | ||||
| 			publicKey: []byte("0xrqeqrequuq"), | ||||
| 			expectedResult: resource.Result{ | ||||
| 				FlagSet: []uint32{flag_invalid_amount}, | ||||
| 				Content: "0.02ms", | ||||
| 				FlagSet:   []uint32{flag_invalid_amount}, | ||||
| 				FlagReset: []uint32{flag_api_error}, | ||||
| 				Content:   "0.02ms", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| @ -1479,7 +1553,7 @@ func TestValidateAmount(t *testing.T) { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 
 | ||||
| 			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.publicKey, nil) | ||||
| 			mockCreateAccountService.On("CheckBalance", string(tt.publicKey)).Return(tt.balance, nil) | ||||
| 			mockCreateAccountService.On("CheckBalance", string(tt.publicKey)).Return(tt.balanceResponse, nil) | ||||
| 			mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, tt.input).Return(nil).Maybe() | ||||
| 
 | ||||
| 			// Call the method under test
 | ||||
| @ -1558,31 +1632,83 @@ func TestValidateRecipient(t *testing.T) { | ||||
| 
 | ||||
| func TestCheckBalance(t *testing.T) { | ||||
| 
 | ||||
| 	mockDataStore := new(mocks.MockUserDataStore) | ||||
| 	sessionId := "session123" | ||||
| 	publicKey := "0X13242618721" | ||||
| 	balance := "0.003 CELO" | ||||
| 
 | ||||
| 	expectedResult := resource.Result{ | ||||
| 		Content: "0.003 CELO", | ||||
| 	} | ||||
| 
 | ||||
| 	mockCreateAccountService := new(mocks.MockAccountService) | ||||
| 	fm, _ := NewFlagManager(flagsPath) | ||||
| 	flag_api_error, _ := fm.GetFlag("flag_api_call_error") | ||||
| 
 | ||||
| 	ctx := context.WithValue(context.Background(), "SessionId", sessionId) | ||||
| 
 | ||||
| 	h := &Handlers{ | ||||
| 		userdataStore:  mockDataStore, | ||||
| 		accountService: mockCreateAccountService, | ||||
| 		//flagManager:    fm.parser,
 | ||||
| 	tests := []struct { | ||||
| 		name           string | ||||
| 		balanceResonse *models.BalanceResponse | ||||
| 		expectedResult resource.Result | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "Test when checking a balance is not a success", | ||||
| 			balanceResonse: &models.BalanceResponse{ | ||||
| 				Ok: false, | ||||
| 				Result: struct { | ||||
| 					Balance string      `json:"balance"` | ||||
| 					Nonce   json.Number `json:"nonce"` | ||||
| 				}{ | ||||
| 					Balance: "0.003 CELO", | ||||
| 					Nonce:   json.Number("0"), | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectedResult: resource.Result{ | ||||
| 				FlagSet: []uint32{flag_api_error}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "Test when checking a  balance is a success", | ||||
| 			balanceResonse: &models.BalanceResponse{ | ||||
| 				Ok: true, | ||||
| 				Result: struct { | ||||
| 					Balance string      `json:"balance"` | ||||
| 					Nonce   json.Number `json:"nonce"` | ||||
| 				}{ | ||||
| 					Balance: "0.003 CELO", | ||||
| 					Nonce:   json.Number("0"), | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectedResult: resource.Result{ | ||||
| 				Content:   "0.003 CELO", | ||||
| 				FlagReset: []uint32{flag_api_error}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	//mock call operations
 | ||||
| 	mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) | ||||
| 	mockCreateAccountService.On("CheckBalance", string(publicKey)).Return(balance, nil) | ||||
| 
 | ||||
| 	res, _ := h.CheckBalance(ctx, "check_balance", []byte("123456")) | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 
 | ||||
| 	assert.Equal(t, res, expectedResult, "Result should contain flag(s) that have been reset") | ||||
| 			mockDataStore := new(mocks.MockUserDataStore) | ||||
| 			mockCreateAccountService := new(mocks.MockAccountService) | ||||
| 			mockState := state.NewState(16) | ||||
| 
 | ||||
| 			// Create the Handlers instance with the mock store
 | ||||
| 			h := &Handlers{ | ||||
| 				userdataStore:  mockDataStore, | ||||
| 				flagManager:    fm.parser, | ||||
| 				st:             mockState, | ||||
| 				accountService: mockCreateAccountService, | ||||
| 			} | ||||
| 
 | ||||
| 			// Set up the expected behavior of the mock
 | ||||
| 			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) | ||||
| 			mockCreateAccountService.On("CheckBalance", string(publicKey)).Return(tt.balanceResonse, nil) | ||||
| 
 | ||||
| 			// Call the method
 | ||||
| 			res, _ := h.CheckBalance(ctx, "check_balance", []byte("")) | ||||
| 
 | ||||
| 			// Assert that expectations were met
 | ||||
| 			mockDataStore.AssertExpectations(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") | ||||
| 
 | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| @ -1592,23 +1718,50 @@ func TestGetProfile(t *testing.T) { | ||||
| 
 | ||||
| 	mockDataStore := new(mocks.MockUserDataStore) | ||||
| 	mockCreateAccountService := new(mocks.MockAccountService) | ||||
| 	mockState := state.NewState(16) | ||||
| 
 | ||||
| 	h := &Handlers{ | ||||
| 		userdataStore:  mockDataStore, | ||||
| 		accountService: mockCreateAccountService, | ||||
| 		st:             mockState, | ||||
| 	} | ||||
| 	ctx := context.WithValue(context.Background(), "SessionId", sessionId) | ||||
| 
 | ||||
| 	tests := []struct { | ||||
| 		name        string | ||||
| 		keys        []utils.DataTyp | ||||
| 		profileInfo []string | ||||
| 		result      resource.Result | ||||
| 		name         string | ||||
| 		languageCode string | ||||
| 		keys         []utils.DataTyp | ||||
| 		profileInfo  []string | ||||
| 		result       resource.Result | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:        "Test with full profile information", | ||||
| 			keys:        []utils.DataTyp{utils.DATA_FAMILY_NAME, utils.DATA_FIRST_NAME, utils.DATA_GENDER, utils.DATA_OFFERINGS, utils.DATA_LOCATION, utils.DATA_YOB}, | ||||
| 			profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, | ||||
| 			name:         "Test with full profile information in eng", | ||||
| 			keys:         []utils.DataTyp{utils.DATA_FAMILY_NAME, utils.DATA_FIRST_NAME, utils.DATA_GENDER, utils.DATA_OFFERINGS, utils.DATA_LOCATION, utils.DATA_YOB}, | ||||
| 			profileInfo:  []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, | ||||
| 			languageCode: "eng", | ||||
| 			result: resource.Result{ | ||||
| 				Content: fmt.Sprintf( | ||||
| 					"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", | ||||
| 					"John Doee", "Male", "48", "Kilifi", "Bananas", | ||||
| 				), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:         "Test with with profile information in swa ", | ||||
| 			keys:         []utils.DataTyp{utils.DATA_FAMILY_NAME, utils.DATA_FIRST_NAME, utils.DATA_GENDER, utils.DATA_OFFERINGS, utils.DATA_LOCATION, utils.DATA_YOB}, | ||||
| 			profileInfo:  []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, | ||||
| 			languageCode: "swa", | ||||
| 			result: resource.Result{ | ||||
| 				Content: fmt.Sprintf( | ||||
| 					"Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\n", | ||||
| 					"John Doee", "Male", "48", "Kilifi", "Bananas", | ||||
| 				), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:         "Test with with profile information with language that is not yet supported", | ||||
| 			keys:         []utils.DataTyp{utils.DATA_FAMILY_NAME, utils.DATA_FIRST_NAME, utils.DATA_GENDER, utils.DATA_OFFERINGS, utils.DATA_LOCATION, utils.DATA_YOB}, | ||||
| 			profileInfo:  []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, | ||||
| 			languageCode: "nor", | ||||
| 			result: resource.Result{ | ||||
| 				Content: fmt.Sprintf( | ||||
| 					"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", | ||||
| @ -1619,9 +1772,14 @@ func TestGetProfile(t *testing.T) { | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 			ctx := context.WithValue(context.Background(), "SessionId", sessionId) | ||||
| 			ctx = context.WithValue(ctx, "Language", lang.Language{ | ||||
| 				Code: tt.languageCode, | ||||
| 			}) | ||||
| 			for index, key := range tt.keys { | ||||
| 				mockDataStore.On("ReadEntry", ctx, sessionId, key).Return([]byte(tt.profileInfo[index]), nil) | ||||
| 				mockDataStore.On("ReadEntry", ctx, sessionId, key).Return([]byte(tt.profileInfo[index]), nil).Maybe() | ||||
| 			} | ||||
| 
 | ||||
| 			res, _ := h.GetProfileInfo(ctx, "get_profile_info", []byte("")) | ||||
| 
 | ||||
| 			// Assert that expectations were met
 | ||||
| @ -1778,3 +1936,85 @@ func TestConfirmPin(t *testing.T) { | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func TestFetchCustodialBalances(t *testing.T) { | ||||
| 	fm, err := NewFlagManager(flagsPath) | ||||
| 	if err != nil { | ||||
| 		t.Logf(err.Error()) | ||||
| 	} | ||||
| 	flag_api_error, _ := fm.GetFlag("flag_api_call_error") | ||||
| 
 | ||||
| 	// Define test data
 | ||||
| 	sessionId := "session123" | ||||
| 	publicKey := "0X13242618721" | ||||
| 	ctx := context.WithValue(context.Background(), "SessionId", sessionId) | ||||
| 
 | ||||
| 	tests := []struct { | ||||
| 		name           string | ||||
| 		balanceResonse *models.BalanceResponse | ||||
| 		expectedResult resource.Result | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "Test when fetch custodial balances is not a success", | ||||
| 			balanceResonse: &models.BalanceResponse{ | ||||
| 				Ok: false, | ||||
| 				Result: struct { | ||||
| 					Balance string      `json:"balance"` | ||||
| 					Nonce   json.Number `json:"nonce"` | ||||
| 				}{ | ||||
| 					Balance: "0.003 CELO", | ||||
| 					Nonce:   json.Number("0"), | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectedResult: resource.Result{ | ||||
| 				FlagSet: []uint32{flag_api_error}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "Test when fetch custodial balances is a success", | ||||
| 			balanceResonse: &models.BalanceResponse{ | ||||
| 				Ok: true, | ||||
| 				Result: struct { | ||||
| 					Balance string      `json:"balance"` | ||||
| 					Nonce   json.Number `json:"nonce"` | ||||
| 				}{ | ||||
| 					Balance: "0.003 CELO", | ||||
| 					Nonce:   json.Number("0"), | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectedResult: resource.Result{ | ||||
| 				FlagReset: []uint32{flag_api_error}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 
 | ||||
| 			mockDataStore := new(mocks.MockUserDataStore) | ||||
| 			mockCreateAccountService := new(mocks.MockAccountService) | ||||
| 			mockState := state.NewState(16) | ||||
| 
 | ||||
| 			// Create the Handlers instance with the mock store
 | ||||
| 			h := &Handlers{ | ||||
| 				userdataStore:  mockDataStore, | ||||
| 				flagManager:    fm.parser, | ||||
| 				st:             mockState, | ||||
| 				accountService: mockCreateAccountService, | ||||
| 			} | ||||
| 
 | ||||
| 			// Set up the expected behavior of the mock
 | ||||
| 			mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) | ||||
| 			mockCreateAccountService.On("CheckBalance", string(publicKey)).Return(tt.balanceResonse, nil) | ||||
| 
 | ||||
| 			// Call the method
 | ||||
| 			res, _ := h.FetchCustodialBalances(ctx, "fetch_custodial_balances", []byte("")) | ||||
| 
 | ||||
| 			// Assert that expectations were met
 | ||||
| 			mockDataStore.AssertExpectations(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") | ||||
| 
 | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -15,12 +15,12 @@ func (m *MockAccountService) CreateAccount() (*models.AccountResponse, error) { | ||||
| 	return args.Get(0).(*models.AccountResponse), args.Error(1) | ||||
| } | ||||
| 
 | ||||
| func (m *MockAccountService) CheckBalance(publicKey string) (string, error) { | ||||
| func (m *MockAccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { | ||||
| 	args := m.Called(publicKey) | ||||
| 	return args.String(0), args.Error(1) | ||||
| 	return args.Get(0).(*models.BalanceResponse), args.Error(1) | ||||
| } | ||||
| 
 | ||||
| func (m *MockAccountService) CheckAccountStatus(trackingId string) (string, error) { | ||||
| func (m *MockAccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { | ||||
| 	args := m.Called(trackingId) | ||||
| 	return args.String(0), args.Error(1) | ||||
| 	return args.Get(0).(*models.TrackStatusResponse), args.Error(1) | ||||
| } | ||||
| @ -5,6 +5,7 @@ MOUT back 0 | ||||
| HALT | ||||
| LOAD validate_amount 64 | ||||
| RELOAD validate_amount | ||||
| CATCH api_failure  flag_api_call_error  1 | ||||
| CATCH invalid_amount flag_invalid_amount 1 | ||||
| INCMP _ 0 | ||||
| LOAD get_recipient 12 | ||||
|  | ||||
							
								
								
									
										1
									
								
								services/registration/api_failure
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								services/registration/api_failure
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| Failed to connect to the custodial service.Please try again. | ||||
							
								
								
									
										5
									
								
								services/registration/api_failure.vis
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								services/registration/api_failure.vis
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| MOUT retry 0 | ||||
| MOUT quit 9 | ||||
| HALT | ||||
| INCMP _ 0 | ||||
| INCMP quit 9 | ||||
| @ -1,4 +1,5 @@ | ||||
| LOAD reset_account_authorized 0 | ||||
| RELOAD reset_account_authorized | ||||
| MOUT my_balance 1 | ||||
| MOUT community_balance 2 | ||||
| MOUT back 0 | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Your community balance is: 0.00SRF | ||||
| {{.fetch_custodial_balances}} | ||||
| @ -1,5 +1,11 @@ | ||||
| LOAD reset_incorrect 0 | ||||
| LOAD reset_incorrect 6 | ||||
| LOAD fetch_custodial_balances 0 | ||||
| CATCH api_failure  flag_api_call_error  1 | ||||
| MAP fetch_custodial_balances | ||||
| CATCH incorrect_pin flag_incorrect_pin 1 | ||||
| CATCH pin_entry flag_account_authorized 0 | ||||
| LOAD quit_with_balance 0 | ||||
| MOUT back 0 | ||||
| MOUT quit 9 | ||||
| HALT | ||||
| INCMP _ 0 | ||||
| INCMP quit 9 | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| LOAD check_balance 64 | ||||
| RELOAD check_balance | ||||
| CATCH api_failure  flag_api_call_error  1 | ||||
| MAP check_balance | ||||
| MOUT send 1 | ||||
| MOUT vouchers 2 | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Your balance is: 0.00 SRF | ||||
| {{.fetch_custodial_balances}} | ||||
| @ -1,5 +1,11 @@ | ||||
| LOAD reset_incorrect 0 | ||||
| LOAD reset_incorrect 6 | ||||
| LOAD fetch_custodial_balances 0 | ||||
| CATCH api_failure  flag_api_call_error  1 | ||||
| MAP fetch_custodial_balances | ||||
| CATCH incorrect_pin flag_incorrect_pin 1 | ||||
| CATCH pin_entry flag_account_authorized 0 | ||||
| LOAD quit_with_balance 0 | ||||
| MOUT back 0 | ||||
| MOUT quit 9 | ||||
| HALT | ||||
| INCMP _ 0 | ||||
| INCMP quit 9 | ||||
|  | ||||
| @ -14,3 +14,4 @@ flag,flag_valid_pin,20,this is set when the given PIN is valid | ||||
| flag,flag_allow_update,21,this is set to allow a user to update their profile data | ||||
| flag,flag_single_edit,22,this is set to allow a user to edit a single profile item such as year of birth | ||||
| flag,flag_incorrect_date_format,23,this is set when the given year of birth is invalid | ||||
| flag,flag_api_call_error,25,this is set when communication  to an external service fails | ||||
|  | ||||
| 
 | 
| @ -1,6 +1,8 @@ | ||||
| CATCH select_language flag_language_set 0 | ||||
| CATCH terms flag_account_created 0 | ||||
| LOAD check_account_status 0 | ||||
| RELOAD check_account_status | ||||
| CATCH api_failure  flag_api_call_error  1 | ||||
| CATCH account_pending flag_account_pending 1 | ||||
| CATCH create_pin flag_pin_set 0 | ||||
| CATCH main flag_account_success 1 | ||||
|  | ||||
							
								
								
									
										1
									
								
								services/registration/view_menu_swa
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								services/registration/view_menu_swa
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| Angalia Wasifu | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user