Skip to content

Commit

Permalink
fix(tests): resolve API authentication issue in MtnMomoAiTest
Browse files Browse the repository at this point in the history
  • Loading branch information
AlvinCoded committed Jan 23, 2025
1 parent f780958 commit 5a19cd2
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 41 deletions.
3 changes: 2 additions & 1 deletion src/AI/LLMFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ public function __construct(array $config)
* - ChatGPT: OpenAI's GPT model for general analysis and text generation
* - Claude: Anthropic's Claude model for complex reasoning
* - Gemini: Google's Gemini model for natural language processing
* - Deepseek: Deepseek model for natural language processing
*
* @param string $model The name of the LLM model to create ('ChatGPT', 'Claude', or 'Gemini')
* @param string $model The name of the LLM model to create ('ChatGPT', 'Claude', 'Gemini' or 'Deepseek')
* @return LLMInterface An instance of the requested LLM model
* @throws InvalidArgumentException If an unsupported model is requested
*/
Expand Down
14 changes: 2 additions & 12 deletions src/Console/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ private function setupEnvironment()

$envFile = base_path('.env');
$envContents = File::get($envFile);

// Generate API User UUID
$apiUserId = Str::uuid()->toString();

$subscriptionKey = $this->ask('🔐 What is your MTN MOMO Subscription Key?');
Expand All @@ -100,7 +98,7 @@ private function setupEnvironment()
'MTN_MOMO_ENVIRONMENT' => $this->choice('🌍 Which environment are you using?', ['sandbox', 'production'], 'sandbox'),
'MTN_MOMO_PROVIDER_CALLBACK_HOST' => $callbackHost,
'MTN_MOMO_DEFAULT_CURRENCY' => $this->choice('💰 Which currency would you like to use by default?', ['EUR' => 'Euro', 'USD' => 'US Dollar', 'GHS' => 'Ghana Cedi', 'UGX' => 'Ugandan Shilling', 'XAF' => 'Central African CFA Franc', 'XOF' => 'West African CFA Franc'], 'EUR'),
'DEFAULT_LLM' => $this->choice('🤖 Which AI model would you like to use by default?', ['ChatGPT', 'Claude', 'Gemini'], 'ChatGPT'),
'DEFAULT_LLM' => $this->choice('🤖 Which AI model would you like to use by default?', ['ChatGPT', 'Claude', 'Gemini', 'DeepSeek'], 'ChatGPT'),
'OPENAI_API_KEY' => $this->secret('🔑 What is your OpenAI API Key? (Leave blank if not using)'),
'ANTHROPIC_API_KEY' => $this->secret('🔑 What is your Anthropic API Key? (Leave blank if not using)'),
'GEMINI_API_KEY' => $this->secret('🔑 What is your Gemini API Key? (Leave blank if not using)'),
Expand All @@ -112,7 +110,6 @@ private function setupEnvironment()
$apiKey = $this->createApiUser($apiUserId, $variables['MTN_MOMO_SUBSCRIPTION_KEY']);
$variables['MTN_MOMO_API_KEY'] = $apiKey;

// Check which variables are missing
$missingVariables = [];
foreach ($variables as $key => $value) {
$escapedKey = preg_quote($key, '/');
Expand All @@ -121,7 +118,6 @@ private function setupEnvironment()
}
}

