chore: Google sheet shared drive support added behind a flag (#37776)

## Description
This PR hides shared drive support for Google Sheets Integration behind
a feature flag as we need to do thorough testing for it.

The feature flag implementation done in this PR involves passing feature
flags from server to google sheets plugin module. This temporary feature
flagging solution tech debt can be removed once the testing is done and
once we would release this feature to all.

**Why feature flags are only available at server module?**
Because they have a dependency on UserIdentifierService,
SessionUserService, TenantService etc which exists at server module.
Supporting feature flags out of the box at plugin module level would
require significant efforts to migrate these dependencies.


Fixes #37714 
_or_  
Fixes `Issue URL`
> [!WARNING]  
> _If no issue exists, please create an issue first, and check with the
maintainers if the issue is valid._

## Automation

/ok-to-test tags="@tag.Authentication, @tag.Datasource"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/12063930619>
> Commit: 47f08f9903e78e050f18ad304dd736acb61b8b28
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=12063930619&attempt=2"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Authentication, @tag.Datasource`
> Spec:
> <hr>Thu, 28 Nov 2024 07:38:58 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [x] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

- **New Features**
- Introduced support for Google Sheets shared drive through feature
flags.
- Added new methods to handle feature flags in plugin execution and
triggering processes.
- Enhanced action execution and triggering logic to utilize feature
flags for dynamic behavior.

- **Bug Fixes**
	- Improved error handling for plugin execution processes.

- **Tests**
- Integrated `FeatureFlagService` into the testing framework for
enhanced test coverage.
- Expanded test scenarios to include various response types and error
conditions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: “sneha122” <“sneha@appsmith.com”>
This commit is contained in:
sneha122 2024-11-28 13:40:32 +05:30 committed by GitHub
parent 6a31cacba5
commit 8d32ee8f22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 185 additions and 30 deletions

View File

@ -14,6 +14,7 @@ public enum FeatureFlagEnum {
APP_NAVIGATION_LOGO_UPLOAD,
release_embed_hide_share_settings_enabled,
rollout_datasource_test_rate_limit_enabled,
release_google_sheets_shared_drive_support_enabled,
// Deprecated CE flags over here
release_git_autocommit_feature_enabled,

View File

@ -247,6 +247,50 @@ public interface PluginExecutor<C> extends ExtensionPoint, CrudTemplateService {
.tap(Micrometer.observation(observationRegistry));
}
// TODO: Following methods of executeParameterizedWithFlags, executeParameterizedWithMetricsAndFlags,
// triggerWithFlags are
// added
// to support feature flags in the plugin modules. Current implementation of featureFlagService is only available in
// server module
// and not available in any of the plugin modules due to dependencies on SessionUserService, TenantService etc.
// Hence, these methods are added to support feature flags in the plugin modules.
// Ideal solution would be to move featureFlagService and its dependencies to the shared interface module
// But this is a bigger change and will be done in future. Current change of passing flags was done to resolve
// release blocker
// https://github.com/appsmithorg/appsmith/issues/37714
// Once thorogh testing of shared drive support is done, we can remove this tech debt of passing feature flags like
// this.
default Mono<ActionExecutionResult> executeParameterizedWithFlags(
C connection,
ExecuteActionDTO executeActionDTO,
DatasourceConfiguration datasourceConfiguration,
ActionConfiguration actionConfiguration,
Map<String, Boolean> featureFlagMap) {
return this.executeParameterized(connection, executeActionDTO, datasourceConfiguration, actionConfiguration);
}
default Mono<ActionExecutionResult> executeParameterizedWithMetricsAndFlags(
C connection,
ExecuteActionDTO executeActionDTO,
DatasourceConfiguration datasourceConfiguration,
ActionConfiguration actionConfiguration,
ObservationRegistry observationRegistry,
Map<String, Boolean> featureFlagMap) {
return this.executeParameterizedWithFlags(
connection, executeActionDTO, datasourceConfiguration, actionConfiguration, featureFlagMap)
.tag("plugin", this.getClass().getName())
.name(ACTION_EXECUTION_PLUGIN_EXECUTION)
.tap(Micrometer.observation(observationRegistry));
}
default Mono<TriggerResultDTO> triggerWithFlags(
C connection,
DatasourceConfiguration datasourceConfiguration,
TriggerRequestDTO request,
Map<String, Boolean> featureFlagMap) {
return this.trigger(connection, datasourceConfiguration, request);
}
/**
* This function is responsible for preparing the action and datasource configurations to be ready for execution.
*

View File

@ -77,7 +77,9 @@ public interface ExecutionMethod {
return Mono.just(true);
}
WebClient.RequestHeadersSpec<?> getExecutionClient(WebClient webClient, MethodConfig methodConfig);
default WebClient.RequestHeadersSpec<?> getExecutionClient(WebClient webClient, MethodConfig methodConfig) {
return null;
}
default JsonNode transformExecutionResponse(
JsonNode response, MethodConfig methodConfig, Set<String> userAuthorizedSheetIds) {
@ -102,4 +104,9 @@ public interface ExecutionMethod {
conversionMap.put(DataType.FLOAT, DataType.DOUBLE);
return conversionMap;
}
default WebClient.RequestHeadersSpec<?> getExecutionClientWithFlags(
WebClient webClient, MethodConfig methodConfig, Map<String, Boolean> featureFlagMap) {
return getExecutionClient(webClient, methodConfig);
}
}

View File

@ -1,5 +1,6 @@
package com.external.config;
import com.appsmith.external.enums.FeatureFlagEnum;
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException;
import com.external.constants.ErrorMessages;
import com.external.enums.GoogleSheetMethodEnum;
@ -24,8 +25,9 @@ import static com.external.utils.SheetsUtil.getSpreadsheetData;
* API reference: https://developers.google.com/sheets/api/guides/migration#list_spreadsheets_for_the_authenticated_user
*/
public class FileListMethod implements ExecutionMethod, TriggerMethod {
ObjectMapper objectMapper;
private final String SHARED_DRIVE_PARAMS =
"&includeItemsFromAllDrives=true&supportsAllDrives=true&corpora=allDrives";
public FileListMethod(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
@ -37,10 +39,16 @@ public class FileListMethod implements ExecutionMethod, TriggerMethod {
}
@Override
public WebClient.RequestHeadersSpec<?> getExecutionClient(WebClient webClient, MethodConfig methodConfig) {
public WebClient.RequestHeadersSpec<?> getExecutionClientWithFlags(
WebClient webClient, MethodConfig methodConfig, Map<String, Boolean> featureFlagMap) {
// TODO: Flags are needed here for google sheets integration to support shared drive behind a flag
// Once thoroughly tested, this flag can be removed
Boolean isSharedDriveSupportEnabled = featureFlagMap.getOrDefault(
FeatureFlagEnum.release_google_sheets_shared_drive_support_enabled.name(), Boolean.FALSE);
UriComponentsBuilder uriBuilder = getBaseUriBuilder(
this.BASE_DRIVE_API_URL,
"?includeItemsFromAllDrives=true&supportsAllDrives=true&orderBy=name&q=mimeType%3D'application%2Fvnd.google-apps.spreadsheet'%20and%20trashed%3Dfalse",
"?orderBy=name&q=mimeType%3D'application%2Fvnd.google-apps.spreadsheet'%20and%20trashed%3Dfalse"
+ (isSharedDriveSupportEnabled.equals(Boolean.TRUE) ? SHARED_DRIVE_PARAMS : ""),
true);
return webClient
@ -74,8 +82,9 @@ public class FileListMethod implements ExecutionMethod, TriggerMethod {
}
@Override
public WebClient.RequestHeadersSpec<?> getTriggerClient(WebClient webClient, MethodConfig methodConfig) {
return this.getExecutionClient(webClient, methodConfig);
public WebClient.RequestHeadersSpec<?> getTriggerClientWithFlags(
WebClient webClient, MethodConfig methodConfig, Map<String, Boolean> featureFlagMap) {
return this.getExecutionClientWithFlags(webClient, methodConfig, featureFlagMap);
}
@Override

View File

@ -3,6 +3,7 @@ package com.external.config;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.web.reactive.function.client.WebClient;
import java.util.Map;
import java.util.Set;
/**
@ -21,7 +22,17 @@ public interface TriggerMethod {
/**
* Returns with the specification required to hit that particular trigger request
*/
WebClient.RequestHeadersSpec<?> getTriggerClient(WebClient webClient, MethodConfig methodConfig);
default WebClient.RequestHeadersSpec<?> getTriggerClient(WebClient webClient, MethodConfig methodConfig) {
return null;
}
/**
* Returns with the specification required to hit that particular trigger request
*/
default WebClient.RequestHeadersSpec<?> getTriggerClientWithFlags(
WebClient webClient, MethodConfig methodConfig, Map<String, Boolean> featureFlagMap) {
return getTriggerClient(webClient, methodConfig);
}
/**
* Transforms the response from the end point into an Appsmith friendly structure

View File

@ -81,6 +81,23 @@ public class GoogleSheetsPlugin extends BasePlugin {
ExecuteActionDTO executeActionDTO,
DatasourceConfiguration datasourceConfiguration,
ActionConfiguration actionConfiguration) {
return executeParameterizedWithFlags(
connection, executeActionDTO, datasourceConfiguration, actionConfiguration, null);
}
@Override
public Mono<TriggerResultDTO> trigger(
Void connection, DatasourceConfiguration datasourceConfiguration, TriggerRequestDTO request) {
return triggerWithFlags(connection, datasourceConfiguration, request, null);
}
@Override
public Mono<ActionExecutionResult> executeParameterizedWithFlags(
Void connection,
ExecuteActionDTO executeActionDTO,
DatasourceConfiguration datasourceConfiguration,
ActionConfiguration actionConfiguration,
Map<String, Boolean> featureFlagMap) {
log.debug(Thread.currentThread().getName() + ": executeParameterized() called for GoogleSheets plugin.");
boolean smartJsonSubstitution;
@ -133,13 +150,14 @@ public class GoogleSheetsPlugin extends BasePlugin {
prepareConfigurationsForExecution(executeActionDTO, actionConfiguration, datasourceConfiguration);
return this.executeCommon(connection, datasourceConfiguration, actionConfiguration);
return this.executeCommon(connection, datasourceConfiguration, actionConfiguration, featureFlagMap);
}
public Mono<ActionExecutionResult> executeCommon(
Void connection,
DatasourceConfiguration datasourceConfiguration,
ActionConfiguration actionConfiguration) {
ActionConfiguration actionConfiguration,
Map<String, Boolean> featureFlagMap) {
log.debug(Thread.currentThread().getName() + ": executeCommon() called for GoogleSheets plugin.");
// Initializing object for error condition
@ -185,7 +203,7 @@ public class GoogleSheetsPlugin extends BasePlugin {
// method
.flatMap(res -> {
return executionMethod
.getExecutionClient(client, methodConfig)
.getExecutionClientWithFlags(client, methodConfig, featureFlagMap)
.headers(headers -> headers.set(
"Authorization",
"Bearer "
@ -319,8 +337,11 @@ public class GoogleSheetsPlugin extends BasePlugin {
}
@Override
public Mono<TriggerResultDTO> trigger(
Void connection, DatasourceConfiguration datasourceConfiguration, TriggerRequestDTO request) {
public Mono<TriggerResultDTO> triggerWithFlags(
Void connection,
DatasourceConfiguration datasourceConfiguration,
TriggerRequestDTO request,
Map<String, Boolean> featureFlagMap) {
log.debug(Thread.currentThread().getName() + ": trigger() called for GoogleSheets plugin.");
final TriggerMethod triggerMethod = GoogleSheetsMethodStrategy.getTriggerMethod(request, objectMapper);
MethodConfig methodConfig = new MethodConfig(request);
@ -343,7 +364,7 @@ public class GoogleSheetsPlugin extends BasePlugin {
validateAndGetUserAuthorizedSheetIds(datasourceConfiguration, methodConfig);
return triggerMethod
.getTriggerClient(client, methodConfig)
.getTriggerClientWithFlags(client, methodConfig, featureFlagMap)
.headers(headers -> headers.set(
"Authorization",
"Bearer " + oauth2.getAuthenticationResponse().getToken()))

View File

@ -9,6 +9,7 @@ import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.helpers.PluginExecutorHelper;
import com.appsmith.server.repositories.PluginRepository;
import com.appsmith.server.services.ConfigService;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.services.TenantService;
import com.appsmith.server.solutions.DatasourceTriggerSolution;
import org.apache.commons.lang3.StringUtils;
@ -28,18 +29,21 @@ public class PluginTriggerSolutionCEImpl implements PluginTriggerSolutionCE {
private final PluginRepository pluginRepository;
private final ConfigService configService;
private final TenantService tenantService;
private final FeatureFlagService featureFlagService;
public PluginTriggerSolutionCEImpl(
DatasourceTriggerSolution datasourceTriggerSolution,
PluginExecutorHelper pluginExecutorHelper,
PluginRepository pluginRepository,
ConfigService configService,
TenantService tenantService) {
TenantService tenantService,
FeatureFlagService featureFlagService) {
this.datasourceTriggerSolution = datasourceTriggerSolution;
this.pluginExecutorHelper = pluginExecutorHelper;
this.pluginRepository = pluginRepository;
this.configService = configService;
this.tenantService = tenantService;
this.featureFlagService = featureFlagService;
}
/**
@ -74,6 +78,11 @@ public class PluginTriggerSolutionCEImpl implements PluginTriggerSolutionCE {
Mono<PluginExecutor> pluginExecutorMono =
pluginMono.flatMap(plugin -> pluginExecutorHelper.getPluginExecutor(Mono.just(plugin)));
// TODO: Flags are needed here for google sheets integration to support shared drive behind a flag
// Once thoroughly tested, this flag can be removed
Map<String, Boolean> featureFlagMap =
featureFlagService.getCachedTenantFeatureFlags().getFeatures();
/*
* Since there is no datasource provided, we are passing the Datasource Context connection and datasourceConfiguration as null.
* We will leave the execution to respective plugin executor.
@ -83,8 +92,8 @@ public class PluginTriggerSolutionCEImpl implements PluginTriggerSolutionCE {
PluginExecutor pluginExecutor = pair.getT2();
setHeadersToTriggerRequest(plugin, httpHeaders, triggerRequestDTO);
return setTenantAndInstanceId(triggerRequestDTO)
.flatMap(updatedTriggerRequestDTO ->
((PluginExecutor<Object>) pluginExecutor).trigger(null, null, updatedTriggerRequestDTO));
.flatMap(updatedTriggerRequestDTO -> ((PluginExecutor<Object>) pluginExecutor)
.triggerWithFlags(null, null, updatedTriggerRequestDTO, featureFlagMap));
});
}

View File

@ -3,6 +3,7 @@ package com.appsmith.server.plugins.solutions;
import com.appsmith.server.helpers.PluginExecutorHelper;
import com.appsmith.server.repositories.PluginRepository;
import com.appsmith.server.services.ConfigService;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.services.TenantService;
import com.appsmith.server.solutions.DatasourceTriggerSolution;
import org.springframework.stereotype.Component;
@ -14,7 +15,14 @@ public class PluginTriggerSolutionImpl extends PluginTriggerSolutionCEImpl imple
PluginExecutorHelper pluginExecutorHelper,
PluginRepository pluginRepository,
ConfigService configService,
TenantService tenantService) {
super(datasourceTriggerSolution, pluginExecutorHelper, pluginRepository, configService, tenantService);
TenantService tenantService,
FeatureFlagService featureFlagService) {
super(
datasourceTriggerSolution,
pluginExecutorHelper,
pluginRepository,
configService,
tenantService,
featureFlagService);
}
}

View File

@ -13,6 +13,7 @@ import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.AuthenticationValidator;
import com.appsmith.server.services.ConfigService;
import com.appsmith.server.services.DatasourceContextService;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.services.SessionUserService;
import com.appsmith.server.services.TenantService;
import com.appsmith.server.solutions.ce.ActionExecutionSolutionCEImpl;
@ -42,7 +43,8 @@ public class ActionExecutionSolutionImpl extends ActionExecutionSolutionCEImpl i
ConfigService configService,
TenantService tenantService,
CommonConfig commonConfig,
ActionExecutionSolutionHelper actionExecutionSolutionHelper) {
ActionExecutionSolutionHelper actionExecutionSolutionHelper,
FeatureFlagService featureFlagService) {
super(
newActionService,
actionPermission,
@ -63,6 +65,7 @@ public class ActionExecutionSolutionImpl extends ActionExecutionSolutionCEImpl i
configService,
tenantService,
commonConfig,
actionExecutionSolutionHelper);
actionExecutionSolutionHelper,
featureFlagService);
}
}

View File

@ -7,6 +7,7 @@ import com.appsmith.server.plugins.base.PluginService;
import com.appsmith.server.services.AuthenticationValidator;
import com.appsmith.server.services.ConfigService;
import com.appsmith.server.services.DatasourceContextService;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.services.TenantService;
import com.appsmith.server.solutions.ce.DatasourceTriggerSolutionCEImpl;
import lombok.extern.slf4j.Slf4j;
@ -28,7 +29,8 @@ public class DatasourceTriggerSolutionImpl extends DatasourceTriggerSolutionCEIm
DatasourcePermission datasourcePermission,
EnvironmentPermission environmentPermission,
ConfigService configService,
TenantService tenantService) {
TenantService tenantService,
FeatureFlagService featureFlagService) {
super(
datasourceService,
datasourceStorageService,
@ -40,6 +42,7 @@ public class DatasourceTriggerSolutionImpl extends DatasourceTriggerSolutionCEIm
datasourcePermission,
environmentPermission,
configService,
tenantService);
tenantService,
featureFlagService);
}
}

View File

@ -45,6 +45,7 @@ import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.AuthenticationValidator;
import com.appsmith.server.services.ConfigService;
import com.appsmith.server.services.DatasourceContextService;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.services.SessionUserService;
import com.appsmith.server.services.TenantService;
import com.appsmith.server.solutions.ActionPermission;
@ -73,6 +74,7 @@ import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@ -122,6 +124,7 @@ public class ActionExecutionSolutionCEImpl implements ActionExecutionSolutionCE
private final TenantService tenantService;
private final ActionExecutionSolutionHelper actionExecutionSolutionHelper;
private final CommonConfig commonConfig;
private final FeatureFlagService featureFlagService;
static final String PARAM_KEY_REGEX = "^k\\d+$";
static final String BLOB_KEY_REGEX =
@ -150,7 +153,8 @@ public class ActionExecutionSolutionCEImpl implements ActionExecutionSolutionCE
ConfigService configService,
TenantService tenantService,
CommonConfig commonConfig,
ActionExecutionSolutionHelper actionExecutionSolutionHelper) {
ActionExecutionSolutionHelper actionExecutionSolutionHelper,
FeatureFlagService featureFlagService) {
this.newActionService = newActionService;
this.actionPermission = actionPermission;
this.observationRegistry = observationRegistry;
@ -171,6 +175,7 @@ public class ActionExecutionSolutionCEImpl implements ActionExecutionSolutionCE
this.tenantService = tenantService;
this.commonConfig = commonConfig;
this.actionExecutionSolutionHelper = actionExecutionSolutionHelper;
this.featureFlagService = featureFlagService;
this.patternList.add(Pattern.compile(PARAM_KEY_REGEX));
this.patternList.add(Pattern.compile(BLOB_KEY_REGEX));
@ -726,13 +731,20 @@ public class ActionExecutionSolutionCEImpl implements ActionExecutionSolutionCE
// Now that we have the context (connection details), execute the action.
Instant requestedAt = Instant.now();
Map<String, Boolean> features = featureFlagService.getCachedTenantFeatureFlags() != null
? featureFlagService.getCachedTenantFeatureFlags().getFeatures()
: Collections.emptyMap();
// TODO: Flags are needed here for google sheets integration to support shared drive behind a flag
// Once thoroughly tested, this flag can be removed
return ((PluginExecutor<Object>) pluginExecutor)
.executeParameterizedWithMetrics(
.executeParameterizedWithMetricsAndFlags(
resourceContext.getConnection(),
executeActionDTO,
datasourceStorage1.getDatasourceConfiguration(),
actionDTO.getActionConfiguration(),
observationRegistry)
observationRegistry,
features)
.map(actionExecutionResult -> {
ActionExecutionRequest actionExecutionRequest = actionExecutionResult.getRequest();
if (actionExecutionRequest == null) {

View File

@ -17,6 +17,7 @@ import com.appsmith.server.plugins.base.PluginService;
import com.appsmith.server.services.AuthenticationValidator;
import com.appsmith.server.services.ConfigService;
import com.appsmith.server.services.DatasourceContextService;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.services.TenantService;
import com.appsmith.server.solutions.DatasourcePermission;
import com.appsmith.server.solutions.DatasourceStructureSolution;
@ -27,6 +28,7 @@ import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@ -53,6 +55,7 @@ public class DatasourceTriggerSolutionCEImpl implements DatasourceTriggerSolutio
private final EnvironmentPermission environmentPermission;
private final ConfigService configService;
private final TenantService tenantService;
private final FeatureFlagService featureFlagService;
public Mono<TriggerResultDTO> trigger(
String datasourceId, String environmentId, TriggerRequestDTO triggerRequestDTO) {
@ -104,6 +107,12 @@ public class DatasourceTriggerSolutionCEImpl implements DatasourceTriggerSolutio
final Plugin plugin = tuple.getT2();
final PluginExecutor pluginExecutor = tuple.getT3();
// TODO: Flags are needed here for google sheets integration to support shared drive behind a flag
// Once thoroughly tested, this flag can be removed
Map<String, Boolean> featureFlagMap = featureFlagService.getCachedTenantFeatureFlags() != null
? featureFlagService.getCachedTenantFeatureFlags().getFeatures()
: Collections.emptyMap();
return datasourceContextService
.getDatasourceContext(datasourceStorage, plugin)
// Now that we have the context (connection details), execute the action.
@ -111,10 +120,11 @@ public class DatasourceTriggerSolutionCEImpl implements DatasourceTriggerSolutio
// However the context comes from evaluated datasource.
.flatMap(resourceContext -> setTenantAndInstanceId(triggerRequestDTO)
.flatMap(updatedTriggerRequestDTO -> ((PluginExecutor<Object>) pluginExecutor)
.trigger(
.triggerWithFlags(
resourceContext.getConnection(),
datasourceStorage.getDatasourceConfiguration(),
updatedTriggerRequestDTO)));
updatedTriggerRequestDTO,
featureFlagMap)));
});
// If the plugin hasn't implemented the trigger function, go for the default implementation

View File

@ -24,6 +24,7 @@ import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.AuthenticationValidator;
import com.appsmith.server.services.ConfigService;
import com.appsmith.server.services.DatasourceContextService;
import com.appsmith.server.services.FeatureFlagService;
import com.appsmith.server.services.SessionUserService;
import com.appsmith.server.services.TenantService;
import com.appsmith.server.solutions.ActionPermission;
@ -136,6 +137,9 @@ class ActionExecutionSolutionCEImplTest {
@SpyBean
ActionExecutionSolutionHelper actionExecutionSolutionHelper;
@SpyBean
FeatureFlagService featureFlagService;
@Autowired
EnvironmentPermission environmentPermission;
@ -167,7 +171,8 @@ class ActionExecutionSolutionCEImplTest {
configService,
tenantService,
commonConfig,
actionExecutionSolutionHelper);
actionExecutionSolutionHelper,
featureFlagService);
ObservationRegistry.ObservationConfig mockObservationConfig =
Mockito.mock(ObservationRegistry.ObservationConfig.class);

View File

@ -327,6 +327,8 @@ public class ActionExecutionSolutionCETest {
Mockito.when(pluginExecutorHelper.getPluginExecutor(any())).thenReturn(Mono.just(pluginExecutor));
Mockito.when(pluginExecutor.executeParameterizedWithMetrics(any(), any(), any(), any(), any()))
.thenReturn(Mono.just(mockResult));
Mockito.when(pluginExecutor.executeParameterizedWithMetricsAndFlags(any(), any(), any(), any(), any(), any()))
.thenReturn(Mono.just(mockResult));
Mockito.when(pluginExecutor.datasourceCreate(any())).thenReturn(Mono.empty());
Mockito.doReturn(Mono.just(false))
.when(spyDatasourceService)
@ -527,6 +529,8 @@ public class ActionExecutionSolutionCETest {
Mockito.when(pluginExecutorHelper.getPluginExecutor(any())).thenReturn(Mono.just(pluginExecutor));
Mockito.when(pluginExecutor.executeParameterizedWithMetrics(any(), any(), any(), any(), any()))
.thenReturn(Mono.error(pluginException));
Mockito.when(pluginExecutor.executeParameterizedWithMetricsAndFlags(any(), any(), any(), any(), any(), any()))
.thenReturn(Mono.error(pluginException));
Mockito.when(pluginExecutor.datasourceCreate(any())).thenReturn(Mono.empty());
Mockito.doReturn(Mono.just(false))
.when(spyDatasourceService)
@ -584,6 +588,8 @@ public class ActionExecutionSolutionCETest {
Mockito.when(pluginExecutorHelper.getPluginExecutor(any())).thenReturn(Mono.just(pluginExecutor));
Mockito.when(pluginExecutor.executeParameterizedWithMetrics(any(), any(), any(), any(), any()))
.thenReturn(Mono.error(pluginException));
Mockito.when(pluginExecutor.executeParameterizedWithMetricsAndFlags(any(), any(), any(), any(), any(), any()))
.thenReturn(Mono.error(pluginException));
Mockito.when(pluginExecutor.datasourceCreate(any())).thenReturn(Mono.empty());
Mockito.doReturn(Mono.just(false))
.when(spyDatasourceService)
@ -635,6 +641,9 @@ public class ActionExecutionSolutionCETest {
Mockito.when(pluginExecutor.executeParameterizedWithMetrics(any(), any(), any(), any(), any()))
.thenReturn(Mono.error(new StaleConnectionException()))
.thenReturn(Mono.error(new StaleConnectionException()));
Mockito.when(pluginExecutor.executeParameterizedWithMetricsAndFlags(any(), any(), any(), any(), any(), any()))
.thenReturn(Mono.error(new StaleConnectionException()))
.thenReturn(Mono.error(new StaleConnectionException()));
Mockito.when(pluginExecutor.datasourceCreate(any())).thenReturn(Mono.empty());
Mockito.doReturn(Mono.just(false))
.when(spyDatasourceService)
@ -686,6 +695,8 @@ public class ActionExecutionSolutionCETest {
Mockito.when(pluginExecutorHelper.getPluginExecutor(any())).thenReturn(Mono.just(pluginExecutor));
Mockito.when(pluginExecutor.executeParameterizedWithMetrics(any(), any(), any(), any(), any()))
.thenAnswer(x -> Mono.delay(Duration.ofMillis(1000)).ofType(ActionExecutionResult.class));
Mockito.when(pluginExecutor.executeParameterizedWithMetricsAndFlags(any(), any(), any(), any(), any(), any()))
.thenAnswer(x -> Mono.delay(Duration.ofMillis(1000)).ofType(ActionExecutionResult.class));
Mockito.when(pluginExecutor.datasourceCreate(any())).thenReturn(Mono.empty());
Mockito.doReturn(Mono.just(false))
.when(spyDatasourceService)
@ -716,8 +727,9 @@ public class ActionExecutionSolutionCETest {
Mockito.when(pluginExecutorHelper.getPluginExecutor(any())).thenReturn(Mono.just(pluginExecutor));
Mockito.when(pluginExecutor.executeParameterizedWithMetrics(any(), any(), any(), any(), any()))
.thenThrow(new StaleConnectionException())
.thenReturn(Mono.just(mockResult));
.thenThrow(new StaleConnectionException());
Mockito.when(pluginExecutor.executeParameterizedWithMetricsAndFlags(any(), any(), any(), any(), any(), any()))
.thenThrow(new StaleConnectionException());
Mockito.when(pluginExecutor.datasourceCreate(any())).thenReturn(Mono.empty());
Mockito.when(pluginExecutor.getHintMessages(any(), any()))
.thenReturn(Mono.zip(Mono.just(new HashSet<>()), Mono.just(new HashSet<>())));