2022-07-04 23:14:13 +02:00
#include <IOTestHelpers.h>
#include "ServiceMock.h"
#include <Constants.h>
#include <Onboarding/Accounts/AccountsService.h>
#include <Onboarding/OnboardingController.h>
#include <StatusGo/Accounts/Accounts.h>
2022-10-19 15:41:53 +02:00
#include <StatusGo/SignalsManager.h>
2022-07-04 23:14:13 +02:00
#include <ScopedTestAccount.h>
#include <QCoreApplication>
#include <gtest/gtest.h>
namespace Testing = Status :: Testing ;
namespace Onboarding = Status :: Onboarding ;
namespace fs = std :: filesystem ;
2022-10-19 15:41:53 +02:00
namespace Status :: Testing
{
2022-07-04 23:14:13 +02:00
static std :: unique_ptr < Onboarding :: AccountsService > m_accountsServiceMock ;
TEST ( OnboardingModule , TestInitService )
{
Testing :: AutoCleanTempTestDir fusedTestFolder { test_info_ -> name ()};
auto testFolderPath = fusedTestFolder . tempFolder () / Constants :: statusGoDataDirName ;
fs :: create_directory ( testFolderPath );
auto accountsService = std :: make_unique < Onboarding :: AccountsService > ();
ASSERT_TRUE ( accountsService -> init ( testFolderPath ));
}
/// This integration end to end test is here for documentation purpose and until all the functionality is covered by unit-tests
/// \warning the test depends on IO and it is not deterministic, fast, focused or reliable and uses production classes. It is here for documenting only and dev process
/// \todo refactor into unit-tests with mocked interfaces
TEST ( OnboardingModule , TestCreateAndLoginAccountEndToEnd )
{
int argc = 1 ;
std :: string appName { "test" };
char * args [] = { appName . data ()};
QCoreApplication dummyApp { argc , reinterpret_cast < char **> ( args )};
Testing :: AutoCleanTempTestDir fusedTestFolder { test_info_ -> name ()};
auto testFolderPath = fusedTestFolder . tempFolder () / "Status Desktop" ;
fs :: create_directory ( testFolderPath );
// Setup accounts
auto accountsService = std :: make_shared < Onboarding :: AccountsService > ();
auto result = accountsService -> init ( testFolderPath );
ASSERT_TRUE ( result );
// TODO refactor and merge account creation events with login into Onboarding controller
//
// Create Login early to register and not miss onLoggedIn event signal from setupAccountAndLogin
//
// Beware, smartpointer is a requirement
auto onboarding = std :: make_shared < Onboarding :: OnboardingController > ( accountsService );
EXPECT_EQ ( onboarding -> getOpenedAccounts (). size (), 0 );
int accountLoggedInCount = 0 ;
QObject :: connect ( onboarding . get (), & Onboarding :: OnboardingController :: accountLoggedIn , [ & accountLoggedInCount ]() {
accountLoggedInCount ++ ;
});
bool accountLoggedInError = false ;
QObject :: connect ( onboarding . get (), & Onboarding :: OnboardingController :: accountLoginError , [ & accountLoggedInError ]() {
accountLoggedInError = true ;
});
// Create Accounts
auto genAccounts = accountsService -> generatedAccounts ();
ASSERT_GT ( genAccounts . size (), 0 );
ASSERT_FALSE ( accountsService -> isFirstTimeAccountLogin ());
constexpr auto accountName = "test_name" ;
constexpr auto accountPassword = "test_pwd*" ;
ASSERT_TRUE ( accountsService -> setupAccountAndLogin ( genAccounts [ 0 ]. id , accountPassword , accountName ));
ASSERT_TRUE ( accountsService -> isFirstTimeAccountLogin ());
ASSERT_TRUE ( accountsService -> getLoggedInAccount (). isValid ());
ASSERT_TRUE ( accountsService -> getLoggedInAccount (). name == accountName );
ASSERT_FALSE ( accountsService -> getImportedAccount (). isValid ());
using namespace std :: chrono_literals ;
auto maxWaitTime = 2000 ms ;
auto iterationSleepTime = 2 ms ;
2022-10-19 15:41:53 +02:00
auto remainingIterations = maxWaitTime / iterationSleepTime ;
while ( remainingIterations -- > 0 && accountLoggedInCount == 0 )
{
2022-07-04 23:14:13 +02:00
QCoreApplication :: sendPostedEvents ();
2022-10-14 13:38:41 +03:00
std :: this_thread :: sleep_for ( iterationSleepTime );
2022-07-04 23:14:13 +02:00
}
EXPECT_EQ ( accountLoggedInCount , 1 );
EXPECT_FALSE ( accountLoggedInError );
EXPECT_FALSE ( Status :: StatusGo :: Accounts :: logout (). containsError ());
}
/// This integration end to end test is here for documentation purpose and until all the functionality is covered by unit-tests
/// \warning the test depends on IO and it is not deterministic, fast, focused or reliable. It is here for validation only
/// \todo find a way to test the integration within a test environment. Also how about reusing an existing account
/// \todo due to keeping status-go keeping the state thsi works only run separately
TEST ( OnboardingModule , TestLoginEndToEnd )
{
// Create test account and login
//
bool createAndLogin = false ;
2022-10-19 15:41:53 +02:00
QObject :: connect ( StatusGo :: SignalsManager :: instance (),
& StatusGo :: SignalsManager :: nodeLogin ,
[ & createAndLogin ]( const QString & error ) {
2022-10-14 13:38:41 +03:00
if ( error . isEmpty ()) createAndLogin = ! createAndLogin ;
2022-10-19 15:41:53 +02:00
});
2022-07-04 23:14:13 +02:00
constexpr auto accountName = "TestLoginAccountName" ;
2022-07-15 09:30:16 +02:00
ScopedTestAccount testAccount ( test_info_ -> name (), accountName );
2022-10-14 13:38:41 +03:00
testAccount . processMessages ( 1000 , [ & createAndLogin ]() { return ! createAndLogin ; });
2022-07-04 23:14:13 +02:00
ASSERT_TRUE ( createAndLogin );
testAccount . logOut ();
// Test account log in
//
// Setup accounts
auto accountsService = std :: make_shared < Onboarding :: AccountsService > ();
2022-10-14 13:38:41 +03:00
auto result = accountsService -> init ( testAccount . testDataDir ());
2022-07-04 23:14:13 +02:00
ASSERT_TRUE ( result );
auto onboarding = std :: make_shared < Onboarding :: OnboardingController > ( accountsService );
// We don't have a way yet to simulate status-go process exit
2022-07-15 09:30:16 +02:00
EXPECT_EQ ( onboarding -> getOpenedAccounts (). size (), 1 );
2022-07-04 23:14:13 +02:00
auto accounts = accountsService -> openAndListAccounts ();
ASSERT_GT ( accounts . size (), 0 );
int accountLoggedInCount = 0 ;
QObject :: connect ( onboarding . get (), & Onboarding :: OnboardingController :: accountLoggedIn , [ & accountLoggedInCount ]() {
accountLoggedInCount ++ ;
});
bool accountLoggedInError = false ;
2022-10-19 15:41:53 +02:00
QObject :: connect ( onboarding . get (),
& Onboarding :: OnboardingController :: accountLoginError ,
2022-07-15 09:30:16 +02:00
[ & accountLoggedInError ]( const QString & error ) {
2022-10-19 15:41:53 +02:00
qDebug () << "Failed logging in in test" << test_info_ -> name () << "with error:" << error ;
2022-10-14 13:38:41 +03:00
accountLoggedInError = true ;
2022-10-19 15:41:53 +02:00
});
2022-07-04 23:14:13 +02:00
2022-10-19 15:41:53 +02:00
auto ourAccountRes =
std :: find_if ( accounts . begin (), accounts . end (), [ accountName ]( const auto & a ) { return a . name == accountName ; });
2022-07-15 09:30:16 +02:00
auto errorString = accountsService -> login ( * ourAccountRes , testAccount . password ());
2022-07-04 23:14:13 +02:00
ASSERT_EQ ( errorString . length (), 0 );
2022-10-14 13:38:41 +03:00
testAccount . processMessages ( 1000 , [ & accountLoggedInCount , & accountLoggedInError ]() {
2022-07-04 23:14:13 +02:00
return accountLoggedInCount == 0 && ! accountLoggedInError ;
});
ASSERT_EQ ( accountLoggedInError , 0 );
2022-10-14 13:38:41 +03:00
ASSERT_EQ ( accountLoggedInCount , 1 );
2022-07-04 23:14:13 +02:00
}
2022-07-15 09:30:16 +02:00
TEST ( OnboardingModule , TestLoginEndToEnd_WrongPassword )
{
constexpr auto testRootAccountName = "test-login_wrong_pass-name" ;
ScopedTestAccount testAccount ( test_info_ -> name (), testRootAccountName );
testAccount . logOut ();
auto accountsService = std :: make_shared < Onboarding :: AccountsService > ();
2022-10-14 13:38:41 +03:00
auto result = accountsService -> init ( testAccount . testDataDir ());
2022-07-15 09:30:16 +02:00
ASSERT_TRUE ( result );
auto onboarding = std :: make_shared < Onboarding :: OnboardingController > ( accountsService );
auto accounts = accountsService -> openAndListAccounts ();
ASSERT_GT ( accounts . size (), 0 );
int accountLoggedInCount = 0 ;
QObject :: connect ( onboarding . get (), & Onboarding :: OnboardingController :: accountLoggedIn , [ & accountLoggedInCount ]() {
accountLoggedInCount ++ ;
});
bool accountLoggedInError = false ;
QString loginErrorMessage ;
2022-10-19 15:41:53 +02:00
QObject :: connect ( onboarding . get (),
& Onboarding :: OnboardingController :: accountLoginError ,
2022-07-15 09:30:16 +02:00
[ & loginErrorMessage , & accountLoggedInError ]( const QString & error ) {
2022-10-19 15:41:53 +02:00
accountLoggedInError = true ;
loginErrorMessage = error ;
});
2022-07-15 09:30:16 +02:00
2022-10-19 15:41:53 +02:00
auto ourAccountRes = std :: find_if ( accounts . begin (), accounts . end (), [ testRootAccountName ]( const auto & a ) {
return a . name == testRootAccountName ;
});
2022-07-15 09:30:16 +02:00
auto errorString = accountsService -> login ( * ourAccountRes , testAccount . password () + "extra" );
ASSERT_EQ ( errorString . length (), 0 );
2022-10-14 13:38:41 +03:00
testAccount . processMessages ( 1000 , [ & accountLoggedInCount , & accountLoggedInError ]() {
2022-07-15 09:30:16 +02:00
return accountLoggedInCount == 0 && ! accountLoggedInError ;
});
ASSERT_EQ ( accountLoggedInError , 1 );
ASSERT_EQ ( accountLoggedInCount , 0 );
ASSERT_EQ ( loginErrorMessage , "file is not a database" );
}
2022-10-19 15:41:53 +02:00
} // namespace Status::Testing