// Only update existing variables or add missing ones
foreach ($variables as $key => $value) {
if (!empty($value)) {
if (in_array($key, $missingVariables)) {
Expand Down Expand Up @@ -159,7 +155,6 @@ private function createApiUser($apiUserId, $subscriptionKey)
$client = new Client();

try {
// Step 1
$createUserResponse = $client->post('https://sandbox.momodeveloper.mtn.com/v1_0/apiuser', [
'headers' => [
'X-Reference-Id' => $apiUserId,
Expand All @@ -175,7 +170,6 @@ private function createApiUser($apiUserId, $subscriptionKey)
throw new MtnMomoApiException('Failed to create API user');
}

// Step 2
$createKeyResponse = $client->post('https://sandbox.momodeveloper.mtn.com/v1_0/apiuser/' . $apiUserId . '/apikey',
[
'headers' => [
Expand All @@ -191,7 +185,6 @@ private function createApiUser($apiUserId, $subscriptionKey)

$apiKey = json_decode($createKeyResponse->getBody()->getContents(), true)['apiKey'];

// Step 3
$getUserResponse = $client->get('https://sandbox.momodeveloper.mtn.com/v1_0/apiuser/' . $apiUserId,
[
'headers' => [
Expand Down Expand Up @@ -270,14 +263,11 @@ private function addPlaceholders()
$variableName = substr($key, 0, strpos($key, '='));
$pattern = "/^#.*\n{$variableName}=.*$/m";
if (preg_match($pattern, $envContents)) {
// Variable exists - remove old entry (including comment)
$envContents = preg_replace($pattern, '', $envContents);
}
// Add new entry with comment
$envContents .= "\n" . $comment . "\n" . $key;
}

// Clean up any double blank lines

$envContents = preg_replace("/\n\n\n+/", "\n\n", $envContents);

File::put($envFile, $envContents);
Expand Down
6 changes: 0 additions & 6 deletions src/MtnMomoAi.php
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,6 @@ public function handleError($errorCode, $context, $model = null)
return $this->formatErrorResponse($explanation);
}

// Collection API methods

/**
* Request to pay via Collections API
*
Expand Down Expand Up @@ -265,8 +263,6 @@ public function getAccountHolder($accountHolderId, $accountHolderIdType)
return $this->collections->getAccountHolder($accountHolderId, $accountHolderIdType);
}

// Disbursement API methods

/**
* Transfer funds via Disbursements API
*
Expand Down Expand Up @@ -304,8 +300,6 @@ public function getDisbursementAccountBalance()
return $this->disbursements->getAccountBalance();
}

// Remittance API methods

/**
* Send remittance via Remittance API
*
Expand Down
1 change: 0 additions & 1 deletion src/Traits/MakesHttpRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ protected function getAccessToken()

$token = $this->requestNewAccessToken();

// Cache for 59 minutes (3540 seconds) to ensure token refresh before expiration
Cache::put($cacheKey, $token, 3540);

return $token;
Expand Down
87 changes: 66 additions & 21 deletions tests/MtnMomoAiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,54 +25,99 @@ protected function getPackageAliases($app)
];
}

public function testAnalyzeTransaction()
protected function setUp(): void
{
$mockLLM = Mockery::mock('AlvinCoded\MtnMomoAi\AI\Interfaces\LLMInterface');
$mockLLM->shouldReceive('analyze')->once()->andReturn('Transaction analysis result');
parent::setUp();

$mockFactory = Mockery::mock(LLMFactory::class);
$mockFactory->shouldReceive('create')->once()->andReturn($mockLLM);

$this->app->instance(LLMFactory::class, $mockFactory);

$result = MtnMomoAi::analyzeTransaction(['transaction_data']);
$this->assertEquals('Transaction analysis result', $result);
$this->app['config']->set('mtn-momo-ai.subscription_key', 'your_actual_subscription_key_here');
$this->app['config']->set('mtn-momo-ai.base_url', 'https://sandbox.momodeveloper.mtn.com');
$this->app['config']->set('mtn-momo-ai.environment', 'sandbox');
$this->app['config']->set('mtn-momo-ai.version', 'v1_0');
}


public function testRequestToPay()
{
$mockCollections = Mockery::mock(Collections::class);
$mockCollections->shouldReceive('requestToPay')->once()->andReturn(['status' => 'success']);

$mockCollections->shouldReceive('requestToPay')->once()->andReturn(['status' => 'SUCCESS']);
$this->app->instance(Collections::class, $mockCollections);

$result = MtnMomoAi::requestToPay(100, 'EUR', 'ext123', 'party123', 'Payment', 'Note');
$this->assertEquals(['status' => 'success'], $result);
$result = MtnMomoAi::requestToPay('100', 'EUR', 'ext123', 'party123', 'Payment', 'Note');
$this->assertEquals(['status' => 'SUCCESS'], $result);
}

public function testTransfer()
{
$mockDisbursements = Mockery::mock(Disbursements::class);
$mockDisbursements->shouldReceive('transfer')->once()->andReturn(['status' => 'success']);
$mockDisbursements->shouldReceive('transfer')->once()->andReturn(['status' => 'SUCCESS']);

$this->app->instance(Disbursements::class, $mockDisbursements);

$result = MtnMomoAi::transfer(100, 'EUR', 'ext123', 'party123', 'Payment', 'Note');
$this->assertEquals(['status' => 'success'], $result);
$result = MtnMomoAi::transfer('100', 'EUR', 'ext123', 'party123', 'Payment', 'Note');
$this->assertEquals(['status' => 'SUCCESS'], $result);
}

public function testRemit()
{
$mockRemittances = Mockery::mock(Remittances::class);
$mockRemittances->shouldReceive('transfer')->once()->andReturn(['status' => 'success']);
$mockRemittances->shouldReceive('transfer')->once()->andReturn(['status' => 'SUCCESS']);

$this->app->instance(Remittances::class, $mockRemittances);

$result = MtnMomoAi::remit(100, 'EUR', 'ext123', 'party123', 'Payment', 'Note');
$this->assertEquals(['status' => 'success'], $result);
$result = MtnMomoAi::remit('100', 'EUR', 'ext123', 'party123', 'Payment', 'Note');
$this->assertEquals(['status' => 'SUCCESS'], $result);
}

// More tests coming soon...
public function testAnalyzeTransaction()
{
$mockCollections = Mockery::mock(Collections::class);
$mockCollections->shouldReceive('getTransactionStatus')->andReturn(['status' => 'SUCCESS']);
$this->app->instance(Collections::class, $mockCollections);

$mockLLM = Mockery::mock('AlvinCoded\MtnMomoAi\AI\Interfaces\LLMInterface');
$mockLLM->shouldReceive('analyze')->once()->andReturn('Transaction analysis result');

$mockFactory = Mockery::mock(LLMFactory::class, [['chatgpt' => [], 'claude' => [], 'gemini' => [], 'deepseek' => []]])->makePartial();
$mockFactory->shouldReceive('create')->once()->andReturn($mockLLM);

$this->app->instance(LLMFactory::class, $mockFactory);

$result = MtnMomoAi::analyzeTransaction('transaction123');
$this->assertEquals('Transaction analysis result', $result);
}


public function testDetectFraud()
{
$mockLLM = Mockery::mock('AlvinCoded\MtnMomoAi\AI\Interfaces\LLMInterface');
$mockLLM->shouldReceive('detectFraud')->once()->andReturn(['fraud_score' => 0.2]);

$mockFactory = Mockery::mock(LLMFactory::class);
$mockFactory->shouldReceive('create')->once()->andReturn($mockLLM);

$this->app->instance(LLMFactory::class, $mockFactory);

$result = MtnMomoAi::detectFraud(['transaction_data']);
$this->assertEquals(['fraud_score' => 0.2], $result);
}

public function testScheduleDisbursement()
{
$mockLLM = Mockery::mock('AlvinCoded\MtnMomoAi\AI\Interfaces\LLMInterface');
$mockLLM->shouldReceive('suggestDisbursementTime')->once()->andReturn('2025-01-24 10:00:00');

$mockFactory = Mockery::mock(LLMFactory::class);
$mockFactory->shouldReceive('create')->once()->andReturn($mockLLM);

$mockDisbursements = Mockery::mock(Disbursements::class);
$mockDisbursements->shouldReceive('transfer')->once()->andReturn(['status' => 'PENDING']);

$this->app->instance(LLMFactory::class, $mockFactory);
$this->app->instance(Disbursements::class, $mockDisbursements);

$result = MtnMomoAi::scheduleDisbursement(100, 'recipient123', 'EUR');
$this->assertEquals(['status' => 'PENDING'], $result);
}

protected function tearDown(): void
{
Expand Down

0 comments on commit 5a19cd2

Please sign in to comment.