Do not load target profile twice when copying a profiletags/6.4-RC1
@@ -34,9 +34,14 @@ public interface QProfileBackuper { | |||
void backup(DbSession dbSession, QualityProfileDto profile, Writer backupWriter); | |||
/** | |||
* Restore a profile backup in the specified organization. The parameter {@code overriddenProfileName} | |||
* is the name of the profile to be used. If null then name is loaded from backup. | |||
* Restore backup on a profile in the specified organization. The parameter {@code overriddenProfileName} | |||
* is the name of the profile to be used. If the parameter is null, then the name is loaded from the backup. | |||
* The profile is created if it does not exist. | |||
*/ | |||
QProfileRestoreSummary restore(DbSession dbSession, Reader backup, OrganizationDto organization, @Nullable String overriddenProfileName); | |||
/** | |||
* Restore backup on an existing profile. | |||
*/ | |||
QProfileRestoreSummary restore(DbSession dbSession, Reader backup, QualityProfileDto profile); | |||
} |
@@ -20,7 +20,6 @@ | |||
package org.sonar.server.qualityprofile; | |||
import com.google.common.base.Joiner; | |||
import com.google.common.base.MoreObjects; | |||
import com.google.common.collect.Lists; | |||
import com.google.common.collect.Maps; | |||
import com.google.common.collect.Sets; | |||
@@ -31,6 +30,7 @@ import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.function.Function; | |||
import javax.annotation.Nullable; | |||
import javax.xml.stream.XMLInputFactory; | |||
import javax.xml.stream.XMLStreamException; | |||
@@ -49,17 +49,21 @@ import org.sonar.db.qualityprofile.ActiveRuleDto; | |||
import org.sonar.db.qualityprofile.ActiveRuleParamDto; | |||
import org.sonar.db.qualityprofile.QualityProfileDto; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
@ServerSide | |||
public class QProfileBackuperImpl implements QProfileBackuper { | |||
private static final Joiner RULE_KEY_JOINER = Joiner.on(", ").skipNulls(); | |||
private final QProfileReset reset; | |||
private final DbClient db; | |||
private final QProfileReset profileReset; | |||
private final QProfileFactory profileFactory; | |||
public QProfileBackuperImpl(QProfileReset reset, DbClient db) { | |||
this.reset = reset; | |||
public QProfileBackuperImpl(DbClient db, QProfileReset profileReset, QProfileFactory profileFactory) { | |||
this.db = db; | |||
this.profileReset = profileReset; | |||
this.profileFactory = profileFactory; | |||
} | |||
@Override | |||
@@ -97,6 +101,25 @@ public class QProfileBackuperImpl implements QProfileBackuper { | |||
@Override | |||
public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, OrganizationDto organization, @Nullable String overriddenProfileName) { | |||
return restore(dbSession, backup, nameInBackup -> { | |||
QProfileName targetName = nameInBackup; | |||
if (overriddenProfileName != null) { | |||
targetName = new QProfileName(nameInBackup.getLanguage(), overriddenProfileName); | |||
} | |||
return profileFactory.getOrCreate(dbSession, organization, targetName); | |||
}); | |||
} | |||
@Override | |||
public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, QualityProfileDto profile) { | |||
return restore(dbSession, backup, nameInBackup -> { | |||
checkArgument(profile.getLanguage().equals(nameInBackup.getLanguage()), | |||
"Can't restore %s backup on %s profile with key [%s]. Languages are different.", nameInBackup.getLanguage(), profile.getLanguage(), profile.getKey()); | |||
return profile; | |||
}); | |||
} | |||
private QProfileRestoreSummary restore(DbSession dbSession, Reader backup, Function<QProfileName, QualityProfileDto> profileLoader) { | |||
try { | |||
String profileLang = null; | |||
String profileName = null; | |||
@@ -122,8 +145,10 @@ public class QProfileBackuperImpl implements QProfileBackuper { | |||
} | |||
} | |||
QProfileName target = new QProfileName(profileLang, MoreObjects.firstNonNull(overriddenProfileName, profileName)); | |||
return reset.reset(dbSession, organization, target, ruleActivations); | |||
QProfileName targetName = new QProfileName(profileLang, profileName); | |||
QualityProfileDto targetProfile = profileLoader.apply(targetName); | |||
BulkChangeResult changes = profileReset.reset(dbSession, targetProfile, ruleActivations); | |||
return new QProfileRestoreSummary(targetProfile, changes); | |||
} catch (XMLStreamException e) { | |||
throw new IllegalStateException("Fail to restore Quality profile backup", e); | |||
} |
@@ -33,7 +33,6 @@ import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.qualityprofile.QualityProfileDto; | |||
import org.sonar.server.qualityprofile.ws.QProfileWsSupport; | |||
import static java.nio.charset.StandardCharsets.UTF_8; | |||
@@ -44,25 +43,23 @@ public class QProfileCopier { | |||
private final QProfileFactory factory; | |||
private final QProfileBackuper backuper; | |||
private final TempFolder temp; | |||
private final QProfileWsSupport qProfileWsSupport; | |||
public QProfileCopier(DbClient db, QProfileFactory factory, QProfileBackuper backuper, TempFolder temp, QProfileWsSupport qProfileWsSupport) { | |||
public QProfileCopier(DbClient db, QProfileFactory factory, QProfileBackuper backuper, TempFolder temp) { | |||
this.db = db; | |||
this.factory = factory; | |||
this.backuper = backuper; | |||
this.temp = temp; | |||
this.qProfileWsSupport = qProfileWsSupport; | |||
} | |||
public QualityProfileDto copyToName(DbSession dbSession, String fromKey, String toName) { | |||
QualityProfileDto from = db.qualityProfileDao().selectOrFailByKey(dbSession, fromKey); | |||
OrganizationDto organization = db.organizationDao().selectByUuid(dbSession, from.getOrganizationUuid()) | |||
.orElseThrow(() -> new IllegalStateException("Organization with UUID [" + from.getOrganizationUuid() + "] does not exist")); | |||
.orElseThrow(() -> new IllegalStateException("Organization with UUID [" + from.getOrganizationUuid() + "] does not exist")); | |||
QualityProfileDto to = prepareTarget(dbSession, organization, from, toName); | |||
File backupFile = temp.newFile(); | |||
try { | |||
backup(dbSession, from, backupFile); | |||
restore(dbSession, backupFile, organization, to.getName()); | |||
restore(dbSession, backupFile, to); | |||
return to; | |||
} finally { | |||
org.sonar.core.util.FileUtils.deleteQuietly(backupFile); | |||
@@ -74,8 +71,6 @@ public class QProfileCopier { | |||
verify(from, toProfileName); | |||
QualityProfileDto toProfile = db.qualityProfileDao().selectByNameAndLanguage(organization, toProfileName.getName(), toProfileName.getLanguage(), dbSession); | |||
if (toProfile == null) { | |||
// Do not delegate creation to QProfileBackuper because we need to keep | |||
// the parent-child association, if exists. | |||
toProfile = factory.checkAndCreate(dbSession, organization, toProfileName); | |||
toProfile.setParentKee(from.getParentKee()); | |||
db.qualityProfileDao().update(dbSession, toProfile); | |||
@@ -87,12 +82,12 @@ public class QProfileCopier { | |||
private void verify(QualityProfileDto fromProfile, QProfileName toProfileName) { | |||
if (!StringUtils.equals(fromProfile.getLanguage(), toProfileName.getLanguage())) { | |||
throw new IllegalArgumentException(String.format( | |||
"Source and target profiles do not have the same language: %s and %s", | |||
fromProfile.getLanguage(), toProfileName.getLanguage())); | |||
"Source and target profiles do not have the same language: %s and %s", | |||
fromProfile.getLanguage(), toProfileName.getLanguage())); | |||
} | |||
if (fromProfile.getName().equals(toProfileName.getName())) { | |||
throw new IllegalArgumentException(String.format("Source and target profiles are equal: %s", | |||
fromProfile.getName())); | |||
fromProfile.getName())); | |||
} | |||
} | |||
@@ -104,9 +99,9 @@ public class QProfileCopier { | |||
} | |||
} | |||
private void restore(DbSession dbSession, File backupFile, OrganizationDto org, String profileName) { | |||
private void restore(DbSession dbSession, File backupFile, QualityProfileDto profile) { | |||
try (Reader reader = new InputStreamReader(FileUtils.openInputStream(backupFile), UTF_8)) { | |||
backuper.restore(dbSession, reader, org, profileName); | |||
backuper.restore(dbSession, reader, profile); | |||
} catch (IOException e) { | |||
throw new IllegalStateException("Fail to create temporary backup file: " + backupFile, e); | |||
} |
@@ -22,6 +22,7 @@ package org.sonar.server.qualityprofile; | |||
import java.util.Collection; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.qualityprofile.QualityProfileDto; | |||
public interface QProfileReset { | |||
/** | |||
@@ -31,7 +32,7 @@ public interface QProfileReset { | |||
void resetLanguage(DbSession dbSession, OrganizationDto organization, String language); | |||
/** | |||
* Reset the profile, which is created if it does not exist | |||
* Reset the rules of the specified profile. | |||
*/ | |||
QProfileRestoreSummary reset(DbSession dbSession, OrganizationDto organization, QProfileName profileName, Collection<RuleActivation> activations); | |||
BulkChangeResult reset(DbSession dbSession, QualityProfileDto profile, Collection<RuleActivation> activations); | |||
} |
@@ -19,7 +19,6 @@ | |||
*/ | |||
package org.sonar.server.qualityprofile; | |||
import com.google.common.base.Preconditions; | |||
import com.google.common.collect.ArrayListMultimap; | |||
import com.google.common.collect.ListMultimap; | |||
import com.google.common.collect.Lists; | |||
@@ -46,6 +45,7 @@ import org.sonar.db.rule.RuleParamDto; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.sonar.server.ws.WsUtils.checkRequest; | |||
@ServerSide | |||
@@ -92,23 +92,13 @@ public class QProfileResetImpl implements QProfileReset { | |||
activations.add(activation); | |||
} | |||
} | |||
doReset(dbSession, profile, activations); | |||
reset(dbSession, profile, activations); | |||
} | |||
} | |||
@Override | |||
public QProfileRestoreSummary reset(DbSession dbSession, OrganizationDto organization, QProfileName profileName, Collection<RuleActivation> activations) { | |||
QualityProfileDto profile = factory.getOrCreate(dbSession, organization, profileName); | |||
BulkChangeResult ruleChanges = doReset(dbSession, profile, activations); | |||
return new QProfileRestoreSummary(organization, profile, ruleChanges); | |||
} | |||
/** | |||
* @param dbSession | |||
* @param profile must exist | |||
*/ | |||
private BulkChangeResult doReset(DbSession dbSession, QualityProfileDto profile, Collection<RuleActivation> activations) { | |||
Preconditions.checkNotNull(profile.getId(), "Quality profile must be persisted"); | |||
public BulkChangeResult reset(DbSession dbSession, QualityProfileDto profile, Collection<RuleActivation> activations) { | |||
requireNonNull(profile.getId(), "Quality profile must be persisted"); | |||
BulkChangeResult result = new BulkChangeResult(); | |||
Set<RuleKey> ruleToBeDeactivated = Sets.newHashSet(); | |||
// Keep reference to all the activated rules before backup restore |
@@ -19,26 +19,19 @@ | |||
*/ | |||
package org.sonar.server.qualityprofile; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.qualityprofile.QualityProfileDto; | |||
import static java.util.Objects.requireNonNull; | |||
public final class QProfileRestoreSummary { | |||
private final OrganizationDto organization; | |||
private final QualityProfileDto profile; | |||
private final BulkChangeResult ruleChanges; | |||
public QProfileRestoreSummary(OrganizationDto organization, QualityProfileDto profile, BulkChangeResult ruleChanges) { | |||
this.organization = requireNonNull(organization); | |||
public QProfileRestoreSummary(QualityProfileDto profile, BulkChangeResult ruleChanges) { | |||
this.profile = requireNonNull(profile); | |||
this.ruleChanges = requireNonNull(ruleChanges); | |||
} | |||
public OrganizationDto getOrganization() { | |||
return organization; | |||
} | |||
public QualityProfileDto getProfile() { | |||
return profile; | |||
} |
@@ -94,21 +94,21 @@ public class RestoreAction implements QProfileWsAction { | |||
userSession.checkPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); | |||
QProfileRestoreSummary summary = backuper.restore(dbSession, reader, organization, null); | |||
writeResponse(response.newJsonWriter(), summary); | |||
writeResponse(response.newJsonWriter(), organization, summary); | |||
} finally { | |||
IOUtils.closeQuietly(reader); | |||
IOUtils.closeQuietly(backup); | |||
} | |||
} | |||
private void writeResponse(JsonWriter json, QProfileRestoreSummary summary) { | |||
private void writeResponse(JsonWriter json, OrganizationDto organization, QProfileRestoreSummary summary) { | |||
QualityProfileDto profile = summary.getProfile(); | |||
String languageKey = profile.getLanguage(); | |||
Language language = languages.get(languageKey); | |||
JsonWriter jsonProfile = json.beginObject().name("profile").beginObject(); | |||
jsonProfile | |||
.prop("organization", summary.getOrganization().getKey()) | |||
.prop("organization", organization.getKey()) | |||
.prop("key", profile.getKey()) | |||
.prop("name", profile.getName()) | |||
.prop("language", languageKey) |
@@ -51,7 +51,7 @@ public class BackupActionTest { | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
private QProfileBackuper backuper = new QProfileBackuperImpl(null, db.getDbClient()); | |||
private QProfileBackuper backuper = new QProfileBackuperImpl(db.getDbClient(), null, null); | |||
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); | |||
private QProfileWsSupport wsSupport = new QProfileWsSupport(db.getDbClient(), userSession, defaultOrganizationProvider); | |||
private Languages languages = LanguageTesting.newLanguages(A_LANGUAGE); |
@@ -19,147 +19,255 @@ | |||
*/ | |||
package org.sonar.server.qualityprofile.ws; | |||
import org.junit.Before; | |||
import java.io.Reader; | |||
import java.io.Writer; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.runner.RunWith; | |||
import org.mockito.Mock; | |||
import org.mockito.runners.MockitoJUnitRunner; | |||
import org.sonar.api.resources.Languages; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.utils.internal.JUnitTempFolder; | |||
import org.sonar.core.util.SequenceUuidFactory; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.permission.OrganizationPermission; | |||
import org.sonar.db.qualityprofile.QualityProfileDto; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.UnauthorizedException; | |||
import org.sonar.server.language.LanguageTesting; | |||
import org.sonar.server.organization.DefaultOrganizationProvider; | |||
import org.sonar.server.organization.TestDefaultOrganizationProvider; | |||
import org.sonar.server.qualityprofile.BulkChangeResult; | |||
import org.sonar.server.qualityprofile.QProfileBackuper; | |||
import org.sonar.server.qualityprofile.QProfileCopier; | |||
import org.sonar.server.qualityprofile.QProfileFactory; | |||
import org.sonar.server.qualityprofile.QProfileRestoreSummary; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.WsTester; | |||
import org.sonar.server.ws.TestResponse; | |||
import org.sonar.server.ws.WsActionTester; | |||
import static org.mockito.Matchers.any; | |||
import static org.mockito.Matchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.when; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
@RunWith(MockitoJUnitRunner.class) | |||
public class CopyActionTest { | |||
private static final String DEFAULT_ORG_UUID = "U1"; | |||
private static final String LANGUAGE_1 = "lang1"; | |||
private static final String LANGUAGE_2 = "lang2"; | |||
@Rule | |||
public DbTester db = DbTester.create(); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public UserSessionRule userSessionRule = UserSessionRule.standalone(); | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
@Rule | |||
public JUnitTempFolder tempDir = new JUnitTempFolder(); | |||
private QProfileFactory profileFactory = new QProfileFactory(db.getDbClient(), new SequenceUuidFactory(), System2.INSTANCE); | |||
private TestBackuper backuper = new TestBackuper(); | |||
private QProfileCopier profileCopier = new QProfileCopier(db.getDbClient(), profileFactory, backuper, tempDir); | |||
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); | |||
private Languages languages = LanguageTesting.newLanguages(LANGUAGE_1, LANGUAGE_2); | |||
private QProfileWsSupport wsSupport = new QProfileWsSupport(db.getDbClient(), userSession, defaultOrganizationProvider); | |||
private CopyAction underTest = new CopyAction(db.getDbClient(), profileCopier, languages, wsSupport); | |||
private WsActionTester tester = new WsActionTester(underTest); | |||
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.fromUuid(DEFAULT_ORG_UUID); | |||
private WsTester tester; | |||
@Test | |||
public void test_definition() { | |||
WebService.Action definition = tester.getDef(); | |||
// TODO Replace with proper DbTester + EsTester medium test during removal of DaoV2 | |||
@Mock | |||
private QProfileCopier qProfileCopier; | |||
assertThat(definition.key()).isEqualTo("copy"); | |||
assertThat(definition.isInternal()).isFalse(); | |||
assertThat(definition.since()).isEqualTo("5.2"); | |||
assertThat(definition.isPost()).isTrue(); | |||
@Before | |||
public void setUp() { | |||
tester = new WsTester(new QProfilesWs( | |||
mock(RuleActivationActions.class), | |||
mock(BulkRuleActivationActions.class), | |||
new CopyAction(db.getDbClient(), qProfileCopier, LanguageTesting.newLanguages("xoo"), new QProfileWsSupport(db.getDbClient(), userSessionRule, defaultOrganizationProvider)))); | |||
assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("fromKey", "toName"); | |||
assertThat(definition.param("fromKey").isRequired()).isTrue(); | |||
assertThat(definition.param("toName").isRequired()).isTrue(); | |||
} | |||
@Test | |||
public void copy_nominal() throws Exception { | |||
public void create_profile_with_specified_name_and_copy_rules_from_source_profile() throws Exception { | |||
logInAsQProfileAdministrator(); | |||
QualityProfileDto sourceProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE_1)); | |||
TestResponse response = tester.newRequest() | |||
.setMethod("POST") | |||
.setParam("fromKey", sourceProfile.getKey()) | |||
.setParam("toName", "target-name") | |||
.execute(); | |||
String fromProfileKey = "xoo-sonar-way-23456"; | |||
String toName = "Other Sonar Way"; | |||
String generatedUuid = "1"; | |||
assertJson(response.getInput()).isSimilarTo("{" + | |||
" \"key\": \"" + generatedUuid + "\"," + | |||
" \"name\": \"target-name\"," + | |||
" \"language\": \"lang1\"," + | |||
" \"languageName\": \"Lang1\"," + | |||
" \"isDefault\": false," + | |||
" \"isInherited\": false" + | |||
"}"); | |||
QualityProfileDto loadedProfile = db.getDbClient().qualityProfileDao().selectByNameAndLanguage(db.getDefaultOrganization(), "target-name", sourceProfile.getLanguage(), | |||
db.getSession()); | |||
assertThat(loadedProfile.getKey()).isEqualTo(generatedUuid); | |||
assertThat(loadedProfile.isDefault()).isFalse(); | |||
assertThat(loadedProfile.getParentKee()).isNull(); | |||
assertThat(backuper.backupedProfile.getKey()).isEqualTo(sourceProfile.getKey()); | |||
assertThat(backuper.restoredProfile.getOrganizationUuid()).isEqualTo(sourceProfile.getOrganizationUuid()); | |||
assertThat(backuper.restoredProfile.getLanguage()).isEqualTo(sourceProfile.getLanguage()); | |||
assertThat(backuper.restoredProfile.getName()).isEqualTo("target-name"); | |||
assertThat(backuper.restoredProfile.getKey()).isEqualTo(generatedUuid); | |||
assertThat(backuper.restoredProfile.getParentKee()).isNull(); | |||
} | |||
when(qProfileCopier.copyToName(any(DbSession.class), eq(fromProfileKey), eq(toName))).thenReturn( | |||
QualityProfileDto.createFor("xoo-other-sonar-way-12345") | |||
.setName(toName) | |||
.setLanguage("xoo")); | |||
@Test | |||
public void copy_rules_on_existing_profile() throws Exception { | |||
logInAsQProfileAdministrator(); | |||
QualityProfileDto sourceProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE_1)); | |||
QualityProfileDto targetProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE_1)); | |||
tester.newPostRequest("api/qualityprofiles", "copy") | |||
.setParam("fromKey", fromProfileKey) | |||
.setParam("toName", toName) | |||
.execute().assertJson(getClass(), "copy_nominal.json"); | |||
TestResponse response = tester.newRequest() | |||
.setMethod("POST") | |||
.setParam("fromKey", sourceProfile.getKey()) | |||
.setParam("toName", targetProfile.getName()) | |||
.execute(); | |||
verify(qProfileCopier).copyToName(any(DbSession.class), eq(fromProfileKey), eq(toName)); | |||
assertJson(response.getInput()).isSimilarTo("{" + | |||
" \"key\": \"" + targetProfile.getKey() + "\"," + | |||
" \"name\": \"" + targetProfile.getName() + "\"," + | |||
" \"language\": \"lang1\"," + | |||
" \"languageName\": \"Lang1\"," + | |||
" \"isDefault\": " + targetProfile.isDefault() + "," + | |||
" \"isInherited\": false" + | |||
"}"); | |||
QualityProfileDto loadedProfile = db.getDbClient().qualityProfileDao().selectByKey(db.getSession(), targetProfile.getKey()); | |||
assertThat(loadedProfile).isNotNull(); | |||
assertThat(backuper.backupedProfile.getKey()).isEqualTo(sourceProfile.getKey()); | |||
assertThat(backuper.restoredProfile.getKey()).isEqualTo(targetProfile.getKey()); | |||
} | |||
@Test | |||
public void copy_with_parent() throws Exception { | |||
public void create_profile_with_same_parent_as_source_profile() throws Exception { | |||
logInAsQProfileAdministrator(); | |||
String fromProfileKey = "xoo-sonar-way-23456"; | |||
String toName = "Other Sonar Way"; | |||
when(qProfileCopier.copyToName(any(DbSession.class), eq(fromProfileKey), eq(toName))).thenReturn( | |||
QualityProfileDto.createFor("xoo-other-sonar-way-12345") | |||
.setName(toName) | |||
.setLanguage("xoo") | |||
.setParentKee("xoo-parent-profile-01324")); | |||
QualityProfileDto parentProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE_1)); | |||
QualityProfileDto sourceProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE_1), p -> p.setParentKee(parentProfile.getKey())); | |||
tester.newPostRequest("api/qualityprofiles", "copy") | |||
.setParam("fromKey", fromProfileKey) | |||
.setParam("toName", toName) | |||
.execute().assertJson(getClass(), "copy_with_parent.json"); | |||
TestResponse response = tester.newRequest() | |||
.setMethod("POST") | |||
.setParam("fromKey", sourceProfile.getKey()) | |||
.setParam("toName", "target-name") | |||
.execute(); | |||
verify(qProfileCopier).copyToName(any(DbSession.class), eq(fromProfileKey), eq(toName)); | |||
String generatedUuid = "1"; | |||
assertJson(response.getInput()).isSimilarTo("{" + | |||
" \"key\": \"" + generatedUuid + "\"," + | |||
" \"name\": \"target-name\"," + | |||
" \"language\": \"lang1\"," + | |||
" \"languageName\": \"Lang1\"," + | |||
" \"isDefault\": false," + | |||
" \"isInherited\": true" + | |||
"}"); | |||
QualityProfileDto loadedProfile = db.getDbClient().qualityProfileDao().selectByNameAndLanguage(db.getDefaultOrganization(), "target-name", sourceProfile.getLanguage(), | |||
db.getSession()); | |||
assertThat(loadedProfile.getKey()).isEqualTo(generatedUuid); | |||
assertThat(loadedProfile.isDefault()).isFalse(); | |||
assertThat(loadedProfile.getParentKee()).isEqualTo(parentProfile.getKey()); | |||
assertThat(backuper.backupedProfile.getKey()).isEqualTo(sourceProfile.getKey()); | |||
assertThat(backuper.restoredProfile.getOrganizationUuid()).isEqualTo(sourceProfile.getOrganizationUuid()); | |||
assertThat(backuper.restoredProfile.getLanguage()).isEqualTo(sourceProfile.getLanguage()); | |||
assertThat(backuper.restoredProfile.getName()).isEqualTo("target-name"); | |||
assertThat(backuper.restoredProfile.getKey()).isEqualTo(generatedUuid); | |||
assertThat(backuper.restoredProfile.getParentKee()).isEqualTo(parentProfile.getKey()); | |||
} | |||
@Test | |||
public void fail_if_parameter_fromKey_is_missing() throws Exception { | |||
logInAsQProfileAdministrator(); | |||
public void throw_UnauthorizedException_if_not_logged_in() { | |||
userSession.anonymous(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("The 'fromKey' parameter is missing"); | |||
expectedException.expect(UnauthorizedException.class); | |||
expectedException.expectMessage("Authentication is required"); | |||
tester.newPostRequest("api/qualityprofiles", "copy") | |||
.setParam("toName", "Other Sonar Way") | |||
tester.newRequest() | |||
.setMethod("POST") | |||
.setParam("fromKey", "foo") | |||
.setParam("toName", "bar") | |||
.execute(); | |||
} | |||
@Test | |||
public void fail_if_parameter_toName_is_missing() throws Exception { | |||
logInAsQProfileAdministrator(); | |||
public void throw_ForbiddenException_if_not_profile_administrator() { | |||
userSession.logIn().addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization()); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("The 'toName' parameter is missing"); | |||
expectedException.expect(ForbiddenException.class); | |||
expectedException.expectMessage("Insufficient privileges"); | |||
tester.newPostRequest("api/qualityprofiles", "copy") | |||
.setParam("fromKey", "sonar-way-xoo1-13245") | |||
tester.newRequest() | |||
.setMethod("POST") | |||
.setParam("fromKey", "foo") | |||
.setParam("toName", "bar") | |||
.execute(); | |||
} | |||
@Test | |||
public void throw_ForbiddenException_if_not_profile_administrator() throws Exception { | |||
userSessionRule.logIn(); | |||
public void fail_if_parameter_fromKey_is_missing() throws Exception { | |||
logInAsQProfileAdministrator(); | |||
expectedException.expect(ForbiddenException.class); | |||
expectedException.expectMessage("Insufficient privileges"); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("The 'fromKey' parameter is missing"); | |||
tester.newPostRequest("api/qualityprofiles", "copy").execute(); | |||
tester.newRequest() | |||
.setParam("toName", "bar") | |||
.execute(); | |||
} | |||
@Test | |||
public void throw_UnauthorizedException_if_not_logged_in() throws Exception { | |||
expectedException.expect(UnauthorizedException.class); | |||
expectedException.expectMessage("Authentication is required"); | |||
public void fail_if_parameter_toName_is_missing() throws Exception { | |||
logInAsQProfileAdministrator(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("The 'toName' parameter is missing"); | |||
tester.newPostRequest("api/qualityprofiles", "copy").execute(); | |||
tester.newRequest() | |||
.setParam("fromKey", "foo") | |||
.execute(); | |||
} | |||
private void logInAsQProfileAdministrator() { | |||
userSessionRule | |||
userSession | |||
.logIn() | |||
.addPermission(ADMINISTER_QUALITY_PROFILES, defaultOrganizationProvider.get().getUuid()); | |||
} | |||
private static class TestBackuper implements QProfileBackuper { | |||
private QualityProfileDto backupedProfile; | |||
private QualityProfileDto restoredProfile; | |||
@Override | |||
public void backup(DbSession dbSession, QualityProfileDto profile, Writer backupWriter) { | |||
if (this.backupedProfile != null) { | |||
throw new IllegalStateException("Already backup-ed/backed-up"); | |||
} | |||
this.backupedProfile = profile; | |||
} | |||
@Override | |||
public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, OrganizationDto organization, @Nullable String overriddenProfileName) { | |||
throw new UnsupportedOperationException(); | |||
} | |||
@Override | |||
public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, QualityProfileDto profile) { | |||
if (this.restoredProfile != null) { | |||
throw new IllegalStateException("Already restored"); | |||
} | |||
this.restoredProfile = profile; | |||
return new QProfileRestoreSummary(profile, new BulkChangeResult()); | |||
} | |||
} | |||
} |
@@ -259,5 +259,10 @@ public class ExportActionTest { | |||
public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, OrganizationDto organization, @Nullable String overriddenProfileName) { | |||
throw new UnsupportedOperationException(); | |||
} | |||
@Override | |||
public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, QualityProfileDto profile) { | |||
throw new UnsupportedOperationException(); | |||
} | |||
} | |||
} |
@@ -92,7 +92,6 @@ public class RestoreActionTest { | |||
logInAsQProfileAdministrator(db.getDefaultOrganization()); | |||
TestResponse response = restore("<backup/>", null); | |||
assertThat(backuper.restoredSummary.getOrganization().getUuid()).isEqualTo(db.getDefaultOrganization().getUuid()); | |||
assertThat(backuper.restoredBackup).isEqualTo("<backup/>"); | |||
assertThat(backuper.restoredSummary.getProfile().getName()).isEqualTo("the-name-in-backup"); | |||
JsonAssert.assertJson(response.getInput()).isSimilarTo("{" + | |||
@@ -115,7 +114,6 @@ public class RestoreActionTest { | |||
logInAsQProfileAdministrator(org); | |||
TestResponse response = restore("<backup/>", org.getKey()); | |||
assertThat(backuper.restoredSummary.getOrganization().getUuid()).isEqualTo(org.getUuid()); | |||
assertThat(backuper.restoredBackup).isEqualTo("<backup/>"); | |||
assertThat(backuper.restoredSummary.getProfile().getName()).isEqualTo("the-name-in-backup"); | |||
JsonAssert.assertJson(response.getInput()).isSimilarTo("{" + | |||
@@ -226,8 +224,13 @@ public class RestoreActionTest { | |||
.setDefault(false) | |||
.setLanguage("xoo") | |||
.setName(overriddenProfileName != null ? overriddenProfileName : "the-name-in-backup"); | |||
restoredSummary = new QProfileRestoreSummary(organization, profile, new BulkChangeResult()); | |||
restoredSummary = new QProfileRestoreSummary(profile, new BulkChangeResult()); | |||
return restoredSummary; | |||
} | |||
@Override | |||
public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, QualityProfileDto profile) { | |||
throw new UnsupportedOperationException(); | |||
} | |||
} | |||
} |
@@ -1,8 +0,0 @@ | |||
{ | |||
"key": "xoo-other-sonar-way-12345", | |||
"name": "Other Sonar Way", | |||
"language": "xoo", | |||
"languageName": "Xoo", | |||
"isDefault": false, | |||
"isInherited": false | |||
} |
@@ -1,9 +0,0 @@ | |||
{ | |||
"key": "xoo-other-sonar-way-12345", | |||
"name": "Other Sonar Way", | |||
"language": "xoo", | |||
"languageName": "Xoo", | |||
"isDefault": false, | |||
"isInherited": true, | |||
"parentKey": "xoo-parent-profile-01324" | |||
} |