fix: State management for tenant activation (#27371)

## Description
While running the feature based migrations, updates are being made to
the tenant object. As we are using the `repository.save` method it
resulted in deserialising the tenant object from Spring giving the diff
between the DB object and the object received by the downstream methods
as we are overriding the tenant config object. To avoid this we are now
retrieving the object explicitly after the object is saved to DB.

Note: This needs to be looked after as it's increasing the DB calls.
Create a ticket for tracking this request
https://github.com/appsmithorg/appsmith-ee/issues/2386

EE PR: https://github.com/appsmithorg/appsmith-ee/pull/2375

#### PR fixes following issue(s)
Fixes https://github.com/appsmithorg/appsmith-ee/issues/2361

#### Type of change
- Bug fix (non-breaking change which fixes an issue)

## Testing
#### How Has This Been Tested?
- [x] Manual
- [x] JUnit
- [ ] Jest
- [ ] Cypress
>
>
#### Test Plan
> Add Testsmith test cases links that relate to this PR
>
>
#### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
>
>
>
## Checklist:
#### Dev activity
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
This commit is contained in:
Abhijeet 2023-09-19 10:39:45 +05:30 committed by GitHub
parent 0e4cd23c0e
commit f470396b61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 4 deletions

View File

@ -67,6 +67,9 @@ public class TenantConfigurationCE {
instanceName = ObjectUtils.defaultIfNull(tenantConfiguration.getInstanceName(), instanceName); instanceName = ObjectUtils.defaultIfNull(tenantConfiguration.getInstanceName(), instanceName);
emailVerificationEnabled = emailVerificationEnabled =
ObjectUtils.defaultIfNull(tenantConfiguration.getEmailVerificationEnabled(), emailVerificationEnabled); ObjectUtils.defaultIfNull(tenantConfiguration.getEmailVerificationEnabled(), emailVerificationEnabled);
featuresWithPendingMigration = tenantConfiguration.getFeaturesWithPendingMigration();
migrationStatus = tenantConfiguration.getMigrationStatus();
} }
public Boolean getEmailVerificationEnabled() { public Boolean getEmailVerificationEnabled() {

View File

@ -13,6 +13,14 @@ import java.util.Map;
@NoRepositoryBean @NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> extends ReactiveMongoRepository<T, ID> { public interface BaseRepository<T, ID extends Serializable> extends ReactiveMongoRepository<T, ID> {
/**
* This function should be used to get an object from the DB without applying any ACL rules
*
* @param id The identifier for this type
* @return Mono<T>
*/
Mono<T> retrieveById(ID id);
/** /**
* This function sets the deleted flag to true and then saves the modified document. * This function sets the deleted flag to true and then saves the modified document.
* *

View File

@ -121,6 +121,18 @@ public class BaseRepositoryImpl<T extends BaseDomain, ID extends Serializable>
}); });
} }
@Override
public Mono<T> retrieveById(ID id) {
Query query = new Query(getIdCriteria(id));
query.addCriteria(notDeleted());
return mongoOperations
.query(entityInformation.getJavaType())
.inCollection(entityInformation.getCollectionName())
.matching(query)
.one();
}
@Override @Override
public Mono<T> findById(ID id) { public Mono<T> findById(ID id) {
return this.findByIdAndFieldNames(id, null); return this.findByIdAndFieldNames(id, null);

View File

@ -203,8 +203,7 @@ public class TenantServiceCEImpl extends BaseService<TenantRepository, Tenant, S
*/ */
@Override @Override
public Mono<Tenant> checkAndExecuteMigrationsForTenantFeatureFlags(Tenant tenant) { public Mono<Tenant> checkAndExecuteMigrationsForTenantFeatureFlags(Tenant tenant) {
if (tenant.getTenantConfiguration() == null if (!isMigrationRequired(tenant)) {
|| CollectionUtils.isNullOrEmpty(tenant.getTenantConfiguration().getFeaturesWithPendingMigration())) {
return Mono.just(tenant); return Mono.just(tenant);
} }
Map<FeatureFlagEnum, FeatureMigrationType> featureMigrationTypeMap = Map<FeatureFlagEnum, FeatureMigrationType> featureMigrationTypeMap =
@ -222,10 +221,25 @@ public class TenantServiceCEImpl extends BaseService<TenantRepository, Tenant, S
} else { } else {
tenant.getTenantConfiguration().setMigrationStatus(MigrationStatus.IN_PROGRESS); tenant.getTenantConfiguration().setMigrationStatus(MigrationStatus.IN_PROGRESS);
} }
return this.save(tenant).flatMap(this::checkAndExecuteMigrationsForTenantFeatureFlags); return this.save(tenant)
// Fetch the tenant again from DB to make sure the downstream chain is consuming the
// latest
// DB object and not the modified one because of the client pertinent changes
.then(repository.retrieveById(tenant.getId()))
.flatMap(this::checkAndExecuteMigrationsForTenantFeatureFlags);
} }
return Mono.error( return Mono.error(
new AppsmithException(AppsmithError.FeatureFlagMigrationFailure, featureFlagEnum, "")); new AppsmithException(AppsmithError.FeatureFlagMigrationFailure, featureFlagEnum, ""));
}); });
} }
private boolean isMigrationRequired(Tenant tenant) {
return tenant.getTenantConfiguration() != null
&& (!CollectionUtils.isNullOrEmpty(
tenant.getTenantConfiguration().getFeaturesWithPendingMigration())
|| (CollectionUtils.isNullOrEmpty(
tenant.getTenantConfiguration().getFeaturesWithPendingMigration())
&& !MigrationStatus.COMPLETED.equals(
tenant.getTenantConfiguration().getMigrationStatus())));
}
} }

View File

@ -264,7 +264,6 @@ class TenantServiceCETest {
final Mono<Tenant> resultMono = tenantService.checkAndExecuteMigrationsForTenantFeatureFlags(tenant); final Mono<Tenant> resultMono = tenantService.checkAndExecuteMigrationsForTenantFeatureFlags(tenant);
StepVerifier.create(resultMono) StepVerifier.create(resultMono)
.assertNext(tenant1 -> { .assertNext(tenant1 -> {
assertThat(tenant1).isEqualTo(tenant);
assertThat(tenant1.getTenantConfiguration().getFeaturesWithPendingMigration()) assertThat(tenant1.getTenantConfiguration().getFeaturesWithPendingMigration())
.isEmpty(); .isEmpty();
assertThat(tenant1.getTenantConfiguration().getMigrationStatus()) assertThat(tenant1.getTenantConfiguration().getMigrationStatus())