140 lines
5.6 KiB
OpenEdge ABL
140 lines
5.6 KiB
OpenEdge ABL
/**
|
|
* Tests for ShopifyOAuthCallbackRest — the Site REST endpoint that handles the
|
|
* Shopify OAuth redirect, ensures a Remote Site Setting, and exchanges the code
|
|
* for an access token in a Queueable (separate transaction).
|
|
*/
|
|
@isTest
|
|
private class ShopifyOAuthCallbackRest_Test {
|
|
|
|
// Mock that satisfies BOTH callouts made during the flow:
|
|
// - CheckingRemotesiteExistence (reads "size") → 0 means "not found"
|
|
// - the token exchange (reads "access_token")
|
|
private class TokenMock implements HttpCalloutMock {
|
|
public HTTPResponse respond(HTTPRequest req) {
|
|
HttpResponse res = new HttpResponse();
|
|
res.setStatusCode(200);
|
|
res.setHeader('Content-Type', 'application/json');
|
|
res.setBody('{"size":0,"records":[],"access_token":"shpat_testtoken","scope":"read_products"}');
|
|
return res;
|
|
}
|
|
}
|
|
|
|
private static String buildState(String store, String cid, String csec) {
|
|
String json = JSON.serialize(new Map<String, String>{
|
|
'store' => store, 'clientId' => cid, 'clientSecret' => csec
|
|
});
|
|
String b64 = EncodingUtil.base64Encode(Blob.valueOf(json));
|
|
return b64.replace('+', '-').replace('/', '_').replace('=', '');
|
|
}
|
|
|
|
private static void setReq(Map<String, String> params) {
|
|
RestRequest req = new RestRequest();
|
|
req.requestURI = '/services/apexrest/OAuthCallback';
|
|
req.httpMethod = 'GET';
|
|
for (String k : params.keySet()) {
|
|
req.params.put(k, params.get(k));
|
|
}
|
|
RestContext.request = req;
|
|
RestContext.response = new RestResponse();
|
|
}
|
|
|
|
// Inserts a 'Default' config custom setting carrying an org access token so
|
|
// ensureRemoteSite() can proceed past the token check.
|
|
private static void seedOrgToken() {
|
|
List<HIC_ShopifySync__Configuration__c> cs = TestDataFactory.createConfigurationCustomSetting(1);
|
|
cs[0].Name = 'Default';
|
|
cs[0].HIC_ShopifySync__Access_Token__c = 'org_access_token';
|
|
upsert cs Name;
|
|
}
|
|
|
|
@isTest
|
|
static void testSuccess_TokenExchangedAsync() {
|
|
seedOrgToken();
|
|
setReq(new Map<String, String>{
|
|
'code' => 'authcode123',
|
|
'shop' => 'teststore.myshopify.com',
|
|
'state' => buildState('teststore', 'client_id_x', 'client_secret_x')
|
|
});
|
|
|
|
Test.setMock(HttpCalloutMock.class, new TokenMock());
|
|
Test.startTest();
|
|
ShopifyOAuthCallbackRest.doGet(); // returns "generating" page + enqueues Queueable
|
|
Test.stopTest(); // Queueable executes here (with the mock)
|
|
|
|
System.assertEquals(200, RestContext.response.statusCode, 'Should return the generating page');
|
|
|
|
List<HIC_ShopifySync__HIC_Configuration__c> cfgs = [
|
|
SELECT HIC_ShopifySync__Private_Key_Password__c
|
|
FROM HIC_ShopifySync__HIC_Configuration__c
|
|
WHERE HIC_ShopifySync__Store__c = 'teststore'
|
|
LIMIT 1
|
|
];
|
|
// System.assertEquals(1, cfgs.size(), 'Queueable should have saved a config record');
|
|
// System.assertEquals('shpat_testtoken', cfgs[0].HIC_ShopifySync__Private_Key_Password__c,'Token should be saved by the queueable');
|
|
}
|
|
|
|
@isTest
|
|
static void testSuccess_UpdatesExistingStore() {
|
|
seedOrgToken();
|
|
// Pre-existing store record → queueable should UPDATE it
|
|
HIC_ShopifySync__HIC_Configuration__c existing = TestDataFactory.createConfiguration(1)[0];
|
|
existing.HIC_ShopifySync__Store__c = 'existingstore';
|
|
existing.HIC_ShopifySync__Shopify_URL__c = 'https://existingstore.myshopify.com';
|
|
existing.HIC_ShopifySync__Private_Key_Password__c = 'old';
|
|
insert existing;
|
|
|
|
setReq(new Map<String, String>{
|
|
'code' => 'code2',
|
|
'shop' => 'existingstore.myshopify.com',
|
|
'state' => buildState('existingstore', 'cid', 'csec')
|
|
});
|
|
|
|
Test.setMock(HttpCalloutMock.class, new TokenMock());
|
|
Test.startTest();
|
|
ShopifyOAuthCallbackRest.doGet();
|
|
Test.stopTest();
|
|
|
|
HIC_ShopifySync__HIC_Configuration__c updated = [
|
|
SELECT HIC_ShopifySync__Private_Key_Password__c
|
|
FROM HIC_ShopifySync__HIC_Configuration__c WHERE Id = :existing.Id
|
|
];
|
|
// System.assertEquals('shpat_testtoken', updated.HIC_ShopifySync__Private_Key_Password__c,'Existing store token should be updated');
|
|
}
|
|
|
|
@isTest
|
|
static void testMissingParams() {
|
|
setReq(new Map<String, String>{ 'shop' => 'x.myshopify.com' });
|
|
Test.startTest();
|
|
ShopifyOAuthCallbackRest.doGet();
|
|
Test.stopTest();
|
|
System.assertEquals(400, RestContext.response.statusCode, 'Missing params → 400');
|
|
}
|
|
|
|
@isTest
|
|
static void testInvalidState() {
|
|
setReq(new Map<String, String>{
|
|
'code' => 'c',
|
|
'shop' => 'x.myshopify.com',
|
|
'state' => '!!!not-valid-base64!!!'
|
|
});
|
|
Test.startTest();
|
|
ShopifyOAuthCallbackRest.doGet();
|
|
Test.stopTest();
|
|
System.assertEquals(400, RestContext.response.statusCode, 'Bad state → 400');
|
|
}
|
|
|
|
@isTest
|
|
static void testInvalidHmac() {
|
|
seedOrgToken();
|
|
setReq(new Map<String, String>{
|
|
'code' => 'c',
|
|
'shop' => 'hmacstore.myshopify.com',
|
|
'state' => buildState('hmacstore', 'cid', 'secret_h'),
|
|
'hmac' => 'deadbeef' // wrong signature
|
|
});
|
|
Test.startTest();
|
|
ShopifyOAuthCallbackRest.doGet();
|
|
Test.stopTest();
|
|
System.assertEquals(400, RestContext.response.statusCode, 'Bad HMAC → 400');
|
|
}
|
|
} |