FOUNDRY
C8 Platform
← Tasks

Integration testing for Salesforce ISV package

completedvalidateP2

Description

End-to-end testing of Salesforce ISV package: /api/v1/classify endpoint, bulk classification, error handling, rate limiting. Test with Salesforce sandbox org.
Assignee
-
Claimed By
Cloud Lu → Claude Sonnet
Created
21d ago
Completed
1d ago

Quality

Overall
62%
Pass
FAIL
Graded By
-
Graded At
-

Cost

Input Tokens
-
Output Tokens
-
Est. USD
-

Result

{
  "cost": {
    "input_tokens": 57,
    "estimated_usd": 0.133566,
    "output_tokens": 8893
  },
  "model": "claude-sonnet-4-20250514",
  "status": "success",
  "transport": "anthropic_api",
  "latency_ms": 102099,
  "response_text": "I'll help you create a comprehensive integration testing strategy for your Salesforce ISV package. Here's a complete testing framework:\n\n## 1. Test Environment Setup\n\n### Salesforce Sandbox Configuration\n\n```apex\n// TestDataFactory.cls\n@isTest\npublic class TestDataFactory {\n    public static final String TEST_NAMESPACE = 'YourPackageNamespace';\n    \n    public static Account createTestAccount(String name) {\n        Account acc = new Account(\n            Name = name,\n            Industry = 'Technology',\n            Type = 'Customer'\n        );\n        insert acc;\n        return acc;\n    }\n    \n    public static List<Contact> createTestContacts(Integer count, Id accountId) {\n        List<Contact> contacts = new List<Contact>();\n        for (Integer i = 0; i < count; i++) {\n            contacts.add(new Contact(\n                FirstName = 'Test' + i,\n                LastName = 'Contact' + i,\n                Email = 'test' + i + '@example.com',\n                AccountId = accountId\n            ));\n        }\n        insert contacts;\n        return contacts;\n    }\n    \n    public static Custom_Classification__c createClassificationRecord(String type, String status) {\n        Custom_Classification__c classification = new Custom_Classification__c(\n            Classification_Type__c = type,\n            Status__c = status,\n            Processing_Date__c = System.now()\n        );\n        insert classification;\n        return classification;\n    }\n}\n```\n\n### Test Configuration Class\n\n```apex\n// ClassificationTestConfig.cls\n@isTest\npublic class ClassificationTestConfig {\n    public static final String VALID_API_ENDPOINT = '/services/apexrest/YourPackageNamespace/api/v1/classify';\n    public static final Integer BULK_TEST_SIZE = 100;\n    public static final Integer RATE_LIMIT_THRESHOLD = 1000;\n    \n    public class TestResponse {\n        public Boolean success;\n        public String message;\n        public Object data;\n        public String errorCode;\n        \n        public TestResponse(Boolean success, String message) {\n            this.success = success;\n            this.message = message;\n        }\n    }\n}\n```\n\n## 2. API Endpoint Testing\n\n### REST API Implementation\n\n```apex\n// ClassificationRestAPI.cls\n@RestResource(urlMapping='/api/v1/classify/*')\nglobal with sharing class ClassificationRestAPI {\n    \n    @HttpPost\n    global static ClassificationResponse classify() {\n        try {\n            RestRequest request = RestContext.request;\n            ClassificationRequest classificationRequest = \n                (ClassificationRequest) JSON.deserialize(\n                    request.requestBody.toString(), \n                    ClassificationRequest.class\n                );\n            \n            // Rate limiting check\n            if (!RateLimitingService.checkRateLimit(UserInfo.getUserId())) {\n                RestContext.response.statusCode = 429;\n                return new ClassificationResponse(false, 'Rate limit exceeded', null);\n            }\n            \n            // Process classification\n            ClassificationResult result = ClassificationService.processClassification(\n                classificationRequest\n            );\n            \n            return new ClassificationResponse(true, 'Success', result);\n            \n        } catch (Exception e) {\n            RestContext.response.statusCode = 500;\n            return new ClassificationResponse(false, e.getMessage(), null);\n        }\n    }\n    \n    @HttpGet\n    global static ClassificationResponse getClassificationStatus() {\n        try {\n            String classificationId = RestContext.request.params.get('id');\n            if (String.isEmpty(classificationId)) {\n                RestContext.response.statusCode = 400;\n                return new ClassificationResponse(false, 'Missing classification ID', null);\n            }\n            \n            ClassificationResult result = ClassificationService.getClassificationById(\n                classificationId\n            );\n            \n            return new ClassificationResponse(true, 'Success', result);\n            \n        } catch (Exception e) {\n            RestContext.response.statusCode = 404;\n            return new ClassificationResponse(false, 'Classification not found', null);\n        }\n    }\n}\n```\n\n### API Test Class\n\n```apex\n// ClassificationAPITest.cls\n@isTest\nprivate class ClassificationAPITest {\n    \n    @testSetup\n    static void setupTestData() {\n        Account testAccount = TestDataFactory.createTestAccount('Test Account');\n        TestDataFactory.createTestContacts(5, testAccount.Id);\n    }\n    \n    @isTest\n    static void testSingleClassificationSuccess() {\n        Test.startTest();\n        \n        // Prepare request\n        ClassificationRequest request = new ClassificationRequest();\n        request.text = 'This is a test classification text';\n        request.type = 'SENTIMENT';\n        request.options = new Map<String, Object>{\n            'language' => 'en',\n            'confidence_threshold' => 0.8\n        };\n        \n        // Set up REST context\n        RestRequest restRequest = new RestRequest();\n        RestResponse restResponse = new RestResponse();\n        restRequest.requestBody = Blob.valueOf(JSON.serialize(request));\n        RestContext.request = restRequest;\n        RestContext.response = restResponse;\n        \n        // Call API\n        ClassificationResponse response = ClassificationRestAPI.classify();\n        \n        Test.stopTest();\n        \n        // Assertions\n        System.assert(response.success, 'Classification should succeed');\n        System.assertEquals(200, RestContext.response.statusCode);\n        System.assertNotEquals(null, response.data);\n    }\n    \n    @isTest\n    static void testInvalidRequestHandling() {\n        Test.startTest();\n        \n        // Prepare invalid request\n        RestRequest restRequest = new RestRequest();\n        RestResponse restResponse = new RestResponse();\n        restRequest.requestBody = Blob.valueOf('invalid json');\n        RestContext.request = restRequest;\n        RestContext.response = restResponse;\n        \n        // Call API\n        ClassificationResponse response = ClassificationRestAPI.classify();\n        \n        Test.stopTest();\n        \n        // Assertions\n        System.assert(!response.success, 'Invalid request should fail');\n        System.assertEquals(500, RestContext.response.statusCode);\n    }\n    \n    @isTest\n    static void testGetClassificationStatus() {\n        Test.startTest();\n        \n        // Create test classification\n        Custom_Classification__c classification = TestDataFactory.createClassificationRecord(\n            'SENTIMENT', 'COMPLETED'\n        );\n        \n        // Set up REST context\n        RestRequest restRequest = new RestRequest();\n        RestResponse restResponse = new RestResponse();\n        restRequest.params = new Map<String, String>{\n            'id' => classification.Id\n        };\n        RestContext.request = restRequest;\n        RestContext.response = restResponse;\n        \n        // Call API\n        ClassificationResponse response = ClassificationRestAPI.getClassificationStatus();\n        \n        Test.stopTest();\n        \n        // Assertions\n        System.assert(response.success, 'Get status should succeed');\n        System.assertEquals(200, RestContext.response.statusCode);\n    }\n}\n```\n\n## 3. Bulk Classification Testing\n\n### Bulk Classification Service\n\n```apex\n// BulkClassificationService.cls\npublic with sharing class BulkClassificationService {\n    \n    public static final Integer MAX_BATCH_SIZE = 200;\n    public static final Integer DEFAULT_BATCH_SIZE = 50;\n    \n    public class BulkClassificationRequest {\n        public List<ClassificationItem> items;\n        public String batchId;\n        public Map<String, Object> globalOptions;\n    }\n    \n    public class ClassificationItem {\n        public String id;\n        public String text;\n        public String type;\n        public Map<String, Object> options;\n    }\n    \n    @future(callout=true)\n    public static void processBulkClassification(String requestJson) {\n        try {\n            BulkClassificationRequest request = (BulkClassificationRequest) \n                JSON.deserialize(requestJson, BulkClassificationRequest.class);\n            \n            List<Custom_Classification__c> results = new List<Custom_Classification__c>();\n            \n            for (ClassificationItem item : request.items) {\n                Custom_Classification__c result = processIndividualClassification(item);\n                result.Batch_Id__c = request.batchId;\n                results.add(result);\n            }\n            \n            upsert results External_Id__c;\n            \n            // Update batch status\n            updateBatchStatus(request.batchId, 'COMPLETED');\n            \n        } catch (Exception e) {\n            updateBatchStatus(request.batchId, 'FAILED');\n            throw e;\n        }\n    }\n    \n    private static Custom_Classification__c processIndividualClassification(\n        ClassificationItem item\n    ) {\n        // Process individual classification logic\n        Custom_Classification__c result = new Custom_Classification__c(\n            External_Id__c = item.id,\n            Input_Text__c = item.text,\n            Classification_Type__c = item.type,\n            Status__c = 'PROCESSING'\n        );\n        \n        // Simulate classification processing\n        result.Confidence_Score__c = Math.random();\n        result.Classification_Result__c = 'POSITIVE'; // Mock result\n        result.Status__c = 'COMPLETED';\n        \n        return result;\n    }\n    \n    private static void updateBatchStatus(String batchId, String status) {\n        Classification_Batch__c batch = [\n            SELECT Id, Status__c \n            FROM Classification_Batch__c \n            WHERE Batch_Id__c = :batchId \n            LIMIT 1\n        ];\n        batch.Status__c = status;\n        batch.Completed_Date__c = System.now();\n        update batch;\n    }\n}\n```\n\n### Bulk Classification Tests\n\n```apex\n// BulkClassificationTest.cls\n@isTest\nprivate class BulkClassificationTest {\n    \n    @testSetup\n    static void setupBulkTestData() {\n        // Create batch record\n        Classification_Batch__c batch = new Classification_Batch__c(\n            Batch_Id__c = 'TEST_BATCH_001',\n            Status__c = 'PENDING',\n            Total_Items__c = 100,\n            Created_Date__c = System.now()\n        );\n        insert batch;\n    }\n    \n    @isTest\n    static void testBulkClassificationSuccess() {\n        Test.startTest();\n        \n        // Prepare bulk request\n        BulkClassificationService.BulkClassificationRequest request = \n            new BulkClassificationService.BulkClassificationRequest();\n        request.batchId = 'TEST_BATCH_001';\n        request.items = new List<BulkClassificationService.ClassificationItem>();\n        \n        // Create test items\n        for (Integer i = 0; i < 10; i++) {\n            BulkClassificationService.ClassificationItem item = \n                new BulkClassificationService.ClassificationItem();\n            item.id = 'ITEM_' + i;\n            item.text = 'Test text for classification ' + i;\n            item.type = 'SENTIMENT';\n            request.items.add(item);\n        }\n        \n        // Process bulk classification\n        String requestJson = JSON.serialize(request);\n        BulkClassificationService.processBulkClassification(requestJson);\n        \n        Test.stopTest();\n        \n        // Verify results\n        List<Custom_Classification__c> results = [\n            SELECT Id, External_Id__c, Status__c, Batch_Id__c \n            FROM Custom_Classification__c \n            WHERE Batch_Id__c = 'TEST_BATCH_001'\n        ];\n        \n        System.assertEquals(10, results.size(), 'Should create 10 classification records');\n        \n        for (Custom_Classification__c result : results) {\n            System.assertEquals('COMPLETED', result.Status__c);\n        }\n    }\n    \n    @isTest\n    static void testBulkClassificationBatchSizeLimit() {\n        Test.startTest();\n        \n        // Test with oversized batch\n        BulkClassificationService.BulkClassificationRequest request = \n            new BulkClassificationService.BulkClassificationRequest();\n        request.batchId = 'TEST_BATCH_LARGE';\n        request.items = new List<BulkClassificationService.ClassificationItem>();\n        \n        // Create items exceeding batch size limit\n        for (Integer i = 0; i < BulkClassificationService.MAX_BATCH_SIZE + 10; i++) {\n            BulkClassificationService.ClassificationItem item = \n                new BulkClassificationService.ClassificationItem();\n            item.id = 'LARGE_ITEM_' + i;\n            item.text = 'Test text ' + i;\n            item.type = 'SENTIMENT';\n            request.items.add(item);\n        }\n        \n        Boolean exceptionThrown = false;\n        try {\n            String requestJson = JSON.serialize(request);\n            BulkClassificationService.processBulkClassification(requestJson);\n        } catch (Exception e) {\n            exceptionThrown = true;\n        }\n        \n        Test.stopTest();\n        \n        // Should handle large batches appropriately\n        System.assert(exceptionThrown || request.items.size() <= BulkClassificationService.MAX_BATCH_SIZE);\n    }\n}\n```\n\n## 4. Error Handling Tests\n\n### Error Handling Test Class\n\n```apex\n// ErrorHandlingTest.cls\n@isTest\nprivate class ErrorHandlingTest {\n    \n    @isTest\n    static void testNetworkTimeoutHandling() {\n        Test.startTest();\n        Test.setMock(HttpCalloutMock.class, new TimeoutMockResponse());\n        \n        ClassificationRequest request = new ClassificationRequest();\n        request.text = 'Test timeout scenario';\n        request.type = 'SENTIMENT';\n        \n        RestRequest restRequest = new RestRequest();\n        RestResponse restResponse = new RestResponse();\n        restRequest.requestBody = Blob.valueOf(JSON.serialize(request));\n        RestContext.request = restRequest;\n        RestContext.response = restResponse;\n        \n        ClassificationResponse response = ClassificationRestAPI.classify();\n        \n        Test.stopTest();\n        \n        System.assert(!response.success);\n        System.assert(response.message.contains('timeout') || response.message.contains('error'));\n    }\n    \n    @isTest\n    static void testInvalidAPIKeyHandling() {\n        Test.startTest();\n        Test.setMock(HttpCalloutMock.class, new UnauthorizedMockResponse());\n        \n        ClassificationRequest request = new ClassificationRequest();\n        request.text = 'Test unauthorized scenario';\n        request.type = 'SENTIMENT';\n        \n        RestRequest restRequest = new RestRequest();\n        RestResponse restResponse = new RestResponse();\n        restRequest.requestBody = Blob.valueOf(JSON.serialize(request));\n        RestContext.request = restRequest;\n        RestContext.response = restResponse;\n        \n        ClassificationResponse response = ClassificationRestAPI.classify();\n        \n        Test.stopTest();\n        \n        System.assert(!response.success);\n        System.assertEquals(401, RestContext.response.statusCode);\n    }\n    \n    @isTest\n    static void testDatabaseConstraintViolation() {\n        Test.startTest();\n        \n        // Create duplicate records to trigger constraint violation\n        Custom_Classification__c record1 = new Custom_Classification__c(\n            External_Id__c = 'DUPLICATE_ID',\n            Classification_Type__c = 'SENTIMENT'\n        );\n        insert record1;\n        \n        Boolean exceptionCaught = false;\n        try {\n            Custom_Classification__c record2 = new Custom_Classification__c(\n                External_Id__c = 'DUPLICATE_ID',\n                Classification_Type__c = 'SENTIMENT'\n            );\n            insert record2;\n        } catch (DmlException e) {\n            exceptionCaught = true;\n            System.assert(e.getMessage().contains('DUPLICATE_VALUE'));\n        }\n        \n        Test.stopTest();\n        \n        System.assert(exceptionCaught, 'Should catch duplicate value exception');\n    }\n}\n\n// Mock classes for error testing\n@isTest\npublic class TimeoutMockResponse implements HttpCalloutMock {\n    public HTTPResponse respond(HTTPRequest req) {\n        CalloutException ex = new CalloutException();\n        ex.setMessage('Read timed out');\n        throw ex;\n    }\n}\n\n@isTest\npublic class UnauthorizedMockResponse implements HttpCalloutMock {\n    public HTTPResponse respond(HTTPRequest req) {\n        HttpResponse res = new HttpResponse();\n        res.setStatusCode(401);\n        res.setBody('Unauthorized');\n        return res;\n    }\n}\n```\n\n## 5. Rate Limiting Tests\n\n### Rate Limiting Service\n\n```apex\n// RateLimitingService.cls\npublic with sharing class RateLimitingService {\n    \n    public static final Integer HOURLY_LIMIT = 1000;\n    public static final Integer DAILY_LIMIT = 10000;\n    \n    public static Boolean checkRateLimit(String userId) {\n        DateTime now = System.now();\n        DateTime hourAgo = now.addHours(-1);\n        DateTime dayAgo = now.addDays(-1);\n        \n        // Check hourly limit\n        Integer hourlyCount = [\n            SELECT COUNT() \n            FROM API_Usage__c \n            WHERE User_Id__c = :userId \n            AND Request_Time__c >= :hourAgo\n        ];\n        \n        if (hourlyCount >= HOURLY_LIMIT) {\n            return false;\n        }\n        \n        // Check daily limit\n        Integer dailyCount = [\n            SELECT COUNT() \n            FROM API_Usage__c \n            WHERE User_Id__c = :userId \n            AND Request_Time__c >= :dayAgo\n        ];\n        \n        if (dailyCount >= DAILY_LIMIT) {\n            return false;\n        }\n        \n        // Record API usage\n        recordAPIUsage(userId);\n        \n        return true;\n    }\n    \n    private static void recordAPIUsage(String userId) {\n        API_Usage__c usage = new API_Usage__c(\n            User_Id__c = userId,\n            Request_Time__c = System.now(),\n            Endpoint__c = '/api/v1/classify'\n        );\n        insert usage;\n    }\n    \n    public static Map<String, Integer> getRateLimitStatus(String userId) {\n        DateTime now = System.now();\n        DateTime hourAgo = now.addHours(-1);\n        DateTime dayAgo = now.addDays(-1);\n        \n        Integer hourlyUsed = [\n            SELECT COUNT() \n            FROM API_Usage__c \n            WHERE User_Id__c = :userId \n            AND Request_Time__c >= :hourAgo\n        ];\n        \n        Integer dailyUsed = [\n            SELECT COUNT() \n            FROM API_Usage__c \n            WHERE User_Id__c = :userId \n            AND Request_Time__c >= :dayAgo\n        ];\n        \n        return new Map<String, Integer>{\n            'hourly_used' => hourlyUsed,\n            'hourly_limit' => HOURLY_LIMIT,\n            'hourly_remaining' => HOURLY_LIMIT - hourlyUsed,\n            'daily_used' => dailyUsed,\n            'daily_limit' => DAILY_LIMIT,\n            'daily_remaining' => DAILY_LIMIT - dailyUsed\n        };\n    }\n}\n```\n\n### Rate Limiting Tests\n\n```apex\n// RateLimitingTest.cls\n@isTest\nprivate class RateLimitingTest {\n    \n    @testSetup\n    static void setupRateLimitData() {\n        // Create test user usage records\n        String testUserId = UserInfo.getUserId();\n        List<API_Usage__c> usageRecords = new List<API_Usage__c>();\n        \n        DateTime now = System.now();\n        \n        // Create records approaching hourly limit\n        for (Integer i = 0; i < 950; i++) {\n            usageRecords.add(new API_Usage__c(\n                User_Id__c = testUserId,\n                Request_Time__c = now.addMinutes(-i),\n                Endpoint__c = '/api/v1/classify'\n            ));\n        }\n        \n        insert usageRecords;\n    }\n    \n    @isTest\n    static void testRateLimitNotExceeded() {\n        Test.startTest();\n        \n        String testUserId = UserInfo.getUserId();\n        Boolean allowed = RateLimitingService.checkRateLimit(testUserId);\n        \n        Test.stopTest();\n        \n        System.assert(allowed, 'Request should be allowed when under rate limit');\n    }\n    \n    @isTest\n    static void testHourlyRateLimitExceeded() {\n        Test.startTest();\n        \n        String testUserId = UserInfo.getUserId();\n        \n        // Add more records to exceed hourly limit\n        List<API_Usage__c> additionalUsage = new List<API_Usage__c>();\n        for (Integer i = 0; i < 60; i++) {\n            additionalUsage.add(new API_Usage__c(\n                User_Id__c = testUserId,\n                Request_Time__c = System.now().addMinutes(-5),\n                Endpoint__c = '/api/v1/classify'\n            ));\n        }\n        insert additionalUsage;\n        \n        Boolean allowed = RateLimitingService.checkRateLimit(testUserId);\n        \n        Test.stopTest();\n        \n        System.assert(!allowed, 'Request should be blocked when hourly rate limit exceeded');\n    }\n    \n    @isTest\n    static void testRateLimitStatusRetrieval() {\n        Test.startTest();\n        \n        String testUserId = UserInfo.getUserId();\n        Map<String, Integer> status = RateLimitingService.getRateLimitStatus(testUserId);\n        \n        Test.stopTest();\n        \n        System.assertNotEquals(null, status.get('hourly_used'));\n        System.assertNotEquals(null, status.get('daily_used'));\n        System.assertEquals(RateLimitingService.HOURLY_LIMIT, status.get('hourly_limit'));\n        System.assertEquals(RateLimitingService.DAILY_LIMIT, status.get('daily_limit'));\n    }\n    \n    @isTest\n    static void testRateLimitAPIResponse() {\n        Test.startTest();\n        \n        // Simulate rate limit exceeded scenario\n        String testUserId = UserInfo.getUserId();\n        \n        // Fill up to hourly limit\n        List<API_Usage__c> maxUsage = new List<API_Usage__c>();\n        for (Integer i = 0; i < 60; i++) {\n            maxUsage.add(new API_Usage__c(\n                User_Id__c = testUserId,\n                Request_Time__c = System.now().addMinutes(-1),\n                Endpoint__c = '/api/v1/classify'\n            ));\n        }\n        insert maxUsage;\n        \n        // Try to make API call\n        ClassificationRequest request = new ClassificationRequest();\n        request.text = 'Test rate limit';\n        request.type = 'SENTIMENT';\n        \n        RestRequest restRequest = new RestRequest();\n        RestResponse restResponse = new RestResponse();\n        restRequest.requestBody = Blob.valueOf(JSON.serialize(request));\n        RestContext.request = restRequest;\n        RestContext.response = restResponse;\n        \n        ClassificationResponse response = ClassificationRestAPI.classify();\n        \n        Test.stopTest();\n        \n        System.assert(!response.success, 'Should fail due to rate limit');\n        System.assertEquals(429, RestContext.response.statusCode);\n        System.assert(response.message.contains('Rate limit exceeded'));\n    }\n}\n```\n\n## 6. End-to-End Test Suite\n\n### Comprehensive Integration Test\n\n```apex\n// IntegrationTestSuite.cls\n@isTest\nprivate class IntegrationTestSuite {\n    \n    @testSetup\n    static void setupIntegrationTestData() {\n        // Set up comprehensive test data\n        Account testAccount = TestDataFactory.createTestAccount('Integration Test Account');\n        List<Contact> contacts = TestDataFactory.createTestContacts(20, testAccount.Id);\n        \n        // Create test classification batch\n        Classification_Batch__c batch = new Classification_Batch__c(\n            Batch_Id__c = 'INTEGRATION_BATCH_001',\n            Status__c = 'PENDING',\n            Total_Items__c = 50\n        );\n        insert batch;\n    }\n    \n    @isTest\n    static void testFullWorkflowIntegration() {\n        Test.startTest();\n        \n        // Step 1: Single classification\n        ClassificationRequest singleRequest = new ClassificationRequest();\n        singleRequest.text = 'This is a positive review of our product';\n        singleRequest.type = 'SENTIMENT';\n        \n        RestRequest restRequest = new RestRequest();\n        RestResponse restResponse = new RestResponse();\n        restRequest.requestBody = Blob.valueOf(JSON.serialize(singleRequest));\n        RestContext.request = restRequest;\n        RestContext.response = restResponse;\n        \n        ClassificationResponse singleResponse = ClassificationRestAPI.classify();\n        System.assert(singleResponse.success, 'Single classification should succeed');\n        \n        // Step 2: Bulk classification\n        BulkClassificationService.BulkClassificationRequest bulkRequest = \n            new BulkClassificationService.BulkClassificationRequest();\n        bulkRequest.batchId = 'INTEGRATION_BATCH_001';\n        bulkRequest.items = new List<BulkClassificationService.ClassificationItem>();\n        \n        for (Integer i = 0; i < 25; i++) {\n            BulkClassificationService.ClassificationItem item = \n                new BulkClassificationService.ClassificationItem();\n            item.id = 'INTEGRATION_ITEM_' + i;\n            item.text = 'Integration test text ' + i;\n            item.type = 'SENTIMENT';\n            bulkRequest.items.add(item);\n        }\n        \n        BulkClassificationService.processBulkClassification(JSON.serialize(bulkRequest));\n        \n        Test.stopTest();\n        \n        // Verify bulk processing results\n        List<Custom_Classification__c> bulkResults = [\n            SELECT Id, Status__c, Confidence_Score__c \n            FROM Custom_Classification__c \n            WHERE Batch_Id__c = 'INTEGRATION_BATCH_001'\n        ];\n        \n        System.assertEquals(25, bulkResults.size(), 'Should process all bulk items');\n        \n        // Step 3: Verify rate limiting tracking\n        String userId = UserInfo.getUserId();\n        Map<String, Integer> rateLimitStatus = RateLimitingService.getRateLimitStatus(userId);\n        System.assert(rateLimitStatus.get('hourly_used') > 0, 'Should track API usage');\n    }\n    \n    @isTest\n    static void testErrorRecoveryWorkflow() {\n        Test.startTest();\n        Test.setMock(HttpCalloutMock.class, new PartialFailureMockResponse());\n        \n        // Test partial failure handling in bulk processing\n        BulkClassificationService.BulkClassificationRequest request = \n            new BulkClassificationService.BulkClassificationRequest();\n        request.batchId = 'ERROR_BATCH_001';\n        request.items = new List<BulkClassificationService.ClassificationItem>();\n        \n        // Add items that will partially fail\n        for (Integer i = 0; i < 10; i++) {\n            BulkClassificationService.ClassificationItem item = \n                new BulkClassificationService.ClassificationItem();\n            item.id = 'ERROR_ITEM_' + i;\n            item.text = i < 5 ? 'valid text' : 'invalid_trigger_error';\n            item.type = 'SENTIMENT';\n            request.items.add(item);\n        }\n        \n        try {\n            BulkClassificationService.processBulkClassification(JSON.serialize(request));\n        } catch (Exception e) {\n            // Expected for error testing\n        }\n        \n        Test.stopTest();\n        \n        // Verify error handling and partial success\n        List<Custom_Classification__c> results = [\n            SELECT Id, Status__c \n            FROM Custom_Classification__c \n            WHERE Batch_Id__c = 'ERROR_BATCH_001'\n        ];\n        \n        // Should handle errors gracefully\n        System.assert(results.size() >= 0, 'Should handle errors without complete failure');\n    }\n}\n\n// Mock for partial failure testing\n@isTest\npublic class PartialFailureMockResponse implements HttpCalloutMock {\n    public HTTPResponse respond(HTTPRequest req) {\n        HttpResponse res = new HttpResponse();\n        if (req.getBody().contains('invalid_trigger_error')) {\n            res.setStatusCode(400);\n            res.setBody('{\"error\": \"Invalid input\"}');\n        } else {\n            res.setStatusCode(200);\n            res.setBody('{\"success\": true, \"classification\": \"positive\"}');\n        }\n        return res;\n    }\n}\n```\n\n## 7. Performance and Load Testing\n\n### Performance Test Class\n\n```apex\n// PerformanceTest.cls\n@isTest\nprivate class PerformanceTest {\n    \n    @isTest\n    static void testHighVolumeClassification() {\n        Test.startTest();\n        \n        // Test processing time for large batches\n        List<String> testTexts = new List<String>();\n        for (Integer i = 0; i < 200; i++) {\n            testTexts.add('Performance test text sample number ' + i + \n                         '. This is a longer text to simulate real-world usage scenarios.');\n        }\n        \n        Long startTime = System.currentTimeMillis();\n        \n        // Process classifications\n        List<Custom_Classification__c> results = new List<Custom_Classification__c>();\n        for (String text : testTexts) {\n            Custom_Classification__c result = new Custom_Classification__c(\n                Input_Text__c = text,\n                Classification_Type__c = 'SENTIMENT',\n                Status__c = 'COMPLETED',\n                Processing_Date__c = System.now()\n            );\n            results.add(result);\n        }\n        \n        insert results;\n        \n        Long endTime = System.currentTimeMillis();\n        Long processingTime = endTime - startTime;\n        \n        Test.stopTest();\n        \n        // Performance assertions\n        System.assertEquals(200, results.size(), 'Should process all items');\n        System.assert(processingTime < 10000, 'Processing should complete within 10 seconds');\n        \n        // Verify CPU usage stays within limits\n        System.assert(Limits.getCpuTime() < Limits.getLimitCpuTime() * 0.8, \n                     'CPU usage should stay under 80%');\n    }\n    \n    @isTest\n    static void testConcurrentAPIRequests() {\n        Test.startTest();\n        \n        // Simulate concurrent requests\n        List<ClassificationResponse> responses = new List<ClassificationResponse>();\n        \n        for (Integer i = 0; i < 5; i++) {\n            ClassificationRequest request = new ClassificationRequest();\n            request.text = 'Concurrent test ' + i;\n            request.type = 'SENTIMENT';\n            \n            RestRequest restRequest = new RestRequest();\n            RestResponse restResponse = new RestResponse();\n            restRequest.requestBody = Blob.valueOf(JSON.serialize(request));\n            RestContext.request = restRequest;\n            RestContext.response = restResponse;\n            \n            ClassificationResponse response = ClassificationRestAPI.classify();\n            responses.add(response);\n        }\n        \n        Test.stopTest();\n        \n        // Verify all requests succeeded\n        for (ClassificationResponse response : responses) {\n            System.assert(response.success, 'Concurrent requests should all succeed');\n        }\n    }\n}\n```\n\n## 8. Test Execution and Monitoring\n\n### Test Runner Utility\n\n```apex\n// TestRunner.cls\npublic class TestRunner {\n    \n    public static void runAllIntegrationTests() {\n        // Run specific test classes in order\n        List<String> testClasses = new List<String>{\n            'ClassificationAPITest',\n            'BulkClassificationTest',\n            'ErrorHandlingTest',\n            'RateLimitingTest',\n            'IntegrationTestSuite',\n            'PerformanceTest'\n        };\n        \n        for (String testClass : testClasses) {\n            System.debug('Running test class: ' + testClass);\n            Test.runTests(new List<String>{testClass});\n        }\n    }\n    \n    public static void generateTestReport() {\n        // Query test results\n        List<ApexTestResult> results = [\n            SELECT Id, MethodName, Outcome, Message, StackTrace\n            FROM ApexTestResult\n            WHERE AsyncApexJobId IN (\n                SELECT Id FROM AsyncApexJob \n                WHERE JobType = 'TestRequest'\n                AND CompletedDate = TODAY\n            )\n            ORDER BY CompletedDate DESC\n        ];\n        \n        // Generate report\n        Integer passed = 0;\n        Integer failed = 0;\n        List<String> failures = new List<String>();\n        \n        for (ApexTestResult result : results) {\n            if (result.Outcome == 'Pass') {\n                passed++;\n            } else {\n                failed++;\n                failures.add(result.MethodName + ': ' + result.Message);\n            }\n        }\n        \n        System.debug('=== INTEGRATION TEST REPORT ===');\n        System.debug('Total Tests: ' + results.size());\n        System.debug('Passed: ' + passed);\n        System.debug('Failed: ' + failed);\n        System.debug('Success Rate: ' + ((Decimal)passed / results.size() * 100).setScale(2) + '%');\n        \n        if (!failures.isEmpty()) {\n            System.debug('=== FAILURES ===');\n            for (String failure : failures) {\n                System.debug(failure);\n            }\n        }\n    }\n}\n```\n\n## 9. Deployment Validation\n\n### Package Validation Script\n\n```bash\n#!/bin/bash\n# deploy_validation.sh\n\necho \"Starting Salesforce ISV Package Validation...\"\n\n# Set variables\nSANDBOX_USERNAME=\"your-sandbox@example.com\"\nPACKAGE_VERSION=\"1.0.0\"\n\n# Deploy to sandbox\necho \"Deploying to sandbox...\"\nsf project deploy start --target-org $SANDBOX_USERNAME --dry-run\n\n# Run tests\necho \"Running integration tests...\"\nsf apex run test --target-org $SANDBOX_USERNAME --test-suite \"IntegrationTestSuite\" --result-format human --coverage-format text\n\n# Validate package\necho \"Validating package...\"\nsf package version promote --package \"$PACKAGE_VERSION\" --target-dev-hub $SANDBOX_USERNAME\n\necho \"Validation complete!\"\n```\n\nThis comprehensive integration testing framework provides:\n\n1. **Complete API endpoint testing** with success and error scenarios\n2. **Bulk processing validation** with size limits and error handling\n3. **Rate limiting enforcement** and monitoring\n4. **Error handling** for network, authentication, and data issues\n5. **Performance testing** for high-volume scenarios\n6. **End-to-end workflow validation**\n7. **Test reporting and monitoring utilities**\n\nThe tests are designed to run in Salesforce sandbox environments and validate all aspects of your ISV package before production deployment."
}

Audit Trail (2)

1d agotask_completedTerminal Lu
1d agotask_claimedTerminal Lu
Task ID: ee18b6f7-e018-44a1-ae19-b3aa8a08949f