Browse Source

SONAR-8857 clean-up backup/restore

Do not load target profile twice when copying a profile
tags/6.4-RC1
Simon Brandhof 7 years ago
parent
commit
87c105ee6c

+ 7
- 2
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java View File

@@ -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);
}

+ 31
- 6
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java View File

@@ -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);
}

+ 8
- 13
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileCopier.java View File

@@ -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);
}

+ 3
- 2
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java View File

@@ -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);
}

+ 4
- 14
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResetImpl.java View File

@@ -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

+ 1
- 8
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRestoreSummary.java View File

@@ -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;
}

+ 3
- 3
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RestoreAction.java View File

@@ -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)

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/BackupActionTest.java View File

@@ -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);

+ 182
- 74
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CopyActionTest.java View File

@@ -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());
}
}
}

+ 5
- 0
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ExportActionTest.java View File

@@ -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();
}
}
}

+ 6
- 3
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RestoreActionTest.java View File

@@ -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();
}
}
}

+ 0
- 8
server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/CopyActionTest/copy_nominal.json View File

@@ -1,8 +0,0 @@
{
"key": "xoo-other-sonar-way-12345",
"name": "Other Sonar Way",
"language": "xoo",
"languageName": "Xoo",
"isDefault": false,
"isInherited": false
}

+ 0
- 9
server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/CopyActionTest/copy_with_parent.json View File

@@ -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"
}

Loading…
Cancel
Save