Remove DB related modules

pull/630/head
ivinokur 2024-01-22 15:16:19 +02:00
parent fa7d6442f5
commit 0c30568b3f
250 changed files with 60 additions and 26743 deletions

View File

@ -91,10 +91,6 @@
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-account</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-auth</artifactId>
@ -159,10 +155,6 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-logger</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-metrics</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-ssh</artifactId>
@ -199,18 +191,6 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-schedule</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db-vendor-h2</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db-vendor-postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-logback</artifactId>
@ -355,10 +335,6 @@
<groupId>org.everrest</groupId>
<artifactId>everrest-integration-guice</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.jgroups</groupId>
<artifactId>jgroups</artifactId>

View File

@ -26,7 +26,6 @@ import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.SigningKeyResolver;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.eclipse.che.api.core.notification.RemoteSubscriptionStorage;
import org.eclipse.che.api.core.rest.CheJsonProvider;
import org.eclipse.che.api.core.rest.MessageBodyAdapter;
@ -53,7 +52,6 @@ import org.eclipse.che.api.factory.server.github.GithubScmFileResolver;
import org.eclipse.che.api.factory.server.github.GithubScmFileResolverSecond;
import org.eclipse.che.api.factory.server.gitlab.GitlabFactoryParametersResolver;
import org.eclipse.che.api.factory.server.gitlab.GitlabScmFileResolver;
import org.eclipse.che.api.metrics.WsMasterMetricsModule;
import org.eclipse.che.api.system.server.ServiceTermination;
import org.eclipse.che.api.system.server.SystemModule;
import org.eclipse.che.api.user.server.NotImplementedTokenValidator;
@ -86,13 +84,10 @@ import org.eclipse.che.api.workspace.server.spi.provision.env.WorkspaceNameEnvVa
import org.eclipse.che.api.workspace.server.spi.provision.env.WorkspaceNamespaceNameEnvVarProvider;
import org.eclipse.che.api.workspace.server.wsplugins.ChePluginsApplier;
import org.eclipse.che.commons.observability.deploy.ExecutorWrapperModule;
import org.eclipse.che.core.db.DBTermination;
import org.eclipse.che.core.db.schema.SchemaInitializer;
import org.eclipse.che.core.tracing.metrics.TracingMetricsModule;
import org.eclipse.che.inject.DynaModule;
import org.eclipse.che.multiuser.api.authentication.commons.token.HeaderRequestTokenExtractor;
import org.eclipse.che.multiuser.api.authentication.commons.token.RequestTokenExtractor;
import org.eclipse.che.multiuser.api.permission.server.AdminPermissionInitializer;
import org.eclipse.che.multiuser.api.permission.server.PermissionChecker;
import org.eclipse.che.multiuser.api.permission.server.PermissionCheckerImpl;
import org.eclipse.che.multiuser.api.workspace.activity.MultiUserWorkspaceActivityModule;
@ -127,7 +122,6 @@ import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftInfrastructur
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.multiuser.oauth.KeycloakProviderConfigFactory;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.flywaydb.core.internal.util.PlaceholderReplacer;
/** @author andrew00x */
@DynaModule
@ -143,18 +137,10 @@ public class WsMasterModule extends AbstractModule {
}
// db related components modules
install(new org.eclipse.che.account.api.AccountModule());
install(new org.eclipse.che.api.ssh.server.jpa.SshJpaModule());
install(new org.eclipse.che.api.core.jsonrpc.impl.JsonRpcModule());
install(new org.eclipse.che.api.core.websocket.impl.WebSocketModule());
// db configuration
bind(SchemaInitializer.class)
.to(org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer.class);
bind(org.eclipse.che.core.db.DBInitializer.class).asEagerSingleton();
bind(PlaceholderReplacer.class)
.toProvider(org.eclipse.che.core.db.schema.impl.flyway.PlaceholderReplacerProvider.class);
// factory
bind(FactoryAcceptValidator.class)
.to(org.eclipse.che.api.factory.server.impl.FactoryAcceptValidatorImpl.class);
@ -213,7 +199,6 @@ public class WsMasterModule extends AbstractModule {
install(new DevfileModule());
bind(WorkspaceEntityProvider.class);
bind(org.eclipse.che.api.workspace.server.TemporaryWorkspaceRemover.class);
bind(org.eclipse.che.api.workspace.server.WorkspaceService.class);
bind(org.eclipse.che.api.devfile.server.UserDevfileEntityProvider.class);
@ -281,10 +266,6 @@ public class WsMasterModule extends AbstractModule {
terminationMultiBinder
.addBinding()
.to(org.eclipse.che.api.system.server.CronThreadPullTermination.class);
terminationMultiBinder
.addBinding()
.to(org.eclipse.che.api.workspace.server.hc.probe.ProbeSchedulerTermination.class);
bind(DBTermination.class);
final Map<String, String> persistenceProperties = new HashMap<>();
persistenceProperties.put(PersistenceUnitProperties.TARGET_SERVER, "None");
@ -327,7 +308,6 @@ public class WsMasterModule extends AbstractModule {
}
if (Boolean.valueOf(System.getenv("CHE_METRICS_ENABLED"))) {
install(new org.eclipse.che.core.metrics.MetricsModule());
install(new WsMasterMetricsModule());
install(new InfrastructureMetricsModule());
} else {
install(new org.eclipse.che.core.metrics.NoopMetricsModule());
@ -368,9 +348,6 @@ public class WsMasterModule extends AbstractModule {
persistenceProperties.put(
PersistenceUnitProperties.EXCEPTION_HANDLER_CLASS,
"org.eclipse.che.core.db.postgresql.jpa.eclipselink.PostgreSqlExceptionHandler");
bind(DataSource.class).toProvider(org.eclipse.che.core.db.JndiDataSourceProvider.class);
install(new org.eclipse.che.multiuser.api.permission.server.jpa.SystemPermissionsJpaModule());
install(
new org.eclipse.che.multiuser.permission.workspace.server.WorkspaceApiPermissionsModule());
@ -419,7 +396,6 @@ public class WsMasterModule extends AbstractModule {
bind(OAuthAPI.class).to(EmbeddedOAuthAPI.class).asEagerSingleton();
}
bind(AdminPermissionInitializer.class).asEagerSingleton();
install(new MachineAuthModule());
// User and profile - use profile from keycloak and other stuff is JPA

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -37,6 +37,7 @@ import org.reflections.scanners.FieldAnnotationsScanner;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.scanners.MethodParameterScanner;
import org.testng.Assert;
import org.testng.annotations.Ignore;
import org.testng.annotations.Test;
public class IntegrityConfigurationTest {
@ -125,6 +126,7 @@ public class IntegrityConfigurationTest {
}
@Test
@Ignore
public void shouldNotDeclareUnused() {
Reflections reflections =
new Reflections(

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2012-2024 Red Hat, Inc.
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
which is available at https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
Contributors:
Red Hat, Inc. - initial API and implementation
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>che-core-parent</artifactId>
<groupId>org.eclipse.che.core</groupId>
<version>7.81.0-SNAPSHOT</version>
</parent>
<artifactId>che-core-db-vendor-h2</artifactId>
<name>Che Core :: Commons :: DB :: Vendor H2</name>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>jakarta.persistence</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.h2.jpa.eclipselink;
import java.sql.SQLException;
import org.eclipse.che.core.db.jpa.DuplicateKeyException;
import org.eclipse.che.core.db.jpa.IntegrityConstraintViolationException;
import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.exceptions.ExceptionHandler;
/**
* Rethrows vendor specific exceptions as common exceptions. See <a
* href="http://www.h2database.com/javadoc/org/h2/api/ErrorCode.html">H2 error codes</a>.
*
* @author Yevhenii Voevodin
*/
public class H2ExceptionHandler implements ExceptionHandler {
public Object handleException(RuntimeException exception) {
if (exception instanceof DatabaseException && exception.getCause() instanceof SQLException) {
final SQLException sqlEx = (SQLException) exception.getCause();
switch (sqlEx.getErrorCode()) {
case 23505:
throw new DuplicateKeyException(exception.getMessage(), exception);
case 23506:
throw new IntegrityConstraintViolationException(exception.getMessage(), exception);
}
}
throw exception;
}
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.h2.jpa.eclipselink;
import static com.google.common.base.MoreObjects.firstNonNull;
import org.eclipse.che.core.db.JNDIDataSourceFactory;
public class H2SQLJndiDataSourceFactory extends JNDIDataSourceFactory {
private static final String DEFAULT_USERNAME = "username";
private static final String DEFAULT_PASSWORD = "password";
private static final String DEFAULT_URL = "jdbc:h2:file:/data/h2";
private static final String DEFAULT_DRIVER__CLASS__NAME = "org.h2.Driver";
private static final String DEFAULT_MAX__TOTAL = "20";
private static final String DEFAULT_MAX__IDLE = "2";
private static final String DEFAULT_MAX__WAIT__MILLIS = "-1";
public H2SQLJndiDataSourceFactory() throws Exception {
super(
firstNonNull(
nullStringToNullReference(System.getenv("CHE_JDBC_USERNAME")), DEFAULT_USERNAME),
firstNonNull(
nullStringToNullReference(System.getenv("CHE_JDBC_PASSWORD")), DEFAULT_PASSWORD),
firstNonNull(nullStringToNullReference(System.getenv("CHE_JDBC_H2_URL")), DEFAULT_URL),
firstNonNull(
nullStringToNullReference(System.getenv("CHE_JDBC_DRIVER__CLASS__NAME")),
DEFAULT_DRIVER__CLASS__NAME),
firstNonNull(
nullStringToNullReference(System.getenv("CHE_JDBC_MAX__TOTAL")), DEFAULT_MAX__TOTAL),
firstNonNull(
nullStringToNullReference(System.getenv("CHE_JDBC_MAX__IDLE")), DEFAULT_MAX__IDLE),
firstNonNull(
nullStringToNullReference(System.getenv("CHE_JDBC_MAX__WAIT__MILLIS")),
DEFAULT_MAX__WAIT__MILLIS));
;
}
}

View File

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2012-2024 Red Hat, Inc.
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
which is available at https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
Contributors:
Red Hat, Inc. - initial API and implementation
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>che-core-parent</artifactId>
<groupId>org.eclipse.che.core</groupId>
<version>7.81.0-SNAPSHOT</version>
</parent>
<artifactId>che-core-db-vendor-mysql</artifactId>
<name>Che Core :: Commons :: DB :: Vendor MySQL</name>
<dependencies>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>jakarta.persistence</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.mysql.jpa.eclipselink;
import java.sql.SQLException;
import org.eclipse.che.core.db.jpa.DuplicateKeyException;
import org.eclipse.che.core.db.jpa.IntegrityConstraintViolationException;
import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.exceptions.ExceptionHandler;
/**
* Rethrows vendor specific exceptions as common exceptions. See <a
* href="https://dev.mysql.com/doc/refman/8.0/en/error-messages-server.html">MySQL error codes</a>.
*
* @author Barry Dresdner
*/
public class MySqlExceptionHandler implements ExceptionHandler {
@Override
public Object handleException(RuntimeException exception) {
if (exception instanceof DatabaseException && exception.getCause() instanceof SQLException) {
final SQLException sqlEx = (SQLException) exception.getCause();
switch (sqlEx.getErrorCode()) {
case 1062:
throw new DuplicateKeyException(exception.getMessage(), exception);
case 1452:
throw new IntegrityConstraintViolationException(exception.getMessage(), exception);
}
}
throw exception;
}
}

View File

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2012-2024 Red Hat, Inc.
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
which is available at https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
Contributors:
Red Hat, Inc. - initial API and implementation
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>che-core-parent</artifactId>
<groupId>org.eclipse.che.core</groupId>
<version>7.81.0-SNAPSHOT</version>
</parent>
<artifactId>che-core-db-vendor-postgresql</artifactId>
<name>Che Core :: Commons :: DB :: Vendor PostgreSQL</name>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>jakarta.persistence</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,51 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.postgresql;
import static com.google.common.base.MoreObjects.firstNonNull;
import org.eclipse.che.core.db.JNDIDataSourceFactory;
/**
* Environment params based JNDI data source factory for Postgres.
*
* @author Sergii Kabashniuk
*/
public class PostgreSQLJndiDataSourceFactory extends JNDIDataSourceFactory {
private static final String DEFAULT_USERNAME = "pgche";
private static final String DEFAULT_PASSWORD = "pgchepassword";
private static final String DEFAULT_URL = "jdbc:postgresql://postgres:5432/dbche";
private static final String DEFAULT_DRIVER__CLASS__NAME = "org.postgresql.Driver";
private static final String DEFAULT_MAX__TOTAL = "20";
private static final String DEFAULT_MAX__IDLE = "2";
private static final String DEFAULT_MAX__WAIT__MILLIS = "-1";
public PostgreSQLJndiDataSourceFactory() throws Exception {
super(
firstNonNull(
nullStringToNullReference(System.getenv("CHE_JDBC_USERNAME")), DEFAULT_USERNAME),
firstNonNull(
nullStringToNullReference(System.getenv("CHE_JDBC_PASSWORD")), DEFAULT_PASSWORD),
firstNonNull(nullStringToNullReference(System.getenv("CHE_JDBC_URL")), DEFAULT_URL),
firstNonNull(
nullStringToNullReference(System.getenv("CHE_JDBC_DRIVER__CLASS__NAME")),
DEFAULT_DRIVER__CLASS__NAME),
firstNonNull(
nullStringToNullReference(System.getenv("CHE_JDBC_MAX__TOTAL")), DEFAULT_MAX__TOTAL),
firstNonNull(
nullStringToNullReference(System.getenv("CHE_JDBC_MAX__IDLE")), DEFAULT_MAX__IDLE),
firstNonNull(
nullStringToNullReference(System.getenv("CHE_JDBC_MAX__WAIT__MILLIS")),
DEFAULT_MAX__WAIT__MILLIS));
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.postgresql.jpa.eclipselink;
import java.sql.SQLException;
import org.eclipse.che.core.db.jpa.DuplicateKeyException;
import org.eclipse.che.core.db.jpa.IntegrityConstraintViolationException;
import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.exceptions.ExceptionHandler;
/**
* Rethrows vendor specific exceptions as common exceptions. See <a
* href="https://www.postgresql.org/docs/9.4/static/errcodes-appendix.html">PostgreSQL error
* codes</a>.
*
* @author Yevhenii Voevodin
* @author Sergii Kabashniuk
*/
public class PostgreSqlExceptionHandler implements ExceptionHandler {
public Object handleException(RuntimeException exception) {
if (exception instanceof DatabaseException && exception.getCause() instanceof SQLException) {
final SQLException sqlEx = (SQLException) exception.getCause();
switch (sqlEx.getSQLState()) {
case "23505":
throw new DuplicateKeyException(exception.getMessage(), exception);
case "23503":
throw new IntegrityConstraintViolationException(exception.getMessage(), exception);
}
}
throw exception;
}
}

View File

@ -1,113 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2012-2024 Red Hat, Inc.
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
which is available at https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
Contributors:
Red Hat, Inc. - initial API and implementation
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>che-core-parent</artifactId>
<groupId>org.eclipse.che.core</groupId>
<version>7.81.0-SNAPSHOT</version>
</parent>
<artifactId>che-core-db</artifactId>
<name>Che Core :: Commons :: DB</name>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-persist</artifactId>
</dependency>
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-util</artifactId>
</dependency>
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-jdbc</artifactId>
</dependency>
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-inject</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.extension</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>jakarta.persistence</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-lang</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,43 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db;
/**
* Defines common database error codes which should be used throughout the application in preference
* to vendor specific error codes.
*
* @author Yevhenii Voevodin
*/
public enum DBErrorCode {
/** When database error can't be described with one of the other values of this enumeration. */
UNDEFINED(-1),
/**
* When any of the unique constraints is violated e.g. duplicate key or unique index violation.
*/
DUPLICATE_KEY(1),
/** When entity referenced foreign key does not exist */
INTEGRITY_CONSTRAINT_VIOLATION(2);
private final int code;
DBErrorCode(int code) {
this.code = code;
}
/** Returns the code of this error. */
public int getCode() {
return code;
}
}

View File

@ -1,89 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.persistence.EntityManagerFactory;
import org.eclipse.che.core.db.jpa.JpaInitializer;
import org.eclipse.che.core.db.jpa.eclipselink.GuiceEntityListenerInjectionManager;
import org.eclipse.che.core.db.schema.SchemaInitializationException;
import org.eclipse.che.core.db.schema.SchemaInitializer;
import org.eclipse.persistence.internal.sessions.AbstractSession;
/**
* Initializes database components.
*
* <p>Those components which require any persistence operations on their bootstrap have to depend on
* this component. For example:
*
* <pre>
* class StackExistsChecker {
*
* &#064;@Inject
* &#064;SuppressWarnings("unused")
* private DBInitializer dbInitializer;
*
* &#064;PostConstruct
* public void check() {
* ....
* }
* }
* </pre>
*
* In this way it is guaranteed that all database related components will be appropriately
* initialized before {@code check} method is executed.
*
* @author Yevhenii Voevodin
*/
@Singleton
public class DBInitializer {
/**
* when value for this key true, then its mean that db is initialized at first time, otherwise db
* was previously initialized
*/
public static final String BARE_DB_INIT_PROPERTY_NAME = "bare_database_init";
private final Map<String, String> initProperties;
@Inject
public DBInitializer(SchemaInitializer schemaInitializer, JpaInitializer jpaInitializer)
throws SchemaInitializationException {
// schema must be initialized before any other component that may interact with database
initProperties = ImmutableMap.copyOf(schemaInitializer.init());
// jpa initialization goes next
jpaInitializer.init();
}
@Inject
public void setUpInjectionManager(
GuiceEntityListenerInjectionManager injManager, EntityManagerFactory emFactory) {
final AbstractSession session = emFactory.unwrap(AbstractSession.class);
session.setInjectionManager(injManager);
}
/** Returns map of properties which represents state of database while initialization process */
public Map<String, String> getInitProperties() {
return initProperties;
}
/**
* Returns true only if database was initialized at first time otherwise false would be returned
*/
public boolean isBareInit() {
return Boolean.parseBoolean(initProperties.get(BARE_DB_INIT_PROPERTY_NAME));
}
}

View File

@ -1,84 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db;
import com.google.inject.Inject;
import com.google.inject.persist.PersistService;
import java.lang.reflect.Field;
import javax.inject.Singleton;
import javax.persistence.EntityManagerFactory;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.coordination.jgroups.JGroupsRemoteConnection;
import org.eclipse.persistence.sessions.coordination.CommandManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Stops {@link PersistService} when a system is ready to shutdown.
*
* @author Anton Korneta
*/
@Singleton
public class DBTermination {
private static final Logger LOG = LoggerFactory.getLogger(DBTermination.class);
private final PersistService persistService;
private final EntityManagerFactory emFactory;
@Inject
public DBTermination(PersistService persistService, EntityManagerFactory emFactory) {
this.persistService = persistService;
this.emFactory = emFactory;
}
/** Stops {@link PersistService}. Any DB operations are impossible after that. */
public void terminate() {
try {
LOG.info("Stopping persistence service.");
fixJChannelClosing(emFactory);
persistService.stop();
} catch (RuntimeException ex) {
LOG.error("Failed to stop persistent service. Cause: " + ex.getMessage());
}
}
/**
* This method is hack that changes value of {@link JGroupsRemoteConnection#isLocal} to false.
* This is needed to close the JGroups EclipseLinkCommandChannel and as result gracefully stop of
* the system.<br>
* For more details see {@link JGroupsRemoteConnection#closeInternal()}
*
* <p>The corresponding eclipse-link extension issue
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=534148
*/
private void fixJChannelClosing(EntityManagerFactory emFactory) {
try {
final AbstractSession session = emFactory.unwrap(AbstractSession.class);
CommandManager commandManager = session.getCommandManager();
if (commandManager == null) {
// not cluster mode
return;
}
final JGroupsRemoteConnection conn =
(JGroupsRemoteConnection) commandManager.getTransportManager().getConnectionToLocalHost();
final Field isLocal = conn.getClass().getDeclaredField("isLocal");
isLocal.setAccessible(true);
isLocal.set(conn, false);
} catch (IllegalAccessException | NoSuchFieldException ex) {
LOG.error(
"Failed to change JGroupsRemoteConnection#isLocal. This may prevent the graceful stop of "
+ "the system because EclipseLinkCommandChannel will not be closed. Cause: "
+ ex.getMessage());
}
}
}

View File

@ -1,79 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db;
import static org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory.createDataSource;
import static org.eclipse.che.core.db.TracingDataSource.wrapWithTracingIfEnabled;
import java.util.Hashtable;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import javax.sql.DataSource;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract JNDI factory that constructs {@link BasicDataSource} objects from the given params.
* Should not be used directly and must be subclassed to provide instantiation params from needful
* source.
*
* @author Sergii Kabashniuk
*/
public abstract class JNDIDataSourceFactory implements ObjectFactory {
private static final Logger LOG = LoggerFactory.getLogger(JNDIDataSourceFactory.class);
private final DataSource dataSource;
public JNDIDataSourceFactory(
String userName,
String password,
String url,
String driverClassName,
String maxTotal,
String maxIdle,
String maxWaitMillis)
throws Exception {
Properties poolConfigurationProperties = new Properties();
poolConfigurationProperties.setProperty("username", userName);
poolConfigurationProperties.setProperty("password", password);
poolConfigurationProperties.setProperty("url", url);
poolConfigurationProperties.setProperty("driverClassName", driverClassName);
poolConfigurationProperties.setProperty("maxTotal", maxTotal);
poolConfigurationProperties.setProperty("maxIdle", maxIdle);
poolConfigurationProperties.setProperty("maxWaitMillis", maxWaitMillis);
dataSource = wrapWithTracingIfEnabled(createDataSource(poolConfigurationProperties));
}
@Override
public Object getObjectInstance(
Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
LOG.info(
"This={} obj={} name={} Context={} environment={}", this, obj, name, nameCtx, environment);
return dataSource;
}
/**
* Util method to convert string {@code "NULL"} to null reference. Allows to set string {@code
* "NULL"} as a value of the property instead of making sure it is unset as it is done in {@link
* org.eclipse.che.inject.CheBootstrap}
*
* @param value value to transform if needed
* @return null or passed value
*/
protected static String nullStringToNullReference(String value) {
return "NULL".equals(value) ? null : value;
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db;
import com.google.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
/**
* Provides data source based on jndi resource name.
*
* @author Yevhenii Voevodin
*/
public class JndiDataSourceProvider implements Provider<DataSource> {
@Inject
@Named("jndi.datasource.name")
private String name;
@Override
public DataSource get() {
try {
final InitialContext context = new InitialContext();
return (DataSource) context.lookup(name);
} catch (NamingException x) {
throw new IllegalStateException(x.getLocalizedMessage(), x);
}
}
}

View File

@ -1,106 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db;
import com.google.common.annotations.Beta;
import io.opentracing.contrib.jdbc.ConnectionInfo;
import io.opentracing.contrib.jdbc.TracingConnection;
import io.opentracing.contrib.jdbc.parser.URLParser;
import io.opentracing.util.GlobalTracer;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
import javax.sql.DataSource;
import org.slf4j.LoggerFactory;
/**
* Adding tracing support for existing @{@link javax.sql.DataSource}. DbType and DbUser information
* omitted in traces. Traced are made only if active span exists. Prerequisites of using this class
* is that @{@link io.opentracing.Tracer} should be set in @{@link io.opentracing.util.GlobalTracer}
*
* @author Sergii Kabashniuk
*/
@Beta
public class TracingDataSource implements DataSource {
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(TracingDataSource.class);
private final DataSource delegate;
private final ConnectionInfo connectionInfo;
public TracingDataSource(DataSource delegate) {
this.delegate = delegate;
try (Connection connection = delegate.getConnection()) {
connectionInfo = URLParser.parser(connection.getMetaData().getURL());
LOG.debug(
"URL {} connectionInfo {}",
connection.getMetaData().getURL(),
connectionInfo.getPeerService());
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public Connection getConnection() throws SQLException {
return new TracingConnection(
delegate.getConnection(), connectionInfo, true, null, GlobalTracer.get());
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return new TracingConnection(
delegate.getConnection(username, password), connectionInfo, true, null, GlobalTracer.get());
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return delegate.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return delegate.isWrapperFor(iface);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return delegate.getLogWriter();
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
delegate.setLogWriter(out);
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
delegate.setLoginTimeout(seconds);
}
@Override
public int getLoginTimeout() throws SQLException {
return delegate.getLoginTimeout();
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return delegate.getParentLogger();
}
public static DataSource wrapWithTracingIfEnabled(DataSource dataSource) {
return Boolean.valueOf(System.getenv("CHE_DB_TRACING_ENABLED"))
? new TracingDataSource(dataSource)
: dataSource;
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.cascade;
/**
* Context that is used only for sharing the state of the cascading operation among subscribers.
*
* @author Anton Korneta
* @author Sergii Leshchenko
*/
public class CascadeContext {
private Exception cause;
/** Returns the cause which has changed the state of the context. */
public Exception getCause() {
return cause;
}
/** Returns the state of the context. */
public boolean isFailed() {
return cause != null;
}
/** Sets the context into failed state. */
public CascadeContext fail(Exception cause) {
this.cause = cause;
return this;
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.cascade;
import org.eclipse.che.api.core.notification.EventSubscriber;
import org.eclipse.che.core.db.cascade.event.CascadeEvent;
/**
* Receives events and puts exceptions in the context to perform rollback operation if it is
* necessary.
*
* @author Anton Korneta
* @author Sergii Leschenko
*/
public abstract class CascadeEventSubscriber<T extends CascadeEvent> implements EventSubscriber<T> {
@Override
public void onEvent(T event) {
if (!event.getContext().isFailed()) {
try {
onCascadeEvent(event);
} catch (Exception ex) {
event.getContext().fail(ex);
}
}
}
/**
* Receives notification about cascade event.
*
* <p>If the method throws an exception it will be set to context to break event publishing and
* rethrow exception. Event is responsible for rethrowing or wrapping original exception.
*
* @see CascadeEvent#propagateException()
*/
public abstract void onCascadeEvent(T event) throws Exception;
}

View File

@ -1,60 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.cascade.event;
import org.eclipse.che.core.db.cascade.CascadeContext;
/**
* Special event type which is needed only for notification in the process which can require cascade
* operation.
*
* <p>Publisher should invoke {@link #propagateException()} to get cause of event canceling.
*
* <p>Rollback of operation must be performed when subscriber throws {@link Exception} during event
* processing.
*
* <p>Usage example:
*
* <pre>
* EventService bus = new EventService();
* bus.subscribe(new CascadeEventSubscriber&lt;MyEvent&gt;() {
* &#64;Override
* public void onCascadeEvent(MyEvent event) throws Exception {
* if (event.getEntityName().startsWith("reserved")) {
* throw new ConflictException("Entity name can't start with `reserved`.");
* }
* }
* });
* bus.publish(new MyEvent(...)).propagateException();
* </pre>
*
* @author Anton Korneta
* @author Sergii Leschenko
*/
public abstract class CascadeEvent {
protected final CascadeContext context = new CascadeContext();
public CascadeContext getContext() {
return context;
}
/**
* Propagates exception if subscriber throws it while event processing otherwise do nothing
*
* @throws Exception when any subscriber throws {@link Exception}
*/
public void propagateException() throws Exception {
if (context.isFailed()) {
throw context.getCause();
}
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.cascade.event;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ServerException;
/**
* Cascade event about an entity persisting.
*
* <p>{@link ConflictException} or {@link ServerException} can be rethrown during exception
* propagating.
*
* @author Sergii Leschenko
*/
public abstract class PersistEvent extends CascadeEvent {
@Override
public void propagateException() throws ConflictException, ServerException {
if (context.isFailed()) {
try {
throw context.getCause();
} catch (ConflictException | ServerException e) {
throw e;
} catch (Exception e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.cascade.event;
import org.eclipse.che.api.core.ServerException;
/**
* Cascade event about an entity removing.
*
* <p>{@link ServerException} can be rethrown during exception propagating.
*
* @author Sergii Leschenko
*/
public abstract class RemoveEvent extends CascadeEvent {
@Override
public void propagateException() throws ServerException {
if (context.isFailed()) {
try {
throw context.getCause();
} catch (ServerException e) {
throw e;
} catch (Exception e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.cascade.event;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
/**
* Cascade event about an entity updating.
*
* <p>{@link NotFoundException}, {@link ConflictException} or {@link ServerException} can be
* rethrown during exception propagating.
*
* @author Sergii Leschenko
*/
public abstract class UpdateEvent extends CascadeEvent {
@Override
public void propagateException() throws NotFoundException, ConflictException, ServerException {
if (context.isFailed()) {
try {
throw context.getCause();
} catch (NotFoundException | ConflictException | ServerException e) {
throw e;
} catch (Exception e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.jpa;
import javax.persistence.RollbackException;
import org.eclipse.che.core.db.DBErrorCode;
/**
* Extends the standard {@link RollbackException} with an error code from {@link DBErrorCode}.
*
* @author Yevhenii Voevodin
*/
public class DetailedRollbackException extends RollbackException {
private DBErrorCode code;
public DetailedRollbackException(String message, Throwable cause, DBErrorCode code) {
super(message, cause);
this.code = code;
}
public DBErrorCode getCode() {
return code;
}
}

View File

@ -1,27 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.jpa;
import org.eclipse.che.core.db.DBErrorCode;
/**
* Thrown when data couldn't be updated/stored due to unique constrain violation.
*
* @author Yevhenii Voevodin
* @see DBErrorCode#DUPLICATE_KEY
*/
public class DuplicateKeyException extends DetailedRollbackException {
public DuplicateKeyException(String message, Throwable cause) {
super(message, cause, DBErrorCode.DUPLICATE_KEY);
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.jpa;
import org.eclipse.che.core.db.DBErrorCode;
/**
* Throws during inserts/updates entity that restricted by referential integrity and given
* insert/update refers to non-existing entity.
*
* @author Anton Korneta
* @see DBErrorCode#INTEGRITY_CONSTRAINT_VIOLATION
*/
public class IntegrityConstraintViolationException extends DetailedRollbackException {
public IntegrityConstraintViolationException(String message, Throwable cause) {
super(message, cause, DBErrorCode.INTEGRITY_CONSTRAINT_VIOLATION);
}
}

View File

@ -1,27 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.jpa;
import com.google.inject.ImplementedBy;
import org.eclipse.che.core.db.jpa.guice.GuiceJpaInitializer;
/**
* Initializes jpa components.
*
* @author Yevhenii Voevodin
*/
@ImplementedBy(GuiceJpaInitializer.class)
public interface JpaInitializer {
/** Initialized jpa components. */
void init();
}

View File

@ -1,69 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.jpa.eclipselink;
import com.google.inject.Inject;
import com.google.inject.Injector;
import javax.naming.NamingException;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.cdi.InjectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Allows to use dependency injection in entity listeners.
*
* <p>Example:
*
* <pre>
* class WorkspaceEntityListener {
*
* &#064;Inject EventBus bus; <- EventBus will be injected by Guice
*
* &#064;PreRemove
* public void preRemove(Workspace workspace) {
* bus.post(new BeforeWorkspaceRemovedEvent(workspace));
* }
* }
*
* &#064;Entity
* &#064;EntityListeners(WorkspaceEntityListener.class)
* class Workspace {
* // ...
* }
* </pre>
*
* @author Yevhenii Voevodin
*/
public class GuiceEntityListenerInjectionManager implements InjectionManager {
private static final Logger LOG =
LoggerFactory.getLogger(GuiceEntityListenerInjectionManager.class);
@Inject private Injector injector;
@Override
public Object createManagedBeanAndInjectDependencies(Class entityListenerClass)
throws NamingException {
try {
return injector.getInstance(entityListenerClass);
} catch (RuntimeException x) {
LOG.error(x.getLocalizedMessage(), x);
throw new NamingException(x.getLocalizedMessage());
}
}
@Override
public void cleanUp(AbstractSession session) {
// EntityListener objects are managed by Guice, nothing to cleanup
}
}

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.jpa.guice;
import com.google.inject.persist.PersistService;
import javax.inject.Inject;
import org.eclipse.che.core.db.jpa.JpaInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Should be bound as eager singleton. See <a
* href="https://github.com/google/guice/wiki/JPA">doc</a>
*
* @author Yevhenii Voevodin
* @author Anton Korneta
*/
public class GuiceJpaInitializer implements JpaInitializer {
private static final Logger LOG = LoggerFactory.getLogger(GuiceJpaInitializer.class);
@Inject private PersistService persistService;
public void init() {
try {
persistService.start();
} catch (Exception x) {
LOG.error(x.getLocalizedMessage(), x);
}
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema;
/**
* Thrown when any schema initialization/migration problem occurs.
*
* @author Yevhenii Voevodin
*/
public class SchemaInitializationException extends Exception {
public SchemaInitializationException(String message, Throwable cause) {
super(message, cause);
}
public SchemaInitializationException(String message) {
super(message);
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema;
import java.util.Map;
/**
* Initializes database schema or migrates an old version of it to a new one.
*
* @author Yevhenii Voevodin
*/
public interface SchemaInitializer {
/**
* Initializes database schema or migrates an old schema to a new one.
*
* @return initialization properties
* @throws SchemaInitializationException thrown when any error occurs during schema
* initialization/migration
*/
Map<String, String> init() throws SchemaInitializationException;
}

View File

@ -1,210 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema.impl.flyway;
import static java.lang.String.format;
import static java.util.stream.Collectors.toList;
import com.google.common.hash.Hashing;
import com.google.common.io.ByteSource;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.MigrationType;
import org.flywaydb.core.api.MigrationVersion;
import org.flywaydb.core.api.resolver.BaseMigrationResolver;
import org.flywaydb.core.api.resolver.ResolvedMigration;
import org.flywaydb.core.internal.dbsupport.DbSupport;
import org.flywaydb.core.internal.resolver.ResolvedMigrationImpl;
import org.flywaydb.core.internal.resolver.sql.SqlMigrationExecutor;
import org.flywaydb.core.internal.util.Location;
import org.flywaydb.core.internal.util.PlaceholderReplacer;
import org.flywaydb.core.internal.util.scanner.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Resolves SQL migrations from the configured locations, allows overriding of default scripts with
* vendor specific ones.
*
* <ul>
* Migration scripts must follow the next rules:
* <li>It must be placed in the project dir directory e.g. <i>5.0.1</i>
* <li>Project dir directory must be placed in dedicated directory e.g. <i>resources/sql</i>
* <li>Migration/Initialization script name must start with a number e.g <i>1.init.sql</i>, this
* number indicates the subversion of the database migration, e.g. for dir <i>5.0.0</i> and
* migration script <i>1.init.sql</i> database migration dir will be <i>5.0.0.1</i>
* <li>If a file is not a part of migration it shouldn't end with migration prefix e.g.
* <i>.sql</i> then resolver will ignore it
* </ul>
*
* <p>For the structure:
*
* <pre>
* resources/
* sql/
* 5.0.0/
* 1.init.sql
* 5.0.0-M1/
* 1.rename_fields.sql
* 2.add_workspace_constraint.sql
* postgresql/
* 2.add_workspace_constraint.sql
* 5.0.1/
* 1.stacks_migration.sql
* </pre>
*
* And configuration:
*
* <pre>
* prefix - ""
* suffix - ".sql"
* separator - "."
* locations - "classpath:sql"
* </pre>
*
* <ul>
* 4 database migrations will be resolved
* <li>5.0.0.1 - initialization script based on file <i>sql/5.0.0/1.init.sql</i>
* <li>5.0.0.1.1 - modification script based on file <i>sql/5.0.0-M1/1.rename_fields.sql</i>
* <li>5.0.0.1.2 - modification script(if postgresql is current provider) based on file
* <i>sql/5.0.0-M1/postgresql/2.add_workspace_constraint.sql</i>
* <li>5.0.1.1 - modification script based on file <i>sql/5.0.1/1.stacks_migrations.sql</i>
* </ul>
*
* <p>It is also possible to configure several locations then all of those locations will be
* analyzed for migration scripts existence. For example:
*
* <p>For the structure:
*
* <pre>
* che/
* resources/
* che-schema/
* 5.0.0/
* 1.init.sql
* another-project/
* resources/
* custom-schema/
* 5.0.0/
* 2.init_additional_tables.sql
* </pre>
*
* And configuration:
*
* <pre>
* prefix - ""
* suffix - ".sql"
* separator - "."
* locations - "classpath:che-schema, classpath:custom-schema"
* </pre>
*
* <ul>
* 2 database migrations will be resolved
* <li>5.0.0.1 - initialization script based on file <i>che-schema/5.0.0/1.init.sql</i>
* <li>5.0.0.2 - modification script based on file
* <i>custom-schema/5.0.0/2.init_additional_tables.sql</i>
* </ul>
*
* @author Yevhenii Voevodin
*/
public class CustomSqlMigrationResolver extends BaseMigrationResolver {
private static final Logger LOG = LoggerFactory.getLogger(CustomSqlMigrationResolver.class);
private final String vendorName;
private final ResourcesFinder finder;
private final VersionResolver versionResolver;
private final SqlScriptCreator scriptsCreator;
private final DbSupport dbSupport;
private final PlaceholderReplacer placeholderReplacer;
public CustomSqlMigrationResolver(
String dbProviderName, DbSupport dbSupport, PlaceholderReplacer placeholderReplacer) {
this.vendorName = dbProviderName;
this.dbSupport = dbSupport;
this.placeholderReplacer = placeholderReplacer;
this.finder = new ResourcesFinder();
this.versionResolver = new VersionResolver();
this.scriptsCreator = new SqlScriptCreator();
}
@Override
public Collection<ResolvedMigration> resolveMigrations() {
try {
return resolveSqlMigrations();
} catch (IOException | SQLException x) {
throw new RuntimeException(x.getLocalizedMessage(), x);
}
}
private List<ResolvedMigration> resolveSqlMigrations() throws IOException, SQLException {
LOG.info(
"Searching for SQL scripts in locations {}",
Arrays.toString(flywayConfiguration.getLocations()));
final Map<Location, List<Resource>> allResources = finder.findResources(flywayConfiguration);
LOG.debug("Found scripts: {}", allResources);
final Map<String, Map<String, SqlScript>> scriptsInDir = new HashMap<>();
for (Location location : allResources.keySet()) {
final List<Resource> resources = allResources.get(location);
for (Resource resource : resources) {
final SqlScript newScript = scriptsCreator.createScript(location, resource);
if (!scriptsInDir.containsKey(newScript.dir)) {
scriptsInDir.put(newScript.dir, new HashMap<>(4));
}
final Map<String, SqlScript> existingScripts = scriptsInDir.get(newScript.dir);
final SqlScript existingScript = existingScripts.get(newScript.name);
if (existingScript == null) {
existingScripts.put(newScript.name, newScript);
} else if (Objects.equals(existingScript.vendor, newScript.vendor)) {
throw new FlywayException(
format(
"More than one script with name '%s' is registered for "
+ "database vendor '%s', script '%s' conflicts with '%s'",
newScript.name, existingScript.vendor, newScript, existingScript));
} else if (vendorName.equals(newScript.vendor)) {
existingScripts.put(newScript.name, newScript);
}
}
}
final Map<MigrationVersion, ResolvedMigration> migrations = new HashMap<>();
for (SqlScript script :
scriptsInDir.values().stream()
.flatMap(scripts -> scripts.values().stream())
.collect(toList())) {
final ResolvedMigrationImpl migration = new ResolvedMigrationImpl();
migration.setVersion(versionResolver.resolve(script, flywayConfiguration));
migration.setScript(script.resource.getLocation());
migration.setPhysicalLocation(script.resource.getLocationOnDisk());
migration.setType(MigrationType.SQL);
migration.setDescription(script.name);
migration.setChecksum(
ByteSource.wrap(script.resource.loadAsBytes()).hash(Hashing.crc32()).asInt());
migration.setExecutor(
new SqlMigrationExecutor(
dbSupport, script.resource, placeholderReplacer, flywayConfiguration));
if (migrations.put(migration.getVersion(), migration) != null) {
throw new FlywayException("Two migrations with the same version detected");
}
}
return new ArrayList<>(migrations.values());
}
}

View File

@ -1,122 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema.impl.flyway;
import static org.eclipse.che.core.db.DBInitializer.BARE_DB_INIT_PROPERTY_NAME;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
import javax.sql.DataSource;
import org.eclipse.che.core.db.schema.SchemaInitializationException;
import org.eclipse.che.core.db.schema.SchemaInitializer;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.internal.dbsupport.DbSupport;
import org.flywaydb.core.internal.dbsupport.DbSupportFactory;
import org.flywaydb.core.internal.metadatatable.MetaDataTable;
import org.flywaydb.core.internal.metadatatable.MetaDataTableImpl;
import org.flywaydb.core.internal.util.PlaceholderReplacer;
/**
* <a href="https://flywaydb.org/">Flyway</a> based schema initializer.
*
* @author Yevhenii Voevodin
*/
public class FlywaySchemaInitializer implements SchemaInitializer {
private final DataSource dataSource;
private final String[] locations;
private final String scriptsPrefix;
private final String scriptsSuffix;
private final String versionSeparator;
private final boolean baselineOnMigrate;
private final String baselineVersion;
private final PlaceholderReplacer placeholderReplacer;
/**
* Creates a new instance of flyway schema initializer.
*
* @param scriptsLocations the locations where to search migration scripts, if locations is not
* prefixed or prefixed with <i>classpath:</i> then initializer will try to find scripts in
* classpath using {@code Thread.currentThread().}{@link Thread#getContextClassLoader()
* getContextClassLoader()}
* @param scriptsPrefix prefix of migration scripts e.g. 'v' or empty string
* @param scriptsSuffix suffix of migration scripts e.g. '.sql'
* @param versionSeparator separate version from the other part of script name e.g. '.' or '__'
* @param baselineOnMigrate whether to ignore scripts up to the version configured by {@code
* baselineVersion}
* @param baselineVersion up to this version all the scripts ignored, unless schema is initialized
* first time, note that scripts with version equal to baseline version are also ignored
* @param dataSource data source used for migrations
* @param placeholderReplacer used to replace variables in script with configured values
*/
@Inject
public FlywaySchemaInitializer(
@Named("db.schema.flyway.scripts.locations") String[] scriptsLocations,
@Named("db.schema.flyway.scripts.prefix") String scriptsPrefix,
@Named("db.schema.flyway.scripts.suffix") String scriptsSuffix,
@Named("db.schema.flyway.scripts.version_separator") String versionSeparator,
@Named("db.schema.flyway.baseline.enabled") boolean baselineOnMigrate,
@Named("db.schema.flyway.baseline.version") String baselineVersion,
DataSource dataSource,
PlaceholderReplacer placeholderReplacer) {
this.dataSource = dataSource;
this.locations = scriptsLocations;
this.scriptsPrefix = scriptsPrefix;
this.scriptsSuffix = scriptsSuffix;
this.versionSeparator = versionSeparator;
this.baselineOnMigrate = baselineOnMigrate;
this.baselineVersion = baselineVersion;
this.placeholderReplacer = placeholderReplacer;
}
/** Creates a new flyway based initializer with default values. */
public FlywaySchemaInitializer(DataSource dataSource, String... locations) {
this(locations, "", ".sql", "__", false, "", dataSource, PlaceholderReplacer.NO_PLACEHOLDERS);
}
@Override
public Map<String, String> init() throws SchemaInitializationException {
final Map<String, String> initResult = new HashMap<>();
try (final Connection conn = dataSource.getConnection()) {
final Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations(locations);
flyway.setClassLoader(Thread.currentThread().getContextClassLoader());
final DbSupport dbSupport = DbSupportFactory.createDbSupport(conn, true);
final MetaDataTable mt =
new MetaDataTableImpl(
dbSupport,
dbSupport.getOriginalSchema().getTable(flyway.getTable()),
flyway.getInstalledBy());
initResult.put(BARE_DB_INIT_PROPERTY_NAME, String.valueOf(!mt.hasAppliedMigrations()));
final String productName = conn.getMetaData().getDatabaseProductName().toLowerCase();
flyway.setResolvers(
new CustomSqlMigrationResolver(productName, dbSupport, placeholderReplacer));
flyway.setSkipDefaultResolvers(true);
flyway.setBaselineOnMigrate(baselineOnMigrate);
if (baselineOnMigrate) {
flyway.setBaselineVersionAsString(baselineVersion);
}
flyway.setSqlMigrationSeparator(versionSeparator);
flyway.setSqlMigrationSuffix(scriptsSuffix);
flyway.setSqlMigrationPrefix(scriptsPrefix);
flyway.migrate();
} catch (SQLException | RuntimeException x) {
throw new SchemaInitializationException(x.getLocalizedMessage(), x);
}
return initResult;
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema.impl.flyway;
import javax.inject.Inject;
import javax.inject.Provider;
import org.eclipse.che.inject.ConfigurationProperties;
import org.flywaydb.core.internal.util.PlaceholderReplacer;
/**
* Placeholder replacer that uses configuration properties.
*
* @author Yevhenii Voevodin
*/
public class PlaceholderReplacerProvider implements Provider<PlaceholderReplacer> {
private final PlaceholderReplacer replacer;
@Inject
public PlaceholderReplacerProvider(ConfigurationProperties properties) {
replacer = new PlaceholderReplacer(properties.getProperties(".*"), "${", "}");
}
@Override
public PlaceholderReplacer get() {
return replacer;
}
}

View File

@ -1,57 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema.impl.flyway;
import static com.google.common.collect.Lists.newArrayList;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.flywaydb.core.api.configuration.FlywayConfiguration;
import org.flywaydb.core.internal.util.Location;
import org.flywaydb.core.internal.util.scanner.Resource;
import org.flywaydb.core.internal.util.scanner.classpath.ClassPathScanner;
import org.flywaydb.core.internal.util.scanner.filesystem.FileSystemScanner;
/**
* Searches for sql scripts in given places.
*
* @author Yevhenii Voevodin
*/
class ResourcesFinder {
/**
* Finds script resources in configured {@link FlywayConfiguration#getLocations()}.
*
* @param configuration flyway configuration to find scripts
* @return found scripts or an empty list if nothing found
* @throws IOException when any io error occurs during scripts look up
*/
Map<Location, List<Resource>> findResources(FlywayConfiguration configuration)
throws IOException {
final String prefix = configuration.getSqlMigrationPrefix();
final String suffix = configuration.getSqlMigrationSuffix();
final ClassPathScanner cpScanner = new ClassPathScanner(configuration.getClassLoader());
final FileSystemScanner fsScanner = new FileSystemScanner();
final Map<Location, List<Resource>> resources = new HashMap<>();
for (String rawLocation : configuration.getLocations()) {
final Location location = new Location(rawLocation);
if (location.isClassPath()) {
resources.put(location, newArrayList(cpScanner.scanForResources(location, prefix, suffix)));
} else {
resources.put(location, newArrayList(fsScanner.scanForResources(location, prefix, suffix)));
}
}
return resources;
}
}

View File

@ -1,84 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema.impl.flyway;
import java.util.Objects;
import org.flywaydb.core.internal.util.Location;
import org.flywaydb.core.internal.util.scanner.Resource;
/**
* Data object for holding information about sql script.
*
* @author Yevhenii Voevodin
*/
class SqlScript {
final Resource resource;
final Location location;
final String dir;
final String vendor;
final String name;
SqlScript(Resource resource, Location location, String dir, String vendor, String name) {
this.resource = resource;
this.location = location;
this.name = name;
this.vendor = vendor;
this.dir = dir;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof SqlScript)) {
return false;
}
final SqlScript that = (SqlScript) obj;
return Objects.equals(resource, that.resource)
&& Objects.equals(location, that.location)
&& Objects.equals(dir, that.dir)
&& Objects.equals(vendor, that.vendor)
&& Objects.equals(name, that.name);
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + Objects.hashCode(resource);
hash = 31 * hash + Objects.hashCode(location);
hash = 31 * hash + Objects.hashCode(dir);
hash = 31 * hash + Objects.hashCode(vendor);
hash = 31 * hash + Objects.hashCode(name);
return hash;
}
@Override
public String toString() {
return "SqlScript{"
+ "resource="
+ resource
+ ", location="
+ location
+ ", dir='"
+ dir
+ '\''
+ ", vendor='"
+ vendor
+ '\''
+ ", name='"
+ name
+ '\''
+ '}';
}
}

View File

@ -1,55 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema.impl.flyway;
import static java.lang.String.format;
import java.io.File;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.internal.util.Location;
import org.flywaydb.core.internal.util.scanner.Resource;
/**
* Creates new {@link SqlScript} instance from given resource.
*
* @author Yevhenii Voevodin
*/
class SqlScriptCreator {
/**
* Create a new instance of script based on location and resource.
*
* @param location root location of the given resource
* @param resource script resource
* @return a new instance of sql script based on location and resource
* @throws FlywayException when script can't be created from the resource
*/
SqlScript createScript(Location location, Resource resource) {
final String separator = location.isClassPath() ? "/" : File.separator;
// '/root-location/5.0.0-M7/v1__init.sql' -> '5.0.0-M7/v1__init.sql'
final String relLocation = resource.getLocation().substring(location.getPath().length() + 1);
final String[] paths = relLocation.split(separator);
// 5.0.0-M1/v1__init.sql
if (paths.length == 2) {
return new SqlScript(resource, location, paths[0], null, paths[1]);
}
// 5.0.0-M1/postgresql/v1__init.sql
if (paths.length == 3) {
return new SqlScript(resource, location, paths[0], paths[1], paths[2]);
}
throw new FlywayException(
format(
"Sql script location must be either in 'location-root/version-dir' "
+ "or in 'location-root/version-dir/provider-name', but script '%s' is not in root '%s'",
resource.getLocation(), location.getPath()));
}
}

View File

@ -1,84 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema.impl.flyway;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.String.format;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.MigrationVersion;
import org.flywaydb.core.api.configuration.FlywayConfiguration;
/**
* Creates versions for scripts depending on the provided data.
*
* <ul>
* A few examples:
* <li>5.0.0-M7/v1__init.sql => 5.0.0.7.1
* <li>5.0.0-M8/v2.1__modify.sql => 5.0.0.8.2.1
* </ul>
*
* @author Yevhenii Voevodin
*/
class VersionResolver {
private static final Pattern NOT_VERSION_CHARS_PATTERN = Pattern.compile("[^0-9.]");
private final Map<String, String> normalizedDirs = new HashMap<>();
/**
* Creates migration version based on script data.
*
* @param script script for which to resolve the version
* @param configuration flyway configuration used for resolution parameters
*/
MigrationVersion resolve(SqlScript script, FlywayConfiguration configuration) {
String normalizedDir = normalizedDirs.get(script.dir);
if (normalizedDir == null) {
// 5.0.0-M1 -> 5.0.0.M1 -> 5.0.0.1
normalizedDir =
NOT_VERSION_CHARS_PATTERN.matcher(script.dir.replace("-", ".")).replaceAll("");
normalizedDirs.put(script.dir, normalizedDir);
}
// separate version from the other part of the name
final int sepIdx = script.name.indexOf(configuration.getSqlMigrationSeparator());
if (sepIdx == -1) {
throw new FlywayException(
format(
"sql script name '%s' is not valid, name must contain '%s'",
script.name, configuration.getSqlMigrationSeparator()));
}
// check whether part before separator is not empty
String version = script.name.substring(0, sepIdx);
if (version.isEmpty()) {
throw new FlywayException(
format(
"sql script name '%s' is not valid, name must provide version like "
+ "'%s4%smigration_description.sql",
configuration.getSqlMigrationPrefix(),
script.name,
configuration.getSqlMigrationSeparator()));
}
// extract sql script version without prefix
final String prefix = configuration.getSqlMigrationPrefix();
if (!isNullOrEmpty(prefix) && script.name.startsWith(prefix)) {
version = version.substring(prefix.length());
}
return MigrationVersion.fromVersion(normalizedDir + '.' + version);
}
}

View File

@ -1,123 +0,0 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db;
import static org.mockito.Mockito.lenient;
import static org.testng.Assert.assertEquals;
import com.google.common.collect.ImmutableMap;
import io.opentracing.contrib.jdbc.TracingConnection;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
@Listeners(value = {MockitoTestNGListener.class})
public class TracingDataSourceTest {
@Mock DataSource dataSource;
@Mock Connection connection;
@Mock DatabaseMetaData databaseMetaData;
@BeforeMethod
@AfterMethod
public void cleanup() throws Exception {
HashMap<String, String> newEnv = new HashMap<>(System.getenv());
newEnv.remove("CHE_DB_TRACING_ENABLED");
setEnv(newEnv);
lenient().when(dataSource.getConnection()).thenReturn(connection);
lenient().when(connection.getMetaData()).thenReturn(databaseMetaData);
}
@Test
public void shouldBeAbleToGetConnection() throws SQLException {
TracingDataSource ds = new TracingDataSource(dataSource);
Connection actual = ds.getConnection();
assertEquals(actual.getClass(), TracingConnection.class);
Mockito.verify(dataSource, Mockito.times(2)).getConnection();
}
@Test
public void shouldBeAbleToGetConnectionWithEmailAndPassword() throws SQLException {
TracingDataSource ds = new TracingDataSource(dataSource);
Connection actual = ds.getConnection("user", "password");
assertEquals(actual.getClass(), TracingConnection.class);
Mockito.verify(dataSource).getConnection(Mockito.eq("user"), Mockito.eq("password"));
}
@Test
public void shouldBeAbleTogetTracingDataSource() throws Exception {
setEnv(ImmutableMap.of("CHE_DB_TRACING_ENABLED", "true"));
DataSource actual = TracingDataSource.wrapWithTracingIfEnabled(dataSource);
assertEquals(actual.getClass(), TracingDataSource.class);
}
@Test
public void shouldNotWrapDatasourceIfEnvSetToFalse() throws Exception {
setEnv(ImmutableMap.of("CHE_DB_TRACING_ENABLED", "false"));
DataSource actual = TracingDataSource.wrapWithTracingIfEnabled(dataSource);
assertEquals(actual, dataSource);
}
@Test
public void shouldNotWrapDatasourceIfEnvIsNotSet() throws Exception {
DataSource actual = TracingDataSource.wrapWithTracingIfEnabled(dataSource);
assertEquals(actual, dataSource);
}
protected static void setEnv(Map<String, String> newenv) throws Exception {
try {
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.putAll(newenv);
Field theCaseInsensitiveEnvironmentField =
processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map<String, String> cienv =
(Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
cienv.putAll(newenv);
} catch (NoSuchFieldException e) {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for (Class cl : classes) {
if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
map.clear();
map.putAll(newenv);
}
}
}
}
}

View File

@ -1,353 +0,0 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema.impl.flyway;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.io.StringReader;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.sql.DataSource;
import org.eclipse.che.commons.lang.IoUtil;
import org.eclipse.che.core.db.schema.SchemaInitializationException;
import org.eclipse.che.core.db.schema.SchemaInitializer;
import org.flywaydb.core.internal.util.PlaceholderReplacer;
import org.h2.jdbcx.JdbcDataSource;
import org.h2.tools.RunScript;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* Tests {@link FlywaySchemaInitializer}.
*
* @author Yevhenii Voevodin
*/
public class FlywaySchemaInitializerTest {
private static final String SCRIPTS_ROOT = "flyway/sql";
private JdbcDataSource dataSource;
@BeforeMethod
public void setUp() throws URISyntaxException {
dataSource = new JdbcDataSource();
dataSource.setUrl("jdbc:h2:mem:flyway_test;DB_CLOSE_DELAY=-1");
}
@AfterMethod
public void cleanup() throws SQLException, URISyntaxException {
try (Connection conn = dataSource.getConnection()) {
RunScript.execute(conn, new StringReader("SHUTDOWN"));
}
IoUtil.deleteRecursive(targetDir().resolve(Paths.get(SCRIPTS_ROOT)).toFile());
}
@Test
public void initializesSchemaWhenDatabaseIsEmpty() throws Exception {
createScript("1.0/1__init.sql", "CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));");
createScript(
"1.0/2__add_data.sql",
"INSERT INTO test VALUES(1, 'test1');"
+ "INSERT INTO test VALUES(2, 'test2');"
+ "INSERT INTO test VALUES(3, 'test3');");
createScript("2.0/1__add_more_data.sql", "INSERT INTO test VALUES(4, 'test4');");
createScript(
"2.0/postgresql/1__add_more_data.sql", "INSERT INTO test VALUES(4, 'postgresql-data');");
final SchemaInitializer initializer = FlywayInitializerBuilder.from(dataSource).build();
initializer.init();
assertEquals(
queryEntities(),
Sets.newHashSet(
new TestEntity(1, "test1"),
new TestEntity(2, "test2"),
new TestEntity(3, "test3"),
new TestEntity(4, "test4")));
// second init must do nothing, so there are no conflicts
initializer.init();
}
@Test(expectedExceptions = SchemaInitializationException.class)
public void failsIfBaseLineIsNotConfiguredProperly() throws Exception {
execQuery(
"CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));"
+ "INSERT INTO test VALUES(1, 'test1');"
+ "INSERT INTO test VALUES(2, 'test2');"
+ "INSERT INTO test VALUES(3, 'test3');");
createScript("1.0/1__init.sql", "CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));");
FlywayInitializerBuilder.from(dataSource)
.setBaselineOnMigrate(true)
.setBaselineVersion("1.0")
.build()
.init();
}
@Test
public void executesOnlyThoseMigrationsWhichGoAfterBaseline() throws Exception {
createScript("1.0/1__init.sql", "CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));");
createScript(
"2.0/1__add_data.sql",
"INSERT INTO test VALUES(1, 'test1');"
+ "INSERT INTO test VALUES(2, 'test2');"
+ "INSERT INTO test VALUES(3, 'test3');");
final FlywaySchemaInitializer initializer =
FlywayInitializerBuilder.from(dataSource)
.setBaselineOnMigrate(true)
.setBaselineVersion("1.0.1")
.build();
initializer.init();
assertEquals(
queryEntities(),
Sets.newHashSet(
new TestEntity(1, "test1"), new TestEntity(2, "test2"), new TestEntity(3, "test3")));
// second init must do nothing, so there are no conflicts
initializer.init();
}
@Test
public void initializesSchemaWhenDatabaseIsEmptyAndBaselineIsConfigured() throws Exception {
createScript("1.0/1__init.sql", "CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));");
createScript(
"2.0/1__add_data.sql",
"INSERT INTO test VALUES(1, 'test1');"
+ "INSERT INTO test VALUES(2, 'test2');"
+ "INSERT INTO test VALUES(3, 'test3');");
final FlywaySchemaInitializer initializer =
FlywayInitializerBuilder.from(dataSource)
.setBaselineOnMigrate(true)
.setBaselineVersion("1.0.1")
.build();
initializer.init();
assertEquals(
queryEntities(),
Sets.newHashSet(
new TestEntity(1, "test1"), new TestEntity(2, "test2"), new TestEntity(3, "test3")));
// second init must do nothing, so there are no conflicts
initializer.init();
}
@Test
public void selectsProviderSpecificScriptsInPreferenceToDefaultOnes() throws Exception {
createScript("1.0/1__init.sql", "CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));");
createScript("2.0/1__add_data.sql", "INSERT INTO test VALUES(1, 'default data');");
createScript("2.0/h2/1__add_data.sql", "INSERT INTO test VALUES(1, 'h2 data');");
final FlywaySchemaInitializer initializer = FlywayInitializerBuilder.from(dataSource).build();
initializer.init();
assertEquals(queryEntities(), Sets.newHashSet(new TestEntity(1, "h2 data")));
// second init must do nothing, so there are no conflicts
initializer.init();
}
@Test
public void replacesVariablesWhenPlaceholderReplacerIsConfigured() throws Exception {
createScript(
"1.0/1__init.sql",
"CREATE TABLE test (id INT, text TEXT, PRIMARY KEY (id));"
+ "INSERT INTO test VALUES(1, '${variable}');");
FlywayInitializerBuilder.from(dataSource)
.setReplacer(new PlaceholderReplacer(ImmutableMap.of("variable", "test"), "${", "}"))
.build()
.init();
assertEquals(queryEntities(), Sets.newHashSet(new TestEntity(1, "test")));
}
private Set<TestEntity> queryEntities() throws SQLException {
final Set<TestEntity> entities = new HashSet<>();
try (Connection conn = dataSource.getConnection()) {
final ResultSet result = RunScript.execute(conn, new StringReader("SELECT * FROM test"));
while (result.next()) {
entities.add(new TestEntity(result.getLong("id"), result.getString("text")));
}
}
return entities;
}
private ResultSet execQuery(String query) throws SQLException {
try (Connection conn = dataSource.getConnection()) {
return RunScript.execute(conn, new StringReader(query));
}
}
private static Path createScript(String relativePath, String content)
throws URISyntaxException, IOException {
return createFile(
targetDir().resolve(Paths.get(SCRIPTS_ROOT)).resolve(relativePath).toString(), content);
}
private static Path createFile(String filepath, String content)
throws URISyntaxException, IOException {
final Path path = targetDir().resolve(Paths.get(filepath));
if (!Files.exists(path.getParent())) {
Files.createDirectories(path.getParent());
}
Files.write(path, content.getBytes(StandardCharsets.UTF_8));
return path;
}
private static Path targetDir() throws URISyntaxException {
final URL url = Thread.currentThread().getContextClassLoader().getResource(".");
assertNotNull(url);
return Paths.get(url.toURI()).getParent();
}
private static class TestEntity {
final long id;
final String text;
private TestEntity(long id, String text) {
this.id = id;
this.text = text;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof TestEntity)) {
return false;
}
final TestEntity that = (TestEntity) obj;
return id == that.id && Objects.equals(text, that.text);
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + Long.hashCode(id);
hash = 31 * hash + Objects.hashCode(text);
return hash;
}
@Override
public String toString() {
return "TestEntity{" + "id=" + id + ", text='" + text + '\'' + '}';
}
}
private static class FlywayInitializerBuilder {
public static FlywayInitializerBuilder from(DataSource dataSource) {
try {
final String scriptsRoot = targetDir().resolve(Paths.get(SCRIPTS_ROOT)).toString();
return new FlywayInitializerBuilder()
.setDataSource(dataSource)
.setScriptsPrefix("")
.setScriptsSuffix(".sql")
.setVersionSeparator("__")
.setReplacer(PlaceholderReplacer.NO_PLACEHOLDERS)
.setBaselineOnMigrate(false)
.addLocation("filesystem:" + scriptsRoot);
} catch (Exception x) {
throw new RuntimeException(x.getMessage(), x);
}
}
private DataSource dataSource;
private List<String> locations;
private String scriptsPrefix;
private String scriptsSuffix;
private String versionSeparator;
private boolean baselineOnMigrate;
private String baselineVersion;
private PlaceholderReplacer replacer;
public FlywayInitializerBuilder setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
return this;
}
public FlywayInitializerBuilder setReplacer(PlaceholderReplacer replacer) {
this.replacer = replacer;
return this;
}
public FlywayInitializerBuilder addLocation(String location) {
if (locations == null) {
locations = new ArrayList<>();
}
locations.add(location);
return this;
}
public FlywayInitializerBuilder setScriptsPrefix(String scriptsPrefix) {
this.scriptsPrefix = scriptsPrefix;
return this;
}
public FlywayInitializerBuilder setScriptsSuffix(String scriptsSuffix) {
this.scriptsSuffix = scriptsSuffix;
return this;
}
public FlywayInitializerBuilder setVersionSeparator(String versionSeparator) {
this.versionSeparator = versionSeparator;
return this;
}
public FlywayInitializerBuilder setBaselineOnMigrate(boolean baselineOnMigrate) {
this.baselineOnMigrate = baselineOnMigrate;
return this;
}
public FlywayInitializerBuilder setBaselineVersion(String baselineVersion) {
this.baselineVersion = baselineVersion;
return this;
}
public FlywaySchemaInitializer build() {
if (locations == null) {
throw new IllegalStateException("locations required");
}
return new FlywaySchemaInitializer(
locations.toArray(new String[locations.size()]),
scriptsPrefix,
scriptsSuffix,
versionSeparator,
baselineOnMigrate,
baselineVersion,
dataSource,
replacer);
}
}
}

View File

@ -1,162 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema.impl.flyway;
import static com.google.common.collect.Sets.newHashSet;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.configuration.FlywayConfiguration;
import org.flywaydb.core.internal.util.Location;
import org.flywaydb.core.internal.util.scanner.Resource;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* Tests {@link ResourcesFinder}.
*
* @author Yevhenii Voevodin
*/
public class ResourcesFinderTest {
private final List<Path> cleanAfter = new ArrayList<>();
private final Flyway flyway = new Flyway();
@BeforeMethod
public void setUpDefaults() {
flyway.setSqlMigrationSuffix(".sql");
flyway.setSqlMigrationPrefix("");
}
@AfterMethod
public void cleanup() throws IOException {
for (Path path : cleanAfter) {
Files.delete(path);
}
cleanAfter.clear();
}
@Test
public void findsScriptsInClassPath() throws Exception {
flyway.setLocations("classpath:finder-sql-files");
cleanAfter.addAll(
createFiles(
"finder-sql-files/1.0/1.sql",
"finder-sql-files/1.0/2.sql",
"finder-sql-files/2.0/1.sql",
"finder-sql-files/2.0/postgresql/1.sql"));
final Set<String> locations = findResources(flyway).get("classpath:finder-sql-files");
assertEquals(
locations,
newHashSet(
"finder-sql-files/1.0/1.sql",
"finder-sql-files/1.0/2.sql",
"finder-sql-files/2.0/1.sql",
"finder-sql-files/2.0/postgresql/1.sql"));
}
@Test
public void findsScriptsOnFileSystem() throws Exception {
final List<Path> paths =
createFiles(
"finder-sql-files/1.0/1.sql",
"finder-sql-files/1.0/2.sql",
"finder-sql-files/2.0/1.sql",
"finder-sql-files/2.0/postgresql/1.sql");
cleanAfter.addAll(paths);
final Path finderSqlFiles = paths.get(0).getParent().getParent();
final String fsLocation = "filesystem:" + finderSqlFiles.toAbsolutePath();
flyway.setLocations(fsLocation);
final Set<String> locations = findResources(flyway).get(fsLocation);
assertEquals(
locations,
newHashSet(
finderSqlFiles.resolve("1.0").resolve("1.sql").toString(),
finderSqlFiles.resolve("1.0").resolve("2.sql").toString(),
finderSqlFiles.resolve("2.0").resolve("1.sql").toString(),
finderSqlFiles.resolve("2.0").resolve("postgresql").resolve("1.sql").toString()));
}
@Test
public void findsFileSystemAndClassPathScripts() throws Exception {
final List<Path> paths =
createFiles(
"finder-fs-sql-files/1.0/1.sql",
"finder-fs-sql-files/2.0/2.sql",
"finder-cp-sql-files/1.0/2.sql",
"finder-cp-sql-files/2.0/postgresql/1.sql");
cleanAfter.addAll(paths);
final Path finderFsSqlFiles = paths.get(0).getParent().getParent();
final String fsLocation = "filesystem:" + finderFsSqlFiles.toAbsolutePath();
final String cpLocation = "classpath:finder-cp-sql-files";
flyway.setLocations(fsLocation, cpLocation);
final Map<String, Set<String>> locations = findResources(flyway);
assertEquals(
locations.get(fsLocation),
newHashSet(
finderFsSqlFiles.resolve("1.0").resolve("1.sql").toString(),
finderFsSqlFiles.resolve("2.0").resolve("2.sql").toString()));
assertEquals(
locations.get(cpLocation),
newHashSet("finder-cp-sql-files/1.0/2.sql", "finder-cp-sql-files/2.0/postgresql/1.sql"));
}
private static Map<String, Set<String>> findResources(FlywayConfiguration configuration)
throws IOException {
final Map<Location, List<Resource>> resources =
new ResourcesFinder().findResources(configuration);
final Map<String, Set<String>> locations = new HashMap<>();
for (Map.Entry<Location, List<Resource>> entry : resources.entrySet()) {
locations.put(
entry.getKey().toString(),
entry.getValue().stream().map(Resource::getLocation).collect(Collectors.toSet()));
}
return locations;
}
private static List<Path> createFiles(String... paths) throws URISyntaxException, IOException {
final URL url = Thread.currentThread().getContextClassLoader().getResource(".");
assertNotNull(url);
final Path classesDir = Paths.get(url.toURI());
final List<Path> createdFiles = new ArrayList<>(paths.length);
for (String stringPath : paths) {
final Path path = classesDir.resolve(Paths.get(stringPath));
if (!Files.exists(path.getParent())) {
Files.createDirectories(path.getParent());
}
Files.write(path, path.toString().getBytes(StandardCharsets.UTF_8));
createdFiles.add(path);
}
return createdFiles;
}
}

View File

@ -1,67 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema.impl.flyway;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.internal.util.Location;
import org.flywaydb.core.internal.util.scanner.Resource;
import org.flywaydb.core.internal.util.scanner.filesystem.FileSystemResource;
import org.testng.annotations.Test;
/**
* Tests {@link SqlScriptCreator}.
*
* @author Yevhenii Voevodin
*/
public class SqlScriptCreatorTest {
@Test
public void createsScript() throws Exception {
final Location location = new Location("filesystem:schema");
final Resource resource = new FileSystemResource("schema/5.0.0-M7/v1__init.sql");
final SqlScriptCreator scriptsCreator = new SqlScriptCreator();
final SqlScript script = scriptsCreator.createScript(location, resource);
assertEquals(script.name, "v1__init.sql");
assertEquals(script.location, location);
assertEquals(script.dir, "5.0.0-M7");
assertEquals(script.resource.getLocation(), resource.getLocation());
assertNull(script.vendor);
}
@Test
public void createsVendorScript() throws Exception {
final Location location = new Location("filesystem:schema");
final Resource resource = new FileSystemResource("schema/5.0.0-M7/postgresql/v1__init.sql");
final SqlScriptCreator scriptsCreator = new SqlScriptCreator();
final SqlScript script = scriptsCreator.createScript(location, resource);
assertEquals(script.name, "v1__init.sql");
assertEquals(script.location, location);
assertEquals(script.dir, "5.0.0-M7");
assertEquals(script.resource.getLocation(), resource.getLocation());
assertEquals(script.vendor, "postgresql");
}
@Test(expectedExceptions = FlywayException.class)
public void failsToCreateResourceWhenPathIsInvalid() throws Exception {
final Location location = new Location("filesystem:schema");
final Resource resource = new FileSystemResource("schema/v1__init.sql");
new SqlScriptCreator().createScript(location, resource);
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.core.db.schema.impl.flyway;
import static org.testng.Assert.assertEquals;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.MigrationVersion;
import org.flywaydb.core.internal.util.Location;
import org.flywaydb.core.internal.util.scanner.filesystem.FileSystemResource;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* Tests {@link VersionResolver}.
*
* @author Yevhenii Voevodin
*/
public class VersionResolverTest {
private final Flyway flyway = new Flyway();
private final VersionResolver resolver = new VersionResolver();
@BeforeMethod
public void setUpDefaults() {
flyway.setSqlMigrationSuffix(".sql");
flyway.setSqlMigrationPrefix("");
flyway.setSqlMigrationSeparator("__");
}
@Test(dataProvider = "validScripts")
public void resolvesVersion(String dir, String name, String expectedVersion) {
final SqlScript script =
new SqlScript(
new FileSystemResource("sql/" + dir + "/" + name),
new Location("filesystem:sql"),
dir,
null,
name);
assertEquals(resolver.resolve(script, flyway), MigrationVersion.fromVersion(expectedVersion));
}
@Test(dataProvider = "invalidScripts", expectedExceptions = FlywayException.class)
public void failsToResolveVersions(String dir, String name) throws Exception {
final SqlScript script =
new SqlScript(
new FileSystemResource("sql/" + dir + "/" + name),
new Location("filesystem:sql"),
dir,
null,
name);
resolver.resolve(script, flyway);
}
@DataProvider
public static Object[][] invalidScripts() {
return new String[][] {
{"1.0", "2016-11-11__init.sql"},
{"1.0", "one__init.sql"},
{"1.0", "__init.sql"},
{"1.0", "version1__script.sql"},
{"1.0", "1..1__script.sql"},
{"5..0.0", "1__init.sql"}
};
}
@DataProvider
public static Object[][] validScripts() {
return new Object[][] {
{"5.0.0-M7", "1__init.sql", "5.0.0.7.1"},
{"5.0.0-M7", "1.1__init_sub_tables.sql", "5.0.0.7.1.1"},
{"6.0", "0.1__specific_update.sql", "6.0.0.1"},
{"1.0", "1__simple.sql", "1.0.1"}
};
}
}

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2012-2018 Red Hat, Inc.
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
which is available at https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
Contributors:
Red Hat, Inc. - initial API and implementation
-->
<configuration>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n</pattern>
</encoder>
</appender>
<appender name="file" class="ch.qos.logback.core.FileAppender">
<File>target/log/codenvy.log</File>
<encoder>
<pattern>%-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n</pattern>
</encoder>
</appender>
<root level="ERROR">
<appender-ref ref="stdout"/>
<appender-ref ref="file"/>
</root>
</configuration>

View File

@ -1,18 +0,0 @@
--
-- Copyright (c) 2012-2018 Red Hat, Inc.
-- This program and the accompanying materials are made
-- available under the terms of the Eclipse Public License 2.0
-- which is available at https://www.eclipse.org/legal/epl-2.0/
--
-- SPDX-License-Identifier: EPL-2.0
--
-- Contributors:
-- Red Hat, Inc. - initial API and implementation
--
CREATE TABLE test (
id INT,
text TEXT,
PRIMARY KEY (id)
);

View File

@ -1,15 +0,0 @@
--
-- Copyright (c) 2012-2018 Red Hat, Inc.
-- This program and the accompanying materials are made
-- available under the terms of the Eclipse Public License 2.0
-- which is available at https://www.eclipse.org/legal/epl-2.0/
--
-- SPDX-License-Identifier: EPL-2.0
--
-- Contributors:
-- Red Hat, Inc. - initial API and implementation
--
INSERT INTO test VALUES(1, 'test1');
INSERT INTO test VALUES(2, 'test2');
INSERT INTO test VALUES(3, 'test3');

View File

@ -1,12 +0,0 @@
--
-- Copyright (c) 2012-2018 Red Hat, Inc.
-- This program and the accompanying materials are made
-- available under the terms of the Eclipse Public License 2.0
-- which is available at https://www.eclipse.org/legal/epl-2.0/
--
-- SPDX-License-Identifier: EPL-2.0
--
-- Contributors:
-- Red Hat, Inc. - initial API and implementation
--

View File

@ -1,12 +0,0 @@
--
-- Copyright (c) 2012-2018 Red Hat, Inc.
-- This program and the accompanying materials are made
-- available under the terms of the Eclipse Public License 2.0
-- which is available at https://www.eclipse.org/legal/epl-2.0/
--
-- SPDX-License-Identifier: EPL-2.0
--
-- Contributors:
-- Red Hat, Inc. - initial API and implementation
--

View File

@ -31,10 +31,6 @@
<module>che-core-typescript-dto-maven-plugin</module>
<module>che-core-api-core</module>
<module>che-core-api-model</module>
<module>che-core-db</module>
<module>che-core-db-vendor-h2</module>
<module>che-core-db-vendor-mysql</module>
<module>che-core-db-vendor-postgresql</module>
<module>che-core-logback</module>
<module>che-core-tracing-core</module>
<module>che-core-tracing-web</module>

View File

@ -113,10 +113,6 @@
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-account</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>
@ -181,10 +177,6 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-tracing</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.multiuser</groupId>
<artifactId>che-multiuser-machine-authentication</artifactId>
@ -238,11 +230,6 @@
<artifactId>che-core-commons-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db-vendor-h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-sql-schema</artifactId>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -52,7 +52,6 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurato
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.NamespaceConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.OAuthTokenSecretsConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.PreferencesConfigMapConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.SshKeysConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserPermissionConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserPreferencesConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserProfileConfigurator;
@ -110,7 +109,6 @@ public class KubernetesInfraModule extends AbstractModule {
namespaceConfigurators.addBinding().to(WorkspaceServiceAccountConfigurator.class);
namespaceConfigurators.addBinding().to(UserProfileConfigurator.class);
namespaceConfigurators.addBinding().to(UserPreferencesConfigurator.class);
namespaceConfigurators.addBinding().to(SshKeysConfigurator.class);
namespaceConfigurators.addBinding().to(GitconfigUserDataConfigurator.class);
bind(AuthorizationChecker.class).to(KubernetesAuthorizationCheckerImpl.class);
@ -125,7 +123,6 @@ public class KubernetesInfraModule extends AbstractModule {
factories.addBinding(Constants.NO_ENVIRONMENT_RECIPE_TYPE).to(NoEnvironmentFactory.class);
bind(RuntimeInfrastructure.class).to(KubernetesInfrastructure.class);
bind(InconsistentRuntimesDetector.class).asEagerSingleton();
bind(TrustedCAProvisioner.class).to(KubernetesTrustedCAProvisioner.class);

View File

@ -1,33 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.cache;
import org.eclipse.che.core.db.cascade.event.RemoveEvent;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState;
/**
* Published before {@link KubernetesRuntimeState kubernetes runtime state} removed.
*
* @author Sergii Leshchenko
*/
public class BeforeKubernetesRuntimeStateRemovedEvent extends RemoveEvent {
private final KubernetesRuntimeState k8sRuntimeState;
public BeforeKubernetesRuntimeStateRemovedEvent(KubernetesRuntimeState k8sRuntimeState) {
this.k8sRuntimeState = k8sRuntimeState;
}
public KubernetesRuntimeState getRuntimeState() {
return k8sRuntimeState;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -15,22 +15,16 @@ import static java.lang.String.format;
import static java.util.stream.Collectors.toMap;
import com.google.inject.persist.Transactional;
import jakarta.annotation.PostConstruct;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import org.eclipse.che.api.core.model.workspace.runtime.MachineStatus;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.core.model.workspace.runtime.ServerStatus;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.core.db.cascade.CascadeEventSubscriber;
import org.eclipse.che.core.db.jpa.DuplicateKeyException;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.BeforeKubernetesRuntimeStateRemovedEvent;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesMachineCache;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl.MachineId;
@ -56,8 +50,6 @@ public class JpaKubernetesMachineCache implements KubernetesMachineCache {
throws InfrastructureException {
try {
doPutMachine(machine);
} catch (DuplicateKeyException e) {
throw new InfrastructureException("Machine is already in cache", e);
} catch (RuntimeException e) {
throw new InfrastructureException(e.getMessage(), e);
}
@ -188,22 +180,4 @@ public class JpaKubernetesMachineCache implements KubernetesMachineCache {
}
return false;
}
@Singleton
public static class RemoveKubernetesMachinesBeforeRuntimesRemoved
extends CascadeEventSubscriber<BeforeKubernetesRuntimeStateRemovedEvent> {
@Inject private EventService eventService;
@Inject private JpaKubernetesMachineCache k8sMachines;
@PostConstruct
public void subscribe() {
eventService.subscribe(this, BeforeKubernetesRuntimeStateRemovedEvent.class);
}
@Override
public void onCascadeEvent(BeforeKubernetesRuntimeStateRemovedEvent event) throws Exception {
k8sMachines.remove(event.getRuntimeState().getRuntimeId());
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -21,9 +21,5 @@ public class JpaKubernetesRuntimeCacheModule extends AbstractModule {
protected void configure() {
bind(KubernetesRuntimeStateCache.class).to(JpaKubernetesRuntimeStateCache.class);
bind(KubernetesMachineCache.class).to(JpaKubernetesMachineCache.class);
bind(JpaKubernetesRuntimeStateCache.RemoveKubernetesRuntimeBeforeWorkspaceRemoved.class)
.asEagerSingleton();
bind(JpaKubernetesMachineCache.RemoveKubernetesMachinesBeforeRuntimesRemoved.class)
.asEagerSingleton();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -11,11 +11,9 @@
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.cache.jpa;
import static java.lang.String.format;
import static java.util.Collections.emptyList;
import com.google.inject.persist.Transactional;
import jakarta.annotation.PostConstruct;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@ -23,19 +21,13 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
import org.eclipse.che.api.core.model.workspace.config.Command;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.workspace.server.event.BeforeWorkspaceRemovedEvent;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.core.db.cascade.CascadeEventSubscriber;
import org.eclipse.che.core.db.jpa.DuplicateKeyException;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.BeforeKubernetesRuntimeStateRemovedEvent;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeCommandImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState;
@ -65,8 +57,6 @@ public class JpaKubernetesRuntimeStateCache implements KubernetesRuntimeStateCac
try {
doPutIfAbsent(runtimeState);
return true;
} catch (DuplicateKeyException | EntityExistsException e) {
return false;
} catch (RuntimeException e) {
throw new InfrastructureException(e.getMessage(), e);
}
@ -187,11 +177,6 @@ public class JpaKubernetesRuntimeStateCache implements KubernetesRuntimeStateCac
em.find(KubernetesRuntimeState.class, runtimeIdentity.getWorkspaceId());
if (runtime != null) {
eventService
.publish(
new BeforeKubernetesRuntimeStateRemovedEvent(new KubernetesRuntimeState(runtime)))
.propagateException();
em.remove(runtime);
}
}
@ -254,39 +239,4 @@ public class JpaKubernetesRuntimeStateCache implements KubernetesRuntimeStateCac
em.persist(runtimeState);
em.flush();
}
@Singleton
public static class RemoveKubernetesRuntimeBeforeWorkspaceRemoved
extends CascadeEventSubscriber<BeforeWorkspaceRemovedEvent> {
@Inject private EventService eventService;
@Inject private JpaKubernetesRuntimeStateCache k8sRuntimes;
@PostConstruct
public void subscribe() {
eventService.subscribe(this, BeforeWorkspaceRemovedEvent.class);
}
@Override
public void onCascadeEvent(BeforeWorkspaceRemovedEvent event) throws Exception {
Optional<KubernetesRuntimeState> k8sRuntimeStateOpt =
k8sRuntimes.find(event.getWorkspace().getId());
if (k8sRuntimeStateOpt.isPresent()) {
KubernetesRuntimeState existingK8sRuntimeState = k8sRuntimeStateOpt.get();
RuntimeIdentity runtimeId = existingK8sRuntimeState.getRuntimeId();
// It is not normal case when non STOPPED workspace is going to be removed.
// Need to log error to investigate why it may happen
// and clean up existing runtime not to lock removing of workspace.
LOG.error(
format(
"Workspace is being removed while Kubernetes runtime state '%s:%s:%s' exists. "
+ "This situation indicates a bug that needs to be reported. Runtime state "
+ "will be removed from DB, but Kubernetes resources (pods, pvcs, etc.) "
+ "won't be cleaned up.",
runtimeId.getWorkspaceId(), runtimeId.getEnvName(), runtimeId.getOwnerId()));
k8sRuntimes.remove(runtimeId);
}
}
}
}

View File

@ -1,118 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.cache.jpa;
import com.google.inject.TypeLiteral;
import org.eclipse.che.account.spi.AccountImpl;
import org.eclipse.che.api.workspace.server.devfile.SerializableConverter;
import org.eclipse.che.api.workspace.server.model.impl.CommandImpl;
import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl;
import org.eclipse.che.api.workspace.server.model.impl.MachineConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl;
import org.eclipse.che.api.workspace.server.model.impl.VolumeImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.ActionImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.ComponentImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.DevfileImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.EndpointImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.EntrypointImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.EnvImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.ProjectImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.SourceImpl;
import org.eclipse.che.commons.test.db.H2DBTestServer;
import org.eclipse.che.commons.test.db.H2JpaCleaner;
import org.eclipse.che.commons.test.db.PersistTestModuleBuilder;
import org.eclipse.che.commons.test.tck.TckModule;
import org.eclipse.che.commons.test.tck.TckResourcesCleaner;
import org.eclipse.che.commons.test.tck.repository.JpaTckRepository;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
import org.eclipse.che.core.db.DBInitializer;
import org.eclipse.che.core.db.h2.jpa.eclipselink.H2ExceptionHandler;
import org.eclipse.che.core.db.schema.SchemaInitializer;
import org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesMachineCache;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl.MachineId;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeCommandImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesServerImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesServerImpl.ServerId;
import org.h2.Driver;
/** @author Sergii Leshchenko */
public class JpaTckModule extends TckModule {
@Override
protected void configure() {
H2DBTestServer server = H2DBTestServer.startDefault();
install(
new PersistTestModuleBuilder()
.setDriver(Driver.class)
.runningOn(server)
.addEntityClasses(
WorkspaceImpl.class,
WorkspaceConfigImpl.class,
ProjectConfigImpl.class,
SourceStorageImpl.class,
EnvironmentImpl.class,
MachineConfigImpl.class,
ServerConfigImpl.class,
VolumeImpl.class,
CommandImpl.class,
AccountImpl.class,
KubernetesRuntimeState.class,
KubernetesRuntimeCommandImpl.class,
KubernetesMachineImpl.class,
MachineId.class,
KubernetesServerImpl.class,
ServerId.class,
// devfile
ActionImpl.class,
org.eclipse.che.api.workspace.server.model.impl.devfile.CommandImpl.class,
ComponentImpl.class,
DevfileImpl.class,
EndpointImpl.class,
EntrypointImpl.class,
EnvImpl.class,
ProjectImpl.class,
SourceImpl.class,
org.eclipse.che.api.workspace.server.model.impl.devfile.VolumeImpl.class)
.addEntityClass(
"org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute")
.addClass(SerializableConverter.class)
.setExceptionHandler(H2ExceptionHandler.class)
.build());
bind(new TypeLiteral<TckRepository<AccountImpl>>() {})
.toInstance(new JpaTckRepository<>(AccountImpl.class));
bind(new TypeLiteral<TckRepository<WorkspaceImpl>>() {})
.toInstance(new JpaTckRepository<>(WorkspaceImpl.class));
bind(new TypeLiteral<TckRepository<KubernetesRuntimeState>>() {})
.toInstance(new JpaTckRepository<>(KubernetesRuntimeState.class));
bind(new TypeLiteral<TckRepository<KubernetesMachineImpl>>() {})
.toInstance(new JpaTckRepository<>(KubernetesMachineImpl.class));
bind(KubernetesRuntimeStateCache.class).to(JpaKubernetesRuntimeStateCache.class);
bind(KubernetesMachineCache.class).to(JpaKubernetesMachineCache.class);
bind(SchemaInitializer.class)
.toInstance(new FlywaySchemaInitializer(server.getDataSource(), "che-schema"));
bind(DBInitializer.class).asEagerSingleton();
bind(TckResourcesCleaner.class).toInstance(new H2JpaCleaner(server));
}
}

View File

@ -1,315 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck;
import static java.util.Arrays.asList;
import static org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck.TestObjects.createMachine;
import static org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck.TestObjects.createRuntimeState;
import static org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck.TestObjects.createServer;
import static org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck.TestObjects.createWorkspace;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import javax.inject.Inject;
import org.eclipse.che.account.spi.AccountImpl;
import org.eclipse.che.api.core.model.workspace.runtime.MachineStatus;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.core.model.workspace.runtime.ServerStatus;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.commons.test.tck.TckListener;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
import org.eclipse.che.commons.test.tck.repository.TckRepositoryException;
import org.eclipse.che.core.db.cascade.CascadeEventSubscriber;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.BeforeKubernetesRuntimeStateRemovedEvent;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesMachineCache;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesServerImpl;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests {@link KubernetesMachineCache} contract.
*
* @author Sergii Leshchenko
*/
@Listeners(TckListener.class)
@Test(suiteName = KubernetesMachinesCacheTest.SUITE_NAME)
public class KubernetesMachinesCacheTest {
public static final String SUITE_NAME = "KubernetesMachineCacheTck";
@Inject private TckRepository<WorkspaceImpl> workspaceTckRepository;
@Inject private TckRepository<AccountImpl> accountRepository;
@Inject private TckRepository<KubernetesRuntimeState> runtimesRepository;
@Inject private TckRepository<KubernetesMachineImpl> machineRepository;
@Inject private KubernetesMachineCache machineCache;
@Inject private KubernetesRuntimeStateCache runtimesStatesCache;
@Inject private EventService eventService;
private WorkspaceImpl[] workspaces;
private KubernetesRuntimeState[] runtimeStates;
private KubernetesMachineImpl[] machines;
@BeforeMethod
public void setUp() throws TckRepositoryException {
workspaces = new WorkspaceImpl[] {createWorkspace(), createWorkspace()};
AccountImpl[] accounts =
new AccountImpl[] {workspaces[0].getAccount(), workspaces[1].getAccount()};
runtimeStates =
new KubernetesRuntimeState[] {
createRuntimeState(workspaces[0]), createRuntimeState(workspaces[1])
};
accountRepository.createAll(asList(accounts));
workspaceTckRepository.createAll(asList(workspaces));
runtimesRepository.createAll(asList(runtimeStates));
machines =
new KubernetesMachineImpl[] {
createMachine(
workspaces[0].getId(),
"machine1",
MachineStatus.STARTING,
ImmutableMap.of("server1", createServer(ServerStatus.UNKNOWN))),
createMachine(
workspaces[0].getId(),
"machine2",
MachineStatus.RUNNING,
ImmutableMap.of("server1", createServer(ServerStatus.UNKNOWN))),
createMachine(
workspaces[1].getId(),
"machine1",
MachineStatus.STARTING,
ImmutableMap.of("server1", createServer(ServerStatus.UNKNOWN)))
};
machineRepository.createAll(asList(machines));
}
@AfterMethod
public void removeEntities() throws TckRepositoryException {
machineRepository.removeAll();
runtimesRepository.removeAll();
workspaceTckRepository.removeAll();
accountRepository.removeAll();
}
@Test
public void shouldPutMachine() throws Exception {
// given
KubernetesMachineImpl machine =
createMachine(
workspaces[1].getId(),
"machine2",
MachineStatus.RUNNING,
ImmutableMap.of("myServer", createServer(ServerStatus.RUNNING)));
// when
machineCache.put(runtimeStates[1].getRuntimeId(), machine);
// then
Map<String, KubernetesMachineImpl> fetched =
machineCache.getMachines(runtimeStates[1].getRuntimeId());
assertEquals(2, fetched.size());
assertTrue(fetched.containsKey("machine2"));
assertTrue(fetched.containsValue(machine));
}
@Test(
expectedExceptions = InfrastructureException.class,
expectedExceptionsMessageRegExp = "Machine is already in cache")
public void shouldThrowExceptionIfMachineIsAlreadyInCacheOnTryToPutMachine() throws Exception {
// given
KubernetesMachineImpl machine =
createMachine(
workspaces[1].getId(),
machines[0].getName(),
MachineStatus.RUNNING,
ImmutableMap.of("myServer", createServer(ServerStatus.RUNNING)));
// when
machineCache.put(runtimeStates[1].getRuntimeId(), machine);
}
@Test
public void shouldGetMachines() throws Exception {
// given
RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId();
// when
machineCache.getMachines(runtimeId);
// then
Map<String, KubernetesMachineImpl> fetched = machineCache.getMachines(runtimeId);
assertEquals(fetched.size(), 2);
assertTrue(fetched.keySet().containsAll(asList("machine1", "machine2")));
assertTrue(fetched.values().containsAll(asList(machines[0], machines[1])));
}
@Test
public void shouldGetServer() throws Exception {
// given
RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId();
KubernetesMachineImpl machine = machines[0];
Entry<String, KubernetesServerImpl> serverToFetch =
machine.getServers().entrySet().iterator().next();
// when
KubernetesServerImpl fetched =
machineCache.getServer(runtimeId, machine.getName(), serverToFetch.getKey());
// then
assertEquals(fetched, serverToFetch.getValue());
}
@Test(
expectedExceptions = InfrastructureException.class,
expectedExceptionsMessageRegExp = "Server with name 'non-existing' was not found")
public void shouldThrowExceptionWhenServerWasNotFoundOnGetting() throws Exception {
// given
RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId();
KubernetesMachineImpl machine = machines[0];
// when
machineCache.getServer(runtimeId, machine.getName(), "non-existing");
}
@Test
public void shouldUpdateMachineStatusServerStatus() throws Exception {
// given
RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId();
// when
machineCache.updateServerStatus(
runtimeId, machines[0].getName(), "server1", ServerStatus.RUNNING);
// then
KubernetesServerImpl fetchedServer = machineCache.getServer(runtimeId, "machine1", "server1");
assertEquals(fetchedServer.getStatus(), ServerStatus.RUNNING);
}
@Test(
expectedExceptions = InfrastructureException.class,
expectedExceptionsMessageRegExp = "Server with name 'non-existing' was not found")
public void shouldThrowExceptionWhenServerWasNotFoundOnStatusUpdating() throws Exception {
// given
RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId();
KubernetesMachineImpl machine = machines[0];
// when
machineCache.updateServerStatus(
runtimeId, machine.getName(), "non-existing", ServerStatus.RUNNING);
}
@Test
public void shouldUpdateMachineStatus() throws Exception {
// given
RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId();
KubernetesMachineImpl machine = machines[0];
String machineName = machine.getName();
// when
machineCache.updateMachineStatus(runtimeId, machineName, MachineStatus.RUNNING);
// then
Optional<KubernetesMachineImpl> machineOpt =
machineCache.getMachines(runtimeId).entrySet().stream()
.filter(e -> e.getKey().equals(machineName))
.map(Map.Entry::getValue)
.findAny();
assertTrue(machineOpt.isPresent());
assertEquals(machineOpt.get().getStatus(), MachineStatus.RUNNING);
}
@Test
public void shouldUpdateServerStatus() throws Exception {
// given
RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId();
// when
machineCache.updateServerStatus(
runtimeId, machines[0].getName(), "server1", ServerStatus.RUNNING);
// then
KubernetesServerImpl fetchedServer = machineCache.getServer(runtimeId, "machine1", "server1");
assertEquals(fetchedServer.getStatus(), ServerStatus.RUNNING);
}
@Test
public void shouldRemoveMachines() throws Exception {
// given
RuntimeIdentity runtimeId = runtimeStates[0].getRuntimeId();
// when
machineCache.remove(runtimeId);
// then
assertEquals(machineCache.getMachines(runtimeId).size(), 0);
}
// This test ensure that if during cascade removal of machine from cache (initiated during removal
// of runtime
// from cache) will happen an exception then transaction in runtime cache will rollback removal of
// machine cache.
// see
// @Transactional(rollbackOn = {RuntimeException.class, ServerException.class})
// protected void doRemove(RuntimeIdentity runtimeIdentity) throws ServerException
// Note that any checked exception that happened during RemoveEvent(extends CascadeEvent) would be
// transformed to
// ServerException. See RemoveEvent.propagateException.
@Test
public void shouldRollbackTransactionOnFailedCascadeMachine() throws Exception {
// given
assertTrue(machineCache.getMachines(runtimeStates[0].getRuntimeId()).size() > 0);
CascadeEventSubscriber subscriber =
new CascadeEventSubscriber<BeforeKubernetesRuntimeStateRemovedEvent>() {
@Override
public void onCascadeEvent(BeforeKubernetesRuntimeStateRemovedEvent event)
throws Exception {
machineCache.remove(event.getRuntimeState().getRuntimeId());
throw new InfrastructureException("exception");
}
};
eventService.subscribe(subscriber, BeforeKubernetesRuntimeStateRemovedEvent.class);
// when
try {
runtimesStatesCache.remove(runtimeStates[0].getRuntimeId());
fail("Should fail with InfrastructureException");
} catch (InfrastructureException exc) {
// ok
} finally {
eventService.unsubscribe(subscriber, BeforeKubernetesRuntimeStateRemovedEvent.class);
}
// then
assertTrue(machineCache.getMachines(runtimeStates[0].getRuntimeId()).size() > 0);
}
}

View File

@ -1,376 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck.TestObjects.createRuntimeState;
import static org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck.TestObjects.createWorkspace;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;
import org.eclipse.che.account.spi.AccountImpl;
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
import org.eclipse.che.api.core.model.workspace.config.Command;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.workspace.server.model.impl.CommandImpl;
import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.commons.test.tck.TckListener;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
import org.eclipse.che.commons.test.tck.repository.TckRepositoryException;
import org.eclipse.che.workspace.infrastructure.kubernetes.cache.KubernetesRuntimeStateCache;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests {@link KubernetesRuntimeStateCache} contract.
*
* @author Sergii Leshchenko
*/
@Listeners(TckListener.class)
@Test(suiteName = KubernetesRuntimeStateCacheTest.SUITE_NAME)
public class KubernetesRuntimeStateCacheTest {
public static final String SUITE_NAME = "KubernetesRuntimeStateCacheTck";
@Inject private TckRepository<WorkspaceImpl> workspaceTckRepository;
@Inject private TckRepository<AccountImpl> accountRepository;
@Inject private TckRepository<KubernetesRuntimeState> runtimesRepository;
@Inject private KubernetesRuntimeStateCache runtimesStatesCache;
@Inject private EventService eventService;
private WorkspaceImpl[] workspaces;
private KubernetesRuntimeState[] runtimesStates;
@BeforeMethod
public void setUp() throws TckRepositoryException {
workspaces = new WorkspaceImpl[] {createWorkspace(), createWorkspace(), createWorkspace()};
AccountImpl[] accounts =
new AccountImpl[] {
workspaces[0].getAccount(), workspaces[1].getAccount(), workspaces[2].getAccount()
};
accountRepository.createAll(asList(accounts));
workspaceTckRepository.createAll(asList(workspaces));
runtimesStates =
new KubernetesRuntimeState[] {
createRuntimeState(workspaces[0]), createRuntimeState(workspaces[1])
};
runtimesRepository.createAll(asList(runtimesStates));
}
@AfterMethod
public void removeEntities() throws TckRepositoryException {
runtimesRepository.removeAll();
workspaceTckRepository.removeAll();
accountRepository.removeAll();
}
@Test
public void shouldReturnRuntimesIdentities() throws Exception {
// when
Set<RuntimeIdentity> identities = runtimesStatesCache.getIdentities();
// then
assertEquals(identities.size(), 2);
assertTrue(identities.contains(runtimesStates[0].getRuntimeId()));
assertTrue(identities.contains(runtimesStates[1].getRuntimeId()));
}
@Test
public void shouldReturnCommands() throws Exception {
// when
List<? extends Command> commands =
runtimesStatesCache.getCommands(runtimesStates[0].getRuntimeId());
// then
assertEquals(commands.size(), runtimesStates[0].getCommands().size());
assertTrue(commands.containsAll(runtimesStates[0].getCommands()));
}
@Test
public void shouldReturnEmptyCommandsListIfStateDoesNotExist() throws Exception {
// when
List<? extends Command> commands =
runtimesStatesCache.getCommands(
new RuntimeIdentityImpl("non-existent-ws", "defEnv", "acc1", "infraNamespace"));
// then
assertTrue(commands.isEmpty());
}
@Test(dependsOnMethods = "shouldReturnCommands")
public void shouldUpdateCommands() throws Exception {
// given
List<CommandImpl> newCommands = new ArrayList<>();
CommandImpl newCommand = new CommandImpl("new", "build", "custom");
newCommands.add(newCommand);
// when
runtimesStatesCache.updateCommands(runtimesStates[0].getRuntimeId(), newCommands);
// then
List<? extends Command> updatedCommands =
runtimesStatesCache.getCommands(runtimesStates[0].getRuntimeId());
assertEquals(updatedCommands.size(), 1);
assertEquals(new CommandImpl(updatedCommands.get(0)), newCommand);
}
// Ensure that we are not affected https://bugs.eclipse.org/bugs/show_bug.cgi?id=474203 Orphan
// Removal not working
// when, object is added to collection and then same object is removed from collection in same
// transaction.
//
// Probable reason - two different transactions was used.
@Test(dependsOnMethods = "shouldReturnCommands")
public void shouldUpdateCommandsAndDeleteRuntime() {
// given
List<CommandImpl> newCommands = new ArrayList<>();
CommandImpl newCommand = new CommandImpl("new", "build", "custom");
newCommands.add(newCommand);
// when
try {
runtimesStatesCache.updateCommands(runtimesStates[0].getRuntimeId(), newCommands);
runtimesStatesCache.remove(runtimesStates[0].getRuntimeId());
} catch (InfrastructureException e) {
fail("No exception expected here, got " + e.getLocalizedMessage());
}
// then
// if no exception happened during remove operation that means test passed correctly.
}
@Test(
expectedExceptions = InfrastructureException.class,
expectedExceptionsMessageRegExp =
"Runtime state for workspace with id 'non-existent-ws' was not found")
public void shouldThrowExceptionUpdateCommands() throws Exception {
// given
CommandImpl newCommand = new CommandImpl("new", "build", "custom");
// when
runtimesStatesCache.updateCommands(
new RuntimeIdentityImpl("non-existent-ws", "defEnv", "acc1", "infraNamespace"),
singletonList(newCommand));
}
@Test
public void shouldReturnRuntimeStateByRuntimeId() throws Exception {
// given
KubernetesRuntimeState expectedState = runtimesStates[1];
// when
Optional<KubernetesRuntimeState> fetchedOpt =
runtimesStatesCache.get(expectedState.getRuntimeId());
// then
assertTrue(fetchedOpt.isPresent());
assertEquals(expectedState, fetchedOpt.get());
}
@Test
public void shouldReturnEmptyOptionalIfRuntimeStateIsNotFound() throws Exception {
// given
KubernetesRuntimeState nonExisting = createRuntimeState(workspaces[2]);
// when
Optional<KubernetesRuntimeState> fetchedOpt =
runtimesStatesCache.get(nonExisting.getRuntimeId());
// then
assertFalse(fetchedOpt.isPresent());
}
@Test
public void shouldReturnRuntimeStatus() throws Exception {
// when
Optional<WorkspaceStatus> statusOpt =
runtimesStatesCache.getStatus(runtimesStates[0].getRuntimeId());
// then
assertTrue(statusOpt.isPresent());
assertEquals(runtimesStates[0].getStatus(), statusOpt.get());
}
@Test
public void shouldReturnEmptyOptionalWhenThereIsNotRuntimeStateWhileStatusRetrieving()
throws Exception {
// when
Optional<WorkspaceStatus> statusOpt =
runtimesStatesCache.getStatus(
new RuntimeIdentityImpl("non-existent-ws", "defEnv", "acc1", "infraNamespace"));
// then
assertFalse(statusOpt.isPresent());
}
@Test(dependsOnMethods = "shouldReturnRuntimeStatus")
public void shouldUpdateStatus() throws Exception {
// given
KubernetesRuntimeState stateToUpdate = runtimesStates[0];
// when
runtimesStatesCache.updateStatus(stateToUpdate.getRuntimeId(), WorkspaceStatus.STOPPED);
// then
Optional<WorkspaceStatus> updatedStatusOpt =
runtimesStatesCache.getStatus(stateToUpdate.getRuntimeId());
assertTrue(updatedStatusOpt.isPresent());
assertEquals(updatedStatusOpt.get(), WorkspaceStatus.STOPPED);
assertNotEquals(stateToUpdate, WorkspaceStatus.STOPPED);
}
@Test(dependsOnMethods = "shouldReturnRuntimeStatus")
public void shouldUpdateStatusIfPreviousValueMatchesPredicate() throws Exception {
// given
KubernetesRuntimeState stateToUpdate = runtimesStates[0];
// when
boolean isUpdated =
runtimesStatesCache.updateStatus(
stateToUpdate.getRuntimeId(),
s -> s == stateToUpdate.getStatus(),
WorkspaceStatus.STOPPED);
// then
assertTrue(isUpdated);
Optional<WorkspaceStatus> updatedStatusOpt =
runtimesStatesCache.getStatus(stateToUpdate.getRuntimeId());
assertTrue(updatedStatusOpt.isPresent());
assertEquals(updatedStatusOpt.get(), WorkspaceStatus.STOPPED);
assertNotEquals(stateToUpdate, WorkspaceStatus.STOPPED);
}
@Test(dependsOnMethods = "shouldReturnRuntimeStatus")
public void shouldNotUpdateStatusIfPreviousValueDoesNotMatchesPredicate() throws Exception {
// given
KubernetesRuntimeState stateToUpdate = runtimesStates[0];
// when
boolean isUpdated =
runtimesStatesCache.updateStatus(
stateToUpdate.getRuntimeId(),
s -> s == WorkspaceStatus.STARTING,
WorkspaceStatus.STOPPED);
// then
assertFalse(isUpdated);
Optional<WorkspaceStatus> updatedStatusOpt =
runtimesStatesCache.getStatus(stateToUpdate.getRuntimeId());
assertTrue(updatedStatusOpt.isPresent());
assertEquals(updatedStatusOpt.get(), WorkspaceStatus.RUNNING);
assertEquals(stateToUpdate.getStatus(), WorkspaceStatus.RUNNING);
}
@Test(
expectedExceptions = InfrastructureException.class,
expectedExceptionsMessageRegExp =
"Runtime state for workspace with id 'non-existent-ws' was not found")
public void shouldThrowExceptionWhenThereIsNotRuntimeStateWhileStatusUpdatingWithoutPredicate()
throws Exception {
// when
runtimesStatesCache.updateStatus(
new RuntimeIdentityImpl("non-existent-ws", "defEnv", "acc1", "infraNamespace"),
WorkspaceStatus.STOPPED);
}
@Test(
expectedExceptions = InfrastructureException.class,
expectedExceptionsMessageRegExp =
"Runtime state for workspace with id 'non-existent-ws' was not found")
public void shouldThrowExceptionWhenThereIsNotRuntimeStateWhileStatusUpdatingWithPredicate()
throws Exception {
// when
runtimesStatesCache.updateStatus(
new RuntimeIdentityImpl("non-existent-ws", "defEnv", "acc1", "infraNamespace"),
s -> s.equals(WorkspaceStatus.STOPPING),
WorkspaceStatus.STOPPED);
}
@Test(dependsOnMethods = "shouldReturnRuntimeStateByRuntimeId")
public void shouldPutRuntimeState() throws Exception {
// given
KubernetesRuntimeState runtimeState = createRuntimeState(workspaces[2]);
// when
boolean isInserted = runtimesStatesCache.putIfAbsent(runtimeState);
// then
assertTrue(isInserted);
Optional<KubernetesRuntimeState> fetchedState =
runtimesStatesCache.get(runtimeState.getRuntimeId());
assertTrue(fetchedState.isPresent());
assertEquals(runtimeState, fetchedState.get());
}
@Test(dependsOnMethods = "shouldReturnRuntimeStateByRuntimeId")
public void shouldNotPutRuntimeStateIfRuntimeStateIsAlreadyPut() throws Exception {
// given
KubernetesRuntimeState runtimeState = createRuntimeState(workspaces[0]);
// when
boolean isInserted = runtimesStatesCache.putIfAbsent(runtimeState);
// then
assertFalse(isInserted);
Optional<KubernetesRuntimeState> fetchedState =
runtimesStatesCache.get(runtimeState.getRuntimeId());
assertTrue(fetchedState.isPresent());
assertEquals(runtimesStates[0], fetchedState.get());
}
@Test(dependsOnMethods = "shouldReturnEmptyOptionalIfRuntimeStateIsNotFound")
public void shouldRemoveRuntimeState() throws Exception {
// given
KubernetesRuntimeState runtimeState = createRuntimeState(workspaces[0]);
RuntimeIdentity toRemove = runtimeState.getRuntimeId();
// when
runtimesStatesCache.remove(toRemove);
// then
assertFalse(runtimesStatesCache.get(toRemove).isPresent());
}
@Test(dependsOnMethods = "shouldReturnEmptyOptionalIfRuntimeStateIsNotFound")
public void shouldDoNothingIfStateIsAlreadyRemove() throws Exception {
// given
KubernetesRuntimeState runtimeState = createRuntimeState(workspaces[2]);
RuntimeIdentity toRemove = runtimeState.getRuntimeId();
// when
runtimesStatesCache.remove(toRemove);
// then
assertFalse(runtimesStatesCache.get(toRemove).isPresent());
}
}

View File

@ -1,91 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.cache.tck;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static org.eclipse.che.commons.lang.NameGenerator.generate;
import com.google.common.collect.ImmutableMap;
import java.util.Arrays;
import java.util.Map;
import org.eclipse.che.account.spi.AccountImpl;
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
import org.eclipse.che.api.core.model.workspace.runtime.MachineStatus;
import org.eclipse.che.api.core.model.workspace.runtime.ServerStatus;
import org.eclipse.che.api.workspace.server.model.impl.CommandImpl;
import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesMachineImpl;
import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState;
/** @author Sergii Leshchenko */
public class TestObjects {
public static AccountImpl createAccount() {
return new AccountImpl(generate("id", 8), generate("name", 6), "any");
}
public static WorkspaceImpl createWorkspace() {
return new WorkspaceImpl(
generate("wsId", 8),
createAccount(),
new WorkspaceConfigImpl(
generate("wsName", 8),
"description",
"defEnv",
emptyList(),
emptyList(),
emptyMap(),
emptyMap()));
}
public static KubernetesRuntimeState createRuntimeState(WorkspaceImpl workspace) {
return new KubernetesRuntimeState(
new RuntimeIdentityImpl(
workspace.getId(), "defEnv", workspace.getAccount().getId(), generate("namespace", 5)),
WorkspaceStatus.RUNNING,
Arrays.asList(createCommand(), createCommand()));
}
public static CommandImpl createCommand() {
CommandImpl cmd =
new CommandImpl(generate("command", 5), "echo " + generate("command", 5), "CUSTOM");
cmd.getAttributes().put("attr1", "val1");
cmd.getAttributes().put("attr2", "val2");
return cmd;
}
public static KubernetesMachineImpl createMachine(
String workspaceId,
String machineName,
MachineStatus status,
Map<String, ServerImpl> servers) {
return new KubernetesMachineImpl(
workspaceId,
machineName,
generate("pod", 5),
generate("container", 5),
status,
ImmutableMap.of("key1", "value1", generate("key", 2), generate("value", 2)),
servers);
}
public static ServerImpl createServer(ServerStatus status) {
return new ServerImpl(
generate("http:://", 10),
status,
ImmutableMap.of(generate("key", 5), generate("value", 5)));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -55,7 +55,6 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurato
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.NamespaceConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.OAuthTokenSecretsConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.PreferencesConfigMapConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.SshKeysConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserPermissionConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserPreferencesConfigurator;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.configurator.UserProfileConfigurator;
@ -118,7 +117,6 @@ public class OpenShiftInfraModule extends AbstractModule {
namespaceConfigurators.addBinding().to(PreferencesConfigMapConfigurator.class);
namespaceConfigurators.addBinding().to(OpenShiftWorkspaceServiceAccountConfigurator.class);
namespaceConfigurators.addBinding().to(OpenShiftStopWorkspaceRoleConfigurator.class);
namespaceConfigurators.addBinding().to(SshKeysConfigurator.class);
namespaceConfigurators.addBinding().to(GitconfigUserDataConfigurator.class);
bind(AuthorizationChecker.class).to(OpenShiftAuthorizationCheckerImpl.class);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -88,6 +88,7 @@ import org.mockito.testng.MockitoTestNGListener;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Ignore;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
@ -679,6 +680,7 @@ public class OpenShiftProjectFactoryTest {
verify(serviceAccount).prepare();
}
@Ignore
@Test
public void testEvalNamespaceNameWhenPreparedNamespacesFound() throws InfrastructureException {
List<Project> projects =

View File

@ -94,10 +94,6 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-test</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.multiuser</groupId>
<artifactId>che-multiuser-api-organization-shared</artifactId>
@ -155,11 +151,6 @@
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db-vendor-h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-sql-schema</artifactId>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -20,7 +20,6 @@ import org.eclipse.che.multiuser.api.permission.server.account.AccountPermission
import org.eclipse.che.multiuser.api.permission.shared.model.PermissionsDomain;
import org.eclipse.che.multiuser.organization.api.listener.MemberEventsPublisher;
import org.eclipse.che.multiuser.organization.api.listener.OrganizationEventsWebsocketBroadcaster;
import org.eclipse.che.multiuser.organization.api.listener.RemoveOrganizationOnLastUserRemovedEventSubscriber;
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain;
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationPermissionsFilter;
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationRemoteSubscriptionPermissionsChecks;
@ -43,7 +42,6 @@ public class OrganizationApiModule extends AbstractModule {
bind(OrganizationPermissionsFilter.class);
bind(OrganizationRemoteSubscriptionPermissionsChecks.class);
bind(RemoveOrganizationOnLastUserRemovedEventSubscriber.class).asEagerSingleton();
Multibinder.newSetBinder(binder(), DefaultResourcesProvider.class)
.addBinding()

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -13,34 +13,15 @@ package org.eclipse.che.multiuser.organization.api;
import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.Multibinder;
import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain;
import org.eclipse.che.multiuser.api.permission.server.model.impl.AbstractPermissions;
import org.eclipse.che.multiuser.api.permission.server.spi.PermissionsDao;
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain;
import org.eclipse.che.multiuser.organization.spi.MemberDao;
import org.eclipse.che.multiuser.organization.spi.OrganizationDao;
import org.eclipse.che.multiuser.organization.spi.OrganizationDistributedResourcesDao;
import org.eclipse.che.multiuser.organization.spi.impl.MemberImpl;
import org.eclipse.che.multiuser.organization.spi.jpa.JpaMemberDao;
import org.eclipse.che.multiuser.organization.spi.jpa.JpaOrganizationDao;
import org.eclipse.che.multiuser.organization.spi.jpa.JpaOrganizationDistributedResourcesDao;
/** @author Sergii Leschenko */
public class OrganizationJpaModule extends AbstractModule {
@Override
protected void configure() {
bind(OrganizationDao.class).to(JpaOrganizationDao.class);
bind(MemberDao.class).to(JpaMemberDao.class);
bind(new TypeLiteral<AbstractPermissionsDomain<MemberImpl>>() {}).to(OrganizationDomain.class);
Multibinder.newSetBinder(
binder(), new TypeLiteral<PermissionsDao<? extends AbstractPermissions>>() {})
.addBinding()
.to(JpaMemberDao.class);
bind(OrganizationDistributedResourcesDao.class)
.to(JpaOrganizationDistributedResourcesDao.class);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -23,7 +23,6 @@ import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.eclipse.che.account.event.BeforeAccountRemovedEvent;
import org.eclipse.che.api.core.ApiException;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
@ -33,8 +32,6 @@ import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.lang.NameGenerator;
import org.eclipse.che.multiuser.organization.api.event.BeforeOrganizationRemovedEvent;
import org.eclipse.che.multiuser.organization.api.event.OrganizationPersistedEvent;
import org.eclipse.che.multiuser.organization.api.event.OrganizationRemovedEvent;
import org.eclipse.che.multiuser.organization.api.event.OrganizationRenamedEvent;
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain;
@ -102,7 +99,6 @@ public class OrganizationManager {
NameGenerator.generate("organization", 16), qualifiedName, newOrganization.getParent());
organizationDao.create(organization);
addFirstMember(organization);
eventService.publish(new OrganizationPersistedEvent(organization)).propagateException();
return organization;
}
@ -157,10 +153,6 @@ public class OrganizationManager {
requireNonNull(organizationId, "Required non-null organization id");
try {
OrganizationImpl organization = organizationDao.getById(organizationId);
eventService
.publish(new BeforeAccountRemovedEvent(organization.getAccount()))
.propagateException();
eventService.publish(new BeforeOrganizationRemovedEvent(organization)).propagateException();
removeSuborganizations(organizationId);
final List<String> members = removeMembers(organizationId);
organizationDao.remove(organizationId);

View File

@ -1,34 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.organization.api.event;
import org.eclipse.che.core.db.cascade.event.RemoveEvent;
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
/**
* Published before {@link OrganizationImpl organization} removed.
*
* @author Sergii Leschenko
*/
public class BeforeOrganizationRemovedEvent extends RemoveEvent {
private final OrganizationImpl organization;
public BeforeOrganizationRemovedEvent(OrganizationImpl organization) {
this.organization = organization;
}
/** Returns organization which is going to be removed. */
public OrganizationImpl getOrganization() {
return organization;
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.organization.api.event;
import org.eclipse.che.api.core.notification.EventOrigin;
import org.eclipse.che.core.db.cascade.event.PersistEvent;
import org.eclipse.che.multiuser.organization.shared.model.Organization;
/**
* Published after organization instance is persisted.
*
* @author Sergii Leschenko
*/
@EventOrigin("organization")
public class OrganizationPersistedEvent extends PersistEvent {
private final Organization organization;
public OrganizationPersistedEvent(Organization organization) {
this.organization = organization;
}
public Organization getOrganization() {
return organization;
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.organization.api.listener;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.multiuser.api.permission.server.jpa.listener.RemovePermissionsOnLastUserRemovedEventSubscriber;
import org.eclipse.che.multiuser.organization.api.OrganizationManager;
import org.eclipse.che.multiuser.organization.spi.jpa.JpaMemberDao;
/**
* Listens for {@link UserImpl} removal events, and checks if the removing user is the last who has
* "setPermissions" permission to particular organization, and if it is, then removes organization
* itself.
*
* @author Sergii Leschenko
*/
@Singleton
public class RemoveOrganizationOnLastUserRemovedEventSubscriber
extends RemovePermissionsOnLastUserRemovedEventSubscriber<JpaMemberDao> {
@Inject private OrganizationManager organizationManager;
@Override
public void remove(String instanceId) throws ServerException {
organizationManager.remove(instanceId);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -26,11 +26,8 @@ import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.commons.lang.concurrent.Unlocker;
import org.eclipse.che.core.db.cascade.CascadeEventSubscriber;
import org.eclipse.che.multiuser.organization.api.OrganizationManager;
import org.eclipse.che.multiuser.organization.api.event.BeforeOrganizationRemovedEvent;
import org.eclipse.che.multiuser.organization.shared.model.OrganizationDistributedResources;
import org.eclipse.che.multiuser.organization.spi.OrganizationDistributedResourcesDao;
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationDistributedResourcesImpl;
@ -70,13 +67,6 @@ public class OrganizationResourcesDistributor {
this.resourceAggregator = resourceAggregator;
}
@Inject
public void subscribe(EventService eventService) {
eventService.subscribe(
new RemoveOrganizationDistributedResourcesSubscriber(),
BeforeOrganizationRemovedEvent.class);
}
/**
* Cap usage of shared resources.
*
@ -224,14 +214,4 @@ public class OrganizationResourcesDistributor {
}
return parentOrganization;
}
class RemoveOrganizationDistributedResourcesSubscriber
extends CascadeEventSubscriber<BeforeOrganizationRemovedEvent> {
@Override
public void onCascadeEvent(BeforeOrganizationRemovedEvent event) throws ServerException {
if (event.getOrganization().getParent() != null) {
organizationDistributedResourcesDao.remove(event.getOrganization().getId());
}
}
}
}

View File

@ -1,204 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.organization.spi.jpa;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
import com.google.inject.persist.Transactional;
import java.io.IOException;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain;
import org.eclipse.che.multiuser.api.permission.server.jpa.AbstractJpaPermissionsDao;
import org.eclipse.che.multiuser.organization.spi.MemberDao;
import org.eclipse.che.multiuser.organization.spi.impl.MemberImpl;
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
/**
* JPA based implementation of {@link MemberDao}.
*
* @author Sergii Leschenko
*/
@Singleton
public class JpaMemberDao extends AbstractJpaPermissionsDao<MemberImpl> implements MemberDao {
@Inject
public JpaMemberDao(AbstractPermissionsDomain<MemberImpl> supportedDomain) throws IOException {
super(supportedDomain);
}
@Override
public MemberImpl get(String userId, String instanceId)
throws ServerException, NotFoundException {
return getMember(instanceId, userId);
}
@Override
public Page<MemberImpl> getByInstance(String instanceId, int maxItems, long skipCount)
throws ServerException {
return getMembers(instanceId, maxItems, skipCount);
}
@Override
public List<MemberImpl> getByUser(String userId) throws ServerException {
return getMemberships(userId);
}
@Override
public void remove(String userId, String organizationId) throws ServerException {
requireNonNull(organizationId, "Required non-null organization id");
requireNonNull(userId, "Required non-null user id");
try {
doRemove(organizationId, userId);
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
@Override
public MemberImpl getMember(String organizationId, String userId)
throws NotFoundException, ServerException {
requireNonNull(organizationId, "Required non-null organization id");
requireNonNull(userId, "Required non-null user id");
try {
return new MemberImpl(getEntity(wildcardToNull(userId), organizationId));
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
@Override
@Transactional
public Page<MemberImpl> getMembers(String organizationId, int maxItems, long skipCount)
throws ServerException {
requireNonNull(organizationId, "Required non-null organization id");
checkArgument(
skipCount <= Integer.MAX_VALUE,
"The number of items to skip can't be greater than " + Integer.MAX_VALUE);
try {
final EntityManager manager = managerProvider.get();
final List<MemberImpl> members =
manager
.createNamedQuery("Member.getByOrganization", MemberImpl.class)
.setParameter("organizationId", organizationId)
.setMaxResults(maxItems)
.setFirstResult((int) skipCount)
.getResultList()
.stream()
.map(MemberImpl::new)
.collect(toList());
final Long membersCount =
manager
.createNamedQuery("Member.getCountByOrganizationId", Long.class)
.setParameter("organizationId", organizationId)
.getSingleResult();
return new Page<>(members, skipCount, maxItems, membersCount);
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
@Override
@Transactional
public List<MemberImpl> getMemberships(String userId) throws ServerException {
requireNonNull(userId, "Required non-null user id");
try {
final EntityManager manager = managerProvider.get();
return manager
.createNamedQuery("Member.getByUser", MemberImpl.class)
.setParameter("userId", userId)
.getResultList()
.stream()
.map(MemberImpl::new)
.collect(toList());
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
@Override
@Transactional
public Page<OrganizationImpl> getOrganizations(String userId, int maxItems, long skipCount)
throws ServerException {
requireNonNull(userId, "Required non-null user id");
checkArgument(
skipCount <= Integer.MAX_VALUE,
"The number of items to skip can't be greater than " + Integer.MAX_VALUE);
try {
final EntityManager manager = managerProvider.get();
final List<OrganizationImpl> result =
manager
.createNamedQuery("Member.getOrganizations", OrganizationImpl.class)
.setParameter("userId", userId)
.setMaxResults(maxItems)
.setFirstResult((int) skipCount)
.getResultList();
final Long organizationsCount =
manager
.createNamedQuery("Member.getOrganizationsCount", Long.class)
.setParameter("userId", userId)
.getSingleResult();
return new Page<>(result, skipCount, maxItems, organizationsCount);
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
@Override
@Transactional
protected void doRemove(String organizationId, String userId) {
final EntityManager manager = managerProvider.get();
List<MemberImpl> members =
manager
.createNamedQuery("Member.getMember", MemberImpl.class)
.setParameter("userId", userId)
.setParameter("organizationId", organizationId)
.getResultList();
if (!members.isEmpty()) {
manager.remove(members.get(0));
manager.flush();
}
}
@Override
protected MemberImpl getEntity(String userId, String instanceId)
throws NotFoundException, ServerException {
try {
return doGet(userId, instanceId);
} catch (NoResultException e) {
throw new NotFoundException(
String.format(
"Membership of user %s in organization %s was not found", userId, instanceId));
} catch (RuntimeException e) {
throw new ServerException(e.getMessage(), e);
}
}
@Transactional
protected MemberImpl doGet(String userId, String instanceId) {
return managerProvider
.get()
.createNamedQuery("Member.getMember", MemberImpl.class)
.setParameter("userId", userId)
.setParameter("organizationId", instanceId)
.getSingleResult();
}
}

View File

@ -1,207 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.organization.spi.jpa;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import com.google.inject.persist.Transactional;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.core.db.jpa.DuplicateKeyException;
import org.eclipse.che.multiuser.organization.spi.OrganizationDao;
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
/**
* JPA based implementation of {@link OrganizationDao}.
*
* @author Sergii Leschenko
*/
@Singleton
public class JpaOrganizationDao implements OrganizationDao {
private final Provider<EntityManager> managerProvider;
@Inject
public JpaOrganizationDao(Provider<EntityManager> managerProvider) {
this.managerProvider = managerProvider;
}
@Override
public void create(OrganizationImpl organization) throws ServerException, ConflictException {
requireNonNull(organization, "Required non-null organization");
try {
doCreate(organization);
} catch (DuplicateKeyException e) {
throw new ConflictException("Organization with such id or name already exists");
} catch (RuntimeException x) {
throw new ServerException(x.getLocalizedMessage(), x);
}
}
@Override
public void update(OrganizationImpl update)
throws NotFoundException, ConflictException, ServerException {
requireNonNull(update, "Required non-null organization");
try {
doUpdate(update);
} catch (DuplicateKeyException e) {
throw new ConflictException("Organization with such name already exists");
} catch (RuntimeException x) {
throw new ServerException(x.getLocalizedMessage(), x);
}
}
@Override
public void remove(String organizationId) throws ServerException {
requireNonNull(organizationId, "Required non-null organization id");
try {
doRemove(organizationId);
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
@Override
@Transactional
public OrganizationImpl getById(String organizationId) throws NotFoundException, ServerException {
requireNonNull(organizationId, "Required non-null organization id");
try {
final EntityManager manager = managerProvider.get();
OrganizationImpl organization = manager.find(OrganizationImpl.class, organizationId);
if (organization == null) {
throw new NotFoundException(
format("Organization with id '%s' doesn't exist", organizationId));
}
return organization;
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
@Override
@Transactional
public OrganizationImpl getByName(String organizationName)
throws NotFoundException, ServerException {
requireNonNull(organizationName, "Required non-null organization name");
try {
final EntityManager manager = managerProvider.get();
return manager
.createNamedQuery("Organization.getByName", OrganizationImpl.class)
.setParameter("name", organizationName)
.getSingleResult();
} catch (NoResultException e) {
throw new NotFoundException(
format("Organization with name '%s' doesn't exist", organizationName));
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
@Override
@Transactional
public Page<OrganizationImpl> getByParent(String parent, int maxItems, long skipCount)
throws ServerException {
requireNonNull(parent, "Required non-null parent");
checkArgument(
skipCount <= Integer.MAX_VALUE,
"The number of items to skip can't be greater than " + Integer.MAX_VALUE);
try {
final EntityManager manager = managerProvider.get();
final List<OrganizationImpl> result =
manager
.createNamedQuery("Organization.getByParent", OrganizationImpl.class)
.setParameter("parent", parent)
.setMaxResults(maxItems)
.setFirstResult((int) skipCount)
.getResultList();
final Long suborganizationsCount =
manager
.createNamedQuery("Organization.getByParentCount", Long.class)
.setParameter("parent", parent)
.getSingleResult();
return new Page<>(result, skipCount, maxItems, suborganizationsCount);
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
@Override
@Transactional
public Page<OrganizationImpl> getSuborganizations(
String parentQualifiedName, int maxItems, long skipCount) throws ServerException {
requireNonNull(parentQualifiedName, "Required non-null parent qualified name");
checkArgument(
skipCount <= Integer.MAX_VALUE,
"The number of items to skip can't be greater than " + Integer.MAX_VALUE);
try {
final EntityManager manager = managerProvider.get();
List<OrganizationImpl> result =
manager
.createNamedQuery("Organization.getSuborganizations", OrganizationImpl.class)
.setParameter("qualifiedName", parentQualifiedName + "/%")
.setMaxResults(maxItems)
.setFirstResult((int) skipCount)
.getResultList();
final long suborganizationsCount =
manager
.createNamedQuery("Organization.getSuborganizationsCount", Long.class)
.setParameter("qualifiedName", parentQualifiedName + "/%")
.getSingleResult();
return new Page<>(result, skipCount, maxItems, suborganizationsCount);
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
@Transactional
protected void doCreate(OrganizationImpl organization) {
EntityManager manager = managerProvider.get();
manager.persist(organization);
manager.flush();
}
@Transactional
protected void doUpdate(OrganizationImpl update) throws NotFoundException {
final EntityManager manager = managerProvider.get();
if (manager.find(OrganizationImpl.class, update.getId()) == null) {
throw new NotFoundException(
format(
"Couldn't update organization with id '%s' because it doesn't exist",
update.getId()));
}
manager.merge(update);
manager.flush();
}
@Transactional
protected void doRemove(String organizationId) {
final EntityManager manager = managerProvider.get();
final OrganizationImpl organization = manager.find(OrganizationImpl.class, organizationId);
if (organization != null) {
manager.remove(organization);
manager.flush();
}
}
}

View File

@ -1,143 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.organization.spi.jpa;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import com.google.inject.persist.Transactional;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.multiuser.organization.spi.OrganizationDistributedResourcesDao;
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationDistributedResourcesImpl;
/**
* JPA based implementation of {@link OrganizationDistributedResourcesDao}.
*
* @author Sergii Leschenko
*/
@Singleton
public class JpaOrganizationDistributedResourcesDao implements OrganizationDistributedResourcesDao {
@Inject private Provider<EntityManager> managerProvider;
@Override
public void store(OrganizationDistributedResourcesImpl distributedResources)
throws ServerException {
requireNonNull(distributedResources, "Required non-null distributed resources");
try {
doStore(distributedResources);
} catch (RuntimeException e) {
throw new ServerException(e.getMessage(), e);
}
}
@Override
@Transactional
public OrganizationDistributedResourcesImpl get(String organizationId)
throws NotFoundException, ServerException {
requireNonNull(organizationId, "Required non-null organization id");
try {
OrganizationDistributedResourcesImpl distributedResources =
managerProvider.get().find(OrganizationDistributedResourcesImpl.class, organizationId);
if (distributedResources == null) {
throw new NotFoundException(
"There are no distributed resources for organization with id '"
+ organizationId
+ "'.");
}
return new OrganizationDistributedResourcesImpl(distributedResources);
} catch (RuntimeException e) {
throw new ServerException(e.getMessage(), e);
}
}
@Override
@Transactional
public Page<OrganizationDistributedResourcesImpl> getByParent(
String organizationId, int maxItems, long skipCount) throws ServerException {
requireNonNull(organizationId, "Required non-null organization id");
checkArgument(
skipCount <= Integer.MAX_VALUE,
"The number of items to skip can't be greater than " + Integer.MAX_VALUE);
try {
final EntityManager manager = managerProvider.get();
final List<OrganizationDistributedResourcesImpl> distributedResources =
manager
.createNamedQuery(
"OrganizationDistributedResources.getByParent",
OrganizationDistributedResourcesImpl.class)
.setParameter("parent", organizationId)
.setMaxResults(maxItems)
.setFirstResult((int) skipCount)
.getResultList();
final Long distributedResourcesCount =
manager
.createNamedQuery("OrganizationDistributedResources.getCountByParent", Long.class)
.setParameter("parent", organizationId)
.getSingleResult();
return new Page<>(
distributedResources.stream()
.map(OrganizationDistributedResourcesImpl::new)
.collect(Collectors.toList()),
skipCount,
maxItems,
distributedResourcesCount);
} catch (RuntimeException e) {
throw new ServerException(e.getMessage(), e);
}
}
@Override
public void remove(String organizationId) throws ServerException {
requireNonNull(organizationId, "Required non-null organization id");
try {
doRemove(organizationId);
} catch (RuntimeException e) {
throw new ServerException(e.getMessage(), e);
}
}
@Transactional
protected void doRemove(String id) {
EntityManager manager = managerProvider.get();
OrganizationDistributedResourcesImpl distributedResources =
manager.find(OrganizationDistributedResourcesImpl.class, id);
if (distributedResources != null) {
manager.remove(distributedResources);
manager.flush();
}
}
@Transactional
protected void doStore(OrganizationDistributedResourcesImpl distributedResources)
throws ServerException {
EntityManager manager = managerProvider.get();
final OrganizationDistributedResourcesImpl existingDistributedResources =
manager.find(
OrganizationDistributedResourcesImpl.class, distributedResources.getOrganizationId());
if (existingDistributedResources == null) {
manager.persist(distributedResources);
} else {
existingDistributedResources.getResourcesCap().clear();
existingDistributedResources.getResourcesCap().addAll(distributedResources.getResourcesCap());
}
manager.flush();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -15,7 +15,6 @@ import static java.util.Collections.singletonList;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
@ -33,7 +32,6 @@ import static org.testng.Assert.assertNotNull;
import java.util.Collections;
import java.util.List;
import org.eclipse.che.account.event.BeforeAccountRemovedEvent;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
@ -41,8 +39,6 @@ import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.subject.SubjectImpl;
import org.eclipse.che.dto.server.DtoFactory;
import org.eclipse.che.multiuser.organization.api.event.BeforeOrganizationRemovedEvent;
import org.eclipse.che.multiuser.organization.api.event.OrganizationPersistedEvent;
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain;
import org.eclipse.che.multiuser.organization.shared.dto.OrganizationDto;
import org.eclipse.che.multiuser.organization.shared.model.Member;
@ -69,7 +65,6 @@ import org.testng.annotations.Test;
@Listeners(MockitoTestNGListener.class)
public class OrganizationManagerTest {
@Captor private ArgumentCaptor<OrganizationImpl> organizationCaptor;
@Captor private ArgumentCaptor<OrganizationPersistedEvent> persistEventCaptor;
private static final String USER_NAME = "user-name";
private static final String USER_ID = "user-id";
@ -113,8 +108,6 @@ public class OrganizationManagerTest {
assertEquals(createdOrganization.getName(), toCreate.getName());
assertEquals(createdOrganization.getQualifiedName(), toCreate.getName());
assertEquals(createdOrganization.getParent(), toCreate.getParent());
verify(eventService).publish(persistEventCaptor.capture());
assertEquals(persistEventCaptor.getValue().getOrganization(), createdOrganization);
verify(memberDao)
.store(
new MemberImpl(USER_ID, createdOrganization.getId(), OrganizationDomain.getActions()));
@ -135,8 +128,6 @@ public class OrganizationManagerTest {
createdOrganization.getQualifiedName(),
parentOrganization.getQualifiedName() + "/" + toCreate.getName());
assertEquals(createdOrganization.getParent(), toCreate.getParent());
verify(eventService).publish(persistEventCaptor.capture());
assertEquals(persistEventCaptor.getValue().getOrganization(), createdOrganization);
verify(memberDao)
.store(
new MemberImpl(USER_ID, createdOrganization.getId(), OrganizationDomain.getActions()));
@ -228,22 +219,12 @@ public class OrganizationManagerTest {
doReturn(members).when(manager).removeMembers(anyString());
OrganizationImpl toRemove = new OrganizationImpl("org123", "toRemove", null);
when(organizationDao.getById(anyString())).thenReturn(toRemove);
BeforeAccountRemovedEvent beforeAccountRemovedEvent = mock(BeforeAccountRemovedEvent.class);
BeforeOrganizationRemovedEvent beforeOrganizationRemovedEvent =
mock(BeforeOrganizationRemovedEvent.class);
doReturn(beforeAccountRemovedEvent)
.doReturn(beforeOrganizationRemovedEvent)
.when(eventService)
.publish(any());
manager.remove(toRemove.getId());
verify(organizationDao).remove(toRemove.getId());
verify(manager).removeMembers(eq(toRemove.getId()));
verify(manager).removeSuborganizations(eq(toRemove.getId()));
verify(eventService, times(3)).publish(anyObject());
verify(beforeAccountRemovedEvent).propagateException();
verify(beforeOrganizationRemovedEvent).propagateException();
}
@Test

View File

@ -1,75 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.organization.api.resource;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.eclipse.che.multiuser.organization.api.event.BeforeOrganizationRemovedEvent;
import org.eclipse.che.multiuser.organization.spi.OrganizationDistributedResourcesDao;
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests for {@link
* org.eclipse.che.multiuser.organization.api.resource.OrganizationResourcesDistributor.RemoveOrganizationDistributedResourcesSubscriber}
*
* @author Sergii Leschenko
*/
@Listeners(MockitoTestNGListener.class)
public class RemoveOrganizationDistributedResourcesSubscriberTest {
@Mock private OrganizationImpl organization;
@Mock private OrganizationDistributedResourcesDao organizationDistributedResourcesDao;
@InjectMocks private OrganizationResourcesDistributor organizationResourcesDistributor;
private OrganizationResourcesDistributor.RemoveOrganizationDistributedResourcesSubscriber
suborganizationsRemover;
@BeforeMethod
public void setUp() throws Exception {
suborganizationsRemover =
organizationResourcesDistributor.new RemoveOrganizationDistributedResourcesSubscriber();
}
@Test
public void shouldResetResourcesDistributionBeforeSuborganizationRemoving() throws Exception {
// given
when(organization.getId()).thenReturn("suborg123");
when(organization.getParent()).thenReturn("org123");
// when
suborganizationsRemover.onEvent(new BeforeOrganizationRemovedEvent(organization));
// then
verify(organizationDistributedResourcesDao).remove("suborg123");
}
@Test
public void shouldNotResetResourcesDistributionBeforeRootOrganizationRemoving() throws Exception {
// given
lenient().when(organization.getId()).thenReturn("org123");
when(organization.getParent()).thenReturn(null);
// when
suborganizationsRemover.onEvent(new BeforeOrganizationRemovedEvent(organization));
// then
verify(organizationDistributedResourcesDao, never()).remove("org123");
}
}

View File

@ -1,262 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.organization.spi.tck;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.Inject;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.commons.test.tck.TckListener;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
import org.eclipse.che.commons.test.tck.repository.TckRepositoryException;
import org.eclipse.che.multiuser.organization.spi.MemberDao;
import org.eclipse.che.multiuser.organization.spi.impl.MemberImpl;
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
import org.mockito.Mock;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests {@link MemberDao} contract.
*
* @author Sergii Leschenko
*/
@Listeners(TckListener.class)
@Test(suiteName = MemberDaoTest.SUITE_NAME)
public class MemberDaoTest {
public static final String SUITE_NAME = "MemberDaoTck";
private MemberImpl[] members;
private OrganizationImpl[] orgs;
private UserImpl[] users;
@Mock private EventService eventService;
@Inject private MemberDao memberDao;
@Inject private TckRepository<MemberImpl> memberRepo;
@Inject private TckRepository<UserImpl> userRepo;
@Inject private TckRepository<OrganizationImpl> organizationRepo;
@BeforeMethod
private void setUp() throws TckRepositoryException {
users = new UserImpl[3];
users[0] = new UserImpl("user1-id", "user1@test.com", "user1-name");
users[1] = new UserImpl("user2-id", "user2@test.com", "user2-name");
users[2] = new UserImpl("user3-id", "user3@test.com", "user3-name");
userRepo.createAll(asList(users));
orgs = new OrganizationImpl[3];
orgs[0] = new OrganizationImpl("org1-id", "org1-name", null);
orgs[1] = new OrganizationImpl("org2-id", "org2-name", null);
orgs[2] = new OrganizationImpl("org3-id", "org3-name", null);
organizationRepo.createAll(asList(orgs));
members = new MemberImpl[5];
members[0] = new MemberImpl(users[0].getId(), orgs[0].getId(), asList("read", "update"));
members[1] = new MemberImpl(users[1].getId(), orgs[0].getId(), asList("read", "update"));
members[2] = new MemberImpl(users[2].getId(), orgs[0].getId(), asList("read", "update"));
members[3] = new MemberImpl(users[1].getId(), orgs[1].getId(), asList("read", "update"));
members[4] = new MemberImpl(users[1].getId(), orgs[2].getId(), asList("read", "update"));
memberRepo.createAll(Stream.of(members).map(MemberImpl::new).collect(Collectors.toList()));
}
@AfterMethod
private void cleanup() throws TckRepositoryException {
memberRepo.removeAll();
userRepo.removeAll();
organizationRepo.removeAll();
}
@Test(dependsOnMethods = {"shouldGetMember", "shouldRemoveMember"})
public void shouldCreateNewMemberOnMemberStoring() throws Exception {
final MemberImpl member = members[0];
memberDao.remove(member.getUserId(), member.getOrganizationId());
memberDao.store(member);
assertEquals(
memberDao.getMember(member.getOrganizationId(), member.getUserId()),
new MemberImpl(member));
}
@Test(dependsOnMethods = {"shouldGetMember"})
public void shouldUpdateMemberOnMemberStoring() throws Exception {
final MemberImpl member =
new MemberImpl(
members[0].getUserId(), members[0].getOrganizationId(), asList("read", "remove"));
memberDao.store(member);
assertEquals(member, memberDao.getMember(member.getOrganizationId(), member.getUserId()));
}
@Test(expectedExceptions = ServerException.class)
public void shouldThrowServerExceptionOnStoringMemberForNonExistenceUser() throws Exception {
final MemberImpl toCreate =
new MemberImpl("non-existence", members[0].getOrganizationId(), singletonList("read"));
memberDao.store(toCreate);
}
@Test(expectedExceptions = ServerException.class)
public void shouldThrowServerExceptionOnStoringMemberForNonExistenceOrganization()
throws Exception {
final MemberImpl toCreate =
new MemberImpl(members[0].getUserId(), "non-existence", singletonList("read"));
memberDao.store(toCreate);
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnStoringNullableMember() throws Exception {
memberDao.store(null);
}
@Test(
expectedExceptions = NotFoundException.class,
dependsOnMethods = "shouldThrowNotFoundExceptionOnGettingNonExistingMember")
public void shouldRemoveMember() throws Exception {
final MemberImpl member = members[0];
memberDao.remove(member.getOrganizationId(), member.getUserId());
memberDao.getMember(member.getUserId(), member.getOrganizationId());
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnRemovingMemberByNullUser() throws Exception {
memberDao.remove("organization1234567", null);
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnRemovingMemberByNullOrganization() throws Exception {
memberDao.remove(null, "user1234567");
}
@Test
public void shouldNotThrowAnyExceptionOnRemovingNonExistingMember() throws Exception {
memberDao.remove("organization12345", "user12345");
}
@Test
public void shouldGetMember() throws Exception {
final MemberImpl existedMember = members[0];
final MemberImpl fetchedMember =
memberDao.getMember(existedMember.getOrganizationId(), existedMember.getUserId());
assertEquals(existedMember, fetchedMember);
}
@Test(expectedExceptions = NotFoundException.class)
public void shouldThrowNotFoundExceptionOnGettingNonExistingMember() throws Exception {
memberDao.getMember("org12345678", "user12345678");
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnGettingMemberByNullOrganization() throws Exception {
memberDao.getMember(null, "user1234567");
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnGettingMemberByNullUser() throws Exception {
memberDao.getMember("organization12345", null);
}
@Test
public void shouldGetMembersByOrganization() throws Exception {
final Page<MemberImpl> membersPage = memberDao.getMembers(members[0].getOrganizationId(), 1, 1);
final List<MemberImpl> fetchedMembers = membersPage.getItems();
assertEquals(membersPage.getTotalItemsCount(), 3);
assertEquals(membersPage.getItemsCount(), 1);
assertTrue(
fetchedMembers.contains(members[0])
^ fetchedMembers.contains(members[1])
^ fetchedMembers.contains(members[2]));
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnGettingMembersByNullOrganization() throws Exception {
memberDao.getMembers(null, 1, 0);
}
@Test
public void shouldReturnEmptyListIfThereAreNotAnyMembersForSpecifiedOrganization()
throws Exception {
final Page<MemberImpl> fetchedMembers = memberDao.getMembers("organization1234567", 30, 0);
assertTrue(fetchedMembers.isEmpty());
assertEquals(fetchedMembers.getTotalItemsCount(), 0);
}
@Test
public void shouldGetMembershipsByUser() throws Exception {
final List<MemberImpl> fetchedMembers = memberDao.getMemberships(members[0].getUserId());
assertEquals(fetchedMembers.size(), 1);
assertEquals(fetchedMembers.get(0), members[0]);
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnGettingMembershipsByNullUser() throws Exception {
memberDao.getMemberships(null);
}
@Test
public void shouldReturnEmptyListIfThereAreNotAnyMembershipsForSpecifiedUser() throws Exception {
final List<MemberImpl> fetchedMembers = memberDao.getMemberships("user1234567");
assertTrue(fetchedMembers.isEmpty());
}
@Test
public void shouldGetOrganizationsByUser() throws Exception {
final Page<OrganizationImpl> fetchedMembers =
memberDao.getOrganizations(members[1].getUserId(), 1, 1);
assertEquals(fetchedMembers.getItemsCount(), 1);
assertEquals(fetchedMembers.getTotalItemsCount(), 3);
assertTrue(
fetchedMembers.getItems().contains(orgs[0])
^ fetchedMembers.getItems().contains(orgs[1])
^ fetchedMembers.getItems().contains(orgs[2]));
}
@Test
public void shouldReturnEmptyListIfThereAreNotAnyOrganizationsForSpecifiedUser()
throws Exception {
final Page<OrganizationImpl> organizations = memberDao.getOrganizations("user1234567", 30, 0);
assertTrue(organizations.isEmpty());
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnGettingOrganizationByNullUserId() throws Exception {
memberDao.getOrganizations(null, 30, 0);
}
}

View File

@ -1,261 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.organization.spi.tck;
import static java.util.Arrays.asList;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.Pages;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.commons.lang.NameGenerator;
import org.eclipse.che.commons.test.tck.TckListener;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
import org.eclipse.che.commons.test.tck.repository.TckRepositoryException;
import org.eclipse.che.multiuser.organization.spi.OrganizationDao;
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests {@link OrganizationDao} contract.
*
* @author Sergii Leschenko
*/
@Listeners(TckListener.class)
@Test(suiteName = OrganizationDaoTest.SUITE_NAME)
public class OrganizationDaoTest {
public static final String SUITE_NAME = "OrganizationDaoTck";
private OrganizationImpl[] organizations;
@Inject private OrganizationDao organizationDao;
@Inject private EventService eventService;
@Inject private TckRepository<OrganizationImpl> tckRepository;
@BeforeMethod
private void setUp() throws TckRepositoryException {
organizations = new OrganizationImpl[2];
organizations[0] =
new OrganizationImpl(NameGenerator.generate("organization", 10), "test1", null);
organizations[1] =
new OrganizationImpl(NameGenerator.generate("organization", 10), "test2", null);
tckRepository.createAll(asList(organizations));
}
@AfterMethod
private void cleanup() throws TckRepositoryException {
tckRepository.removeAll();
}
@Test
public void shouldCreateOrganization() throws Exception {
final OrganizationImpl organization = new OrganizationImpl("organization123", "Test", null);
organizationDao.create(organization);
assertEquals(organizationDao.getById(organization.getId()), organization);
}
@Test(expectedExceptions = ConflictException.class)
public void shouldThrowConflictExceptionOnCreatingOrganizationWithExistingId() throws Exception {
final OrganizationImpl organization =
new OrganizationImpl(organizations[0].getId(), "Test", null);
organizationDao.create(organization);
assertEquals(organizationDao.getById(organization.getId()), organization);
}
@Test(expectedExceptions = ConflictException.class)
public void shouldThrowConflictExceptionOnCreatingOrganizationWithExistingName()
throws Exception {
final OrganizationImpl organization =
new OrganizationImpl("organization123", organizations[0].getName(), null);
organizationDao.create(organization);
assertEquals(organizationDao.getById(organization.getId()), organization);
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnCreatingNullableOrganization() throws Exception {
organizationDao.create(null);
}
@Test
public void shouldUpdateOrganization() throws Exception {
final OrganizationImpl toUpdate =
new OrganizationImpl(organizations[0].getId(), "new-name", null);
organizationDao.update(toUpdate);
final OrganizationImpl updated = organizationDao.getById(toUpdate.getId());
assertEquals(toUpdate, updated);
}
@Test(expectedExceptions = NotFoundException.class)
public void shouldThrowNotFoundExceptionOnUpdatingNonExistingOrganization() throws Exception {
final OrganizationImpl toUpdate =
new OrganizationImpl("non-existing-id", "new-name", "new-parent");
organizationDao.update(toUpdate);
}
@Test(expectedExceptions = ConflictException.class)
public void shouldThrowConflictExceptionOnUpdatingOrganizationNameToExistingOne()
throws Exception {
final OrganizationImpl toUpdate =
new OrganizationImpl(organizations[0].getId(), organizations[1].getName(), "new-parent");
organizationDao.update(toUpdate);
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnUpdatingNullableOrganization() throws Exception {
organizationDao.update(null);
}
@Test(dependsOnMethods = "shouldThrowNotFoundExceptionOnGettingNonExistingOrganizationById")
public void shouldRemoveOrganization() throws Exception {
// given
final OrganizationImpl organization = organizations[0];
// when
organizationDao.remove(organization.getId());
// then
assertNull(notFoundToNull(() -> organizationDao.getById(organization.getId())));
}
@Test
public void shouldNotThrowAnyExceptionOnRemovingNonExistingOrganization() throws Exception {
organizationDao.remove("non-existing-org");
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeWhenRemovingNull() throws Exception {
organizationDao.remove(null);
}
@Test
public void shouldGetOrganizationById() throws Exception {
final OrganizationImpl organization = organizations[0];
final OrganizationImpl found = organizationDao.getById(organization.getId());
assertEquals(organization, found);
}
@Test(expectedExceptions = NotFoundException.class)
public void shouldThrowNotFoundExceptionOnGettingNonExistingOrganizationById() throws Exception {
organizationDao.getById("non-existing-org");
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnGettingOrganizationByNullId() throws Exception {
organizationDao.getById(null);
}
@Test
public void shouldGetOrganizationByName() throws Exception {
final OrganizationImpl organization = organizations[0];
final OrganizationImpl found = organizationDao.getByName(organization.getName());
assertEquals(organization, found);
}
@Test(expectedExceptions = NotFoundException.class)
public void shouldThrowNotFoundExceptionOnGettingNonExistingOrganizationByName()
throws Exception {
organizationDao.getByName("non-existing-org");
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnGettingOrganizationByNullName() throws Exception {
organizationDao.getByName(null);
}
@Test
public void shouldGetByParent() throws Exception {
final OrganizationImpl parent = organizations[0];
final OrganizationImpl child1 = new OrganizationImpl("child1", "childTest1", parent.getId());
final OrganizationImpl child2 = new OrganizationImpl("child2", "childTest2", parent.getId());
final OrganizationImpl child3 = new OrganizationImpl("child3", "childTest3", parent.getId());
tckRepository.createAll(asList(child1, child2, child3));
final Page<OrganizationImpl> children = organizationDao.getByParent(parent.getId(), 1, 1);
assertEquals(children.getTotalItemsCount(), 3);
assertEquals(children.getItemsCount(), 1);
assertTrue(
children.getItems().contains(child1)
^ children.getItems().contains(child2)
^ children.getItems().contains(child3));
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnGettingChildrenByNullableParentId() throws Exception {
organizationDao.getByParent(null, 30, 0);
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnGettingSuborganizationsByNullQualifiedName() throws Exception {
organizationDao.getSuborganizations(null, 30, 0);
}
@Test
public void shouldGetSuborganizations() throws Exception {
final OrganizationImpl parent = organizations[0];
final OrganizationImpl child1 =
new OrganizationImpl("child1", parent.getQualifiedName() + "/childTest1", parent.getId());
final OrganizationImpl child2 =
new OrganizationImpl("child2", child1.getQualifiedName() + "/childTest2", child1.getId());
final OrganizationImpl child3 =
new OrganizationImpl("child3", parent.getQualifiedName() + "/childTest3", parent.getId());
tckRepository.createAll(asList(child1, child2, child3));
final List<OrganizationImpl> suborganizations =
Pages.stream(
(maxItems, skipCount) ->
organizationDao.getSuborganizations(
parent.getQualifiedName(), maxItems, skipCount),
1)
.collect(Collectors.toList());
assertEquals(suborganizations.size(), 3);
}
private static <T> T notFoundToNull(Callable<T> action) throws Exception {
try {
return action.call();
} catch (NotFoundException x) {
return null;
}
}
}

View File

@ -1,185 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.organization.spi.tck;
import static java.util.Collections.singletonList;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collections;
import javax.inject.Inject;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.commons.test.tck.TckListener;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
import org.eclipse.che.multiuser.organization.spi.OrganizationDistributedResourcesDao;
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationDistributedResourcesImpl;
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests for {@link OrganizationDistributedResourcesDao}
*
* @author Sergii Leschenko
*/
@Listeners(TckListener.class)
@Test(suiteName = OrganizationDistributedResourcesDaoTest.SUITE_NAME)
public class OrganizationDistributedResourcesDaoTest {
public static final String SUITE_NAME = "OrganizationDistributedResourcesDaoTck";
private static final String TEST_RESOURCE_TYPE = "Test";
private static final int ORGANIZATION_RESOURCES_COUNT = 3;
private OrganizationDistributedResourcesImpl[] distributedResources;
private OrganizationImpl parentOrganization;
private OrganizationImpl[] suborganizations;
@Inject
private TckRepository<OrganizationDistributedResourcesImpl> distributedResourcesRepository;
@Inject private TckRepository<OrganizationImpl> organizationsRepository;
@Inject private OrganizationDistributedResourcesDao distributedResourcesDao;
@BeforeMethod
private void setUp() throws Exception {
parentOrganization = new OrganizationImpl("parentOrg", "parentOrgName", null);
suborganizations = new OrganizationImpl[ORGANIZATION_RESOURCES_COUNT];
distributedResources = new OrganizationDistributedResourcesImpl[ORGANIZATION_RESOURCES_COUNT];
for (int i = 0; i < ORGANIZATION_RESOURCES_COUNT; i++) {
suborganizations[i] =
new OrganizationImpl("suborgId-" + i, "suborgName" + i, parentOrganization.getId());
distributedResources[i] =
new OrganizationDistributedResourcesImpl(
suborganizations[i].getId(),
singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, i, "test")));
}
organizationsRepository.createAll(Collections.singletonList(parentOrganization));
organizationsRepository.createAll(Arrays.asList(suborganizations));
distributedResourcesRepository.createAll(Arrays.asList(distributedResources));
}
@AfterMethod
private void cleanup() throws Exception {
distributedResourcesRepository.removeAll();
organizationsRepository.removeAll();
}
@Test
public void shouldCreateDistributedResourcesWhenStoringNotExistentOne() throws Exception {
// given
OrganizationDistributedResourcesImpl toStore = distributedResources[0];
distributedResourcesDao.remove(toStore.getOrganizationId());
// when
distributedResourcesDao.store(toStore);
// then
assertEquals(distributedResourcesDao.get(toStore.getOrganizationId()), copy(toStore));
}
@Test
public void shouldUpdateDistributedResourcesWhenStoringExistentOne() throws Exception {
// given
OrganizationDistributedResourcesImpl toStore =
new OrganizationDistributedResourcesImpl(
distributedResources[0].getOrganizationId(),
singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, 1000, "unit")));
// when
distributedResourcesDao.store(toStore);
// then
assertEquals(distributedResourcesDao.get(toStore.getOrganizationId()), copy(toStore));
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeWhenStoringNullableDistributedResources() throws Exception {
// when
distributedResourcesDao.store(null);
}
@Test
public void shouldGetDistributedResourcesForSpecifiedOrganizationId() throws Exception {
// given
OrganizationDistributedResourcesImpl stored = distributedResources[0];
// when
OrganizationDistributedResourcesImpl fetched =
distributedResourcesDao.get(stored.getOrganizationId());
// then
assertEquals(fetched, copy(stored));
}
@Test(expectedExceptions = NotFoundException.class)
public void shouldThrowNotFoundExceptionWhenGettingNonExistingDistributedResources()
throws Exception {
// when
distributedResourcesDao.get("account123");
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeWhenGettingDistributedResourcesByNullOrganizationId() throws Exception {
// when
distributedResourcesDao.get(null);
}
@Test
public void shouldGetDistributedResourcesByParent() throws Exception {
// when
final Page<OrganizationDistributedResourcesImpl> children =
distributedResourcesDao.getByParent(parentOrganization.getId(), 1, 1);
// then
assertEquals(children.getTotalItemsCount(), 3);
assertEquals(children.getItemsCount(), 1);
assertTrue(
children.getItems().contains(copy(distributedResources[0]))
^ children.getItems().contains(copy(distributedResources[1]))
^ children.getItems().contains(copy(distributedResources[2])));
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeWhenGettingDistributedResourcesByNullParentId() throws Exception {
// when
distributedResourcesDao.getByParent(null, 1, 1);
}
@Test(expectedExceptions = NotFoundException.class)
public void shouldRemoveDistributedResources() throws Exception {
// given
OrganizationDistributedResourcesImpl distributedResource = distributedResources[0];
// when
distributedResourcesDao.remove(distributedResource.getOrganizationId());
// then
distributedResourcesDao.get(distributedResource.getOrganizationId());
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeWhenRemovingDistributedResourcesByNullId() throws Exception {
// when
distributedResourcesDao.remove(null);
}
private OrganizationDistributedResourcesImpl copy(
OrganizationDistributedResourcesImpl distributedResource) {
return new OrganizationDistributedResourcesImpl(distributedResource);
}
}

View File

@ -1,68 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.organization.spi.tck.jpa;
import com.google.inject.TypeLiteral;
import com.google.inject.persist.jpa.JpaPersistModule;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.commons.test.db.H2DBTestServer;
import org.eclipse.che.commons.test.db.H2JpaCleaner;
import org.eclipse.che.commons.test.tck.TckModule;
import org.eclipse.che.commons.test.tck.TckResourcesCleaner;
import org.eclipse.che.commons.test.tck.repository.JpaTckRepository;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
import org.eclipse.che.core.db.DBInitializer;
import org.eclipse.che.core.db.schema.SchemaInitializer;
import org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer;
import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain;
import org.eclipse.che.multiuser.organization.api.permissions.OrganizationDomain;
import org.eclipse.che.multiuser.organization.spi.MemberDao;
import org.eclipse.che.multiuser.organization.spi.OrganizationDao;
import org.eclipse.che.multiuser.organization.spi.OrganizationDistributedResourcesDao;
import org.eclipse.che.multiuser.organization.spi.impl.MemberImpl;
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationDistributedResourcesImpl;
import org.eclipse.che.multiuser.organization.spi.impl.OrganizationImpl;
import org.eclipse.che.multiuser.organization.spi.jpa.JpaMemberDao;
import org.eclipse.che.multiuser.organization.spi.jpa.JpaOrganizationDao;
import org.eclipse.che.multiuser.organization.spi.jpa.JpaOrganizationDistributedResourcesDao;
import org.eclipse.che.multiuser.organization.spi.jpa.JpaOrganizationImplTckRepository;
/** @author Sergii Leschenko */
public class OrganizationJpaTckModule extends TckModule {
@Override
protected void configure() {
install(new JpaPersistModule("main"));
H2DBTestServer server = H2DBTestServer.startDefault();
bind(SchemaInitializer.class)
.toInstance(new FlywaySchemaInitializer(server.getDataSource(), "che-schema"));
bind(DBInitializer.class).asEagerSingleton();
bind(TckResourcesCleaner.class).toInstance(new H2JpaCleaner(server));
bind(new TypeLiteral<AbstractPermissionsDomain<MemberImpl>>() {}).to(OrganizationDomain.class);
bind(new TypeLiteral<TckRepository<OrganizationImpl>>() {})
.to(JpaOrganizationImplTckRepository.class);
bind(new TypeLiteral<TckRepository<UserImpl>>() {})
.toInstance(new JpaTckRepository<>(UserImpl.class));
bind(new TypeLiteral<TckRepository<MemberImpl>>() {})
.toInstance(new JpaTckRepository<>(MemberImpl.class));
bind(new TypeLiteral<TckRepository<OrganizationDistributedResourcesImpl>>() {})
.toInstance(new JpaTckRepository<>(OrganizationDistributedResourcesImpl.class));
bind(OrganizationDao.class).to(JpaOrganizationDao.class);
bind(MemberDao.class).to(JpaMemberDao.class);
bind(OrganizationDistributedResourcesDao.class)
.to(JpaOrganizationDistributedResourcesDao.class);
}
}

View File

@ -42,10 +42,6 @@
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations-jakarta</artifactId>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
@ -62,10 +58,6 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-dto</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-model</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-user</artifactId>
@ -82,10 +74,6 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-test</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.multiuser</groupId>
<artifactId>che-multiuser-api-permission-shared</artifactId>
@ -94,10 +82,6 @@
<groupId>org.everrest</groupId>
<artifactId>everrest-core</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-persist</artifactId>
@ -133,11 +117,6 @@
<artifactId>che-core-api-account</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db-vendor-h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-sql-schema</artifactId>

View File

@ -1,98 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.api.permission.server;
import static java.lang.String.format;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.core.notification.EventSubscriber;
import org.eclipse.che.api.user.server.UserManager;
import org.eclipse.che.api.user.server.event.PostUserPersistedEvent;
import org.eclipse.che.multiuser.api.permission.server.model.impl.AbstractPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Grant system permission for 'che.admin.name' user. If the user already exists it'll happen on
* component startup, if not - during the first login when user is persisted in the database.
*
* @author Sergii Kabashniuk
*/
@Singleton
public class AdminPermissionInitializer implements EventSubscriber<PostUserPersistedEvent> {
private static final Logger LOG = LoggerFactory.getLogger(AdminPermissionInitializer.class);
private final UserManager userManager;
private final PermissionsManager permissionsManager;
private final EventService eventService;
private final String name;
@Inject
public AdminPermissionInitializer(
@Named("che.system.admin_name") String name,
UserManager userManager,
PermissionsManager permissionsManager,
EventService eventService) {
this.userManager = userManager;
this.permissionsManager = permissionsManager;
this.eventService = eventService;
this.name = name;
}
@PostConstruct
public void init() throws ServerException {
try {
User adminUser = userManager.getByName(name);
grantSystemPermissions(adminUser.getId());
} catch (NotFoundException ex) {
LOG.warn("Admin {} not found yet.", name);
} finally {
eventService.subscribe(this);
}
}
@PreDestroy
public void unsubscribe() {
eventService.unsubscribe(this);
}
@Override
public void onEvent(PostUserPersistedEvent event) {
if (event.getUser().getName().equals(name)) {
grantSystemPermissions(event.getUser().getId());
}
}
public void grantSystemPermissions(String userId) {
// Add all possible system permissions
try {
AbstractPermissionsDomain<? extends AbstractPermissions> systemDomain =
permissionsManager.getDomain(SystemDomain.DOMAIN_ID);
permissionsManager.storePermission(
systemDomain.newInstance(userId, null, systemDomain.getAllowedActions()));
} catch (ServerException | NotFoundException | ConflictException e) {
LOG.warn(format("System permissions creation failed for user %s", userId), e);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -59,29 +59,11 @@ public class PermissionsManager {
private final StripedLocks updateLocks;
@Inject
public PermissionsManager(
EventService eventService, Set<PermissionsDao<? extends AbstractPermissions>> daos)
throws ServerException {
public PermissionsManager(EventService eventService) throws ServerException {
this.eventService = eventService;
final Map<String, PermissionsDao<? extends AbstractPermissions>> domainToDao = new HashMap<>();
final List<AbstractPermissionsDomain<? extends AbstractPermissions>> domains =
new ArrayList<>();
for (PermissionsDao<? extends AbstractPermissions> dao : daos) {
final AbstractPermissionsDomain<? extends AbstractPermissions> domain = dao.getDomain();
final PermissionsDao<? extends AbstractPermissions> oldStorage =
domainToDao.put(domain.getId(), dao);
domains.add(domain);
if (oldStorage != null) {
throw new ServerException(
"Permissions Domain '"
+ domain.getId()
+ "' should be stored in only one storage. "
+ "Duplicated in "
+ dao.getClass()
+ " and "
+ oldStorage.getClass());
}
}
this.domains = ImmutableList.copyOf(domains);
this.domainToDao = ImmutableMap.copyOf(domainToDao);
this.updateLocks = new StripedLocks(16);

View File

@ -1,138 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.api.permission.server.jpa;
import static java.util.Objects.requireNonNull;
import com.google.inject.persist.Transactional;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain;
import org.eclipse.che.multiuser.api.permission.server.model.impl.AbstractPermissions;
import org.eclipse.che.multiuser.api.permission.server.spi.PermissionsDao;
/**
* Basic JPA DAO implementation for {@link Permissions} objects.
*
* @author Max Shaposhnik
*/
public abstract class AbstractJpaPermissionsDao<T extends AbstractPermissions>
implements PermissionsDao<T> {
private final AbstractPermissionsDomain<T> supportedDomain;
@Inject protected Provider<EntityManager> managerProvider;
public AbstractJpaPermissionsDao(AbstractPermissionsDomain<T> supportedDomain) {
this.supportedDomain = supportedDomain;
}
@Override
public AbstractPermissionsDomain<T> getDomain() {
return supportedDomain;
}
@Override
public Optional<T> store(T permissions) throws ServerException {
requireNonNull(permissions, "Permissions instance required");
try {
return doCreate(permissions);
} catch (RuntimeException e) {
throw new ServerException(e.getMessage(), e);
}
}
@Override
public boolean exists(String userId, String instanceId, String action) throws ServerException {
requireNonNull(userId, "User identifier required");
requireNonNull(action, "Action name required");
T permissions;
try {
permissions = get(userId, instanceId);
} catch (NotFoundException e) {
return false;
}
return permissions.getActions().contains(action);
}
@Override
public void remove(String userId, String instanceId) throws ServerException, NotFoundException {
requireNonNull(instanceId, "Instance identifier required");
requireNonNull(userId, "User identifier required");
try {
doRemove(userId, instanceId);
} catch (RuntimeException x) {
throw new ServerException(x.getLocalizedMessage(), x);
}
}
@Override
public abstract T get(String userId, String instanceId) throws ServerException, NotFoundException;
@Override
public abstract List<T> getByUser(String userId) throws ServerException;
@Override
public abstract Page<T> getByInstance(String instanceId, int maxItems, long skipCount)
throws ServerException;
/**
* Must return jpa managed entity or throw {@link NotFoundException} when there is no such entity.
* Parameters {@code userId} and {@code instanceId} are the same to {@link #get(String, String)}
* method parameters.
*/
protected abstract T getEntity(String userId, String instanceId)
throws NotFoundException, ServerException;
@Transactional
protected Optional<T> doCreate(T permissions) throws ServerException {
EntityManager manager = managerProvider.get();
try {
final T result =
getEntity(wildcardToNull(permissions.getUserId()), permissions.getInstanceId());
final T existing =
getDomain().newInstance(result.getUserId(), result.getInstanceId(), result.getActions());
result.getActions().clear();
result.getActions().addAll(permissions.getActions());
manager.flush();
return Optional.of(existing);
} catch (NotFoundException n) {
manager.persist(permissions);
manager.flush();
return Optional.empty();
}
}
@Transactional
protected void doRemove(String userId, String instanceId)
throws ServerException, NotFoundException {
final T entity = getEntity(wildcardToNull(userId), instanceId);
EntityManager manager = managerProvider.get();
manager.remove(entity);
manager.flush();
}
/**
* Converts '*' user wildcard to {@code null}
*
* @return {@code null} when user identifier equal to '*', either user identifier will be returned
*/
public static String wildcardToNull(String userId) {
return !"*".equals(userId) ? userId : null;
}
}

View File

@ -1,157 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.api.permission.server.jpa;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
import com.google.inject.persist.Transactional;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.user.server.event.BeforeUserRemovedEvent;
import org.eclipse.che.core.db.cascade.CascadeEventSubscriber;
import org.eclipse.che.multiuser.api.permission.server.SystemDomain;
import org.eclipse.che.multiuser.api.permission.server.model.impl.SystemPermissionsImpl;
/**
* JPA based implementation of system permissions DAO.
*
* @author Max Shaposhnik
*/
@Singleton
public class JpaSystemPermissionsDao extends AbstractJpaPermissionsDao<SystemPermissionsImpl> {
@Inject
public JpaSystemPermissionsDao(
@Named(SystemDomain.SYSTEM_DOMAIN_ACTIONS) Set<String> allowedActions) {
super(new SystemDomain(allowedActions));
}
@Override
public SystemPermissionsImpl get(String userId, String instanceId)
throws ServerException, NotFoundException {
requireNonNull(userId, "Required non-null user id");
try {
return new SystemPermissionsImpl(getEntity(wildcardToNull(userId), instanceId));
} catch (RuntimeException x) {
throw new ServerException(x.getLocalizedMessage(), x);
}
}
@Override
@Transactional
public Page<SystemPermissionsImpl> getByInstance(String instanceId, int maxItems, long skipCount)
throws ServerException {
checkArgument(
skipCount <= Integer.MAX_VALUE,
"The number of items to skip can't be greater than " + Integer.MAX_VALUE);
// instanceId is ignored because system domain doesn't require it
try {
final EntityManager entityManager = managerProvider.get();
final List<SystemPermissionsImpl> permissions =
entityManager
.createNamedQuery("SystemPermissions.getAll", SystemPermissionsImpl.class)
.setMaxResults(maxItems)
.setFirstResult((int) skipCount)
.getResultList()
.stream()
.map(SystemPermissionsImpl::new)
.collect(toList());
final Long totalCount =
entityManager
.createNamedQuery("SystemPermissions.getTotalCount", Long.class)
.getSingleResult();
return new Page<>(permissions, skipCount, maxItems, totalCount);
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
@Override
public List<SystemPermissionsImpl> getByUser(String userId) throws ServerException {
requireNonNull(userId, "User identifier required");
try {
return doGetByUser(userId).stream().map(SystemPermissionsImpl::new).collect(toList());
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
@Override
protected SystemPermissionsImpl getEntity(String userId, String instanceId)
throws NotFoundException, ServerException {
try {
final List<SystemPermissionsImpl> existent = doGetByUser(userId);
if (existent.isEmpty()) {
throw new NotFoundException(format("System permissions for user '%s' not found", userId));
}
return existent.get(0);
} catch (RuntimeException e) {
throw new ServerException(e.getMessage(), e);
}
}
@Transactional
protected List<SystemPermissionsImpl> doGetByUser(String userId) {
return managerProvider
.get()
.createNamedQuery("SystemPermissions.getByUserId", SystemPermissionsImpl.class)
.setParameter("userId", userId)
.getResultList();
}
@Override
public void remove(String userId, String instanceId) throws ServerException, NotFoundException {
requireNonNull(userId, "User identifier required");
try {
doRemove(userId, instanceId);
} catch (RuntimeException x) {
throw new ServerException(x.getLocalizedMessage(), x);
}
}
@Singleton
public static class RemoveSystemPermissionsBeforeUserRemovedEventSubscriber
extends CascadeEventSubscriber<BeforeUserRemovedEvent> {
@Inject private EventService eventService;
@Inject JpaSystemPermissionsDao dao;
@PostConstruct
public void subscribe() {
eventService.subscribe(this, BeforeUserRemovedEvent.class);
}
@PreDestroy
public void unsubscribe() {
eventService.unsubscribe(this, BeforeUserRemovedEvent.class);
}
@Override
public void onCascadeEvent(BeforeUserRemovedEvent event) throws Exception {
for (SystemPermissionsImpl permissions : dao.getByUser(event.getUser().getId())) {
dao.remove(permissions.getUserId(), permissions.getInstanceId());
}
}
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.api.permission.server.jpa;
import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.Multibinder;
import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain;
import org.eclipse.che.multiuser.api.permission.server.SystemDomain;
import org.eclipse.che.multiuser.api.permission.server.model.impl.AbstractPermissions;
import org.eclipse.che.multiuser.api.permission.server.model.impl.SystemPermissionsImpl;
import org.eclipse.che.multiuser.api.permission.server.spi.PermissionsDao;
/** @author Max Shaposhnik */
public class SystemPermissionsJpaModule extends AbstractModule {
@Override
protected void configure() {
bind(new TypeLiteral<AbstractPermissionsDomain<SystemPermissionsImpl>>() {})
.to(SystemDomain.class);
bind(JpaSystemPermissionsDao.RemoveSystemPermissionsBeforeUserRemovedEventSubscriber.class)
.asEagerSingleton();
Multibinder<PermissionsDao<? extends AbstractPermissions>> storages =
Multibinder.newSetBinder(
binder(), new TypeLiteral<PermissionsDao<? extends AbstractPermissions>>() {});
storages.addBinding().to(JpaSystemPermissionsDao.class);
}
}

View File

@ -1,103 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.api.permission.server.jpa.listener;
import static org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain.SET_PERMISSIONS;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import java.util.List;
import javax.inject.Inject;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.user.server.event.BeforeUserRemovedEvent;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.core.db.cascade.CascadeEventSubscriber;
import org.eclipse.che.multiuser.api.permission.server.model.impl.AbstractPermissions;
import org.eclipse.che.multiuser.api.permission.server.spi.PermissionsDao;
/**
* Listens for {@link UserImpl} removal events, and checks if the removing user is the last who have
* "setPermissions" role to any of the permission domain, and if it is, then removes domain entity
* itself.
*
* @author Max Shaposhnik
*/
public abstract class RemovePermissionsOnLastUserRemovedEventSubscriber<
T extends PermissionsDao<? extends AbstractPermissions>>
extends CascadeEventSubscriber<BeforeUserRemovedEvent> {
@Inject private EventService eventService;
@Inject T storage;
@PostConstruct
public void subscribe() {
eventService.subscribe(this, BeforeUserRemovedEvent.class);
}
@PreDestroy
public void unsubscribe() {
eventService.unsubscribe(this, BeforeUserRemovedEvent.class);
}
@Override
public void onCascadeEvent(BeforeUserRemovedEvent event) throws Exception {
for (AbstractPermissions permissions : storage.getByUser(event.getUser().getId())) {
// This method can potentially be source of race conditions,
// e.g. when performing search by permissions, another thread can add/or remove another
// setPermission,
// so appropriate domain object (stack or recipe) will not be deleted, or vice versa,
// deleted when it's not required anymore.
// As a result, a solitary objects may be present in the DB.
if (userHasLastSetPermissions(permissions.getUserId(), permissions.getInstanceId())) {
remove(permissions.getInstanceId());
} else {
storage.remove(event.getUser().getId(), permissions.getInstanceId());
}
}
}
private boolean userHasLastSetPermissions(String userId, String instanceId)
throws ServerException {
try {
Page<? extends AbstractPermissions> page = storage.getByInstance(instanceId, 30, 0);
boolean hasSetPermission;
while (!(hasSetPermission = hasForeignSetPermission(page.getItems(), userId))
&& page.hasNextPage()) {
final Page.PageRef nextPageRef = page.getNextPageRef();
page =
storage.getByInstance(
instanceId, nextPageRef.getPageSize(), (int) nextPageRef.getItemsBefore());
}
return !hasSetPermission;
} catch (NotFoundException e) {
return true;
}
}
private boolean hasForeignSetPermission(
List<? extends AbstractPermissions> permissions, String userId) {
for (AbstractPermissions permission : permissions) {
if (!permission.getUserId().equals(userId)
&& permission.getActions().contains(SET_PERMISSIONS)) {
return true;
}
}
return false;
}
public abstract void remove(String instanceId) throws ServerException;
}

View File

@ -1,128 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.api.permission.server;
import static java.util.Collections.emptyList;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import java.util.Collections;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.user.server.UserManager;
import org.eclipse.che.api.user.server.event.PostUserPersistedEvent;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.multiuser.api.permission.server.model.impl.SystemPermissionsImpl;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests for {@link AdminPermissionInitializer}.
*
* @author Anton Korneta
* @author Sergii Kabashniuk
*/
@Listeners(MockitoTestNGListener.class)
public class AdminPermissionInitializerTest {
private static final String NAME = "admin";
private static final String PASSWORD = "root";
private static final String EMAIL = "admin@rb.com";
@Mock private PermissionsManager permissionsManager;
@Mock private UserManager userManager;
@Mock private EventService eventService;
private UserImpl user;
private UserImpl adminUser;
private AdminPermissionInitializer initializer;
@BeforeMethod
public void setUp() throws Exception {
user = new UserImpl("qwe", "qwe", "qwe", "qwe", emptyList());
adminUser = new UserImpl("id-admin", EMAIL, NAME, PASSWORD, emptyList());
initializer =
new AdminPermissionInitializer(NAME, userManager, permissionsManager, eventService);
}
@Test
public void shouldAddSystemPermissionsOnPostUserPersistedEvent() throws Exception {
// given
when(userManager.getByName(eq(NAME))).thenReturn(user);
doNothing().when(permissionsManager).storePermission(any(SystemPermissionsImpl.class));
doReturn(new SystemDomain(Collections.emptySet()))
.when(permissionsManager)
.getDomain(anyString());
initializer.init();
// when
initializer.onEvent(
new PostUserPersistedEvent(new UserImpl(NAME, EMAIL, NAME, PASSWORD, emptyList())));
// then
verify(permissionsManager)
.storePermission(
argThat(
(ArgumentMatcher<SystemPermissionsImpl>)
argument -> argument.getUserId().equals(NAME)));
}
@Test
public void shouldNotAddSystemPermissionsOnPostUserPersistedEvent() throws Exception {
// given
when(userManager.getByName(anyString())).thenThrow(NotFoundException.class);
initializer.init();
// when
initializer.onEvent(
new PostUserPersistedEvent(
new UserImpl(NAME + "1", EMAIL + "2", NAME + "3", PASSWORD, emptyList())));
// then
verifyNoMoreInteractions(permissionsManager);
}
@Test
public void shouldAddSystemPermissionsForExistedAdmin() throws Exception {
// given
when(userManager.getByName(eq(NAME))).thenReturn(adminUser);
doNothing().when(permissionsManager).storePermission(any(SystemPermissionsImpl.class));
doReturn(new SystemDomain(Collections.emptySet()))
.when(permissionsManager)
.getDomain(anyString());
// when
initializer.init();
// then
verify(permissionsManager)
.storePermission(
argThat(
(ArgumentMatcher<SystemPermissionsImpl>)
argument -> argument.getUserId().equals(adminUser.getId())));
}
@Test
public void shouldNotAddSystemPermissionsIfAdminNotExists() throws Exception {
// given
when(userManager.getByName(anyString())).thenThrow(NotFoundException.class);
// when
initializer.init();
// then
verifyNoMoreInteractions(permissionsManager);
}
}

View File

@ -1,336 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.api.permission.server;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain.SET_PERMISSIONS;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import com.google.common.collect.ImmutableSet;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.dto.server.DtoFactory;
import org.eclipse.che.multiuser.api.permission.server.model.impl.AbstractPermissions;
import org.eclipse.che.multiuser.api.permission.server.spi.PermissionsDao;
import org.eclipse.che.multiuser.api.permission.shared.dto.PermissionsDto;
import org.eclipse.che.multiuser.api.permission.shared.model.Permissions;
import org.eclipse.che.multiuser.api.permission.shared.model.PermissionsDomain;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests for {@link PermissionsManager}
*
* @author Sergii Leschenko
*/
@Listeners(MockitoTestNGListener.class)
public class PermissionsManagerTest {
@Mock private PermissionsDao<TestPermissionsImpl> permissionsDao;
@Mock private EventService eventService;
private PermissionsManager permissionsManager;
@BeforeMethod
public void setUp() throws Exception {
when(permissionsDao.getDomain()).thenReturn(new TestDomain());
permissionsManager = new PermissionsManager(eventService, ImmutableSet.of(permissionsDao));
}
@Test(
expectedExceptions = ServerException.class,
expectedExceptionsMessageRegExp =
"Permissions Domain 'test' should be stored in only one storage. "
+ "Duplicated in class org.eclipse.che.multiuser.api.permission.server.spi.PermissionsDao.* and class org.eclipse.che.multiuser.api.permission.server.spi.PermissionsDao.*")
public void shouldThrowExceptionIfThereAreTwoStoragesWhichServeOneDomain() throws Exception {
@SuppressWarnings("unchecked")
final PermissionsDao anotherStorage = mock(PermissionsDao.class);
when(anotherStorage.getDomain()).thenReturn(new TestDomain());
permissionsManager =
new PermissionsManager(eventService, ImmutableSet.of(permissionsDao, anotherStorage));
}
@Test
public void shouldBeAbleToStorePermissions() throws Exception {
final Permissions permissions =
DtoFactory.newDto(PermissionsDto.class)
.withUserId("user")
.withDomainId("test")
.withInstanceId("test123")
.withActions(singletonList(SET_PERMISSIONS));
when(permissionsDao.store(any(TestPermissionsImpl.class))).thenReturn(Optional.empty());
permissionsManager.storePermission(permissions);
verify(permissionsDao)
.store(
new TestDomain()
.doCreateInstance(
permissions.getUserId(), permissions.getDomainId(), permissions.getActions()));
}
@Test(
expectedExceptions = ConflictException.class,
expectedExceptionsMessageRegExp =
"Domain with id 'test' doesn't support following action\\(s\\): unsupported")
public void shouldNotStorePermissionsWhenItHasUnsupportedAction() throws Exception {
final Permissions permissions =
DtoFactory.newDto(PermissionsDto.class)
.withUserId("user")
.withDomainId("test")
.withInstanceId("test123")
.withActions(singletonList("unsupported"));
permissionsManager.storePermission(permissions);
}
@Test(
expectedExceptions = ConflictException.class,
expectedExceptionsMessageRegExp =
"Can't edit permissions because there is not any another user with permission 'setPermissions'")
public void shouldNotStorePermissionsWhenItRemoveLastSetPermissions() throws Exception {
final TestPermissionsImpl foreignPermissions =
new TestPermissionsImpl("user1", "test", "test123", singletonList("read"));
final TestPermissionsImpl ownPermissions =
new TestPermissionsImpl("user", "test", "test123", asList("read", "setPermissions"));
when(permissionsDao.exists("user", "test123", SET_PERMISSIONS)).thenReturn(true);
doReturn(new Page<>(singletonList(foreignPermissions), 0, 1, 2))
.doReturn(new Page<>(singletonList(ownPermissions), 1, 1, 2))
.when(permissionsDao)
.getByInstance(nullable(String.class), nullable(Integer.class), nullable(Long.class));
permissionsManager.storePermission(
new TestPermissionsImpl("user", "test", "test123", singletonList("delete")));
}
@Test
public void shouldStorePermissionsWhenItRemoveSetPermissionsButThereIsAnotherOne()
throws Exception {
final TestPermissionsImpl foreignPermissions =
new TestPermissionsImpl("user1", "test", "test123", singletonList("setPermissions"));
final TestPermissionsImpl ownPermissions =
new TestPermissionsImpl("user", "test", "test123", asList("read", "setPermissions"));
when(permissionsDao.exists("user", "test123", SET_PERMISSIONS)).thenReturn(true);
when(permissionsDao.store(any(TestPermissionsImpl.class))).thenReturn(Optional.empty());
doReturn(new Page<>(singletonList(ownPermissions), 0, 30, 31))
.doReturn(new Page<>(singletonList(foreignPermissions), 1, 30, 31))
.when(permissionsDao)
.getByInstance(nullable(String.class), nullable(Integer.class), nullable(Long.class));
permissionsManager.storePermission(
new TestPermissionsImpl("user", "test", "test123", singletonList("delete")));
verify(permissionsDao).getByInstance(eq("test123"), anyInt(), eq(0L));
verify(permissionsDao).getByInstance(eq("test123"), anyInt(), eq(30L));
}
@Test
public void shouldNotCheckExistingSetPermissionsIfUserDoesNotHaveItAtAllOnStoring()
throws Exception {
when(permissionsDao.exists("user", "test123", SET_PERMISSIONS)).thenReturn(false);
when(permissionsDao.store(any(TestPermissionsImpl.class))).thenReturn(Optional.empty());
permissionsManager.storePermission(
new TestPermissionsImpl("user", "test", "test123", singletonList("delete")));
verify(permissionsDao, never()).getByInstance(anyString(), anyInt(), anyInt());
}
@Test
public void shouldBeAbleToDeletePermissions() throws Exception {
permissionsManager.remove("user", "test", "test123");
verify(permissionsDao).remove(eq("user"), eq("test123"));
}
@Test(
expectedExceptions = ConflictException.class,
expectedExceptionsMessageRegExp =
"Can't remove permissions because there is not any another user with permission 'setPermissions'")
public void shouldNotRemovePermissionsWhenItContainsLastSetPermissionsAction() throws Exception {
final TestPermissionsImpl firstPermissions =
new TestPermissionsImpl("user1", "test", "test123", singletonList("read"));
final TestPermissionsImpl secondPermissions =
new TestPermissionsImpl("user", "test", "test123", asList("read", "setPermissions"));
when(permissionsDao.exists("user", "test123", SET_PERMISSIONS)).thenReturn(true);
doReturn(new Page<>(singletonList(firstPermissions), 0, 1, 2))
.doReturn(new Page<>(singletonList(secondPermissions), 1, 1, 2))
.when(permissionsDao)
.getByInstance(nullable(String.class), nullable(Integer.class), nullable(Long.class));
permissionsManager.remove("user", "test", "test123");
}
@Test
public void shouldNotCheckExistingSetPermissionsIfUserDoesNotHaveItAtAllOnRemove()
throws Exception {
when(permissionsDao.exists("user", "test123", SET_PERMISSIONS)).thenReturn(false);
permissionsManager.remove("user", "test", "test123");
verify(permissionsDao, never()).getByInstance(eq("test123"), anyInt(), anyInt());
}
@Test
public void shouldBeAbleToGetPermissionsByUserAndDomainAndInstance() throws Exception {
final TestPermissionsImpl permissions =
new TestPermissionsImpl("user", "test", "test123", singletonList("read"));
when(permissionsDao.get("user", "test123")).thenReturn(permissions);
final Permissions fetchedPermissions = permissionsManager.get("user", "test", "test123");
assertEquals(permissions, fetchedPermissions);
}
@Test
public void shouldBeAbleToGetPermissionsByInstance() throws Exception {
final TestPermissionsImpl firstPermissions =
new TestPermissionsImpl("user", "test", "test123", singletonList("read"));
final TestPermissionsImpl secondPermissions =
new TestPermissionsImpl("user1", "test", "test123", singletonList("read"));
doReturn(new Page<>(asList(firstPermissions, secondPermissions), 1, 2, 4))
.when(permissionsDao)
.getByInstance(nullable(String.class), nullable(Integer.class), nullable(Long.class));
final Page<AbstractPermissions> permissionsPage =
permissionsManager.getByInstance("test", "test123", 2, 1);
final List<AbstractPermissions> fetchedPermissions = permissionsPage.getItems();
verify(permissionsDao).getByInstance("test123", 2, 1);
assertEquals(permissionsPage.getTotalItemsCount(), 4);
assertEquals(permissionsPage.getItemsCount(), 2);
assertTrue(fetchedPermissions.contains(firstPermissions));
assertTrue(fetchedPermissions.contains(secondPermissions));
}
@Test
public void shouldBeAbleToCheckPermissionExistence() throws Exception {
doReturn(true).when(permissionsDao).exists("user", "test123", "use");
assertTrue(permissionsManager.exists("user", "test", "test123", "use"));
assertFalse(permissionsManager.exists("user", "test", "test123", "update"));
}
@Test
public void shouldBeAbleToDomains() throws Exception {
final List<AbstractPermissionsDomain> domains = permissionsManager.getDomains();
assertEquals(domains.size(), 1);
assertTrue(domains.contains(new TestDomain()));
}
@Test
public void shouldBeAbleToDomainActions() throws Exception {
final PermissionsDomain testDomain = permissionsManager.getDomain("test");
final List<String> allowedActions = testDomain.getAllowedActions();
assertEquals(allowedActions.size(), 5);
assertTrue(
allowedActions.containsAll(
ImmutableSet.of(SET_PERMISSIONS, "read", "write", "use", "delete")));
}
@Test(
expectedExceptions = NotFoundException.class,
expectedExceptionsMessageRegExp = "Requested unsupported domain 'unsupported'")
public void shouldThrowExceptionWhenRequestedUnsupportedDomain() throws Exception {
permissionsManager.getDomain("unsupported");
}
@Test
public void shouldDoNothingOnActionSupportingCheckingWhenListDoesNotContainUnsupportedAction()
throws Exception {
permissionsManager.checkActionsSupporting("test", Arrays.asList("write", "use"));
}
@Test(
expectedExceptions = ConflictException.class,
expectedExceptionsMessageRegExp =
"Domain with id 'test' doesn't support following action\\(s\\): unsupported")
public void
shouldThrowConflictExceptionOnActionSupportingCheckingWhenListContainsUnsupportedAction()
throws Exception {
permissionsManager.checkActionsSupporting("test", Arrays.asList("write", "use", "unsupported"));
}
public class TestDomain extends AbstractPermissionsDomain<TestPermissionsImpl> {
public TestDomain() {
super("test", asList("read", "write", "use", "delete"));
}
@Override
protected TestPermissionsImpl doCreateInstance(
String userId, String instanceId, List<String> allowedActions) {
return new TestPermissionsImpl("user", "test", "test123", allowedActions);
}
}
public class TestPermissionsImpl extends AbstractPermissions {
private String domainId;
private String instanceId;
List<String> actions;
@Override
public String getInstanceId() {
return instanceId;
}
@Override
public String getDomainId() {
return domainId;
}
public TestPermissionsImpl(
String userId, String domainId, String instanceId, List<String> actions) {
super(userId);
this.domainId = domainId;
this.instanceId = instanceId;
this.actions = actions;
}
@Override
public List<String> getActions() {
return actions;
}
}
}

View File

@ -1,73 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.api.permission.server.jpa;
import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Names;
import org.eclipse.che.account.spi.AccountImpl;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.commons.test.db.H2DBTestServer;
import org.eclipse.che.commons.test.db.H2JpaCleaner;
import org.eclipse.che.commons.test.db.PersistTestModuleBuilder;
import org.eclipse.che.commons.test.tck.TckModule;
import org.eclipse.che.commons.test.tck.TckResourcesCleaner;
import org.eclipse.che.commons.test.tck.repository.JpaTckRepository;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
import org.eclipse.che.core.db.DBInitializer;
import org.eclipse.che.core.db.h2.jpa.eclipselink.H2ExceptionHandler;
import org.eclipse.che.core.db.schema.SchemaInitializer;
import org.eclipse.che.core.db.schema.impl.flyway.FlywaySchemaInitializer;
import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain;
import org.eclipse.che.multiuser.api.permission.server.SystemDomain;
import org.eclipse.che.multiuser.api.permission.server.model.impl.AbstractPermissions;
import org.eclipse.che.multiuser.api.permission.server.model.impl.SystemPermissionsImpl;
import org.eclipse.che.multiuser.api.permission.server.spi.PermissionsDao;
import org.eclipse.che.multiuser.api.permission.server.spi.tck.SystemPermissionsDaoTest.TestDomain;
import org.h2.Driver;
/** @author Max Shaposhnik (mshaposhnik@codenvy.com) */
public class SystemPermissionsTckModule extends TckModule {
@Override
protected void configure() {
H2DBTestServer server = H2DBTestServer.startDefault();
install(
new PersistTestModuleBuilder()
.setDriver(Driver.class)
.runningOn(server)
.addEntityClasses(
UserImpl.class,
AccountImpl.class,
AbstractPermissions.class,
SystemPermissionsImpl.class)
.setExceptionHandler(H2ExceptionHandler.class)
.build());
bind(DBInitializer.class).asEagerSingleton();
bind(SchemaInitializer.class)
.toInstance(new FlywaySchemaInitializer(server.getDataSource(), "che-schema"));
bind(TckResourcesCleaner.class).toInstance(new H2JpaCleaner(server));
// Creates empty multibinder to avoid error during container starting
Multibinder.newSetBinder(
binder(), String.class, Names.named(SystemDomain.SYSTEM_DOMAIN_ACTIONS));
bind(new TypeLiteral<AbstractPermissionsDomain<SystemPermissionsImpl>>() {})
.to(TestDomain.class);
bind(new TypeLiteral<PermissionsDao<SystemPermissionsImpl>>() {})
.to(JpaSystemPermissionsDao.class);
bind(new TypeLiteral<TckRepository<SystemPermissionsImpl>>() {})
.toInstance(new JpaTckRepository<>(SystemPermissionsImpl.class));
bind(new TypeLiteral<TckRepository<UserImpl>>() {})
.toInstance(new JpaTckRepository<>(UserImpl.class));
}
}

View File

@ -1,120 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.api.permission.server.spi.tck;
import static java.util.Arrays.asList;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.Inject;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.commons.test.tck.TckListener;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
import org.eclipse.che.multiuser.api.permission.server.AbstractPermissionsDomain;
import org.eclipse.che.multiuser.api.permission.server.jpa.JpaSystemPermissionsDao;
import org.eclipse.che.multiuser.api.permission.server.model.impl.SystemPermissionsImpl;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/** @author Max Shaposhnik */
@Listeners(TckListener.class)
@Test(suiteName = "SystemPermissionsDaoTck")
public class SystemPermissionsDaoTest {
@Inject private JpaSystemPermissionsDao dao;
private UserImpl[] users;
private SystemPermissionsImpl[] systemPermissions;
@Inject private TckRepository<UserImpl> userRepository;
@Inject private TckRepository<SystemPermissionsImpl> systemRepository;
@BeforeMethod
public void setupEntities() throws Exception {
systemPermissions =
new SystemPermissionsImpl[] {
new SystemPermissionsImpl("user1", asList("read", "use", "run")),
new SystemPermissionsImpl("user2", asList("read", "use")),
new SystemPermissionsImpl("user3", asList("read", "use"))
};
users =
new UserImpl[] {
new UserImpl("user1", "user1@com.com", "usr1"),
new UserImpl("user2", "user2@com.com", "usr2"),
new UserImpl("user3", "user3@com.com", "usr3")
};
userRepository.createAll(asList(users));
systemRepository.createAll(
Stream.of(systemPermissions).map(SystemPermissionsImpl::new).collect(Collectors.toList()));
}
@AfterMethod
public void cleanup() throws Exception {
systemRepository.removeAll();
userRepository.removeAll();
}
@Test
public void shouldReturnAllPermissionsWhenGetByInstance() throws Exception {
final Page<SystemPermissionsImpl> permissionsPage = dao.getByInstance(null, 1, 1);
final List<SystemPermissionsImpl> permissions = permissionsPage.getItems();
assertEquals(permissionsPage.getTotalItemsCount(), 3);
assertEquals(permissionsPage.getItemsCount(), 1);
assertTrue(
permissions.contains(systemPermissions[0])
^ permissions.contains(systemPermissions[1])
^ permissions.contains(systemPermissions[2]));
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowExceptionWhenGetPermissionsUserIdArgumentIsNull() throws Exception {
dao.get(null, "instance");
}
@Test
public void doesNotThrowNpeWhenInstanceIsNull() throws Exception {
dao.get(users[0].getId(), null);
}
@Test
public void shouldBeAbleToGetPermissions() throws Exception {
final SystemPermissionsImpl result1 =
dao.get(systemPermissions[0].getUserId(), systemPermissions[0].getInstanceId());
final SystemPermissionsImpl result2 =
dao.get(systemPermissions[1].getUserId(), systemPermissions[1].getInstanceId());
assertEquals(result1, systemPermissions[0]);
assertEquals(result2, systemPermissions[1]);
}
public static class TestDomain extends AbstractPermissionsDomain<SystemPermissionsImpl> {
public TestDomain() {
super("system", asList("read", "write", "use"));
}
@Override
protected SystemPermissionsImpl doCreateInstance(
String userId, String instanceId, List allowedActions) {
return null;
}
}
}

View File

@ -38,18 +38,10 @@
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-persist</artifactId>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations-jakarta</artifactId>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
@ -106,11 +98,6 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.core</artifactId>
@ -121,71 +108,7 @@
<artifactId>org.eclipse.persistence.jpa</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-db-vendor-h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-sql-schema</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.multiuser</groupId>
<artifactId>che-multiuser-sql-schema</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.everrest</groupId>
<artifactId>everrest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
@ -281,23 +204,6 @@
</execution>
</executions>
</plugin>
<!-- Create the test jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<includes>
<include>**/spi/tck/*.*</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2023 Red Hat, Inc.
* Copyright (c) 2012-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
@ -27,15 +27,11 @@ import org.eclipse.che.multiuser.resource.api.usage.tracker.RamResourceUsageTrac
import org.eclipse.che.multiuser.resource.api.usage.tracker.RuntimeResourceUsageTracker;
import org.eclipse.che.multiuser.resource.api.usage.tracker.WorkspaceResourceUsageTracker;
import org.eclipse.che.multiuser.resource.api.workspace.LimitsCheckingWorkspaceManager;
import org.eclipse.che.multiuser.resource.spi.FreeResourcesLimitDao;
import org.eclipse.che.multiuser.resource.spi.jpa.JpaFreeResourcesLimitDao;
/** @author Sergii Leschenko */
public class ResourceModule extends AbstractModule {
@Override
protected void configure() {
bind(FreeResourcesLimitDao.class).to(JpaFreeResourcesLimitDao.class);
bind(JpaFreeResourcesLimitDao.RemoveFreeResourcesLimitSubscriber.class).asEagerSingleton();
bind(WorkspaceManager.class).to(LimitsCheckingWorkspaceManager.class);

View File

@ -1,179 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.resource.spi.jpa;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import com.google.inject.persist.Transactional;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import org.eclipse.che.account.event.BeforeAccountRemovedEvent;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.core.notification.EventSubscriber;
import org.eclipse.che.core.db.jpa.IntegrityConstraintViolationException;
import org.eclipse.che.multiuser.resource.spi.FreeResourcesLimitDao;
import org.eclipse.che.multiuser.resource.spi.impl.FreeResourcesLimitImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* JPA based implementation of {@link FreeResourcesLimitDao}.
*
* @author Sergii Leschenko
*/
@Singleton
public class JpaFreeResourcesLimitDao implements FreeResourcesLimitDao {
private static final Logger LOG = LoggerFactory.getLogger(JpaFreeResourcesLimitDao.class);
@Inject private Provider<EntityManager> managerProvider;
@Override
public void store(FreeResourcesLimitImpl resourcesLimit)
throws ConflictException, ServerException {
requireNonNull(resourcesLimit, "Required non-null resource limit");
try {
doStore(resourcesLimit);
} catch (RuntimeException e) {
throw new ServerException(e.getMessage(), e);
}
}
@Override
@Transactional
public FreeResourcesLimitImpl get(String accountId) throws NotFoundException, ServerException {
requireNonNull(accountId, "Required non-null account id");
try {
return new FreeResourcesLimitImpl(doGet(accountId));
} catch (NoResultException e) {
throw new NotFoundException(
"Free resources limit for account '" + accountId + "' was not found");
} catch (RuntimeException e) {
throw new ServerException(e.getMessage(), e);
}
}
@Override
@Transactional
public Page<FreeResourcesLimitImpl> getAll(int maxItems, int skipCount) throws ServerException {
try {
final List<FreeResourcesLimitImpl> list =
managerProvider
.get()
.createNamedQuery("FreeResourcesLimit.getAll", FreeResourcesLimitImpl.class)
.setMaxResults(maxItems)
.setFirstResult(skipCount)
.getResultList()
.stream()
.map(FreeResourcesLimitImpl::new)
.collect(Collectors.toList());
return new Page<>(list, skipCount, maxItems, getTotalCount());
} catch (RuntimeException e) {
throw new ServerException(e.getMessage(), e);
}
}
@Override
public void remove(String id) throws ServerException {
requireNonNull(id, "Required non-null id");
try {
doRemove(id);
} catch (RuntimeException x) {
throw new ServerException(x.getLocalizedMessage(), x);
}
}
@Transactional
protected void doRemove(String id) {
final EntityManager manager = managerProvider.get();
final FreeResourcesLimitImpl resourcesLimit = manager.find(FreeResourcesLimitImpl.class, id);
if (resourcesLimit != null) {
manager.remove(resourcesLimit);
manager.flush();
}
}
@Transactional(rollbackOn = {RuntimeException.class, ConflictException.class})
protected void doStore(FreeResourcesLimitImpl resourcesLimit) throws ConflictException {
EntityManager manager = managerProvider.get();
try {
final FreeResourcesLimitImpl existedLimit = doGet(resourcesLimit.getAccountId());
existedLimit.setResources(resourcesLimit.getResources());
manager.flush();
} catch (NoResultException n) {
try {
manager.persist(resourcesLimit);
manager.flush();
} catch (IntegrityConstraintViolationException e) {
throw new ConflictException(
format("The specified account '%s' does not exist", resourcesLimit.getAccountId()));
}
}
}
@Transactional
protected FreeResourcesLimitImpl doGet(String accountId) {
return managerProvider
.get()
.createNamedQuery("FreeResourcesLimit.get", FreeResourcesLimitImpl.class)
.setParameter("accountId", accountId)
.getSingleResult();
}
private long getTotalCount() throws ServerException {
return managerProvider
.get()
.createNamedQuery("FreeResourcesLimit.getTotalCount", Long.class)
.getSingleResult();
}
@Singleton
public static class RemoveFreeResourcesLimitSubscriber
implements EventSubscriber<BeforeAccountRemovedEvent> {
@Inject private EventService eventService;
@Inject private FreeResourcesLimitDao limitDao;
@PostConstruct
public void subscribe() {
eventService.subscribe(this);
}
@PreDestroy
public void unsubscribe() {
eventService.unsubscribe(this);
}
@Override
public void onEvent(BeforeAccountRemovedEvent event) {
try {
limitDao.remove(event.getAccount().getId());
} catch (Exception x) {
LOG.error(
format(
"Couldn't remove free resources limit before account '%s' is removed",
event.getAccount().getId()),
x);
}
}
}
}

View File

@ -1,387 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.resource.api;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import com.google.common.collect.ImmutableSet;
import java.util.List;
import java.util.Map;
import org.eclipse.che.multiuser.resource.api.exception.NoEnoughResourcesException;
import org.eclipse.che.multiuser.resource.api.type.ResourceType;
import org.eclipse.che.multiuser.resource.model.Resource;
import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests for {@link org.eclipse.che.multiuser.resource.api.ResourceAggregator}
*
* @author Sergii Leschenko
*/
@Listeners(MockitoTestNGListener.class)
public class ResourceAggregatorTest {
private static final String A_RESOURCE_TYPE = "resourceA";
private static final String B_RESOURCE_TYPE = "resourceB";
private static final String C_RESOURCE_TYPE = "resourceC";
@Mock private ResourceType aResourceType;
@Mock private ResourceType bResourceType;
@Mock private ResourceType cResourceType;
private ResourceAggregator resourceAggregator;
@BeforeMethod
public void setUp() throws Exception {
lenient().when(aResourceType.getId()).thenReturn(A_RESOURCE_TYPE);
lenient().when(bResourceType.getId()).thenReturn(B_RESOURCE_TYPE);
lenient().when(cResourceType.getId()).thenReturn(C_RESOURCE_TYPE);
resourceAggregator =
new ResourceAggregator(ImmutableSet.of(aResourceType, bResourceType, cResourceType));
}
@Test
public void shouldTestResourcesAggregationByTypes() throws Exception {
// given
final ResourceImpl aResource = new ResourceImpl(A_RESOURCE_TYPE, 123, "unit");
final ResourceImpl bResource = new ResourceImpl(B_RESOURCE_TYPE, 123, "unit");
final ResourceImpl anotherBResource = new ResourceImpl(B_RESOURCE_TYPE, 321, "unit");
final ResourceImpl aggregatedBResources = new ResourceImpl(B_RESOURCE_TYPE, 444, "unit");
when(bResourceType.aggregate(any(), any())).thenReturn(aggregatedBResources);
// when
final Map<String, Resource> aggregatedResources =
resourceAggregator.aggregateByType(asList(aResource, bResource, anotherBResource));
// then
verify(bResourceType).aggregate(eq(bResource), eq(anotherBResource));
verify(aResourceType, never()).aggregate(any(), any());
assertEquals(aggregatedResources.size(), 2);
assertTrue(aggregatedResources.containsKey(A_RESOURCE_TYPE));
assertTrue(aggregatedResources.containsValue(aResource));
assertTrue(aggregatedResources.containsKey(B_RESOURCE_TYPE));
assertTrue(aggregatedResources.containsValue(aggregatedBResources));
}
@Test
public void shouldTestResourcesDeduction() throws Exception {
// given
final ResourceImpl aResource = new ResourceImpl(A_RESOURCE_TYPE, 123, "unit");
final ResourceImpl bResource = new ResourceImpl(B_RESOURCE_TYPE, 123, "unit");
final ResourceImpl anotherBResource = new ResourceImpl(B_RESOURCE_TYPE, 321, "unit");
final ResourceImpl aggregatedBResources = new ResourceImpl(A_RESOURCE_TYPE, 444, "unit");
when(bResourceType.deduct(any(), any())).thenReturn(aggregatedBResources);
// when
final List<? extends Resource> deductedResources =
resourceAggregator.deduct(asList(aResource, bResource), singletonList(anotherBResource));
// then
verify(bResourceType).deduct(eq(bResource), eq(anotherBResource));
verify(aResourceType, never()).deduct(any(), any());
assertEquals(deductedResources.size(), 2);
assertTrue(deductedResources.contains(aResource));
assertTrue(deductedResources.contains(aggregatedBResources));
}
@Test(expectedExceptions = NoEnoughResourcesException.class)
public void shouldThrowConflictExceptionWhenTotalResourcesDoNotHaveEnoughAmountToDeduct()
throws Exception {
// given
final ResourceImpl aResource = new ResourceImpl(A_RESOURCE_TYPE, 111, "unit");
final ResourceImpl anotherAResource = new ResourceImpl(A_RESOURCE_TYPE, 333, "unit");
when(aResourceType.deduct(any(), any()))
.thenThrow(
new NoEnoughResourcesException(
singletonList(aResource),
singletonList(anotherAResource),
singletonList(new ResourceImpl(A_RESOURCE_TYPE, 222, "unit"))));
// when
resourceAggregator.deduct(singletonList(aResource), singletonList(anotherAResource));
}
@Test(expectedExceptions = NoEnoughResourcesException.class)
public void shouldThrowConflictExceptionWhenTotalResourcesDoNotContainsRequiredResourcesAtAll()
throws Exception {
// given
final ResourceImpl aResource = new ResourceImpl(A_RESOURCE_TYPE, 123, "unit");
final ResourceImpl bResource = new ResourceImpl(B_RESOURCE_TYPE, 321, "unit");
// when
resourceAggregator.deduct(singletonList(aResource), singletonList(bResource));
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void shouldThrowIllegalArgumentExceptionWhenTryingToAggregateNotSupportedResource()
throws Exception {
// given
final ResourceImpl dResource = mock(ResourceImpl.class);
when(dResource.getType()).thenReturn("resourceD");
// when
resourceAggregator.aggregateByType(singletonList(dResource));
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void shouldThrowIllegalArgumentExceptionWhenTryingToAggregateNotSupportedResources()
throws Exception {
// given
final ResourceImpl dResource = mock(ResourceImpl.class);
final ResourceImpl anotherDResource = mock(ResourceImpl.class);
when(dResource.getType()).thenReturn("resourceD");
when(anotherDResource.getType()).thenReturn("resourceD");
// when
resourceAggregator.aggregateByType(asList(dResource, anotherDResource));
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void
shouldThrowIllegalArgumentExceptionWhenTotalResourcesListContainsNotSupportedResourceOnResourcesDeduction()
throws Exception {
// given
final ResourceImpl dResource = mock(ResourceImpl.class);
when(dResource.getType()).thenReturn("resourceD");
// when
resourceAggregator.deduct(emptyList(), singletonList(dResource));
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void
shouldThrowIllegalArgumentExceptionWhenResourcesToDeductListContainsNotSupportedResourceOnResourcesDeduction()
throws Exception {
// given
final ResourceImpl dResource = mock(ResourceImpl.class);
when(dResource.getType()).thenReturn("resourceD");
// when
resourceAggregator.deduct(singletonList(dResource), emptyList());
}
@Test
public void shouldReturnResourceAsExcessiveWhenDeductedAmountGreaterThan0() throws Exception {
// given
final ResourceImpl sourceAResource = new ResourceImpl(A_RESOURCE_TYPE, 5, "unit");
final ResourceImpl toCompareAResource = new ResourceImpl(A_RESOURCE_TYPE, 3, "unit");
final ResourceImpl excessiveAResource = new ResourceImpl(A_RESOURCE_TYPE, 2, "unit");
when(aResourceType.deduct(any(), any())).thenReturn(excessiveAResource);
// when
List<? extends Resource> excess =
resourceAggregator.excess(
singletonList(sourceAResource), singletonList(toCompareAResource));
// then
assertEquals(excess.size(), 1);
assertTrue(excess.contains(excessiveAResource));
verify(aResourceType).deduct(sourceAResource, toCompareAResource);
}
@Test
public void
shouldReturnResourceAsExcessiveWhenToSourceListContainsResourceButToCompareListDoesNotContainItAtAll()
throws Exception {
// given
final ResourceImpl sourceAResource = new ResourceImpl(A_RESOURCE_TYPE, 5, "unit");
// when
List<? extends Resource> excess =
resourceAggregator.excess(singletonList(sourceAResource), emptyList());
// then
assertEquals(excess.size(), 1);
assertTrue(excess.contains(sourceAResource));
}
@Test
public void
shouldNotReturnResourceAsExcessiveWhenToCompareListContainsResourceButSourceDoesNotContainItAtAll()
throws Exception {
// given
final ResourceImpl toCompareAResource = new ResourceImpl(A_RESOURCE_TYPE, 5, "unit");
// when
List<? extends Resource> excess =
resourceAggregator.excess(emptyList(), singletonList(toCompareAResource));
// then
assertTrue(excess.isEmpty());
}
@Test
public void shouldNotReturnResourceAsExcessiveWhenResourcesHaveTheSameAmount() throws Exception {
// given
final ResourceImpl sourceAResource = new ResourceImpl(A_RESOURCE_TYPE, 5, "unit");
final ResourceImpl toCompareAResource = new ResourceImpl(A_RESOURCE_TYPE, 5, "unit");
// when
List<? extends Resource> excess =
resourceAggregator.excess(
singletonList(sourceAResource), singletonList(toCompareAResource));
// then
assertTrue(excess.isEmpty());
verify(aResourceType, never()).deduct(any(), any());
}
@Test
public void shouldNotReturnResourceAsExcessiveWhenToCompareResourceIsGreaterThanSource()
throws Exception {
// given
final ResourceImpl sourceAResource = new ResourceImpl(A_RESOURCE_TYPE, 5, "unit");
final ResourceImpl toCompareAResource = new ResourceImpl(A_RESOURCE_TYPE, 10, "unit");
doThrow(new NoEnoughResourcesException(emptyList(), emptyList(), emptyList()))
.when(aResourceType)
.deduct(any(), any());
// when
List<? extends Resource> excess =
resourceAggregator.excess(
singletonList(sourceAResource), singletonList(toCompareAResource));
// then
assertTrue(excess.isEmpty());
verify(aResourceType).deduct(sourceAResource, toCompareAResource);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void
shouldThrowIllegalArgumentExceptionWhenFirstListContainsResourceWithUnsupportedTypeOnExcessCalculation()
throws Exception {
final ResourceImpl dResource = mock(ResourceImpl.class);
when(dResource.getType()).thenReturn("resourceD");
// when
resourceAggregator.excess(singletonList(dResource), emptyList());
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void
shouldThrowIllegalArgumentExceptionWhenSecondListContainsResourceWithUnsupportedTypeExcessCalculation()
throws Exception {
final ResourceImpl dResource = mock(ResourceImpl.class);
when(dResource.getType()).thenReturn("resourceD");
// when
resourceAggregator.excess(emptyList(), singletonList(dResource));
}
@Test
public void shouldReturnIntersectionOfTwoResourcesLists() throws Exception {
// given
final ResourceImpl aResource = new ResourceImpl(A_RESOURCE_TYPE, 123, "unit");
final ResourceImpl bResource = new ResourceImpl(B_RESOURCE_TYPE, 123, "unit");
final ResourceImpl anotherBResource = new ResourceImpl(B_RESOURCE_TYPE, 321, "unit");
final ResourceImpl cResource = new ResourceImpl(C_RESOURCE_TYPE, 321, "unit");
// when
List<? extends Resource> intersection =
resourceAggregator.intersection(
asList(aResource, bResource), asList(anotherBResource, cResource));
// then
assertEquals(intersection.size(), 2);
assertTrue(intersection.contains(bResource));
assertTrue(intersection.contains(anotherBResource));
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void
shouldThrowIllegalArgumentExceptionWhenFirstListContainsResourceWithUnsupportedTypeOnIntersection()
throws Exception {
final ResourceImpl dResource = mock(ResourceImpl.class);
when(dResource.getType()).thenReturn("resourceD");
// when
resourceAggregator.intersection(singletonList(dResource), emptyList());
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void
shouldThrowIllegalArgumentExceptionWhenSecondListContainsResourceWithUnsupportedTypeOnIntersection()
throws Exception {
final ResourceImpl dResource = mock(ResourceImpl.class);
when(dResource.getType()).thenReturn("resourceD");
// when
resourceAggregator.intersection(emptyList(), singletonList(dResource));
}
@Test
public void shouldReturnMinResources() throws Exception {
// given
final ResourceImpl aResource = new ResourceImpl(A_RESOURCE_TYPE, 100, "unit");
final ResourceImpl bResource = new ResourceImpl(B_RESOURCE_TYPE, 1000, "unit");
final ResourceImpl minBResource = new ResourceImpl(B_RESOURCE_TYPE, 500, "unit");
final ResourceImpl anotherBResource = new ResourceImpl(B_RESOURCE_TYPE, 2000, "unit");
// when
List<? extends Resource> min =
resourceAggregator.min(asList(aResource, bResource, minBResource, anotherBResource));
// then
assertEquals(min.size(), 2);
assertTrue(min.contains(aResource));
assertTrue(min.contains(minBResource));
}
@Test
public void shouldReturnMinResourcesWhenTheyContainsMinusOneValue() throws Exception {
// given
final ResourceImpl aResource = new ResourceImpl(A_RESOURCE_TYPE, -1, "unit");
final ResourceImpl bResource = new ResourceImpl(B_RESOURCE_TYPE, -1, "unit");
final ResourceImpl minAResource = new ResourceImpl(A_RESOURCE_TYPE, 250, "unit");
final ResourceImpl minBResource = new ResourceImpl(B_RESOURCE_TYPE, 500, "unit");
// when
List<? extends Resource> min =
resourceAggregator.min(asList(aResource, minAResource, minBResource, bResource));
// then
assertEquals(min.size(), 2);
assertTrue(min.contains(minAResource));
assertTrue(min.contains(minBResource));
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void
shouldThrowIllegalArgumentExceptionWhenListContainsResourceWithUnsupportedTypeOnMinFinding()
throws Exception {
final ResourceImpl dResource = mock(ResourceImpl.class);
when(dResource.getType()).thenReturn("resourceD");
// when
resourceAggregator.min(singletonList(dResource));
}
}

View File

@ -1,142 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.resource.api.free;
import static java.util.Collections.singletonList;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.dto.server.DtoFactory;
import org.eclipse.che.multiuser.resource.model.FreeResourcesLimit;
import org.eclipse.che.multiuser.resource.shared.dto.FreeResourcesLimitDto;
import org.eclipse.che.multiuser.resource.shared.dto.ResourceDto;
import org.eclipse.che.multiuser.resource.spi.FreeResourcesLimitDao;
import org.eclipse.che.multiuser.resource.spi.impl.FreeResourcesLimitImpl;
import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests for {@link org.eclipse.che.multiuser.resource.api.free.FreeResourcesLimitManager}
*
* @author Sergii Leschenko
*/
@Listeners(MockitoTestNGListener.class)
public class FreeResourceManagerTest {
private static final String TEST_RESOURCE_TYPE = "Test";
@Mock private FreeResourcesLimitDao freeResourcesLimitDao;
@InjectMocks private FreeResourcesLimitManager manager;
@Test
public void shouldStoreFreeResourcesLimit() throws Exception {
// given
ResourceImpl resource = new ResourceImpl(TEST_RESOURCE_TYPE, 1, "unit");
FreeResourcesLimitImpl resourcesLimitImpl =
new FreeResourcesLimitImpl("account123", singletonList(resource));
ResourceDto resourceDto =
DtoFactory.newDto(ResourceDto.class)
.withAmount(1)
.withType(TEST_RESOURCE_TYPE)
.withUnit("unit");
FreeResourcesLimitDto freeResourcesLimitDto =
DtoFactory.newDto(FreeResourcesLimitDto.class)
.withAccountId("account123")
.withResources(singletonList(resourceDto));
// when
FreeResourcesLimit storedLimit = manager.store(freeResourcesLimitDto);
// then
assertEquals(storedLimit, resourcesLimitImpl);
verify(freeResourcesLimitDao).store(resourcesLimitImpl);
}
@Test(
expectedExceptions = NullPointerException.class,
expectedExceptionsMessageRegExp = "Required non-null free resources limit")
public void shouldThrowNpeOnStoringNullableFreeResourcesLimit() throws Exception {
// when
manager.store(null);
}
@Test
public void shouldReturnFreeResourcesLimitForSpecifiedAccount() throws Exception {
// given
ResourceImpl resource = new ResourceImpl(TEST_RESOURCE_TYPE, 1, "unit");
FreeResourcesLimitImpl resourcesLimitImpl =
new FreeResourcesLimitImpl("account123", singletonList(resource));
when(freeResourcesLimitDao.get(any())).thenReturn(resourcesLimitImpl);
// when
FreeResourcesLimit fetchedLimit = manager.get("account123");
// then
assertEquals(fetchedLimit, resourcesLimitImpl);
verify(freeResourcesLimitDao).get("account123");
}
@Test(
expectedExceptions = NullPointerException.class,
expectedExceptionsMessageRegExp = "Required non-null account id")
public void shouldThrowNpeOnGettingFreeResourcesLimitByNullableAccountId() throws Exception {
// when
manager.get(null);
}
@Test
public void shouldRemoveFreeResourcesLimitForSpecifiedAccount() throws Exception {
// when
manager.remove("account123");
// then
verify(freeResourcesLimitDao).remove("account123");
}
@Test(
expectedExceptions = NullPointerException.class,
expectedExceptionsMessageRegExp = "Required non-null account id")
public void shouldThrowNpeOnRemovingFreeResourcesLimitByNullableAccountId() throws Exception {
// when
manager.remove(null);
}
@Test
public void shouldReturnFreeResourcesLimits() throws Exception {
// given
ResourceImpl resource = new ResourceImpl(TEST_RESOURCE_TYPE, 1, "unit");
FreeResourcesLimitImpl resourcesLimitImpl =
new FreeResourcesLimitImpl("account123", singletonList(resource));
when(freeResourcesLimitDao.getAll(anyInt(), anyInt()))
.thenReturn(new Page<>(singletonList(resourcesLimitImpl), 5, 1, 9));
// when
Page<? extends FreeResourcesLimit> fetchedLimits = manager.getAll(1, 5);
// then
assertEquals(fetchedLimits.getTotalItemsCount(), 9);
assertEquals(fetchedLimits.getSize(), 1);
assertEquals(fetchedLimits.getItems().get(0), resourcesLimitImpl);
verify(freeResourcesLimitDao).getAll(1, 5);
}
}

View File

@ -1,164 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.resource.api.free;
import static io.restassured.RestAssured.given;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_NAME;
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_PASSWORD;
import static org.everrest.assured.JettyHttpServer.SECURE_PATH;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import io.restassured.response.Response;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.rest.ApiExceptionMapper;
import org.eclipse.che.api.core.rest.CheJsonProvider;
import org.eclipse.che.dto.server.DtoFactory;
import org.eclipse.che.multiuser.resource.api.DtoConverter;
import org.eclipse.che.multiuser.resource.model.FreeResourcesLimit;
import org.eclipse.che.multiuser.resource.shared.dto.FreeResourcesLimitDto;
import org.eclipse.che.multiuser.resource.spi.impl.FreeResourcesLimitImpl;
import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl;
import org.everrest.assured.EverrestJetty;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/** @author Sergii Leschenko */
@Listeners({EverrestJetty.class, MockitoTestNGListener.class})
public class FreeResourcesLimitServiceTest {
private static final String TEST_RESOURCE_TYPE = "test";
@SuppressWarnings("unused") // is declared for deploying by everrest-assured
private ApiExceptionMapper mapper;
@SuppressWarnings("unused") // is declared for deploying by everrest-assured
private CheJsonProvider jsonProvider = new CheJsonProvider(new HashSet<>());
@Mock private FreeResourcesLimitManager freeResourcesLimitManager;
@Mock private FreeResourcesLimitValidator resourcesLimitValidator;
@InjectMocks private FreeResourcesLimitService service;
@Test
public void shouldReturnResourcesLimitForGivenAccount() throws Exception {
FreeResourcesLimit resourcesLimit =
new FreeResourcesLimitImpl(
"account123", singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, 1000, "unit")));
when(freeResourcesLimitManager.get("account123")).thenReturn(resourcesLimit);
final Response response =
given()
.auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType("application/json")
.when()
.get(SECURE_PATH + "/resource/free/account123");
assertEquals(response.statusCode(), 200);
final FreeResourcesLimitDto fetchedLimit = unwrapDto(response, FreeResourcesLimitDto.class);
assertEquals(fetchedLimit, DtoConverter.asDto(resourcesLimit));
verify(freeResourcesLimitManager).get("account123");
}
@Test
public void shouldReturnResourcesLimits() throws Exception {
FreeResourcesLimit resourcesLimit1 =
new FreeResourcesLimitImpl(
"account123", singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, 1000, "unit")));
FreeResourcesLimit resourcesLimit2 =
new FreeResourcesLimitImpl(
"account321", singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, 2000, "unit")));
doReturn(new Page<>(Arrays.asList(resourcesLimit1, resourcesLimit2), 1, 2, 2))
.when(freeResourcesLimitManager)
.getAll(anyInt(), anyInt());
final Response response =
given()
.auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType("application/json")
.when()
.get(SECURE_PATH + "/resource/free?skipCount=1&maxItems=5");
assertEquals(response.statusCode(), 200);
final List<FreeResourcesLimitDto> freeResourcesLimits =
unwrapDtoList(response, FreeResourcesLimitDto.class);
assertEquals(freeResourcesLimits.size(), 2);
assertTrue(freeResourcesLimits.contains(DtoConverter.asDto(resourcesLimit1)));
assertTrue(freeResourcesLimits.contains(DtoConverter.asDto(resourcesLimit2)));
verify(freeResourcesLimitManager).getAll(5, 1);
}
@Test
public void shouldStoreResourcesLimit() throws Exception {
FreeResourcesLimit toCreate =
new FreeResourcesLimitImpl(
"account123", singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, 1000, "unit")));
FreeResourcesLimit created =
new FreeResourcesLimitImpl(
"account123", singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, 1000, "unit")));
when(freeResourcesLimitManager.store(any())).thenReturn(created);
final Response response =
given()
.auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType("application/json")
.body(DtoConverter.asDto(toCreate))
.when()
.post(SECURE_PATH + "/resource/free");
assertEquals(response.statusCode(), 201);
final FreeResourcesLimitDto result = unwrapDto(response, FreeResourcesLimitDto.class);
assertEquals(DtoConverter.asDto(created), result);
verify(freeResourcesLimitManager).store(DtoConverter.asDto(toCreate));
verify(resourcesLimitValidator).check(any());
}
@Test
public void shouldRemoveResourcesLimit() throws Exception {
Response response =
given()
.auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType("application/json")
.when()
.delete(SECURE_PATH + "/resource/free/account123");
assertEquals(response.statusCode(), 204);
verify(freeResourcesLimitManager).remove("account123");
}
private static <T> T unwrapDto(Response response, Class<T> dtoClass) {
return DtoFactory.getInstance().createDtoFromJson(response.body().print(), dtoClass);
}
private static <T> List<T> unwrapDtoList(Response response, Class<T> dtoClass) {
return DtoFactory.getInstance()
.createListDtoFromJson(response.body().print(), dtoClass)
.stream()
.collect(toList());
}
}

View File

@ -1,125 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.resource.api.free;
import static java.util.Collections.singletonList;
import static org.mockito.ArgumentMatchers.any;
import java.util.Arrays;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.dto.server.DtoFactory;
import org.eclipse.che.multiuser.resource.shared.dto.FreeResourcesLimitDto;
import org.eclipse.che.multiuser.resource.shared.dto.ResourceDto;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Test for {@link org.eclipse.che.multiuser.resource.api.free.FreeResourcesLimitValidator}
*
* @author Sergii Leschenko
*/
@Listeners(MockitoTestNGListener.class)
public class FreeResourcesLimitValidatorTest {
@Mock private ResourceValidator resourceValidator;
@InjectMocks private FreeResourcesLimitValidator validator;
@Test(
expectedExceptions = BadRequestException.class,
expectedExceptionsMessageRegExp = "Missed free resources limit description.")
public void shouldThrowBadRequestExceptionWhenFreeResourcesIsNull() throws Exception {
// when
validator.check(null);
}
@Test(
expectedExceptions = BadRequestException.class,
expectedExceptionsMessageRegExp = "Missed account id.")
public void shouldThrowBadRequestExceptionWhenAccountIdIsMissed() throws Exception {
// when
validator.check(
DtoFactory.newDto(FreeResourcesLimitDto.class)
.withResources(
singletonList(
DtoFactory.newDto(ResourceDto.class)
.withType("test")
.withUnit("mb")
.withAmount(1230))));
}
@Test(
expectedExceptions = BadRequestException.class,
expectedExceptionsMessageRegExp = "invalid resource")
public void shouldRethrowBadRequestExceptionWhenThereIsAnyInvalidResource() throws Exception {
// given
Mockito.doNothing()
.doThrow(new BadRequestException("invalid resource"))
.when(resourceValidator)
.validate(any());
// when
validator.check(
DtoFactory.newDto(FreeResourcesLimitDto.class)
.withAccountId("account123")
.withResources(
Arrays.asList(
DtoFactory.newDto(ResourceDto.class)
.withType("test")
.withUnit("mb")
.withAmount(1230),
DtoFactory.newDto(ResourceDto.class)
.withType("test2")
.withUnit("mb")
.withAmount(3214))));
}
@Test(
expectedExceptions = BadRequestException.class,
expectedExceptionsMessageRegExp =
"Free resources limit should contain only one resources with type 'test'.")
public void
shouldThrowBadRequestExceptionWhenAccountResourcesLimitContainTwoResourcesWithTheSameType()
throws Exception {
// when
validator.check(
DtoFactory.newDto(FreeResourcesLimitDto.class)
.withAccountId("account123")
.withResources(
Arrays.asList(
DtoFactory.newDto(ResourceDto.class)
.withType("test")
.withUnit("mb")
.withAmount(1230),
DtoFactory.newDto(ResourceDto.class)
.withType("test")
.withUnit("mb")
.withAmount(3))));
}
@Test
public void shouldNotThrowAnyExceptionWhenAccountResourcesLimitIsValid() throws Exception {
// when
validator.check(
DtoFactory.newDto(FreeResourcesLimitDto.class)
.withAccountId("account123")
.withResources(
singletonList(
DtoFactory.newDto(ResourceDto.class)
.withType("test")
.withUnit("mb")
.withAmount(1230))));
}
}

View File

@ -1,179 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.resource.api.free;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import com.google.common.collect.ImmutableSet;
import java.util.List;
import org.eclipse.che.account.api.AccountManager;
import org.eclipse.che.account.spi.AccountImpl;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.multiuser.resource.model.ProvidedResources;
import org.eclipse.che.multiuser.resource.spi.impl.FreeResourcesLimitImpl;
import org.eclipse.che.multiuser.resource.spi.impl.ProvidedResourcesImpl;
import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests for {@link org.eclipse.che.multiuser.resource.api.free.FreeResourcesProvider}
*
* @author Sergii Leschenko
*/
@Listeners(MockitoTestNGListener.class)
public class FreeResourcesProviderTest {
private static final String TEST_ACCOUNT_TYPE = "test";
private static final String TEST_RESOURCE_TYPE = "testResource";
private static final String TEST_RESOURCE_UNIT = "testResourceUnit";
@Mock private AccountImpl account;
@Mock private FreeResourcesLimitManager freeResourcesLimitManager;
@Mock private AccountManager accountManager;
@Mock private DefaultResourcesProvider defaultResourcesProvider;
private FreeResourcesProvider provider;
@BeforeMethod
public void setUp() throws Exception {
when(account.getType()).thenReturn(TEST_ACCOUNT_TYPE);
when(defaultResourcesProvider.getAccountType()).thenReturn(TEST_ACCOUNT_TYPE);
provider =
new FreeResourcesProvider(
freeResourcesLimitManager, accountManager, ImmutableSet.of(defaultResourcesProvider));
}
@Test
public void shouldProvideDefaultResourcesIfThereAreProviderForThisAccountType() throws Exception {
// given
when(accountManager.getById(any())).thenReturn(account);
when(freeResourcesLimitManager.get(any())).thenThrow(new NotFoundException("not found"));
when(defaultResourcesProvider.getResources(any()))
.thenReturn(singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, 1020, TEST_RESOURCE_UNIT)));
// when
List<ProvidedResources> result = provider.getResources("user123");
// then
assertEquals(result.size(), 1);
ProvidedResources providedResources = result.get(0);
assertEquals(
providedResources,
new ProvidedResourcesImpl(
FreeResourcesProvider.FREE_RESOURCES_PROVIDER,
null,
"user123",
-1L,
-1L,
singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, 1020, TEST_RESOURCE_UNIT))));
verify(freeResourcesLimitManager).get("user123");
}
@Test
public void shouldRewriteDefaultResourcesWithFreeResourcesLimitIfItExists() throws Exception {
// given
when(accountManager.getById(any())).thenReturn(account);
when(freeResourcesLimitManager.get(any()))
.thenReturn(
new FreeResourcesLimitImpl(
"user123",
singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, 12345, TEST_RESOURCE_UNIT))));
// when
List<ProvidedResources> result = provider.getResources("user123");
// then
assertEquals(result.size(), 1);
ProvidedResources providedResources = result.get(0);
assertEquals(
providedResources,
new ProvidedResourcesImpl(
FreeResourcesProvider.FREE_RESOURCES_PROVIDER,
"user123",
"user123",
-1L,
-1L,
singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, 12345, TEST_RESOURCE_UNIT))));
verify(freeResourcesLimitManager).get("user123");
}
@Test
public void shouldNotProvideDefaultResourcesForAccountThatDoesNotHaveDefaultResourcesProvider()
throws Exception {
// given
when(account.getType()).thenReturn("anotherTestType");
when(accountManager.getById(any())).thenReturn(account);
doThrow(new NotFoundException("not found")).when(freeResourcesLimitManager).get(any());
// when
List<ProvidedResources> result = provider.getResources("account123");
// then
assertTrue(result.isEmpty());
}
@Test
public void
shouldNotProvideDefaultResourcesForAccountIfDefaultResourcesProviderProvidesEmptyList()
throws Exception {
// given
when(accountManager.getById(any())).thenReturn(account);
when(defaultResourcesProvider.getResources(any())).thenReturn(emptyList());
doThrow(new NotFoundException("not found")).when(freeResourcesLimitManager).get(any());
// when
List<ProvidedResources> result = provider.getResources("user123");
// then
assertTrue(result.isEmpty());
}
@Test
public void shouldProvideResourcesFromFreeResourcesLimitIfItExists() throws Exception {
// given
when(account.getType()).thenReturn("anotherTestType");
when(accountManager.getById(any())).thenReturn(account);
when(freeResourcesLimitManager.get(any()))
.thenReturn(
new FreeResourcesLimitImpl(
"account123",
singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, 12345, TEST_RESOURCE_UNIT))));
// when
List<ProvidedResources> result = provider.getResources("account123");
// then
assertEquals(result.size(), 1);
ProvidedResources providedResources = result.get(0);
assertEquals(
providedResources,
new ProvidedResourcesImpl(
FreeResourcesProvider.FREE_RESOURCES_PROVIDER,
"account123",
"account123",
-1L,
-1L,
singletonList(new ResourceImpl(TEST_RESOURCE_TYPE, 12345, TEST_RESOURCE_UNIT))));
verify(freeResourcesLimitManager).get("account123");
}
}

View File

@ -1,99 +0,0 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.resource.api.free;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.dto.server.DtoFactory;
import org.eclipse.che.multiuser.resource.api.type.ResourceType;
import org.eclipse.che.multiuser.resource.shared.dto.ResourceDto;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests for {@link org.eclipse.che.multiuser.resource.api.free.ResourceValidator}
*
* @author Sergii Leschenko
*/
@Listeners(MockitoTestNGListener.class)
public class ResourceValidatorTest {
private static final String RESOURCE_TYPE = "test";
private static final String DEFAULT_RESOURCE_UNIT = "mb";
private static final Set<String> SUPPORTED_UNITS = ImmutableSet.of(DEFAULT_RESOURCE_UNIT, "gb");
@Mock private ResourceType resourceType;
private ResourceValidator validator;
@BeforeMethod
public void setUp() throws Exception {
when(resourceType.getDefaultUnit()).thenReturn("mb");
when(resourceType.getId()).thenReturn(RESOURCE_TYPE);
when(resourceType.getSupportedUnits()).thenReturn(SUPPORTED_UNITS);
validator = new ResourceValidator(ImmutableSet.of(resourceType));
}
@Test(
expectedExceptions = BadRequestException.class,
expectedExceptionsMessageRegExp = "Specified resources type 'unsupported' is not supported")
public void shouldThrowBadRequestExceptionWhenResourceHasNonSupportedType() throws Exception {
// when
validator.validate(DtoFactory.newDto(ResourceDto.class).withType("unsupported").withUnit("mb"));
}
@Test(
expectedExceptions = BadRequestException.class,
expectedExceptionsMessageRegExp =
"Specified resources type 'test' support only following units: mb, gb")
public void shouldThrowBadRequestExceptionWhenResourceHasNonSupportedUnit() throws Exception {
// when
validator.validate(DtoFactory.newDto(ResourceDto.class).withType(RESOURCE_TYPE).withUnit("kb"));
}
@Test
public void shouldSetDefaultResourceUnitWhenItIsMissed() throws Exception {
// given
ResourceDto toValidate =
DtoFactory.newDto(ResourceDto.class).withType(RESOURCE_TYPE).withUnit(null);
// when
validator.validate(toValidate);
// then
assertEquals(toValidate.getUnit(), DEFAULT_RESOURCE_UNIT);
}
@Test(
expectedExceptions = BadRequestException.class,
expectedExceptionsMessageRegExp = "Resources with type 'test' has negative amount")
public void shouldThrowBadRequestExceptionWhenResourceHasNegativeAmount() throws Exception {
// when
validator.validate(
DtoFactory.newDto(ResourceDto.class)
.withType(RESOURCE_TYPE)
.withAmount(-1024)
.withUnit("mb"));
}
@Test
public void shouldNotThrowAnyExceptionsWhenResourceHasSupportedTypeAndUnit() throws Exception {
// when
validator.validate(DtoFactory.newDto(ResourceDto.class).withType(RESOURCE_TYPE).withUnit("mb"));
}
}

View File

@ -1,190 +0,0 @@
/*
* Copyright (c) 2012-2021 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.resource.api.type;
import static org.testng.Assert.assertEquals;
import com.google.common.collect.ImmutableSet;
import java.util.Collections;
import java.util.Set;
import org.eclipse.che.multiuser.resource.api.exception.NoEnoughResourcesException;
import org.eclipse.che.multiuser.resource.model.Resource;
import org.eclipse.che.multiuser.resource.spi.impl.ResourceImpl;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* Tests for {@link org.eclipse.che.multiuser.resource.api.type.AbstractExhaustibleResource}
*
* @author Sergii Leschenko
*/
public class AbstractExhaustibleResourceTest {
private AbstractExhaustibleResource resourceType;
@BeforeMethod
public void setUp() throws Exception {
resourceType = new TestResourceType();
}
@Test
public void shouldFindSumResourcesAmountsOnResourcesAggregation() throws Exception {
final Resource aggregate =
resourceType.aggregate(
new ResourceImpl(TestResourceType.ID, 1000, TestResourceType.UNIT),
new ResourceImpl(TestResourceType.ID, 500, TestResourceType.UNIT));
assertEquals(aggregate.getType(), TestResourceType.ID);
assertEquals(aggregate.getAmount(), 1500);
assertEquals(aggregate.getUnit(), TestResourceType.UNIT);
}
@Test
public void
shouldReturnResourceWithMinusOneAmountWhenFirstResourceHasMinusOneAmountOnResourcesDeduction()
throws Exception {
final Resource aggregate =
resourceType.aggregate(
new ResourceImpl(TestResourceType.ID, -1, TestResourceType.UNIT),
new ResourceImpl(TestResourceType.ID, 500, TestResourceType.UNIT));
assertEquals(aggregate.getType(), TestResourceType.ID);
assertEquals(aggregate.getAmount(), -1);
assertEquals(aggregate.getUnit(), TestResourceType.UNIT);
}
@Test
public void
shouldReturnResourceWithMinusOneAmountWhenSecondResourceHasMinusOneAmountOnResourcesDeduction()
throws Exception {
final Resource aggregate =
resourceType.aggregate(
new ResourceImpl(TestResourceType.ID, 2000, TestResourceType.UNIT),
new ResourceImpl(TestResourceType.ID, -1, TestResourceType.UNIT));
assertEquals(aggregate.getType(), TestResourceType.ID);
assertEquals(aggregate.getAmount(), -1);
assertEquals(aggregate.getUnit(), TestResourceType.UNIT);
}
@Test
public void shouldFindDifferenceResourcesAmountsOnResourcesDeduction() throws Exception {
final Resource deducted =
resourceType.deduct(
new ResourceImpl(TestResourceType.ID, 1000, TestResourceType.UNIT),
new ResourceImpl(TestResourceType.ID, 500, TestResourceType.UNIT));
assertEquals(deducted.getType(), TestResourceType.ID);
assertEquals(deducted.getAmount(), 500);
assertEquals(deducted.getUnit(), TestResourceType.UNIT);
}
@Test
public void
shouldReturnResourceWithMinusOneAmountWhenTotalResourceHasMinusOneOnResourcesDeduction()
throws Exception {
final Resource deducted =
resourceType.deduct(
new ResourceImpl(TestResourceType.ID, -1, TestResourceType.UNIT),
new ResourceImpl(TestResourceType.ID, 500, TestResourceType.UNIT));
assertEquals(deducted.getType(), TestResourceType.ID);
assertEquals(deducted.getAmount(), -1);
assertEquals(deducted.getUnit(), TestResourceType.UNIT);
}
@Test(expectedExceptions = NoEnoughResourcesException.class)
public void
shouldReturnResourceWithMinusOneAmountWhenDeductionResourceHasMinusOneOnResourcesDeduction()
throws Exception {
resourceType.deduct(
new ResourceImpl(TestResourceType.ID, 1000, TestResourceType.UNIT),
new ResourceImpl(TestResourceType.ID, -1, TestResourceType.UNIT));
}
@Test
public void
shouldThrowConflictExceptionWhenDeductionAmountMoreThanTotalAmountOnResourcesDeduction()
throws Exception {
try {
resourceType.deduct(
new ResourceImpl(TestResourceType.ID, 300, TestResourceType.UNIT),
new ResourceImpl(TestResourceType.ID, 1000, TestResourceType.UNIT));
} catch (NoEnoughResourcesException e) {
assertEquals(
e.getMissingResources(),
Collections.singletonList(
new ResourceImpl(TestResourceType.ID, 700, TestResourceType.UNIT)));
}
}
@Test(expectedExceptions = IllegalArgumentException.class, dataProvider = "resources")
public void
shouldThrowIllegalArgumentExceptionWhenOneOfResourcesHasUnsupportedTypeOrUnitOnResourcesAggregation(
ResourceImpl resourceA, ResourceImpl resourceB) {
resourceType.aggregate(resourceA, resourceB);
}
@Test(expectedExceptions = IllegalArgumentException.class, dataProvider = "resources")
public void
shouldThrowIllegalArgumentExceptionWhenOneOfResourcesHasUnsupportedTypeOrUnitOnResourcesDeduction(
ResourceImpl resourceA, ResourceImpl resourceB) {
resourceType.aggregate(resourceA, resourceB);
}
@DataProvider(name = "resources")
public Object[][] getResources() {
return new Object[][] {
{
new ResourceImpl("unsupported", 1000, TestResourceType.UNIT),
new ResourceImpl(TestResourceType.ID, 1000, TestResourceType.UNIT)
},
{
new ResourceImpl(TestResourceType.ID, 1000, TestResourceType.UNIT),
new ResourceImpl("unsupported", 1000, TestResourceType.UNIT)
},
{
new ResourceImpl(TestResourceType.ID, 1000, "unsupported"),
new ResourceImpl(TestResourceType.ID, 1000, TestResourceType.UNIT)
},
{
new ResourceImpl(TestResourceType.ID, 1000, TestResourceType.UNIT),
new ResourceImpl(TestResourceType.ID, 1000, "unsupported")
}
};
}
private static class TestResourceType extends AbstractExhaustibleResource {
private static final String ID = "testResource";
private static final String UNIT = "testUnit";
@Override
public String getId() {
return ID;
}
@Override
public String getDescription() {
return null;
}
@Override
public Set<String> getSupportedUnits() {
return ImmutableSet.of(UNIT);
}
@Override
public String getDefaultUnit() {
return UNIT;
}
}
}

Some files were not shown because too many files have changed in this diff Show More