Skip to content

MQTT Unit Tests: Odoo-ABS Integration

Test Design Pattern: Emit/Echo Validation

Following user memory "MQTT Listener Integration, Topic Structure, and Unit Test Pattern": - Each test publishes an MQTT signal (emit) - Validates the corresponding response signal (echo) - Ensures proper alignment with event-driven architecture

Test Suite 1: Odoo Subscription Synchronization

Test 1.1: Successful Subscription Payment Update

EMIT:

{
  "topic": "emit/Odoo/subscription/12345/payment_updated",
  "payload": {
    "subscription_id": 12345,
    "payment_state": "paid",
    "amount_total": 2500.0,
    "currency_id": "KES",
    "invoice_id": "INV-001",
    "payment_date": "2025-01-15T14:30:00Z"
  }
}

EXPECTED ECHO:

{
  "topic": "echo/ABS/serviceplan/plan-123/sync_completed",
  "payload": {
    "plan_id": "plan-123",
    "success": true,
    "signals": ["ODOO_SYNC_SUCCESS"],
    "metadata": {
      "called": "syncOdooSubscription",
      "sync_status": "success",
      "odoo_subscription_id": 12345,
      "agent_state_updates": {
        "odoo_subscription_id": 12345,
        "odoo_payment_state": "paid",
        "odoo_last_sync_at": "2025-01-15T14:30:00Z"
      },
      "fsm_inputs_generated": 1
    },
    "fsmInputs": [
      {
        "cycle": "payment_cycle",
        "input": "PAYMENT_CONFIRMED"
      }
    ]
  }
}

Test 1.2: Subscription State Change (In Progress)

EMIT:

{
  "topic": "emit/Odoo/subscription/12345/state_changed",
  "payload": {
    "subscription_id": 12345,
    "state": "in_progress",
    "previous_state": "draft",
    "change_reason": "customer_activated",
    "timestamp": "2025-01-15T14:35:00Z"
  }
}

EXPECTED ECHO:

{
  "topic": "echo/ABS/serviceplan/plan-123/sync_completed",
  "payload": {
    "plan_id": "plan-123",
    "success": true,
    "signals": ["ODOO_SYNC_SUCCESS"],
    "metadata": {
      "called": "syncOdooSubscription",
      "sync_status": "success",
      "odoo_subscription_id": 12345,
      "agent_state_updates": {
        "odoo_subscription_id": 12345,
        "odoo_subscription_state": "in_progress",
        "odoo_last_sync_at": "2025-01-15T14:35:00Z"
      },
      "state_mappings": {
        "subscription_state": "SERVICE_ACTIVE"
      },
      "fsm_inputs_generated": 1
    },
    "fsmInputs": [
      {
        "cycle": "service_cycle",
        "input": "CONTINUE_SERVICE_REQUESTED"
      }
    ]
  }
}

Test 1.3: Payment Overdue Notification

EMIT:

{
  "topic": "emit/Odoo/subscription/12345/payment_overdue",
  "payload": {
    "subscription_id": 12345,
    "payment_state": "not_paid",
    "amount_due": 2500.0,
    "currency_id": "KES",
    "days_overdue": 5,
    "grace_period_remaining": 2,
    "invoice_id": "INV-002"
  }
}

EXPECTED ECHO:

{
  "topic": "echo/ABS/serviceplan/plan-123/sync_completed",
  "payload": {
    "plan_id": "plan-123",
    "success": true,
    "signals": ["ODOO_SYNC_SUCCESS"],
    "metadata": {
      "called": "syncOdooSubscription",
      "sync_status": "success",
      "odoo_subscription_id": 12345,
      "agent_state_updates": {
        "odoo_subscription_id": 12345,
        "odoo_payment_state": "not_paid",
        "odoo_last_sync_at": "2025-01-15T14:40:00Z"
      },
      "state_mappings": {
        "payment_state": "PAYMENT_PENDING"
      },
      "fsm_inputs_generated": 1
    },
    "fsmInputs": [
      {
        "cycle": "payment_cycle",
        "input": "PAYMENT_OVERDUE"
      }
    ]
  }
}

Test Suite 2: Error Handling

Test 2.1: Missing Subscription ID

EMIT:

{
  "topic": "emit/Odoo/subscription/unknown/payment_updated",
  "payload": {
    "payment_state": "paid",
    "amount_total": 2500.0,
    "currency_id": "KES"
  }
}

EXPECTED ECHO:

{
  "topic": "echo/ABS/serviceplan/unknown/sync_error",
  "payload": {
    "plan_id": "unknown",
    "success": false,
    "signals": ["ODOO_SYNC_ERROR"],
    "metadata": {
      "called": "syncOdooSubscription",
      "validator_matched": "missing_subscription_id",
      "reason": "Odoo subscription ID missing from sync payload",
      "sync_status": "failed",
      "sync_timestamp": "2025-01-15T14:45:00Z"
    }
  }
}

Test 2.2: Invalid Payment State

EMIT:

{
  "topic": "emit/Odoo/subscription/12345/payment_updated",
  "payload": {
    "subscription_id": 12345,
    "payment_state": "invalid_state",
    "amount_total": 2500.0,
    "currency_id": "KES"
  }
}

EXPECTED ECHO:

{
  "topic": "echo/ABS/serviceplan/plan-123/sync_warning",
  "payload": {
    "plan_id": "plan-123",
    "success": true,
    "signals": ["ODOO_SYNC_WARNING"],
    "metadata": {
      "called": "syncOdooSubscription",
      "sync_status": "success",
      "odoo_subscription_id": 12345,
      "warnings": [
        {
          "name": "invalid_payment_state",
          "reason": "Unknown Odoo payment state received"
        }
      ],
      "agent_state_updates": {
        "odoo_subscription_id": 12345,
        "odoo_last_sync_at": "2025-01-15T14:50:00Z"
      }
    }
  }
}

Test Suite 3: Service Availability with Odoo Integration

Test 3.1: Service Check with Odoo Payment Current

EMIT:

{
  "topic": "emit/BSS/serviceplan/plan-123/check_service",
  "payload": {
    "action": "CHECK_SERVICE",
    "station_id": "STATION_001",
    "battery_type": "TYPE_A",
    "agent_state": {
      "odoo_subscription_id": 12345,
      "odoo_payment_state": "paid",
      "odoo_subscription_state": "in_progress"
    }
  }
}

EXPECTED ECHO:

{
  "topic": "echo/BSS/serviceplan/plan-123/service_available",
  "payload": {
    "plan_id": "plan-123",
    "success": true,
    "signals": ["SERVICE_AVAILABLE"],
    "metadata": {
      "called": "checkServiceAvailability",
      "validator_matched": "service_available",
      "availability_status": "available",
      "station_id": "STATION_001",
      "quota_status": {
        "used": 0,
        "limit": 10,
        "percentage": 0,
        "remaining": 10
      },
      "payment_status": "current",
      "odoo_integration": {
        "subscription_id": 12345,
        "payment_state": "paid",
        "subscription_state": "in_progress"
      }
    }
  }
}

Test Suite 4: Complete Integration Flow

Test 4.1: End-to-End Subscription Creation to Service Usage

Step 1 - EMIT: Odoo Subscription Created

{
  "topic": "emit/Odoo/subscription/12345/created",
  "payload": {
    "subscription_id": 12345,
    "partner_id": "customer-001",
    "template_id": "template-nairobi-monthly-flatfee-v2",
    "state": "in_progress",
    "currency_id": "KES",
    "amount_total": 2500.0,
    "start_date": "2025-01-15"
  }
}

Step 1 - EXPECTED ECHO: ServicePlan Created

