Files
desk-moloni/modules/desk_moloni/tests/contract/ConfigTableTest.php
Emanuel Almeida c19f6fd9ee fix(perfexcrm module): align version to 3.0.1, unify entrypoint, and harden routes/views
- Bump DESK_MOLONI version to 3.0.1 across module
- Normalize hooks to after_client_* and instantiate PerfexHooks safely
- Fix OAuthController view path and API client class name
- Add missing admin views for webhook config/logs; adjust view loading
- Harden client portal routes and admin routes mapping
- Make Dashboard/Logs/Queue tolerant to optional model methods
- Align log details query with existing schema; avoid broken joins

This makes the module operational in Perfex (admin + client), reduces 404s,
and avoids fatal errors due to inconsistent tables/methods.
2025-09-11 17:38:45 +01:00

221 lines
8.0 KiB
PHP

<?php
/**
* Contract Test for desk_moloni_config table
*
* This test MUST FAIL until the Config_model is properly implemented
* Following TDD RED-GREEN-REFACTOR cycle
*
* @package DeskMoloni\Tests\Contract
*/
namespace DeskMoloni\Tests\Contract;
use PHPUnit\Framework\TestCase;
class ConfigTableTest extends TestCase
{
private $CI;
private $db;
protected function setUp(): void
{
// Initialize CodeIgniter instance
$this->CI = &get_instance();
$this->CI->load->database();
$this->db = $this->CI->db;
// Ensure we're in test environment
if (ENVIRONMENT !== 'testing') {
$this->markTestSkipped('Contract tests should only run in testing environment');
}
}
/**
* @test
* Contract: desk_moloni_config table must exist with correct structure
*/
public function config_table_exists_with_required_structure()
{
// ARRANGE: Test database table existence and structure
// ACT: Query table structure
$table_exists = $this->db->table_exists('desk_moloni_config');
// ASSERT: Table must exist
$this->assertTrue($table_exists, 'desk_moloni_config table must exist');
// ASSERT: Required columns exist with correct types
$fields = $this->db->list_fields('desk_moloni_config');
$required_fields = ['id', 'setting_key', 'setting_value', 'encrypted', 'created_at', 'updated_at'];
foreach ($required_fields as $field) {
$this->assertContains($field, $fields, "Required field '{$field}' must exist in desk_moloni_config table");
}
// ASSERT: Check field types and constraints
$field_data = $this->db->field_data('desk_moloni_config');
$field_info = [];
foreach ($field_data as $field) {
$field_info[$field->name] = $field;
}
// Verify setting_key is unique
$this->assertEquals('varchar', strtolower($field_info['setting_key']->type), 'setting_key must be varchar type');
$this->assertEquals(255, $field_info['setting_key']->max_length, 'setting_key must have max_length of 255');
// Verify encrypted is boolean (tinyint in MySQL)
$this->assertEquals('tinyint', strtolower($field_info['encrypted']->type), 'encrypted must be tinyint type');
$this->assertEquals(1, $field_info['encrypted']->default_value, 'encrypted must have default value of 0');
}
/**
* @test
* Contract: Config table must enforce unique constraint on setting_key
*/
public function config_table_enforces_unique_setting_key()
{
// ARRANGE: Clean table and insert test data
$this->db->truncate('desk_moloni_config');
$test_data = [
'setting_key' => 'test_unique_key',
'setting_value' => 'test_value',
'encrypted' => 0
];
// ACT & ASSERT: First insert should succeed
$first_insert = $this->db->insert('desk_moloni_config', $test_data);
$this->assertTrue($first_insert, 'First insert with unique key should succeed');
// ACT & ASSERT: Second insert with same key should fail
$this->expectException(\Exception::class);
$this->db->insert('desk_moloni_config', $test_data);
}
/**
* @test
* Contract: Config table must have proper indexes for performance
*/
public function config_table_has_required_indexes()
{
// ACT: Get table indexes
$indexes = $this->db->query("SHOW INDEX FROM desk_moloni_config")->result_array();
// ASSERT: Primary key exists
$has_primary = false;
$has_setting_key_index = false;
foreach ($indexes as $index) {
if ($index['Key_name'] === 'PRIMARY') {
$has_primary = true;
}
if ($index['Key_name'] === 'idx_setting_key') {
$has_setting_key_index = true;
}
}
$this->assertTrue($has_primary, 'Table must have PRIMARY KEY');
$this->assertTrue($has_setting_key_index, 'Table must have idx_setting_key index for performance');
}
/**
* @test
* Contract: Config table must support encrypted and non-encrypted values
*/
public function config_table_supports_encryption_flag()
{
// ARRANGE: Clean table
$this->db->truncate('desk_moloni_config');
// ACT: Insert encrypted and non-encrypted test data
$encrypted_data = [
'setting_key' => 'oauth_access_token',
'setting_value' => 'encrypted_token_value',
'encrypted' => 1
];
$plain_data = [
'setting_key' => 'api_base_url',
'setting_value' => 'https://api.moloni.pt/v1',
'encrypted' => 0
];
$this->db->insert('desk_moloni_config', $encrypted_data);
$this->db->insert('desk_moloni_config', $plain_data);
// ASSERT: Data inserted correctly with proper encryption flags
$encrypted_row = $this->db->get_where('desk_moloni_config', ['setting_key' => 'oauth_access_token'])->row();
$plain_row = $this->db->get_where('desk_moloni_config', ['setting_key' => 'api_base_url'])->row();
$this->assertEquals(1, $encrypted_row->encrypted, 'Encrypted flag must be set for sensitive data');
$this->assertEquals(0, $plain_row->encrypted, 'Encrypted flag must be false for plain data');
}
/**
* @test
* Contract: Config table must have automatic timestamps
*/
public function config_table_has_automatic_timestamps()
{
// ARRANGE: Clean table
$this->db->truncate('desk_moloni_config');
// ACT: Insert test record
$test_data = [
'setting_key' => 'timestamp_test',
'setting_value' => 'test_value',
'encrypted' => 0
];
$this->db->insert('desk_moloni_config', $test_data);
// ASSERT: Timestamps are automatically set
$row = $this->db->get_where('desk_moloni_config', ['setting_key' => 'timestamp_test'])->row();
$this->assertNotNull($row->created_at, 'created_at must be automatically set');
$this->assertNotNull($row->updated_at, 'updated_at must be automatically set');
// ASSERT: Timestamps are recent (within last 5 seconds)
$created_time = strtotime($row->created_at);
$current_time = time();
$this->assertLessThan(5, abs($current_time - $created_time), 'created_at must be recent');
}
/**
* @test
* Contract: Config table must support TEXT values for large configurations
*/
public function config_table_supports_large_text_values()
{
// ARRANGE: Clean table
$this->db->truncate('desk_moloni_config');
// ACT: Insert large value (simulate large JSON configuration)
$large_value = str_repeat('{"large_config":' . str_repeat('"test"', 1000) . '}', 10);
$test_data = [
'setting_key' => 'large_config_test',
'setting_value' => $large_value,
'encrypted' => 0
];
$insert_success = $this->db->insert('desk_moloni_config', $test_data);
// ASSERT: Large values can be stored
$this->assertTrue($insert_success, 'Table must support large TEXT values');
// ASSERT: Large value is retrieved correctly
$row = $this->db->get_where('desk_moloni_config', ['setting_key' => 'large_config_test'])->row();
$this->assertEquals($large_value, $row->setting_value, 'Large values must be stored and retrieved correctly');
}
protected function tearDown(): void
{
// Clean up test data
if ($this->db) {
$this->db->where('setting_key LIKE', 'test_%');
$this->db->or_where('setting_key LIKE', '%_test');
$this->db->delete('desk_moloni_config');
}
}
}