diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java new file mode 100644 index 0000000000..63bdfd2610 --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java @@ -0,0 +1,186 @@ +// Copyright (C) 2013 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.acceptance; + +import com.google.common.collect.Maps; +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.RequestCleanup; +import com.google.gerrit.server.config.RequestScopedReviewDbProvider; +import com.google.gerrit.server.util.RequestContext; +import com.google.gerrit.server.util.ThreadLocalRequestContext; +import com.google.gerrit.server.util.ThreadLocalRequestScopePropagator; +import com.google.gerrit.server.util.TimeUtil; +import com.google.gwtorm.server.SchemaFactory; +import com.google.inject.Inject; +import com.google.inject.Key; +import com.google.inject.OutOfScopeException; +import com.google.inject.Provider; +import com.google.inject.Scope; +import com.google.inject.util.Providers; + +import java.util.Map; + +/** Guice scopes for state during an Acceptance Test connection. */ +public class AcceptanceTestRequestScope { + private static final Key RC_KEY = + Key.get(RequestCleanup.class); + + private static final Key DB_KEY = + Key.get(RequestScopedReviewDbProvider.class); + + public class Context implements RequestContext { + private final RequestCleanup cleanup = new RequestCleanup(); + private final Map, Object> map = Maps.newHashMap(); + private final SchemaFactory schemaFactory; + private final SshSession session; + private final CurrentUser user; + + final long created; + volatile long started; + volatile long finished; + + private Context(SchemaFactory sf, SshSession s, + CurrentUser u, long at) { + schemaFactory = sf; + session = s; + user = u; + created = started = finished = at; + map.put(RC_KEY, cleanup); + map.put(DB_KEY, new RequestScopedReviewDbProvider( + schemaFactory, + Providers.of(cleanup))); + } + + private Context(Context p, SshSession s, CurrentUser c) { + this(p.schemaFactory, s, c, p.created); + started = p.started; + finished = p.finished; + } + + SshSession getSession() { + return session; + } + + @Override + public CurrentUser getCurrentUser() { + if (user == null) { + throw new IllegalStateException("user == null, forgot to set it?"); + } + return user; + } + + @Override + public Provider getReviewDbProvider() { + return (RequestScopedReviewDbProvider) map.get(DB_KEY); + } + + synchronized T get(Key key, Provider creator) { + @SuppressWarnings("unchecked") + T t = (T) map.get(key); + if (t == null) { + t = creator.get(); + map.put(key, t); + } + return t; + } + } + + static class ContextProvider implements Provider { + @Override + public Context get() { + return requireContext(); + } + } + + static class SshSessionProvider implements Provider { + @Override + public SshSession get() { + return requireContext().getSession(); + } + } + + static class Propagator extends ThreadLocalRequestScopePropagator { + private final AcceptanceTestRequestScope atrScope; + + @Inject + Propagator(AcceptanceTestRequestScope atrScope, ThreadLocalRequestContext local, + Provider dbProviderProvider) { + super(REQUEST, current, local, dbProviderProvider); + this.atrScope = atrScope; + } + + @Override + protected Context continuingContext(Context ctx) { + // The cleanup is not chained, since the RequestScopePropagator executors + // the Context's cleanup when finished executing. + return atrScope.newContinuingContext(ctx); + } + } + + private static final ThreadLocal current = + new ThreadLocal(); + + private static Context requireContext() { + final Context ctx = current.get(); + if (ctx == null) { + throw new OutOfScopeException("Not in command/request"); + } + return ctx; + } + + private final ThreadLocalRequestContext local; + + @Inject + AcceptanceTestRequestScope(ThreadLocalRequestContext local) { + this.local = local; + } + + public Context newContext(SchemaFactory sf, SshSession s, CurrentUser user) { + return new Context(sf, s, user, TimeUtil.nowMs()); + } + + private Context newContinuingContext(Context ctx) { + return new Context(ctx, ctx.getSession(), ctx.getCurrentUser()); + } + + public Context set(Context ctx) { + Context old = current.get(); + current.set(ctx); + local.setContext(ctx); + return old; + } + + /** Returns exactly one instance per command executed. */ + static final Scope REQUEST = new Scope() { + public Provider scope(final Key key, final Provider creator) { + return new Provider() { + public T get() { + return requireContext().get(key, creator); + } + + @Override + public String toString() { + return String.format("%s[%s]", creator, REQUEST); + } + }; + } + + @Override + public String toString() { + return "Acceptance Test Scope.REQUEST"; + } + }; +} diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java index b85ffeae63..31ed136fff 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java @@ -58,4 +58,8 @@ public class TestAccount { server.getHttpAddress().getAddress().getHostAddress(), server.getHttpAddress().getPort()); } + + public Account.Id getId() { + return id; + } } diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshRemotePeerProvider.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshRemotePeerProvider.java index 29ede85ddd..2c7736016d 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshRemotePeerProvider.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshRemotePeerProvider.java @@ -21,7 +21,7 @@ import com.google.inject.Singleton; import java.net.SocketAddress; @Singleton -class SshRemotePeerProvider implements Provider { +public class SshRemotePeerProvider implements Provider { private final Provider session; @Inject diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java index 440f236c7f..9067b9b6b1 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java @@ -35,7 +35,7 @@ import com.google.inject.util.Providers; import java.util.Map; /** Guice scopes for state during an SSH connection. */ -class SshScope { +public class SshScope { private static final Key RC_KEY = Key.get(RequestCleanup.class); @@ -119,7 +119,7 @@ class SshScope { } } - static class SshSessionProvider implements Provider { + public static class SshSessionProvider implements Provider { @Override public SshSession get() { return requireContext().getSession(); @@ -181,7 +181,7 @@ class SshScope { } /** Returns exactly one instance per command executed. */ - static final Scope REQUEST = new Scope() { + public static final Scope REQUEST = new Scope() { public Provider scope(final Key key, final Provider creator) { return new Provider() { public T get() {