Remove DB related modules
parent
fa7d6442f5
commit
0c30568b3f
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
*
|
||||
* @@Inject
|
||||
* @SuppressWarnings("unused")
|
||||
* private DBInitializer dbInitializer;
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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<MyEvent>() {
|
||||
* @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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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 {
|
||||
*
|
||||
* @Inject EventBus bus; <- EventBus will be injected by Guice
|
||||
*
|
||||
* @PreRemove
|
||||
* public void preRemove(Workspace workspace) {
|
||||
* bus.post(new BeforeWorkspaceRemovedEvent(workspace));
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @Entity
|
||||
* @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
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
+ '\''
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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)
|
||||
);
|
||||
|
|
@ -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');
|
||||
|
|
@ -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
|
||||
--
|
||||
|
||||
|
|
@ -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
|
||||
--
|
||||
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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))));
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in New Issue