github.com/condensat/bank-core@v0.1.0/database/query/accountoperation_test.go (about)

     1  // Copyright 2020 Condensat Tech. All rights reserved.
     2  // Use of this source code is governed by a MIT
     3  // license that can be found in the LICENSE file.
     4  
     5  package query
     6  
     7  import (
     8  	"reflect"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/condensat/bank-core/database"
    13  	"github.com/condensat/bank-core/database/model"
    14  	"github.com/condensat/bank-core/database/query/tests"
    15  
    16  	"github.com/jinzhu/gorm"
    17  )
    18  
    19  func TestAppendAccountOperation(t *testing.T) {
    20  	const databaseName = "TestAppendAccountOperation"
    21  	t.Parallel()
    22  
    23  	db := tests.Setup(databaseName, AccountOperationModel())
    24  	defer tests.Teardown(db, databaseName)
    25  
    26  	data := createTestAccountOperationData(db)
    27  	refAccountOperation := createOperation(data.Accounts[0].ID, 1.0, 1.0)
    28  
    29  	first := lastLinkedOperation(createLinkedOperations(db, data.Accounts[0].ID, 1, 1.0))
    30  	nextAccountOperation := createOperation(first.AccountID, -0.5, 0.5)
    31  
    32  	refInvalidAccountID := cloneOperation(refAccountOperation)
    33  	refInvalidAccountID.AccountID = 0
    34  
    35  	refNotExistingAccountID := cloneOperation(refAccountOperation)
    36  	refNotExistingAccountID.AccountID = 42
    37  
    38  	refInvalidPreCheck := cloneOperation(refAccountOperation)
    39  	*refInvalidPreCheck.Balance = 0.0
    40  
    41  	refCurrencyDisabled := createOperation(data.Accounts[1].ID, 1.0, 1.0)
    42  	refAccountDisabled := createOperation(data.Accounts[2].ID, 1.0, 1.0)
    43  
    44  	type args struct {
    45  		db        database.Context
    46  		operation model.AccountOperation
    47  	}
    48  	tests := []struct {
    49  		name    string
    50  		args    args
    51  		want    model.AccountOperation
    52  		wantErr bool
    53  	}{
    54  		{"Default", args{}, model.AccountOperation{}, true},
    55  		{"NilDB", args{nil, refAccountOperation}, model.AccountOperation{}, true},
    56  		{"InvalidAccountID", args{db, refInvalidAccountID}, model.AccountOperation{}, true},
    57  		{"NotExistingAccountID", args{db, refNotExistingAccountID}, model.AccountOperation{}, true},
    58  		{"InvalidPreCheck", args{db, refInvalidPreCheck}, model.AccountOperation{}, true},
    59  
    60  		{"Valid", args{db, refAccountOperation}, refAccountOperation, false},
    61  		{"Next", args{db, nextAccountOperation}, nextAccountOperation, false},
    62  
    63  		{"CurrencyDisabled", args{db, refCurrencyDisabled}, model.AccountOperation{}, true},
    64  		{"AccountOperation", args{db, refAccountDisabled}, model.AccountOperation{}, true},
    65  	}
    66  	for _, tt := range tests {
    67  		tt := tt // capture range variable
    68  		t.Run(tt.name, func(t *testing.T) {
    69  			got, err := AppendAccountOperation(tt.args.db, tt.args.operation)
    70  			if (err != nil) != tt.wantErr {
    71  				t.Errorf("AppendAccountOperation() error = %v, wantErr %v", err, tt.wantErr)
    72  				return
    73  			}
    74  
    75  			tt.want.ID = got.ID
    76  			if !reflect.DeepEqual(got, tt.want) {
    77  				t.Errorf("AppendAccountOperation() = %v, want %v", got, tt.want)
    78  			}
    79  		})
    80  	}
    81  }
    82  
    83  func TestGetPreviousAccountOperation(t *testing.T) {
    84  	const databaseName = "TestGetPreviousAccountOperation"
    85  	t.Parallel()
    86  
    87  	db := tests.Setup(databaseName, AccountOperationModel())
    88  	defer tests.Teardown(db, databaseName)
    89  
    90  	data := createTestAccountStateData(db)
    91  	var ops []model.AccountOperation
    92  	var prev []model.AccountOperation
    93  	for i := 0; i < len(data.Accounts); i++ {
    94  		linked := createLinkedOperations(db, data.Accounts[i].ID, i+1, 1.0)
    95  
    96  		ops = append(ops, linked[len(linked)-1])
    97  		prev = append(prev, linked[len(linked)-2])
    98  	}
    99  	type args struct {
   100  		accountID   model.AccountID
   101  		operationID model.AccountOperationID
   102  	}
   103  	tests := []struct {
   104  		name    string
   105  		args    args
   106  		want    model.AccountOperation
   107  		wantErr bool
   108  	}{
   109  		{"Default", args{}, model.AccountOperation{}, true},
   110  		{"InvalidAccountID", args{0, ops[0].ID}, model.AccountOperation{}, true},
   111  		{"InvalidOperationID", args{ops[0].AccountID, 0}, model.AccountOperation{}, true},
   112  
   113  		{"op1", args{ops[0].AccountID, ops[0].ID}, prev[0], false},
   114  		{"op2", args{ops[1].AccountID, ops[1].ID}, prev[1], false},
   115  		{"op3", args{ops[2].AccountID, ops[2].ID}, prev[2], false},
   116  		{"op4", args{ops[3].AccountID, ops[3].ID}, prev[3], false},
   117  	}
   118  	for _, tt := range tests {
   119  		tt := tt // capture range variable
   120  		t.Run(tt.name, func(t *testing.T) {
   121  			got, err := GetPreviousAccountOperation(db, tt.args.accountID, tt.args.operationID)
   122  			if (err != nil) != tt.wantErr {
   123  				t.Errorf("GetPreviousAccountOperation() error = %v, wantErr %v", err, tt.wantErr)
   124  				return
   125  			}
   126  			if !reflect.DeepEqual(got, tt.want) {
   127  				t.Errorf("GetPreviousAccountOperation() = %v, want %v", got, tt.want)
   128  			}
   129  		})
   130  	}
   131  }
   132  
   133  func TestGetNextAccountOperation(t *testing.T) {
   134  	const databaseName = "TestGetNextAccountOperation"
   135  	t.Parallel()
   136  
   137  	db := tests.Setup(databaseName, AccountOperationModel())
   138  	defer tests.Teardown(db, databaseName)
   139  
   140  	data := createTestAccountStateData(db)
   141  	var ops []model.AccountOperation
   142  	var next []model.AccountOperation
   143  	for i := 0; i < len(data.Accounts); i++ {
   144  		linked := createLinkedOperations(db, data.Accounts[i].ID, i+1, 1.0)
   145  
   146  		ops = append(ops, linked[len(linked)-2])
   147  		next = append(next, linked[len(linked)-1])
   148  	}
   149  
   150  	type args struct {
   151  		accountID   model.AccountID
   152  		operationID model.AccountOperationID
   153  	}
   154  	tests := []struct {
   155  		name    string
   156  		args    args
   157  		want    model.AccountOperation
   158  		wantErr bool
   159  	}{
   160  		{"Default", args{}, model.AccountOperation{}, true},
   161  		{"InvalidAccountID", args{0, ops[0].ID}, model.AccountOperation{}, true},
   162  		{"InvalidOperationID", args{ops[0].AccountID, 0}, model.AccountOperation{}, true},
   163  
   164  		{"op1", args{ops[0].AccountID, ops[0].ID}, next[0], false},
   165  		{"op2", args{ops[1].AccountID, ops[1].ID}, next[1], false},
   166  		{"op3", args{ops[2].AccountID, ops[2].ID}, next[2], false},
   167  		{"op4", args{ops[3].AccountID, ops[3].ID}, next[3], false},
   168  	}
   169  	for _, tt := range tests {
   170  		tt := tt // capture range variable
   171  		t.Run(tt.name, func(t *testing.T) {
   172  			got, err := GetNextAccountOperation(db, tt.args.accountID, tt.args.operationID)
   173  			if (err != nil) != tt.wantErr {
   174  				t.Errorf("GetNextAccountOperation() error = %v, wantErr %v", err, tt.wantErr)
   175  				return
   176  			}
   177  			if !reflect.DeepEqual(got, tt.want) {
   178  				t.Errorf("GetNextAccountOperation() = %v, want %v", got, tt.want)
   179  			}
   180  		})
   181  	}
   182  }
   183  
   184  func TestGetLastAccountOperation(t *testing.T) {
   185  	const databaseName = "TestGetLastAccountOperation"
   186  	t.Parallel()
   187  
   188  	db := tests.Setup(databaseName, AccountOperationModel())
   189  	defer tests.Teardown(db, databaseName)
   190  
   191  	data := createTestAccountStateData(db)
   192  	var ops []model.AccountOperation
   193  	for i := 0; i < len(data.Accounts); i++ {
   194  		ops = append(ops, lastLinkedOperation(createLinkedOperations(db, data.Accounts[i].ID, i+1, 1.0)))
   195  	}
   196  
   197  	type args struct {
   198  		accountID model.AccountID
   199  	}
   200  	tests := []struct {
   201  		name    string
   202  		args    args
   203  		wantID  model.AccountOperationID
   204  		wantErr bool
   205  	}{
   206  		{"Default", args{}, 0, true},
   207  		{"InvalidAccountID", args{0}, 0, true},
   208  
   209  		{"op1", args{ops[0].AccountID}, ops[0].ID, false},
   210  		{"op2", args{ops[1].AccountID}, ops[1].ID, false},
   211  		{"op3", args{ops[2].AccountID}, ops[2].ID, false},
   212  		{"op4", args{ops[3].AccountID}, ops[3].ID, false},
   213  	}
   214  	for _, tt := range tests {
   215  		tt := tt // capture range variable
   216  		t.Run(tt.name, func(t *testing.T) {
   217  			got, err := GetLastAccountOperation(db, tt.args.accountID)
   218  			if (err != nil) != tt.wantErr {
   219  				t.Errorf("GetLastAccountOperation() error = %v, wantErr %v", err, tt.wantErr)
   220  				return
   221  			}
   222  			if got.ID != tt.wantID {
   223  				t.Errorf("GetLastAccountOperation() ID = %v, wantID %v", got.ID, tt.wantID)
   224  			}
   225  		})
   226  	}
   227  }
   228  
   229  func TestGeAccountHistory(t *testing.T) {
   230  	const databaseName = "TestGeAccountHistory"
   231  	t.Parallel()
   232  
   233  	db := tests.Setup(databaseName, AccountOperationModel())
   234  	defer tests.Teardown(db, databaseName)
   235  
   236  	data := createTestAccountStateData(db)
   237  	var ops [][]model.AccountOperation
   238  	for i := 0; i < len(data.Accounts); i++ {
   239  		ops = append(ops, createLinkedOperations(db, data.Accounts[i].ID, i+1, 1.0))
   240  	}
   241  
   242  	type args struct {
   243  		accountID model.AccountID
   244  	}
   245  	tests := []struct {
   246  		name    string
   247  		args    args
   248  		want    []model.AccountOperation
   249  		wantErr bool
   250  	}{
   251  		{"Default", args{}, nil, true},
   252  		{"InvalidAccountID", args{0}, nil, true},
   253  
   254  		{"op1", args{lastLinkedOperation(ops[0]).AccountID}, ops[0], false},
   255  		{"op2", args{lastLinkedOperation(ops[1]).AccountID}, ops[1], false},
   256  		{"op3", args{lastLinkedOperation(ops[2]).AccountID}, ops[2], false},
   257  		{"op4", args{lastLinkedOperation(ops[3]).AccountID}, ops[3], false},
   258  	}
   259  	for _, tt := range tests {
   260  		tt := tt // capture range variable
   261  		t.Run(tt.name, func(t *testing.T) {
   262  			got, err := GeAccountHistory(db, tt.args.accountID)
   263  			if (err != nil) != tt.wantErr {
   264  				t.Errorf("GeAccountHistory() error = %v, wantErr %v", err, tt.wantErr)
   265  				return
   266  			}
   267  			if !reflect.DeepEqual(got, tt.want) {
   268  				t.Errorf("GeAccountHistory() = %v, want %v", got, tt.want)
   269  			}
   270  		})
   271  	}
   272  }
   273  
   274  func TestGeAccountHistoryWithPrevNext(t *testing.T) {
   275  	const databaseName = "TestGeAccountHistoryWithPrevNext"
   276  	t.Parallel()
   277  
   278  	db := tests.Setup(databaseName, AccountOperationModel())
   279  	defer tests.Teardown(db, databaseName)
   280  
   281  	data := createTestAccountStateData(db)
   282  	var ops [][]model.AccountOperation
   283  	for i := 0; i < len(data.Accounts); i++ {
   284  		ops = append(ops, createLinkedOperations(db, data.Accounts[i].ID, i+1, 1.0))
   285  	}
   286  
   287  	type args struct {
   288  		accountID model.AccountID
   289  	}
   290  	tests := []struct {
   291  		name    string
   292  		args    args
   293  		want    []AccountOperationPrevNext
   294  		wantErr bool
   295  	}{
   296  		{"Default", args{}, nil, true},
   297  		{"InvalidAccountID", args{0}, nil, true},
   298  
   299  		{"op1", args{lastLinkedOperation(ops[0]).AccountID}, createAccountOperationPrevNextList(ops[0]), false},
   300  		{"op2", args{lastLinkedOperation(ops[1]).AccountID}, createAccountOperationPrevNextList(ops[1]), false},
   301  		{"op3", args{lastLinkedOperation(ops[2]).AccountID}, createAccountOperationPrevNextList(ops[2]), false},
   302  		{"op4", args{lastLinkedOperation(ops[3]).AccountID}, createAccountOperationPrevNextList(ops[3]), false},
   303  	}
   304  	for _, tt := range tests {
   305  		tt := tt // capture range variable
   306  		t.Run(tt.name, func(t *testing.T) {
   307  			got, err := GeAccountHistoryWithPrevNext(db, tt.args.accountID)
   308  			if (err != nil) != tt.wantErr {
   309  				t.Errorf("GeAccountHistoryWithPrevNext() error = %v, wantErr %v", err, tt.wantErr)
   310  				return
   311  			}
   312  			if !reflect.DeepEqual(got, tt.want) {
   313  				t.Errorf("GeAccountHistoryWithPrevNext() = %+v, want %+v", got, tt.want)
   314  			}
   315  		})
   316  	}
   317  }
   318  
   319  func TestGeAccountHistoryRange(t *testing.T) {
   320  	const databaseName = "TestGeAccountHistoryRange"
   321  	t.Parallel()
   322  
   323  	db := tests.Setup(databaseName, AccountOperationModel())
   324  	defer tests.Teardown(db, databaseName)
   325  
   326  	data := createTestAccountStateData(db)
   327  	var ops [][]model.AccountOperation
   328  	for i := 0; i < len(data.Accounts); i++ {
   329  		ops = append(ops, createLinkedOperations(db, data.Accounts[i].ID, i+1, 1.0))
   330  	}
   331  
   332  	to := time.Now()
   333  	from := to.Add(-10 * time.Second)
   334  
   335  	afterTo := to.Add(time.Minute)
   336  	afterFrom := from.Add(time.Minute)
   337  
   338  	beforeTo := to.Add(-time.Minute)
   339  	beforeFrom := from.Add(-time.Minute)
   340  
   341  	type args struct {
   342  		db        database.Context
   343  		accountID model.AccountID
   344  		from      time.Time
   345  		to        time.Time
   346  	}
   347  	tests := []struct {
   348  		name    string
   349  		args    args
   350  		want    []model.AccountOperation
   351  		wantErr bool
   352  	}{
   353  		{"Default", args{}, nil, true},
   354  		{"NilDB", args{nil, lastLinkedOperation(ops[0]).AccountID, time.Time{}, time.Time{}}, nil, true},
   355  		{"InvalidAccountID", args{db, 0, from, to}, nil, true},
   356  
   357  		{"DefaultRangeOp1", args{db, lastLinkedOperation(ops[0]).AccountID, time.Time{}, time.Time{}}, nil, false},
   358  		{"DefaultRangeOp2", args{db, lastLinkedOperation(ops[1]).AccountID, time.Time{}, time.Time{}}, nil, false},
   359  		{"DefaultRangeOp3", args{db, lastLinkedOperation(ops[2]).AccountID, time.Time{}, time.Time{}}, nil, false},
   360  		{"DefaultRangeOp4", args{db, lastLinkedOperation(ops[3]).AccountID, time.Time{}, time.Time{}}, nil, false},
   361  
   362  		{"Rangeop1", args{db, lastLinkedOperation(ops[0]).AccountID, from, to}, ops[0], false},
   363  		{"Rangeop2", args{db, lastLinkedOperation(ops[1]).AccountID, from, to}, ops[1], false},
   364  		{"Rangeop3", args{db, lastLinkedOperation(ops[2]).AccountID, from, to}, ops[2], false},
   365  		{"Rangeop4", args{db, lastLinkedOperation(ops[3]).AccountID, from, to}, ops[3], false},
   366  
   367  		{"InvertRangeOp1", args{db, lastLinkedOperation(ops[0]).AccountID, to, from}, ops[0], false},
   368  		{"InvertRangeOp2", args{db, lastLinkedOperation(ops[1]).AccountID, to, from}, ops[1], false},
   369  		{"InvertRangeOp3", args{db, lastLinkedOperation(ops[2]).AccountID, to, from}, ops[2], false},
   370  		{"InvertRangeOp4", args{db, lastLinkedOperation(ops[3]).AccountID, to, from}, ops[3], false},
   371  
   372  		{"BeforeRangeOp1", args{db, lastLinkedOperation(ops[0]).AccountID, beforeFrom, beforeTo}, nil, false},
   373  		{"BeforeRangeOp2", args{db, lastLinkedOperation(ops[1]).AccountID, beforeFrom, beforeTo}, nil, false},
   374  		{"BeforeRangeOp3", args{db, lastLinkedOperation(ops[2]).AccountID, beforeFrom, beforeTo}, nil, false},
   375  		{"BeforeRangeOp4", args{db, lastLinkedOperation(ops[3]).AccountID, beforeFrom, beforeTo}, nil, false},
   376  
   377  		{"AfterRangeOp1", args{db, lastLinkedOperation(ops[0]).AccountID, afterFrom, afterTo}, nil, false},
   378  		{"AfterRangeOp2", args{db, lastLinkedOperation(ops[1]).AccountID, afterFrom, afterTo}, nil, false},
   379  		{"AfterRangeOp3", args{db, lastLinkedOperation(ops[2]).AccountID, afterFrom, afterTo}, nil, false},
   380  		{"AfterRangeOp4", args{db, lastLinkedOperation(ops[3]).AccountID, afterFrom, afterTo}, nil, false},
   381  	}
   382  	for _, tt := range tests {
   383  		tt := tt // capture range variable
   384  		t.Run(tt.name, func(t *testing.T) {
   385  			got, err := GeAccountHistoryRange(tt.args.db, tt.args.accountID, tt.args.from, tt.args.to)
   386  			if (err != nil) != tt.wantErr {
   387  				t.Errorf("GeAccountHistoryRange() error = %v, wantErr %v", err, tt.wantErr)
   388  				return
   389  			}
   390  			if !reflect.DeepEqual(got, tt.want) {
   391  				t.Errorf("GeAccountHistoryRange() = %v, want %v", got, tt.want)
   392  			}
   393  		})
   394  	}
   395  }
   396  
   397  func TestFindAccountOperationByReference(t *testing.T) {
   398  	const databaseName = "TestFindAccountOperationByReference"
   399  	t.Parallel()
   400  
   401  	db := tests.Setup(databaseName, AccountOperationModel())
   402  	defer tests.Teardown(db, databaseName)
   403  
   404  	data := createTestAccountOperationData(db)
   405  	ref1, _ := AppendAccountOperation(db, model.NewAccountOperation(0,
   406  		data.Accounts[0].ID,
   407  		model.SynchroneousTypeSync,
   408  		model.OperationTypeDeposit,
   409  		1337,
   410  		time.Now(),
   411  		0.1337, 42.0,
   412  		0.0, 0.0,
   413  	))
   414  	ref2, _ := AppendAccountOperation(db, model.NewAccountOperation(0,
   415  		data.Accounts[0].ID,
   416  		model.SynchroneousTypeAsyncStart,
   417  		model.OperationTypeTransfer,
   418  		1338,
   419  		time.Now(),
   420  		0.1337, 42.0,
   421  		0.0, 0.0,
   422  	))
   423  
   424  	type args struct {
   425  		synchroneousType model.SynchroneousType
   426  		operationType    model.OperationType
   427  		referenceID      model.RefID
   428  	}
   429  	tests := []struct {
   430  		name    string
   431  		args    args
   432  		want    model.AccountOperation
   433  		wantErr bool
   434  	}{
   435  		{"default", args{}, model.AccountOperation{}, true},
   436  
   437  		{"invalid_sync", args{model.SynchroneousTypeInvalid, model.OperationTypeInit, 42}, model.AccountOperation{}, true},
   438  		{"invalid_type", args{model.SynchroneousTypeSync, model.OperationTypeInvalid, 42}, model.AccountOperation{}, true},
   439  		{"invalid_ref", args{model.SynchroneousTypeSync, model.OperationTypeInit, 0}, model.AccountOperation{}, true},
   440  
   441  		{"valid1", args{ref1.SynchroneousType, ref1.OperationType, ref1.ReferenceID}, ref1, false},
   442  		{"valid2", args{ref2.SynchroneousType, ref2.OperationType, ref2.ReferenceID}, ref2, false},
   443  	}
   444  	for _, tt := range tests {
   445  		tt := tt // capture range variable
   446  		t.Run(tt.name, func(t *testing.T) {
   447  			got, err := FindAccountOperationByReference(db, tt.args.synchroneousType, tt.args.operationType, tt.args.referenceID)
   448  			if (err != nil) != tt.wantErr {
   449  				t.Errorf("FindAccountOperationByReference() error = %v, wantErr %v", err, tt.wantErr)
   450  				return
   451  			}
   452  			if !reflect.DeepEqual(got, tt.want) {
   453  				t.Errorf("FindAccountOperationByReference() = %v, want %v", got, tt.want)
   454  			}
   455  		})
   456  	}
   457  }
   458  
   459  func createOperation(account model.AccountID, amount, balance model.Float) model.AccountOperation {
   460  	return model.NewAccountOperation(0, account, model.SynchroneousTypeSync, model.OperationTypeDeposit, 0, time.Now(), amount, balance, 0.0, 0.0)
   461  }
   462  
   463  func cloneOperation(operation model.AccountOperation) model.AccountOperation {
   464  	return createOperation(operation.AccountID, *operation.Amount, *operation.Balance)
   465  }
   466  
   467  func createLinkedOperations(db database.Context, account model.AccountID, count int, amount model.Float) []model.AccountOperation {
   468  	list, _ := GeAccountHistory(db, account)
   469  	var balance model.Float
   470  	for i := 0; i < count; i++ {
   471  		balance += amount
   472  		last := storeOperation(db, createOperation(account, amount, balance))
   473  		if !last.IsValid() {
   474  			panic("Invalid AccountOperation")
   475  		}
   476  		list = append(list, last)
   477  	}
   478  
   479  	return list
   480  }
   481  
   482  func lastLinkedOperation(list []model.AccountOperation) model.AccountOperation {
   483  	if len(list) == 0 {
   484  		panic("empty list")
   485  	}
   486  
   487  	return list[len(list)-1]
   488  }
   489  
   490  func createAccountOperationPrevNext(op model.AccountOperation, previous, next model.AccountOperationID) AccountOperationPrevNext {
   491  	return AccountOperationPrevNext{
   492  		AccountOperation: op,
   493  		Previous:         previous,
   494  		Next:             next,
   495  	}
   496  }
   497  
   498  func createAccountOperationPrevNextList(ops []model.AccountOperation) []AccountOperationPrevNext {
   499  	var list []AccountOperationPrevNext
   500  	for i, op := range ops {
   501  		prev := model.AccountOperationID(0)
   502  		if i > 0 {
   503  			prev = ops[i-1].ID
   504  		}
   505  		next := model.AccountOperationID(0)
   506  		if i < len(ops)-1 {
   507  			next = ops[i+1].ID
   508  		}
   509  		list = append(list, createAccountOperationPrevNext(op, prev, next))
   510  
   511  	}
   512  	return list
   513  }
   514  
   515  func storeOperation(db database.Context, operation model.AccountOperation) model.AccountOperation {
   516  	gdb := db.DB().(*gorm.DB)
   517  	if gdb == nil {
   518  		return model.AccountOperation{}
   519  	}
   520  
   521  	err := gdb.Create(&operation).Error
   522  	if err != nil {
   523  		return model.AccountOperation{}
   524  	}
   525  
   526  	return operation
   527  }
   528  
   529  type AccountOperationTestData struct {
   530  	AccountStateTestData
   531  	AccountStates []model.AccountState
   532  }
   533  
   534  func createTestAccountOperationData(db database.Context) AccountOperationTestData {
   535  	var data AccountOperationTestData
   536  	data.AccountStateTestData = createTestAccountStateData(db)
   537  
   538  	// Disable 2nd currency
   539  	*data.Currencies[1].Available = FlagCurencyDisable
   540  	_, _ = AddOrUpdateCurrency(db, data.Currencies[1])
   541  
   542  	accountState1, _ := AddOrUpdateAccountState(db, model.AccountState{AccountID: data.Accounts[0].ID, State: model.AccountStatusNormal})
   543  	accountState2, _ := AddOrUpdateAccountState(db, model.AccountState{AccountID: data.Accounts[1].ID, State: model.AccountStatusNormal})
   544  	accountState3, _ := AddOrUpdateAccountState(db, model.AccountState{AccountID: data.Accounts[2].ID, State: model.AccountStatusDisabled}) // disable 3rd account
   545  	accountState4, _ := AddOrUpdateAccountState(db, model.AccountState{AccountID: data.Accounts[3].ID, State: model.AccountStatusNormal})
   546  
   547  	data.AccountStates = append(data.AccountStates, accountState1)
   548  	data.AccountStates = append(data.AccountStates, accountState2)
   549  	data.AccountStates = append(data.AccountStates, accountState3)
   550  	data.AccountStates = append(data.AccountStates, accountState4)
   551  
   552  	return data
   553  }