From 5b002a187cb9ca78f931839a574d6da9fdf266bf Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Thu, 27 Jul 2017 14:21:43 +0100 Subject: [PATCH] Add implementation of PluginApi - install - get status - enable - disable - reload Change-Id: I62fdc63372918a7e63760f4ea49b203d7fcb244d --- .../acceptance/api/plugin/PluginIT.java | 79 ++++++++++++++++++- .../extensions/api/plugins/PluginApi.java | 55 +++++++++++++ .../extensions/api/plugins/Plugins.java | 17 +++- .../server/api/plugins/PluginApiImpl.java | 72 +++++++++++++++++ .../server/api/plugins/PluginsImpl.java | 35 +++++++- .../gerrit/server/plugins/DisablePlugin.java | 4 +- .../gerrit/server/plugins/EnablePlugin.java | 4 +- .../gerrit/server/plugins/GetStatus.java | 2 +- .../gerrit/server/plugins/InstallPlugin.java | 2 +- .../server/plugins/PluginRestApiModule.java | 2 + .../server/plugins/PluginsCollection.java | 6 +- .../gerrit/server/plugins/ReloadPlugin.java | 4 +- 12 files changed, 268 insertions(+), 14 deletions(-) create mode 100644 gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/PluginApi.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginApiImpl.java diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/plugin/PluginIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/plugin/PluginIT.java index 3b3f6749c5..58619ade45 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/plugin/PluginIT.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/plugin/PluginIT.java @@ -15,16 +15,89 @@ package com.google.gerrit.acceptance.api.plugin; import static com.google.common.truth.Truth.assertThat; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.stream.Collectors.toList; +import com.google.common.collect.ImmutableList; import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.GerritConfig; import com.google.gerrit.acceptance.NoHttpd; +import com.google.gerrit.common.RawInputUtil; +import com.google.gerrit.extensions.api.plugins.PluginApi; +import com.google.gerrit.extensions.api.plugins.Plugins.ListRequest; +import com.google.gerrit.extensions.common.InstallPluginInput; +import com.google.gerrit.extensions.common.PluginInfo; +import com.google.gerrit.extensions.restapi.MethodNotAllowedException; +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.extensions.restapi.RestApiException; +import java.util.List; import org.junit.Test; @NoHttpd public class PluginIT extends AbstractDaemonTest { + private static final byte[] JS_PLUGIN_CONTENT = + "Gerrit.install(function(self){});\n".getBytes(UTF_8); + private static final List PLUGINS = + ImmutableList.of("plugin-a", "plugin-b", "plugin-c", "plugin-d"); + @Test - public void list() throws Exception { - assertThat(gApi.plugins().list().get()).isEmpty(); - assertThat(gApi.plugins().list().all().get()).isEmpty(); + @GerritConfig(name = "plugins.allowRemoteAdmin", value = "true") + public void pluginManagement() throws Exception { + // No plugins are loaded + assertThat(list().get()).isEmpty(); + assertThat(list().all().get()).isEmpty(); + + PluginApi test; + PluginInfo info; + + // Install all the plugins + InstallPluginInput input = new InstallPluginInput(); + input.raw = RawInputUtil.create(JS_PLUGIN_CONTENT); + for (String plugin : PLUGINS) { + test = gApi.plugins().install(plugin + ".js", input); + assertThat(test).isNotNull(); + info = test.get(); + assertThat(info.id).isEqualTo(plugin); + assertThat(info.disabled).isNull(); + } + assertPlugins(list().get(), PLUGINS); + + // Disable + test = gApi.plugins().name("plugin-a"); + test.disable(); + test = gApi.plugins().name("plugin-a"); + info = test.get(); + assertThat(info.disabled).isTrue(); + assertPlugins(list().get(), PLUGINS.subList(1, PLUGINS.size())); + assertPlugins(list().all().get(), PLUGINS); + + // Enable + test.enable(); + test = gApi.plugins().name("plugin-a"); + info = test.get(); + assertThat(info.disabled).isNull(); + assertPlugins(list().get(), PLUGINS); + } + + @Test + public void installNotAllowed() throws Exception { + exception.expect(MethodNotAllowedException.class); + exception.expectMessage("remote installation is disabled"); + gApi.plugins().install("test.js", new InstallPluginInput()); + } + + @Test + public void getNonExistingThrowsNotFound() throws Exception { + exception.expect(ResourceNotFoundException.class); + gApi.plugins().name("does-not-exist"); + } + + private ListRequest list() throws RestApiException { + return gApi.plugins().list(); + } + + private void assertPlugins(List actual, List expected) { + List _actual = actual.stream().map(p -> p.id).collect(toList()); + assertThat(_actual).containsExactlyElementsIn(expected); } } diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/PluginApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/PluginApi.java new file mode 100644 index 0000000000..b6d78a35e5 --- /dev/null +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/PluginApi.java @@ -0,0 +1,55 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.extensions.api.plugins; + +import com.google.gerrit.extensions.common.PluginInfo; +import com.google.gerrit.extensions.restapi.NotImplementedException; +import com.google.gerrit.extensions.restapi.RestApiException; + +public interface PluginApi { + PluginInfo get() throws RestApiException; + + void enable() throws RestApiException; + + void disable() throws RestApiException; + + void reload() throws RestApiException; + + /** + * A default implementation which allows source compatibility when adding new methods to the + * interface. + */ + class NotImplemented implements PluginApi { + @Override + public PluginInfo get() throws RestApiException { + throw new NotImplementedException(); + } + + @Override + public void enable() throws RestApiException { + throw new NotImplementedException(); + } + + @Override + public void disable() throws RestApiException { + throw new NotImplementedException(); + } + + @Override + public void reload() throws RestApiException { + throw new NotImplementedException(); + } + } +} diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/Plugins.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/Plugins.java index ff2ad3476d..a97073f206 100644 --- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/Plugins.java +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/Plugins.java @@ -14,6 +14,7 @@ package com.google.gerrit.extensions.api.plugins; +import com.google.gerrit.extensions.common.InstallPluginInput; import com.google.gerrit.extensions.common.PluginInfo; import com.google.gerrit.extensions.restapi.NotImplementedException; import com.google.gerrit.extensions.restapi.RestApiException; @@ -24,7 +25,11 @@ import java.util.SortedMap; public interface Plugins { - ListRequest list(); + ListRequest list() throws RestApiException; + + PluginApi name(String name) throws RestApiException; + + PluginApi install(String name, InstallPluginInput input) throws RestApiException; abstract class ListRequest { private boolean all; @@ -59,5 +64,15 @@ public interface Plugins { public ListRequest list() { throw new NotImplementedException(); } + + @Override + public PluginApi name(String name) { + throw new NotImplementedException(); + } + + @Override + public PluginApi install(String name, InstallPluginInput input) throws RestApiException { + throw new NotImplementedException(); + } } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginApiImpl.java new file mode 100644 index 0000000000..2fc2e508c6 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginApiImpl.java @@ -0,0 +1,72 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.api.plugins; + +import com.google.gerrit.extensions.api.plugins.PluginApi; +import com.google.gerrit.extensions.common.PluginInfo; +import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.server.plugins.DisablePlugin; +import com.google.gerrit.server.plugins.EnablePlugin; +import com.google.gerrit.server.plugins.GetStatus; +import com.google.gerrit.server.plugins.PluginResource; +import com.google.gerrit.server.plugins.ReloadPlugin; +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; + +public class PluginApiImpl implements PluginApi { + public interface Factory { + PluginApiImpl create(PluginResource resource); + } + + private final GetStatus getStatus; + private final EnablePlugin enable; + private final DisablePlugin disable; + private final ReloadPlugin reload; + private final PluginResource resource; + + @Inject + PluginApiImpl( + GetStatus getStatus, + EnablePlugin enable, + DisablePlugin disable, + ReloadPlugin reload, + @Assisted PluginResource resource) { + this.getStatus = getStatus; + this.enable = enable; + this.disable = disable; + this.reload = reload; + this.resource = resource; + } + + @Override + public PluginInfo get() throws RestApiException { + return getStatus.apply(resource); + } + + @Override + public void enable() throws RestApiException { + enable.apply(resource, new EnablePlugin.Input()); + } + + @Override + public void disable() throws RestApiException { + disable.apply(resource, new DisablePlugin.Input()); + } + + @Override + public void reload() throws RestApiException { + reload.apply(resource, new ReloadPlugin.Input()); + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginsImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginsImpl.java index 01ab6baf9a..994acbfee7 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginsImpl.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginsImpl.java @@ -14,22 +14,44 @@ package com.google.gerrit.server.api.plugins; +import com.google.gerrit.extensions.api.plugins.PluginApi; import com.google.gerrit.extensions.api.plugins.Plugins; +import com.google.gerrit.extensions.common.InstallPluginInput; import com.google.gerrit.extensions.common.PluginInfo; +import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.extensions.restapi.TopLevelResource; +import com.google.gerrit.server.plugins.InstallPlugin; import com.google.gerrit.server.plugins.ListPlugins; +import com.google.gerrit.server.plugins.PluginsCollection; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; +import java.io.IOException; import java.util.SortedMap; @Singleton public class PluginsImpl implements Plugins { + private final PluginsCollection plugins; private final Provider listProvider; + private final Provider installProvider; + private final PluginApiImpl.Factory pluginApi; @Inject - PluginsImpl(Provider listProvider) { + PluginsImpl( + PluginsCollection plugins, + Provider listProvider, + Provider installProvider, + PluginApiImpl.Factory pluginApi) { + this.plugins = plugins; this.listProvider = listProvider; + this.installProvider = installProvider; + this.pluginApi = pluginApi; + } + + @Override + public PluginApi name(String name) throws RestApiException { + return pluginApi.create(plugins.parse(name)); } @Override @@ -43,4 +65,15 @@ public class PluginsImpl implements Plugins { } }; } + + @Override + public PluginApi install(String name, InstallPluginInput input) throws RestApiException { + try { + Response created = + installProvider.get().setName(name).apply(TopLevelResource.INSTANCE, input); + return pluginApi.create(plugins.parse(created.value().id)); + } catch (IOException e) { + throw new RestApiException("could not install plugin", e); + } + } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/DisablePlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/DisablePlugin.java index 8732e3ef8a..a2da580246 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/DisablePlugin.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/DisablePlugin.java @@ -26,8 +26,8 @@ import com.google.inject.Singleton; @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) @Singleton -class DisablePlugin implements RestModifyView { - static class Input {} +public class DisablePlugin implements RestModifyView { + public static class Input {} private final PluginLoader loader; diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/EnablePlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/EnablePlugin.java index 41f93495f1..f29e36b39d 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/EnablePlugin.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/EnablePlugin.java @@ -29,8 +29,8 @@ import java.io.StringWriter; @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) @Singleton -class EnablePlugin implements RestModifyView { - static class Input {} +public class EnablePlugin implements RestModifyView { + public static class Input {} private final PluginLoader loader; diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/GetStatus.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/GetStatus.java index 650f9fca60..cbd864a2ce 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/GetStatus.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/GetStatus.java @@ -19,7 +19,7 @@ import com.google.gerrit.extensions.restapi.RestReadView; import com.google.inject.Singleton; @Singleton -class GetStatus implements RestReadView { +public class GetStatus implements RestReadView { @Override public PluginInfo apply(PluginResource resource) { return ListPlugins.toPluginInfo(resource.getPlugin()); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/InstallPlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/InstallPlugin.java index 61aed6a824..531e9ac44f 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/InstallPlugin.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/InstallPlugin.java @@ -33,7 +33,7 @@ import java.net.URL; import java.util.zip.ZipException; @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) -class InstallPlugin implements RestModifyView { +public class InstallPlugin implements RestModifyView { private final PluginLoader loader; private String name; diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginRestApiModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginRestApiModule.java index e61c517c13..5f97134777 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginRestApiModule.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginRestApiModule.java @@ -19,6 +19,7 @@ import static com.google.gerrit.server.plugins.PluginResource.PLUGIN_KIND; import com.google.gerrit.extensions.api.plugins.Plugins; import com.google.gerrit.extensions.registration.DynamicMap; import com.google.gerrit.extensions.restapi.RestApiModule; +import com.google.gerrit.server.api.plugins.PluginApiImpl; import com.google.gerrit.server.api.plugins.PluginsImpl; public class PluginRestApiModule extends RestApiModule { @@ -33,5 +34,6 @@ public class PluginRestApiModule extends RestApiModule { post(PLUGIN_KIND, "enable").to(EnablePlugin.class); post(PLUGIN_KIND, "reload").to(ReloadPlugin.class); bind(Plugins.class).to(PluginsImpl.class); + factory(PluginApiImpl.Factory.class); } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginsCollection.java index 314415e19f..a1dc5c1e29 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginsCollection.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginsCollection.java @@ -55,7 +55,11 @@ public class PluginsCollection @Override public PluginResource parse(TopLevelResource parent, IdString id) throws ResourceNotFoundException { - Plugin p = loader.get(id.get()); + return parse(id.get()); + } + + public PluginResource parse(String id) throws ResourceNotFoundException { + Plugin p = loader.get(id); if (p == null) { throw new ResourceNotFoundException(id); } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ReloadPlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ReloadPlugin.java index 426d323cf3..7b464bb14c 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ReloadPlugin.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ReloadPlugin.java @@ -28,8 +28,8 @@ import java.io.StringWriter; @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) @Singleton -class ReloadPlugin implements RestModifyView { - static class Input {} +public class ReloadPlugin implements RestModifyView { + public static class Input {} private final PluginLoader loader;