Merge branch 'stable-3.1'
* stable-3.1: Move documentation for Jetty metrics to a separate section Improve Jetty thread pool metrics Fix commentlinks with same prefix in pattern and link DeleteZombieCommentsRefsTest: Open RevWalk in try-with-resource Use bugs.chromium.org in gr-linked-text_test Expose jetty threadpool metrics via dropwizard Fix editing name & email for service user Fix accountBelongsToRealm implementation Fix support for python3 in download_bower.py NoteDbMigrator: Totally skip migration for orphan changes Change-Id: I4489643f6d8fe9616978393c773c7e081b225b05
This commit is contained in:
commit
24d497844d
@ -65,6 +65,18 @@ objects needing finalization.
|
||||
|
||||
=== HTTP
|
||||
|
||||
==== Jetty
|
||||
|
||||
* `http/server/jetty/threadpool/active_threads`: Active threads
|
||||
* `http/server/jetty/threadpool/idle_threads`: Idle threads
|
||||
* `http/server/jetty/threadpool/reserved_threads`: Reserved threads
|
||||
* `http/server/jetty/threadpool/max_pool_size`: Maximum thread pool size
|
||||
* `http/server/jetty/threadpool/min_pool_size`: Minimum thread pool size
|
||||
* `http/server/jetty/threadpool/pool_size`: Current thread pool size
|
||||
* `http/server/jetty/threadpool/queue_size`: Queued requests waiting for a thread
|
||||
|
||||
==== REST API
|
||||
|
||||
* `http/server/error_count`: Rate of REST API error responses.
|
||||
* `http/server/success_count`: Rate of REST API success responses.
|
||||
* `http/server/rest_api/count`: Rate of REST API calls by view.
|
||||
|
@ -8,6 +8,7 @@ java_library(
|
||||
"//java/com/google/gerrit/common:annotations",
|
||||
"//java/com/google/gerrit/extensions:api",
|
||||
"//java/com/google/gerrit/metrics",
|
||||
"//java/com/google/gerrit/pgm/http/jetty",
|
||||
"//java/com/google/gerrit/server",
|
||||
"//lib:args4j",
|
||||
"//lib:guava",
|
||||
|
@ -8,6 +8,7 @@ java_library(
|
||||
"//java/com/google/gerrit/extensions:api",
|
||||
"//java/com/google/gerrit/httpd",
|
||||
"//java/com/google/gerrit/lifecycle",
|
||||
"//java/com/google/gerrit/metrics",
|
||||
"//java/com/google/gerrit/server",
|
||||
"//java/com/google/gerrit/server/util/time",
|
||||
"//java/com/google/gerrit/sshd",
|
||||
|
91
java/com/google/gerrit/pgm/http/jetty/JettyMetrics.java
Normal file
91
java/com/google/gerrit/pgm/http/jetty/JettyMetrics.java
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright (C) 2020 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.pgm.http.jetty;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gerrit.metrics.CallbackMetric;
|
||||
import com.google.gerrit.metrics.CallbackMetric0;
|
||||
import com.google.gerrit.metrics.Description;
|
||||
import com.google.gerrit.metrics.MetricMaker;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class JettyMetrics {
|
||||
|
||||
@Inject
|
||||
JettyMetrics(JettyServer jetty, MetricMaker metrics) {
|
||||
CallbackMetric0<Integer> minPoolSize =
|
||||
metrics.newCallbackMetric(
|
||||
"http/server/jetty/threadpool/min_pool_size",
|
||||
Integer.class,
|
||||
new Description("Minimum thread pool size").setGauge());
|
||||
CallbackMetric0<Integer> maxPoolSize =
|
||||
metrics.newCallbackMetric(
|
||||
"http/server/jetty/threadpool/max_pool_size",
|
||||
Integer.class,
|
||||
new Description("Maximum thread pool size").setGauge());
|
||||
CallbackMetric0<Integer> poolSize =
|
||||
metrics.newCallbackMetric(
|
||||
"http/server/jetty/threadpool/pool_size",
|
||||
Integer.class,
|
||||
new Description("Current thread pool size").setGauge());
|
||||
CallbackMetric0<Integer> idleThreads =
|
||||
metrics.newCallbackMetric(
|
||||
"http/server/jetty/threadpool/idle_threads",
|
||||
Integer.class,
|
||||
new Description("Idle threads").setGauge().setUnit("threads"));
|
||||
CallbackMetric0<Integer> busyThreads =
|
||||
metrics.newCallbackMetric(
|
||||
"http/server/jetty/threadpool/active_threads",
|
||||
Integer.class,
|
||||
new Description("Active threads").setGauge().setUnit("threads"));
|
||||
CallbackMetric0<Integer> reservedThreads =
|
||||
metrics.newCallbackMetric(
|
||||
"http/server/jetty/threadpool/reserved_threads",
|
||||
Integer.class,
|
||||
new Description("Reserved threads").setGauge().setUnit("threads"));
|
||||
CallbackMetric0<Integer> queueSize =
|
||||
metrics.newCallbackMetric(
|
||||
"http/server/jetty/threadpool/queue_size",
|
||||
Integer.class,
|
||||
new Description("Queued requests waiting for a thread").setGauge().setUnit("requests"));
|
||||
CallbackMetric0<Boolean> lowOnThreads =
|
||||
metrics.newCallbackMetric(
|
||||
"http/server/jetty/threadpool/is_low_on_threads",
|
||||
Boolean.class,
|
||||
new Description("Whether thread pool is low on threads").setGauge());
|
||||
JettyServer.Metrics jettyMetrics = jetty.getMetrics();
|
||||
metrics.newTrigger(
|
||||
ImmutableSet.<CallbackMetric<?>>of(
|
||||
idleThreads,
|
||||
busyThreads,
|
||||
reservedThreads,
|
||||
minPoolSize,
|
||||
maxPoolSize,
|
||||
poolSize,
|
||||
queueSize,
|
||||
lowOnThreads),
|
||||
() -> {
|
||||
minPoolSize.set(jettyMetrics.getMinThreads());
|
||||
maxPoolSize.set(jettyMetrics.getMaxThreads());
|
||||
poolSize.set(jettyMetrics.getThreads());
|
||||
idleThreads.set(jettyMetrics.getIdleThreads());
|
||||
busyThreads.set(jettyMetrics.getBusyThreads());
|
||||
reservedThreads.set(jettyMetrics.getReservedThreads());
|
||||
queueSize.set(jettyMetrics.getQueueSize());
|
||||
lowOnThreads.set(jettyMetrics.isLowOnThreads());
|
||||
});
|
||||
}
|
||||
}
|
@ -31,5 +31,6 @@ public class JettyModule extends LifecycleModule {
|
||||
bind(JettyServer.class);
|
||||
listener().to(JettyServer.Lifecycle.class);
|
||||
install(new FactoryModuleBuilder().build(HttpLogFactory.class));
|
||||
bind(JettyMetrics.class);
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,6 @@ import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
@Singleton
|
||||
@ -117,9 +116,49 @@ public class JettyServer {
|
||||
}
|
||||
}
|
||||
|
||||
static class Metrics {
|
||||
private final QueuedThreadPool threadPool;
|
||||
|
||||
Metrics(QueuedThreadPool threadPool) {
|
||||
this.threadPool = threadPool;
|
||||
}
|
||||
|
||||
public int getIdleThreads() {
|
||||
return threadPool.getIdleThreads();
|
||||
}
|
||||
|
||||
public int getBusyThreads() {
|
||||
return threadPool.getBusyThreads();
|
||||
}
|
||||
|
||||
public int getReservedThreads() {
|
||||
return threadPool.getReservedThreads();
|
||||
}
|
||||
|
||||
public int getMinThreads() {
|
||||
return threadPool.getMinThreads();
|
||||
}
|
||||
|
||||
public int getMaxThreads() {
|
||||
return threadPool.getMaxThreads();
|
||||
}
|
||||
|
||||
public int getThreads() {
|
||||
return threadPool.getThreads();
|
||||
}
|
||||
|
||||
public int getQueueSize() {
|
||||
return threadPool.getQueueSize();
|
||||
}
|
||||
|
||||
public boolean isLowOnThreads() {
|
||||
return threadPool.isLowOnThreads();
|
||||
}
|
||||
}
|
||||
|
||||
private final SitePaths site;
|
||||
private final Server httpd;
|
||||
|
||||
private final Metrics metrics;
|
||||
private boolean reverseProxy;
|
||||
|
||||
@Inject
|
||||
@ -131,8 +170,10 @@ public class JettyServer {
|
||||
HttpLogFactory httpLogFactory) {
|
||||
this.site = site;
|
||||
|
||||
httpd = new Server(threadPool(cfg, threadSettingsConfig));
|
||||
QueuedThreadPool pool = threadPool(cfg, threadSettingsConfig);
|
||||
httpd = new Server(pool);
|
||||
httpd.setConnectors(listen(httpd, cfg));
|
||||
metrics = new Metrics(pool);
|
||||
|
||||
Handler app = makeContext(env, cfg);
|
||||
if (cfg.getBoolean("httpd", "requestLog", !reverseProxy)) {
|
||||
@ -161,6 +202,10 @@ public class JettyServer {
|
||||
httpd.setStopAtShutdown(false);
|
||||
}
|
||||
|
||||
Metrics getMetrics() {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
private Connector[] listen(Server server, Config cfg) {
|
||||
// OpenID and certain web-based single-sign-on products can cause
|
||||
// some very long headers, especially in the Referer header. We
|
||||
@ -336,7 +381,7 @@ public class JettyServer {
|
||||
return site.resolve(path);
|
||||
}
|
||||
|
||||
private ThreadPool threadPool(Config cfg, ThreadSettingsConfig threadSettingsConfig) {
|
||||
private QueuedThreadPool threadPool(Config cfg, ThreadSettingsConfig threadSettingsConfig) {
|
||||
int maxThreads = threadSettingsConfig.getHttpdMaxThreads();
|
||||
int minThreads = cfg.getInt("httpd", null, "minthreads", 5);
|
||||
int maxQueued = cfg.getInt("httpd", null, "maxqueued", 200);
|
||||
|
@ -337,7 +337,7 @@ class LdapRealm extends AbstractRealm {
|
||||
@Override
|
||||
public boolean accountBelongsToRealm(Collection<ExternalId> externalIds) {
|
||||
for (ExternalId id : externalIds) {
|
||||
if (id.toString().contains(SCHEME_GERRIT)) {
|
||||
if (id.isScheme(SCHEME_GERRIT)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ public class OAuthRealm extends AbstractRealm {
|
||||
@Override
|
||||
public boolean accountBelongsToRealm(Collection<ExternalId> externalIds) {
|
||||
for (ExternalId id : externalIds) {
|
||||
if (id.toString().contains(SCHEME_EXTERNAL)) {
|
||||
if (id.isScheme(SCHEME_EXTERNAL)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ package com.google.gerrit.server.restapi.account;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import com.google.gerrit.entities.Account;
|
||||
import com.google.gerrit.extensions.client.AccountFieldName;
|
||||
import com.google.gerrit.extensions.common.Input;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
@ -79,12 +80,14 @@ public class DeleteEmail implements RestModifyView<AccountResource.Email, Input>
|
||||
public Response<?> apply(IdentifiedUser user, String email)
|
||||
throws ResourceNotFoundException, ResourceConflictException, MethodNotAllowedException,
|
||||
IOException, ConfigInvalidException {
|
||||
if (!realm.allowsEdit(AccountFieldName.REGISTER_NEW_EMAIL)) {
|
||||
Account.Id accountId = user.getAccountId();
|
||||
if (realm.accountBelongsToRealm(externalIds.byAccount(accountId))
|
||||
&& !realm.allowsEdit(AccountFieldName.REGISTER_NEW_EMAIL)) {
|
||||
throw new MethodNotAllowedException("realm does not allow deleting emails");
|
||||
}
|
||||
|
||||
Set<ExternalId> extIds =
|
||||
externalIds.byAccount(user.getAccountId()).stream()
|
||||
externalIds.byAccount(accountId).stream()
|
||||
.filter(e -> email.equals(e.email()))
|
||||
.collect(toSet());
|
||||
if (extIds.isEmpty()) {
|
||||
|
@ -15,6 +15,7 @@
|
||||
package com.google.gerrit.server.restapi.account;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.gerrit.entities.Account;
|
||||
import com.google.gerrit.extensions.client.AccountFieldName;
|
||||
import com.google.gerrit.extensions.common.NameInput;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
@ -29,6 +30,7 @@ import com.google.gerrit.server.account.AccountResource;
|
||||
import com.google.gerrit.server.account.AccountState;
|
||||
import com.google.gerrit.server.account.AccountsUpdate;
|
||||
import com.google.gerrit.server.account.Realm;
|
||||
import com.google.gerrit.server.account.externalids.ExternalIds;
|
||||
import com.google.gerrit.server.permissions.GlobalPermission;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
@ -50,6 +52,7 @@ public class PutName implements RestModifyView<AccountResource, NameInput> {
|
||||
private final Provider<CurrentUser> self;
|
||||
private final Realm realm;
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final ExternalIds externalIds;
|
||||
private final Provider<AccountsUpdate> accountsUpdateProvider;
|
||||
|
||||
@Inject
|
||||
@ -57,10 +60,12 @@ public class PutName implements RestModifyView<AccountResource, NameInput> {
|
||||
Provider<CurrentUser> self,
|
||||
Realm realm,
|
||||
PermissionBackend permissionBackend,
|
||||
ExternalIds externalIds,
|
||||
@ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider) {
|
||||
this.self = self;
|
||||
this.realm = realm;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.externalIds = externalIds;
|
||||
this.accountsUpdateProvider = accountsUpdateProvider;
|
||||
}
|
||||
|
||||
@ -81,7 +86,9 @@ public class PutName implements RestModifyView<AccountResource, NameInput> {
|
||||
input = new NameInput();
|
||||
}
|
||||
|
||||
if (!realm.allowsEdit(AccountFieldName.FULL_NAME)) {
|
||||
Account.Id accountId = user.getAccountId();
|
||||
if (realm.accountBelongsToRealm(externalIds.byAccount(accountId))
|
||||
&& !realm.allowsEdit(AccountFieldName.FULL_NAME)) {
|
||||
throw new MethodNotAllowedException("realm does not allow editing name");
|
||||
}
|
||||
|
||||
@ -89,7 +96,7 @@ public class PutName implements RestModifyView<AccountResource, NameInput> {
|
||||
AccountState accountState =
|
||||
accountsUpdateProvider
|
||||
.get()
|
||||
.update("Set Full Name via API", user.getAccountId(), u -> u.setFullName(newName))
|
||||
.update("Set Full Name via API", accountId, u -> u.setFullName(newName))
|
||||
.orElseThrow(() -> new ResourceNotFoundException("account not found"));
|
||||
return Strings.isNullOrEmpty(accountState.account().fullName())
|
||||
? Response.none()
|
||||
|
@ -89,15 +89,16 @@ public class PutUsername implements RestModifyView<AccountResource, UsernameInpu
|
||||
permissionBackend.currentUser().check(GlobalPermission.ADMINISTRATE_SERVER);
|
||||
}
|
||||
|
||||
if (!realm.allowsEdit(AccountFieldName.USER_NAME)) {
|
||||
throw new MethodNotAllowedException("realm does not allow editing username");
|
||||
}
|
||||
|
||||
Account.Id accountId = rsrc.getUser().getAccountId();
|
||||
if (!externalIds.byAccount(accountId, SCHEME_USERNAME).isEmpty()) {
|
||||
throw new MethodNotAllowedException("Username cannot be changed.");
|
||||
}
|
||||
|
||||
if (realm.accountBelongsToRealm(externalIds.byAccount(accountId))
|
||||
&& !realm.allowsEdit(AccountFieldName.USER_NAME)) {
|
||||
throw new MethodNotAllowedException("realm does not allow editing username");
|
||||
}
|
||||
|
||||
if (input == null || Strings.isNullOrEmpty(input.username)) {
|
||||
throw new BadRequestException("input required");
|
||||
}
|
||||
|
@ -0,0 +1,94 @@
|
||||
// Copyright (C) 2020 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.auth.ldap;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GERRIT;
|
||||
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_MAILTO;
|
||||
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
|
||||
import static com.google.gerrit.server.auth.ldap.LdapModule.GROUP_CACHE;
|
||||
import static com.google.gerrit.server.auth.ldap.LdapModule.GROUP_EXIST_CACHE;
|
||||
import static com.google.gerrit.server.auth.ldap.LdapModule.PARENT_GROUPS_CACHE;
|
||||
import static com.google.gerrit.server.auth.ldap.LdapModule.USERNAME_CACHE;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gerrit.entities.Account;
|
||||
import com.google.gerrit.entities.AccountGroup;
|
||||
import com.google.gerrit.server.account.externalids.ExternalId;
|
||||
import com.google.gerrit.server.cache.CacheModule;
|
||||
import com.google.gerrit.testing.InMemoryModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public final class LdapRealmTest {
|
||||
@Inject private LdapRealm ldapRealm = null;
|
||||
|
||||
@Before
|
||||
public void setUpInjector() throws Exception {
|
||||
Injector injector =
|
||||
Guice.createInjector(
|
||||
new InMemoryModule(),
|
||||
new CacheModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
cache(GROUP_CACHE, String.class, new TypeLiteral<Set<AccountGroup.UUID>>() {})
|
||||
.loader(LdapRealm.MemberLoader.class);
|
||||
cache(USERNAME_CACHE, String.class, new TypeLiteral<Optional<Account.Id>>() {})
|
||||
.loader(LdapRealm.UserLoader.class);
|
||||
cache(GROUP_EXIST_CACHE, String.class, new TypeLiteral<Boolean>() {})
|
||||
.loader(LdapRealm.ExistenceLoader.class);
|
||||
cache(
|
||||
PARENT_GROUPS_CACHE, String.class, new TypeLiteral<ImmutableSet<String>>() {});
|
||||
}
|
||||
});
|
||||
injector.injectMembers(this);
|
||||
}
|
||||
|
||||
private ExternalId id(String scheme, String id) {
|
||||
return ExternalId.create(scheme, id, Account.id(1000));
|
||||
}
|
||||
|
||||
private boolean accountBelongsToRealm(ExternalId... ids) {
|
||||
return ldapRealm.accountBelongsToRealm(Arrays.asList(ids));
|
||||
}
|
||||
|
||||
private boolean accountBelongsToRealm(String scheme, String id) {
|
||||
return accountBelongsToRealm(id(scheme, id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accountBelongsToRealm() throws Exception {
|
||||
assertThat(accountBelongsToRealm(SCHEME_GERRIT, "test")).isTrue();
|
||||
assertThat(accountBelongsToRealm(id(SCHEME_USERNAME, "test"), id(SCHEME_GERRIT, "test")))
|
||||
.isTrue();
|
||||
assertThat(accountBelongsToRealm(id(SCHEME_GERRIT, "test"), id(SCHEME_USERNAME, "test")))
|
||||
.isTrue();
|
||||
|
||||
assertThat(accountBelongsToRealm(SCHEME_USERNAME, "test")).isFalse();
|
||||
assertThat(accountBelongsToRealm(SCHEME_MAILTO, "foo@bar.com")).isFalse();
|
||||
|
||||
assertThat(accountBelongsToRealm(SCHEME_USERNAME, "gerrit")).isFalse();
|
||||
assertThat(accountBelongsToRealm(SCHEME_USERNAME, "xxgerritxx")).isFalse();
|
||||
assertThat(accountBelongsToRealm(SCHEME_MAILTO, "gerrit.foo@bar.com")).isFalse();
|
||||
assertThat(accountBelongsToRealm(SCHEME_MAILTO, "bar.gerrit@bar.com")).isFalse();
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
// Copyright (C) 2020 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.auth.oauth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_EXTERNAL;
|
||||
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_MAILTO;
|
||||
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
|
||||
|
||||
import com.google.gerrit.entities.Account;
|
||||
import com.google.gerrit.server.account.externalids.ExternalId;
|
||||
import com.google.gerrit.testing.InMemoryModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import java.util.Arrays;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public final class OAuthRealmTest {
|
||||
@Inject private OAuthRealm oauthRealm = null;
|
||||
|
||||
@Before
|
||||
public void setUpInjector() throws Exception {
|
||||
Injector injector = Guice.createInjector(new InMemoryModule());
|
||||
injector.injectMembers(this);
|
||||
}
|
||||
|
||||
private ExternalId id(String scheme, String id) {
|
||||
return ExternalId.create(scheme, id, Account.id(1000));
|
||||
}
|
||||
|
||||
private boolean accountBelongsToRealm(ExternalId... ids) {
|
||||
return oauthRealm.accountBelongsToRealm(Arrays.asList(ids));
|
||||
}
|
||||
|
||||
private boolean accountBelongsToRealm(String scheme, String id) {
|
||||
return accountBelongsToRealm(id(scheme, id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accountBelongsToRealm() throws Exception {
|
||||
assertThat(accountBelongsToRealm(SCHEME_EXTERNAL, "test")).isTrue();
|
||||
assertThat(accountBelongsToRealm(id(SCHEME_USERNAME, "test"), id(SCHEME_EXTERNAL, "test")))
|
||||
.isTrue();
|
||||
assertThat(accountBelongsToRealm(id(SCHEME_EXTERNAL, "test"), id(SCHEME_USERNAME, "test")))
|
||||
.isTrue();
|
||||
|
||||
assertThat(accountBelongsToRealm(SCHEME_USERNAME, "test")).isFalse();
|
||||
assertThat(accountBelongsToRealm(SCHEME_MAILTO, "foo@bar.com")).isFalse();
|
||||
|
||||
assertThat(accountBelongsToRealm(SCHEME_USERNAME, "external")).isFalse();
|
||||
assertThat(accountBelongsToRealm(SCHEME_USERNAME, "xxexternalxx")).isFalse();
|
||||
assertThat(accountBelongsToRealm(SCHEME_MAILTO, "external.foo@bar.com")).isFalse();
|
||||
assertThat(accountBelongsToRealm(SCHEME_MAILTO, "bar.external@bar.com")).isFalse();
|
||||
}
|
||||
}
|
@ -176,13 +176,14 @@ public class DeleteZombieCommentsRefsTest {
|
||||
|
||||
private static Ref createRefWithNonEmptyTreeCommit(Repository usersRepo, int changeId, int userId)
|
||||
throws IOException {
|
||||
RevWalk rw = new RevWalk(usersRepo);
|
||||
ObjectId fileObj = createBlob(usersRepo, String.format("file %d content", changeId));
|
||||
ObjectId treeObj =
|
||||
createTree(usersRepo, rw.lookupBlob(fileObj), String.format("file%d.txt", changeId));
|
||||
ObjectId commitObj = createCommit(usersRepo, treeObj, null);
|
||||
Ref refObj = createRef(usersRepo, commitObj, getRefName(changeId, userId));
|
||||
return refObj;
|
||||
try (RevWalk rw = new RevWalk(usersRepo)) {
|
||||
ObjectId fileObj = createBlob(usersRepo, String.format("file %d content", changeId));
|
||||
ObjectId treeObj =
|
||||
createTree(usersRepo, rw.lookupBlob(fileObj), String.format("file%d.txt", changeId));
|
||||
ObjectId commitObj = createCommit(usersRepo, treeObj, null);
|
||||
Ref refObj = createRef(usersRepo, commitObj, getRefName(changeId, userId));
|
||||
return refObj;
|
||||
}
|
||||
}
|
||||
|
||||
private static Ref createRefWithEmptyTreeCommit(Repository usersRepo, int changeId, int userId)
|
||||
|
@ -50,7 +50,11 @@ limitations under the License.
|
||||
element.config = {
|
||||
ph: {
|
||||
match: '([Bb]ug|[Ii]ssue)\\s*#?(\\d+)',
|
||||
link: 'https://code.google.com/p/gerrit/issues/detail?id=$2',
|
||||
link: 'https://bugs.chromium.org/p/gerrit/issues/detail?id=$2',
|
||||
},
|
||||
prefixsameinlinkandpattern: {
|
||||
match: '([Hh][Tt][Tt][Pp]example)\\s*#?(\\d+)',
|
||||
link: 'https://bugs.chromium.org/p/gerrit/issues/detail?id=$2',
|
||||
},
|
||||
changeid: {
|
||||
match: '(I[0-9a-f]{8,40})',
|
||||
@ -91,7 +95,7 @@ limitations under the License.
|
||||
|
||||
test('URL pattern was parsed and linked.', () => {
|
||||
// Regular inline link.
|
||||
const url = 'https://code.google.com/p/gerrit/issues/detail?id=3650';
|
||||
const url = 'https://bugs.chromium.org/p/gerrit/issues/detail?id=3650';
|
||||
element.content = url;
|
||||
const linkEl = element.$.output.childNodes[0];
|
||||
assert.equal(linkEl.target, '_blank');
|
||||
@ -105,7 +109,7 @@ limitations under the License.
|
||||
element.content = 'Issue 3650';
|
||||
|
||||
let linkEl = element.$.output.childNodes[0];
|
||||
const url = 'https://code.google.com/p/gerrit/issues/detail?id=3650';
|
||||
const url = 'https://bugs.chromium.org/p/gerrit/issues/detail?id=3650';
|
||||
assert.equal(linkEl.target, '_blank');
|
||||
assert.equal(linkEl.href, url);
|
||||
assert.equal(linkEl.textContent, 'Issue 3650');
|
||||
@ -118,6 +122,18 @@ limitations under the License.
|
||||
assert.equal(linkEl.textContent, 'Bug 3650');
|
||||
});
|
||||
|
||||
test('Pattern with same prefix as link was correctly parsed', () => {
|
||||
// Pattern starts with the same prefix (`http`) as the url.
|
||||
element.content = 'httpexample 3650';
|
||||
|
||||
assert.equal(element.$.output.childNodes.length, 1);
|
||||
const linkEl = element.$.output.childNodes[0];
|
||||
const url = 'https://bugs.chromium.org/p/gerrit/issues/detail?id=3650';
|
||||
assert.equal(linkEl.target, '_blank');
|
||||
assert.equal(linkEl.href, url);
|
||||
assert.equal(linkEl.textContent, 'httpexample 3650');
|
||||
});
|
||||
|
||||
test('Change-Id pattern was parsed and linked', () => {
|
||||
// "Change-Id:" pattern.
|
||||
const changeID = 'I11d6a37f5e9b5df0486f6c922d8836dfa780e03e';
|
||||
@ -159,12 +175,12 @@ limitations under the License.
|
||||
|
||||
assert.equal(linkEl1.target, '_blank');
|
||||
assert.equal(linkEl1.href,
|
||||
'https://code.google.com/p/gerrit/issues/detail?id=3650');
|
||||
'https://bugs.chromium.org/p/gerrit/issues/detail?id=3650');
|
||||
assert.equal(linkEl1.textContent, 'Issue 3650');
|
||||
|
||||
assert.equal(linkEl2.target, '_blank');
|
||||
assert.equal(linkEl2.href,
|
||||
'https://code.google.com/p/gerrit/issues/detail?id=3450');
|
||||
'https://bugs.chromium.org/p/gerrit/issues/detail?id=3450');
|
||||
assert.equal(linkEl2.textContent, 'Issue 3450');
|
||||
});
|
||||
|
||||
@ -177,7 +193,7 @@ limitations under the License.
|
||||
const bug = 'Issue 3650';
|
||||
|
||||
const changeUrl = '/q/' + changeID;
|
||||
const bugUrl = 'https://code.google.com/p/gerrit/issues/detail?id=3650';
|
||||
const bugUrl = 'https://bugs.chromium.org/p/gerrit/issues/detail?id=3650';
|
||||
|
||||
element.content = prefix + changeID + bug;
|
||||
|
||||
|
@ -304,14 +304,15 @@
|
||||
let result = match[0].replace(pattern,
|
||||
patterns[p].html || patterns[p].link);
|
||||
|
||||
let i;
|
||||
// Skip portion of replacement string that is equal to original.
|
||||
for (i = 0; i < result.length; i++) {
|
||||
if (result[i] !== match[0][i]) { break; }
|
||||
}
|
||||
result = result.slice(i);
|
||||
|
||||
if (patterns[p].html) {
|
||||
let i;
|
||||
// Skip portion of replacement string that is equal to original to
|
||||
// allow overlapping patterns.
|
||||
for (i = 0; i < result.length; i++) {
|
||||
if (result[i] !== match[0][i]) { break; }
|
||||
}
|
||||
result = result.slice(i);
|
||||
|
||||
this.addHTML(
|
||||
result,
|
||||
susbtrIndex + match.index + i,
|
||||
@ -321,8 +322,8 @@
|
||||
this.addLink(
|
||||
match[0],
|
||||
result,
|
||||
susbtrIndex + match.index + i,
|
||||
match[0].length - i,
|
||||
susbtrIndex + match.index,
|
||||
match[0].length,
|
||||
outputArray);
|
||||
} else {
|
||||
throw Error('linkconfig entry ' + p +
|
||||
|
@ -46,7 +46,8 @@ def bower_info(bower, name, package, version):
|
||||
raise
|
||||
out, err = p.communicate()
|
||||
if p.returncode:
|
||||
sys.stderr.write(err)
|
||||
# For python3 support we wrap str around err.
|
||||
sys.stderr.write(str(err))
|
||||
raise OSError('Command failed: %s' % ' '.join(cmd))
|
||||
|
||||
try:
|
||||
|
Loading…
Reference in New Issue
Block a user