{
  "topic": "echo/ABS/serviceplan/plan-123/created",
  "payload": {
    "plan_id": "plan-123",
    "success": true,
    "signals": ["SERVICE_PLAN_CREATED"],
    "metadata": {
      "called": "createServicePlanFromOdoo",
      "template_id": "template-nairobi-monthly-flatfee-v2",
      "customer_id": "customer-001",
      "odoo_subscription_id": 12345,
      "initial_agent_state": {
        "odoo_subscription_id": 12345,
        "odoo_subscription_state": "in_progress",
        "odoo_last_sync_at": "2025-01-15T15:00:00Z"
      }
    }
  }
}

Step 2 - EMIT: Service Availability Check

{
  "topic": "emit/BSS/serviceplan/plan-123/check_service",
  "payload": {
    "action": "CHECK_SERVICE",
    "station_id": "STATION_001",
    "battery_type": "TYPE_A"
  }
}

Step 2 - EXPECTED ECHO: Service Available

{
  "topic": "echo/BSS/serviceplan/plan-123/service_available",
  "payload": {
    "plan_id": "plan-123",
    "success": true,
    "signals": ["SERVICE_AVAILABLE"],
    "metadata": {
      "called": "checkServiceAvailability",
      "availability_status": "available",
      "odoo_integration_verified": true
    }
  }
}

Test Implementation Structure

Test Framework Requirements

interface MQTTTestCase {
  name: string;
  emit: {
    topic: string;
    payload: any;
  };
  expectedEcho: {
    topic: string;
    payload: any;
    timeout_ms: number;
  };
  setup?: {
    plan_state?: any;
    agent_state?: any;
  };
  validation: {
    signals: string[];
    metadata_fields: string[];
    fsm_inputs?: Array<{cycle: string; input: string}>;
  };
}

Test Execution Pattern

async function runMQTTTest(testCase: MQTTTestCase): Promise<TestResult> {
  // 1. Setup test environment
  if (testCase.setup) {
    await setupTestEnvironment(testCase.setup);
  }

  // 2. Subscribe to expected echo topic
  const echoPromise = mqttClient.waitForMessage(
    testCase.expectedEcho.topic,
    testCase.expectedEcho.timeout_ms
  );

  // 3. Emit test message
  await mqttClient.publish(testCase.emit.topic, testCase.emit.payload);

  // 4. Wait for and validate echo
  const echo = await echoPromise;

  // 5. Validate response structure and content
  return validateEcho(echo, testCase.expectedEcho, testCase.validation);
}

Test Topic Patterns

Emit Topic Patterns (Input)

  • emit/Odoo/subscription/{subscription_id}/{event}
  • emit/BSS/serviceplan/{plan_id}/{action}
  • emit/ABS/product_template/{template_id}/{event}

Echo Topic Patterns (Expected Output)

  • echo/ABS/serviceplan/{plan_id}/{result_type}
  • echo/BSS/serviceplan/{plan_id}/{service_status}
  • echo/Odoo/product/{product_id}/{sync_status}

Validation Criteria

Signal Validation

  • Success cases: Specific success signals (e.g., ODOO_SYNC_SUCCESS, SERVICE_AVAILABLE)
  • Error cases: Appropriate error signals (e.g., ODOO_SYNC_ERROR, VALIDATION_ERROR)
  • Warning cases: Warning signals with continued operation (e.g., ODOO_SYNC_WARNING)

Metadata Validation

  • Agent state updates: Verify Odoo fields properly updated in agent_state
  • State mappings: Confirm Odoo states correctly mapped to ABS states
  • FSM inputs: Validate appropriate FSM inputs generated for state changes
  • Timestamp accuracy: Ensure sync timestamps are current and accurate

Integration Validation

  • Domain isolation: Confirm Odoo data stays within BSS agent_state
  • Existing functionality: Verify non-Odoo operations remain unaffected
  • Error resilience: Test graceful handling of malformed Odoo payloads
  • Performance: Validate O(1) FSM performance maintained with Odoo integration