All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gerrit.acceptance.GerritServerTestRule Maven / Gradle / Ivy

There is a newer version: 3.11.0-rc4
Show newest version
// Copyright (C) 2024 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 static com.google.common.base.Preconditions.checkState;
import static com.google.common.truth.TruthJUnit.assume;
import static java.util.Objects.requireNonNull;

import com.google.gerrit.acceptance.GerritServer.TestSshServerAddress;
import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
import com.google.gerrit.acceptance.testsuite.account.TestSshKeys;
import com.google.gerrit.acceptance.testsuite.request.SshSessionFactory;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.util.RequestContext;
import com.google.gerrit.testing.SshMode;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

public class GerritServerTestRule implements ServerTestRule {
  /**
   * Test methods without special annotations will use a common server for efficiency reasons. The
   * server is torn down after the test class is done or when the config is changed.
   */
  private static GerritServer commonServer;

  private static Description firstTest;

  private final TemporaryFolder temporaryFolder;
  @Nullable private final Supplier testSysModule;
  @Nullable private final Supplier testAuditModule;
  @Nullable private final Supplier testSshModule;
  private final TestConfigRule config;

  @Inject private TestSshKeys sshKeys;
  @Inject @Nullable @TestSshServerAddress private InetSocketAddress sshAddress;

  @Inject private AccountOperations accountOperations;

  private boolean sshInitialized;

  private final HashMap sshSessionByContext = new HashMap<>();

  public GerritServer server;

  public GerritServerTestRule(
      TestConfigRule config,
      TemporaryFolder temporaryFolder,
      @Nullable Supplier testSysModule,
      @Nullable Supplier testAuditModule,
      @Nullable Supplier testSshModule) {
    this.config = config;
    this.testSysModule = testSysModule;
    this.testAuditModule = testAuditModule;
    this.testSshModule = testSshModule;
    this.temporaryFolder = temporaryFolder;
  }

  @Override
  public Statement apply(Statement statement, Description description) {
    return new Statement() {
      @Override
      public void evaluate() throws Throwable {
        if (firstTest == null) {
          firstTest = description;
        }
        if (config.testRequiresSsh()) {
          // If the test uses ssh, we use assume() to make sure ssh is enabled on
          // the test suite. JUnit will skip tests annotated with @UseSsh if we
          // disable them using the command line flag.
          assume().that(SshMode.useSsh()).isTrue();
        }
        statement.evaluate();
        afterTest();
      }
    };
  }

  public void afterTest() throws Exception {
    closeSsh();
    if (server != commonServer) {
      server.close();
      server = null;
    }
  }

  @Override
  public void initServer() throws Exception {

    if (config.classDescription().equals(config.methodDescription())
        && !config.classDescription().sandboxed()
        && !config.methodDescription().sandboxed()) {
      if (commonServer == null) {
        commonServer =
            GerritServer.initAndStart(
                temporaryFolder,
                config.classDescription(),
                config.baseConfig(),
                testSysModule.get(),
                testAuditModule.get(),
                testSshModule.get());
      }
      server = commonServer;
    } else {
      server =
          GerritServer.initAndStart(
              temporaryFolder,
              config.methodDescription(),
              config.baseConfig(),
              testSysModule.get(),
              testAuditModule.get(),
              testSshModule.get());
    }
    getTestInjector().injectMembers(this);
  }

  @Override
  public void initSsh() throws Exception {
    if (config.testRequiresSsh() && SshMode.useSsh()) {
      checkState(!sshInitialized, "The ssh has been alread initialized. Call closeSsh first.");
      // Create Ssh sessions
      SshSessionFactory.initSsh();
      sshInitialized = true;
    }
  }

  @Override
  public boolean sshInitialized() {
    return sshInitialized;
  }

  @Override
  public SshSession getOrCreateSshSessionForContext(RequestContext ctx) {
    checkState(
        config.testRequiresSsh(),
        "The test or the test class must be annotated with @UseSsh to use this method.");
    return sshSessionByContext.computeIfAbsent(
        ctx,
        (c) ->
            SshSessionFactory.createSession(
                sshKeys,
                sshAddress,
                accountOperations.account(ctx.getUser().getAccountId()).get()));
  }

  /**
   * This method is only required for some tests and is not a part of interface.
   *
   * 

After restarting the server with this method, the caller can still get exit value of the * last command executed before restarting (using non-closed sessions). This is used in * SshDaemonIT tests. */ public void restartKeepSessionOpen() throws Exception { checkState( server != commonServer, "The commonServer can't be restarted; to use this method, the test must be @Sandboxed"); server = GerritServer.restart(server, testSysModule.get(), testSshModule.get()); getTestInjector().injectMembers(this); } @Override public void restart() throws Exception { checkState( server != commonServer, "The commonServer can't be restarted; to use this method, the test must be @Sandboxed"); closeSsh(); server = GerritServer.restart(server, testSysModule.get(), testSshModule.get()); getTestInjector().injectMembers(this); initSsh(); } @Override public void restartAsSlave() throws Exception { checkState( server != commonServer, "The commonServer can't be restarted; to use this method, the test must be @Sandboxed"); closeSsh(); server = GerritServer.restartAsSlave(server); getTestInjector().injectMembers(this); initSsh(); } protected void closeSsh() { sshSessionByContext.values().forEach(SshSession::close); sshSessionByContext.clear(); sshInitialized = false; } @Override public Injector getTestInjector() { return server.getTestInjector(); } @Override public Optional getHttpdInjector() { return server.getHttpdInjector(); } @Override public RestSession createRestSession(@Nullable TestAccount account) { return new GerritServerRestSession(server, account); } @Nullable @Override public ProjectResetter createProjectResetter( BiFunction resetConfigSupplier) throws Exception { // Only commonServer can be shared between tests and should be restored after each // test. It can be that the commonServer is started, but a test actually don't use // it and instead the test uses a separate server instance. // In this case, the separate server is stopped after each test and so doesn't require // cleanup (for simplicity, the commonServer is always cleaned up even if it is not // used in a test). if (commonServer == null) { return null; } Injector testInjector = commonServer.testInjector; ProjectResetter.Config config = requireNonNull( resetConfigSupplier.apply( testInjector.getInstance(AllProjectsName.class), testInjector.getInstance(AllUsersName.class))); ProjectResetter.Builder.Factory projectResetterFactory = testInjector.getInstance(ProjectResetter.Builder.Factory.class); return projectResetterFactory != null ? projectResetterFactory.builder().build(config) : null; } @Override public boolean isReplica() { return server.isReplica(); } @Override public Optional getHttpAddress() { return server.getHttpAddress(); } @Override public String getGitUrl() { return server.getUrl(); } @Override public boolean isUsernameSupported() { return true; } public static void afterConfigChanged() { if (commonServer != null) { try { commonServer.close(); } catch (Exception e) { throw new AssertionError( "Error stopping common server in " + (firstTest != null ? firstTest.getTestClass().getName() : "unknown test class"), e); } finally { commonServer = null; } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy