Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.force</groupId>
<artifactId>dataloader</artifactId>
<version>65.0.0</version>
<version>66.0.0</version>
<packaging>jar</packaging>
<name>Salesforce Data Loader</name>
<url>https://github.com/forcedotcom/dataloader</url>
Expand Down Expand Up @@ -51,7 +51,7 @@
<dependency>
<groupId>com.force.api</groupId>
<artifactId>force-partner-api</artifactId>
<version>64.0.3</version>
<version>66.0.0</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
Expand Down
20 changes: 15 additions & 5 deletions src/main/java/com/salesforce/dataloader/client/ClientBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,17 +136,27 @@ public final boolean connect(SessionInfo sess) {
public static final String SFORCE_CALL_OPTIONS_HEADER = "Sforce-Call-Options";

public static String getClientName(AppConfig cfg) {
return getClientName(cfg.isBulkAPIEnabled(), cfg.isBulkV2APIEnabled(),
cfg.isBatchMode(), cfg.isExternalClientAppConfigured(), Controller.APP_VERSION);
}

static String getClientName(boolean bulkAPI, boolean bulkV2API,
boolean batchMode, boolean externalClientApp, String appVersion) {
String apiType = PARTNER_API_CLIENT_TYPE;
final String interfaceType = cfg.isBatchMode() ? BATCH_CLIENT_STRING : UI_CLIENT_STRING;
if (cfg.isBulkAPIEnabled()) {
if (bulkAPI) {
apiType = BULK_API_CLIENT_TYPE;
}else if (cfg.isBulkV2APIEnabled()) {
} else if (bulkV2API) {
apiType = BULK_V2_API_CLIENT_TYPE;
}

String interfaceType = externalClientApp
? ""
: (batchMode ? BATCH_CLIENT_STRING : UI_CLIENT_STRING);

return new StringBuilder(32).append(BASE_CLIENT_NAME).append(apiType).append(interfaceType)
.append("/")
.append(Controller.APP_VERSION)
.toString(); //$NON-NLS-1$
.append(appVersion)
.toString();
}

public static synchronized String getAPIVersionForTheSession() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ private void setConfiguredSessionId(PartnerConnection conn, String sessionId, Ge

private void loginInternal(final PartnerConnection conn) throws ConnectionException, PasswordExpiredException {
final ConnectorConfig cc = conn.getConfig();
cc.setRequestHeader(AppConfig.CLIENT_ID_HEADER_NAME, appConfig.getClientIDForCurrentEnv());
cc.setRequestHeader(AppConfig.CLIENT_ID_HEADER_NAME, appConfig.getEffectiveClientIdForCurrentEnv());
try {
logger.info(Messages.getMessage(getClass(), "sforceLoginDetail", cc.getAuthEndpoint(), cc.getUsername()));
LoginResult loginResult = runLoginOperation(conn);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ private void setAuthAndClientHeadersForHttpMethod() {
Header clientIdHeaderVal = this.httpMethod.getFirstHeader(AppConfig.CLIENT_ID_HEADER_NAME);
if (clientIdHeaderVal == null) {
AppConfig appConfig = AppConfig.getCurrentConfig();
this.httpMethod.addHeader(AppConfig.CLIENT_ID_HEADER_NAME, appConfig.getClientIDForCurrentEnv());
this.httpMethod.addHeader(AppConfig.CLIENT_ID_HEADER_NAME, appConfig.getEffectiveClientIdForCurrentEnv());
}
Header clientNameHeaderVal = this.httpMethod.getFirstHeader(ClientBase.SFORCE_CALL_OPTIONS_HEADER);
if (clientNameHeaderVal == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.salesforce.dataloader.config.AppConfig;
import com.salesforce.dataloader.controller.Controller;
import com.salesforce.dataloader.ui.Labels;
import com.salesforce.dataloader.util.AppUtil;
import com.salesforce.dataloader.util.DLLogManager;
import com.salesforce.dataloader.util.OAuthServerFlow;
import org.apache.logging.log4j.Logger;
Expand All @@ -53,6 +54,10 @@ public OAuthFlowHandler(AppConfig appConfig, Consumer<String> statusConsumer, Co
this.loginButtonEnabler = loginButtonEnabler;
}

private boolean shouldRunLoginButtonEnabler() {
return loginButtonEnabler != null && !AppUtil.isRunningInBatchMode();
}

/**
* Handles Web Server OAuth flow leveraging Proof Key for Code Exchange(PKCE).
*
Expand All @@ -77,8 +82,10 @@ public boolean handleOAuthLogin() {
try {
if (controller.login()) {
controller.saveConfig();
Display.getDefault().asyncExec(() -> controller.updateLoaderWindowTitleAndCacheUserInfoForTheSession());
if (loginButtonEnabler != null) {
if (!AppUtil.isRunningInBatchMode()) {
Display.getDefault().asyncExec(() -> controller.updateLoaderWindowTitleAndCacheUserInfoForTheSession());
}
if (shouldRunLoginButtonEnabler()) {
Display.getDefault().asyncExec(loginButtonEnabler);
}
return true;
Expand All @@ -88,13 +95,13 @@ public boolean handleOAuthLogin() {
if (statusConsumer != null) {
statusConsumer.accept(Labels.getString("OAuthLoginControl.statusControllerUpdateError"));
}
if (loginButtonEnabler != null) {
if (shouldRunLoginButtonEnabler()) {
Display.getDefault().asyncExec(loginButtonEnabler);
}
return false;
}
}
if (loginButtonEnabler != null) {
if (shouldRunLoginButtonEnabler()) {
Display.getDefault().asyncExec(loginButtonEnabler);
}
return true;
Expand All @@ -111,7 +118,7 @@ public boolean handleOAuthLogin() {
if (statusConsumer != null) {
statusConsumer.accept(Labels.getString("OAuthLoginControl.statusPKCEFailedFallbackBrowser"));
}
if (loginButtonEnabler != null) {
if (shouldRunLoginButtonEnabler()) {
Display.getDefault().asyncExec(loginButtonEnabler);
}
return false;
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/salesforce/dataloader/util/AppUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ public static void extractDirFromJar(String extractionPrefix, String destDirName
public static APP_RUN_MODE getAppRunMode() {
return appRunMode;
}

public static boolean isRunningInBatchMode() {
return appRunMode == APP_RUN_MODE.BATCH;
}

public static boolean isContentSObject(String sObjectName) {
return CONTENT_SOBJECT_LIST.contains(sObjectName.toLowerCase());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright (c) 2015, salesforce.com, inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided with the distribution.
*
* Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package com.salesforce.dataloader.client;

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;

/**
* Unit tests for {@link ClientBase#getClientName}.
* Verifies that External Client App configurations produce neutral client names
* (without UI/Batch suffix) while legacy configurations retain the original format.
*/
public class ClientBaseGetClientNameTest {

private static final String VERSION = "65.0.0";

// --- Legacy (no ECA) ---

@Test
public void legacy_partnerUI() {
assertEquals("DataLoaderPartnerUI/65.0.0",
ClientBase.getClientName(false, false, false, false, VERSION));
}

@Test
public void legacy_partnerBatch() {
assertEquals("DataLoaderPartnerBatch/65.0.0",
ClientBase.getClientName(false, false, true, false, VERSION));
}

@Test
public void legacy_bulkUI() {
assertEquals("DataLoaderBulkUI/65.0.0",
ClientBase.getClientName(true, false, false, false, VERSION));
}

@Test
public void legacy_bulkv2Batch() {
assertEquals("DataLoaderBulkv2Batch/65.0.0",
ClientBase.getClientName(false, true, true, false, VERSION));
}

// --- ECA configured ---

@Test
public void eca_partner() {
String name = ClientBase.getClientName(false, false, false, true, VERSION);
assertEquals("DataLoaderPartner/65.0.0", name);
assertFalse(name.contains("UI"));
assertFalse(name.contains("Batch"));
}

@Test
public void eca_bulk() {
String name = ClientBase.getClientName(true, false, false, true, VERSION);
assertEquals("DataLoaderBulk/65.0.0", name);
assertFalse(name.contains("UI"));
assertFalse(name.contains("Batch"));
}

@Test
public void eca_bulkv2() {
String name = ClientBase.getClientName(false, true, false, true, VERSION);
assertEquals("DataLoaderBulkv2/65.0.0", name);
assertFalse(name.contains("UI"));
assertFalse(name.contains("Batch"));
}

@Test
public void eca_ignoresBatchMode() {
String name = ClientBase.getClientName(false, false, true, true, VERSION);
assertEquals("DataLoaderPartner/65.0.0", name);
assertFalse("ECA path should not include Batch suffix", name.contains("Batch"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2015, salesforce.com, inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided with the distribution.
*
* Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package com.salesforce.dataloader.oauth;

import com.salesforce.dataloader.config.AppConfig;
import com.salesforce.dataloader.controller.Controller;
import com.salesforce.dataloader.util.AppUtil;
import com.salesforce.dataloader.util.OAuthServerFlow;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockedConstruction;

import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;

/**
* Verifies that OAuthFlowHandler works correctly in batch mode
* by skipping Display.getDefault() calls that would crash without SWT.
*/
public class OAuthFlowHandlerTest {

private AppUtil.APP_RUN_MODE originalRunMode;

@Before
public void setUp() {
originalRunMode = AppUtil.getAppRunMode();
}

@After
public void tearDown() {
AppUtil.setAppRunMode(originalRunMode.name().toLowerCase());
}

@Test
public void testHandleOAuthLoginSucceedsInBatchMode() throws Exception {
AppUtil.setAppRunMode("batch");

Controller mockController = mock(Controller.class);
when(mockController.login()).thenReturn(true);
AppConfig mockAppConfig = mock(AppConfig.class);

try (MockedConstruction<OAuthServerFlow> ignored = mockConstruction(
OAuthServerFlow.class,
(mock, context) -> when(mock.performOAuthFlow()).thenReturn(true))) {

assertTrue("Run mode should be BATCH", AppUtil.isRunningInBatchMode());

OAuthFlowHandler handler = new OAuthFlowHandler(
mockAppConfig, status -> {}, mockController, () -> {});

boolean result = handler.handleOAuthLogin();
assertTrue("OAuth login should succeed in batch mode with fix applied", result);
}
}
}
Loading