From 8bcef4ef383a32595a07ff11f211df94a8926ac6 Mon Sep 17 00:00:00 2001 From: Sergii Leshchenko Date: Tue, 10 Apr 2018 13:28:30 +0300 Subject: [PATCH] CHE-5919 Fix existing and add new tests for changes related to K8s/OS caches --- infrastructures/kubernetes/pom.xml | 61 +++++ .../KubernetesInternalRuntimeTest.java | 226 +++++++++++++++- .../kubernetes/cache/jpa/JpaTckModule.java | 96 +++++++ .../tck/KubernetesMachinesCacheTest.java | 256 ++++++++++++++++++ .../tck/KubernetesRuntimeStateCacheTest.java | 252 +++++++++++++++++ .../kubernetes/cache/tck/TestObjects.java | 73 +++++ .../namespace/KubernetesNamespaceTest.java | 33 ++- .../OpenShiftInternalRuntimeTest.java | 8 +- .../project/OpenShiftProjectTest.java | 17 +- pom.xml | 6 + .../integration-tests/postgresql-tck/pom.xml | 12 +- .../src/test/java/PostgreSqlTckModule.java | 48 ++-- 12 files changed, 1040 insertions(+), 48 deletions(-) create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/jpa/JpaTckModule.java create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesMachinesCacheTest.java create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesRuntimeStateCacheTest.java create mode 100644 infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/TestObjects.java diff --git a/infrastructures/kubernetes/pom.xml b/infrastructures/kubernetes/pom.xml index 0044d45af9e..ca32154fca3 100644 --- a/infrastructures/kubernetes/pom.xml +++ b/infrastructures/kubernetes/pom.xml @@ -127,6 +127,46 @@ logback-classic test + + com.h2database + h2 + test + + + org.eclipse.che.core + che-core-api-account + test + + + org.eclipse.che.core + che-core-commons-test + test + + + org.eclipse.che.core + che-core-db-vendor-h2 + test + + + org.eclipse.che.core + che-core-sql-schema + test + + + org.eclipse.persistence + org.eclipse.persistence.core + test + + + org.eclipse.persistence + org.eclipse.persistence.jpa + test + + + org.flywaydb + flyway-core + test + org.hamcrest hamcrest-core @@ -148,4 +188,25 @@ test + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + **/tck/*.* + + + + + + + diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java index 1f23fc9bcdd..330ffcb369a 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntimeTest.java @@ -33,6 +33,7 @@ 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 static org.testng.Assert.fail; @@ -58,14 +59,22 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; +import java.util.stream.Collectors; +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.RuntimeIdentity; +import org.eclipse.che.api.core.model.workspace.runtime.ServerStatus; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.installer.server.model.impl.InstallerImpl; import org.eclipse.che.api.workspace.server.DtoConverter; @@ -78,13 +87,21 @@ import org.eclipse.che.api.workspace.server.model.impl.RuntimeIdentityImpl; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.spi.InternalInfrastructureException; +import org.eclipse.che.api.workspace.server.spi.StateException; import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig; import org.eclipse.che.api.workspace.shared.dto.event.MachineLogEvent; import org.eclipse.che.api.workspace.shared.dto.event.MachineStatusEvent; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesInternalRuntime.MachineLogsPublisher; import org.eclipse.che.workspace.infrastructure.kubernetes.bootstrapper.KubernetesBootstrapper; import org.eclipse.che.workspace.infrastructure.kubernetes.bootstrapper.KubernetesBootstrapperFactory; +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.environment.KubernetesEnvironment; +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.KubernetesRuntimeState; +import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState.RuntimeId; +import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesServerImpl; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesIngresses; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesPods; @@ -99,6 +116,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** @@ -107,7 +125,6 @@ * @author Anton Korneta */ public class KubernetesInternalRuntimeTest { - private static final int EXPOSED_PORT_1 = 4401; private static final int EXPOSED_PORT_2 = 8081; private static final int INTERNAL_PORT = 4411; @@ -144,6 +161,8 @@ public class KubernetesInternalRuntimeTest { @Mock private ProbeScheduler probesScheduler; @Mock private WorkspaceProbes workspaceProbes; @Mock private KubernetesServerResolver kubernetesServerResolver; + private KubernetesRuntimeStateCache runtimeStatesCache; + private KubernetesMachineCache machinesCache; @Captor private ArgumentCaptor machineStatusEventCaptor; @@ -153,6 +172,10 @@ public class KubernetesInternalRuntimeTest { @BeforeMethod public void setup() throws Exception { MockitoAnnotations.initMocks(this); + + runtimeStatesCache = new MapBasedRuntimeStateCache(); + machinesCache = new MapBasedMachinesCache(); + internalRuntime = new KubernetesInternalRuntime<>( 13, @@ -165,6 +188,8 @@ public void setup() throws Exception { workspaceProbesFactory, new RuntimeEventsPublisher(eventService), new KubernetesSharedPool(), + runtimeStatesCache, + machinesCache, context, namespace, emptyList()); @@ -176,7 +201,7 @@ public void setup() throws Exception { when(namespace.services()).thenReturn(services); when(namespace.ingresses()).thenReturn(ingresses); when(namespace.pods()).thenReturn(pods); - when(bootstrapperFactory.create(any(), anyList(), any())).thenReturn(bootstrapper); + when(bootstrapperFactory.create(any(), anyList(), any(), any())).thenReturn(bootstrapper); doReturn( ImmutableMap.of( M1_NAME, @@ -385,6 +410,90 @@ public void schedulesProbesOnRuntimeStart() throws Exception { verify(probesScheduler).schedule(eq(workspaceProbes), any()); } + @Test + public void shouldMarkRuntimeStarting() throws Exception { + // when + internalRuntime.markStarting(); + + assertEquals(internalRuntime.getStatus(), WorkspaceStatus.STARTING); + } + + @Test( + expectedExceptions = StateException.class, + expectedExceptionsMessageRegExp = "Runtime is already started" + ) + public void shouldThrowExceptionIfRuntimeIsAlreadyStarting() throws Exception { + // given + runtimeStatesCache.putIfAbsent( + new KubernetesRuntimeState( + internalRuntime.getContext().getIdentity(), "test", WorkspaceStatus.STARTING)); + + // when + internalRuntime.markStarting(); + } + + @Test + public void shouldMarkRuntimeRunning() throws Exception { + // given + runtimeStatesCache.putIfAbsent( + new KubernetesRuntimeState( + internalRuntime.getContext().getIdentity(), "test", WorkspaceStatus.STARTING)); + + // when + internalRuntime.markRunning(); + + // then + assertEquals(internalRuntime.getStatus(), WorkspaceStatus.RUNNING); + } + + @Test + public void shouldMarkRuntimeStopping() throws Exception { + // given + runtimeStatesCache.putIfAbsent( + new KubernetesRuntimeState( + internalRuntime.getContext().getIdentity(), "test", WorkspaceStatus.RUNNING)); + + // when + internalRuntime.markStopping(); + + // then + assertEquals(internalRuntime.getStatus(), WorkspaceStatus.STOPPING); + } + + @Test( + expectedExceptions = StateException.class, + expectedExceptionsMessageRegExp = "The environment must be running", + dataProvider = "nonRunningStatuses" + ) + public void shouldThrowExceptionWhenTryToMakeNonRunningNorStartingRuntimeAsStopping( + WorkspaceStatus status) throws Exception { + // given + runtimeStatesCache.putIfAbsent( + new KubernetesRuntimeState(internalRuntime.getContext().getIdentity(), "test", status)); + + // when + internalRuntime.markStopping(); + } + + @DataProvider + Object[][] nonRunningStatuses() { + return new Object[][] {{WorkspaceStatus.STOPPING}, {WorkspaceStatus.STOPPED}}; + } + + @Test + public void shouldRemoveRuntimeStateOnMarkingRuntimeStopped() throws Exception { + // given + runtimeStatesCache.putIfAbsent( + new KubernetesRuntimeState( + internalRuntime.getContext().getIdentity(), "test", WorkspaceStatus.STOPPING)); + + // when + internalRuntime.markStopped(); + + // then + assertFalse(runtimeStatesCache.get(internalRuntime.getContext().getIdentity()).isPresent()); + } + private static MachineStatusEvent newEvent(String machineName, MachineStatus status) { return newDto(MachineStatusEvent.class) .withIdentity(DtoConverter.asDto(IDENTITY)) @@ -523,4 +632,117 @@ private static MachineLogEvent asMachineLogEvent(ContainerEvent event) { private static IntOrString intOrString(int port) { return new IntOrStringBuilder().withIntVal(port).withStrVal(String.valueOf(port)).build(); } + + private static class MapBasedRuntimeStateCache implements KubernetesRuntimeStateCache { + private Map runtimesStates = new HashMap<>(); + + @Override + public Set getIdentities() throws InfrastructureException { + return new HashSet<>(runtimesStates.keySet()); + } + + @Override + public boolean putIfAbsent(KubernetesRuntimeState state) throws InfrastructureException { + return runtimesStates.putIfAbsent(state.getRuntimeId(), state) == null; + } + + @Override + public void updateStatus(RuntimeIdentity runtimeId, WorkspaceStatus newStatus) + throws InfrastructureException { + runtimesStates.get(new RuntimeId(runtimeId)).setStatus(newStatus); + } + + @Override + public boolean updateStatus( + RuntimeIdentity identity, Predicate predicate, WorkspaceStatus newStatus) + throws InfrastructureException { + KubernetesRuntimeState state = runtimesStates.get(new RuntimeId(identity)); + if (predicate.test(state.getStatus())) { + state.setStatus(newStatus); + return true; + } + return false; + } + + @Override + public WorkspaceStatus getStatus(RuntimeIdentity runtimeId) throws InfrastructureException { + return runtimesStates.get(new RuntimeId(runtimeId)).getStatus(); + } + + @Override + public Optional get(RuntimeIdentity runtimeId) + throws InfrastructureException { + return Optional.ofNullable(runtimesStates.get(new RuntimeId(runtimeId))); + } + + @Override + public void remove(RuntimeIdentity runtimeId) throws InfrastructureException { + runtimesStates.remove(new RuntimeId(runtimeId)); + } + } + + private static class MapBasedMachinesCache implements KubernetesMachineCache { + private Map machines = new HashMap<>(); + + private MachineId machineIdOf(RuntimeIdentity runtimeId, KubernetesMachineImpl machine) { + return new MachineId(runtimeId.getWorkspaceId(), machine.getName()); + } + + private MachineId machineIdOf(RuntimeIdentity runtimeId, String machineName) { + return new MachineId(runtimeId.getWorkspaceId(), machineName); + } + + @Override + public void put(RuntimeIdentity runtimeIdentity, KubernetesMachineImpl machine) + throws InfrastructureException { + machines.put(machineIdOf(runtimeIdentity, machine), machine); + } + + @Override + public boolean updateServerStatus( + RuntimeIdentity runtimeIdentity, + String machineName, + String serverName, + ServerStatus newStatus) + throws InfrastructureException { + KubernetesServerImpl server = + machines.get(machineIdOf(runtimeIdentity, machineName)).getServers().get(serverName); + + if (server.getStatus().equals(newStatus)) { + return false; + } else { + server.setStatus(newStatus); + return true; + } + } + + @Override + public KubernetesServerImpl getServer( + RuntimeIdentity runtimeIdentity, String machineName, String serverName) + throws InfrastructureException { + return machines.get(machineIdOf(runtimeIdentity, machineName)).getServers().get(serverName); + } + + @Override + public void updateMachineStatus( + RuntimeIdentity runtimeIdentity, String machineName, MachineStatus newStatus) + throws InfrastructureException { + machines.get(machineIdOf(runtimeIdentity, machineName)).setStatus(newStatus); + } + + @Override + public Map getMachines(RuntimeIdentity runtimeIdentity) + throws InfrastructureException { + return machines + .entrySet() + .stream() + .filter(e -> e.getKey().getWorkspaceId().equals(runtimeIdentity.getWorkspaceId())) + .collect(Collectors.toMap(e -> e.getValue().getName(), Entry::getValue)); + } + + @Override + public void remove(RuntimeIdentity identity) throws InfrastructureException { + machines.keySet().removeIf(id -> id.getWorkspaceId().equals(identity.getWorkspaceId())); + } + } } diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/jpa/JpaTckModule.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/jpa/JpaTckModule.java new file mode 100644 index 00000000000..11c625ed369 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/jpa/JpaTckModule.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * 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.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.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.KubernetesRuntimeState; +import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState.RuntimeId; +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, + RuntimeId.class, + KubernetesMachineImpl.class, + MachineId.class, + KubernetesServerImpl.class, + ServerId.class) + .addEntityClass( + "org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute") + .setExceptionHandler(H2ExceptionHandler.class) + .build()); + + bind(new TypeLiteral>() {}) + .toInstance(new JpaTckRepository<>(AccountImpl.class)); + bind(new TypeLiteral>() {}) + .toInstance(new JpaTckRepository<>(WorkspaceImpl.class)); + + bind(new TypeLiteral>() {}) + .toInstance(new JpaTckRepository<>(KubernetesRuntimeState.class)); + + bind(new TypeLiteral>() {}) + .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)); + } +} diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesMachinesCacheTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesMachinesCacheTest.java new file mode 100644 index 00000000000..954547c2092 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesMachinesCacheTest.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * 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.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +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.ServerStatus; +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.KubernetesMachineCache; +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.KubernetesRuntimeState.RuntimeId; +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 workspaceTckRepository; + @Inject private TckRepository accountRepository; + @Inject private TckRepository runtimesRepository; + + @Inject private TckRepository machineRepository; + + @Inject private KubernetesMachineCache machineCache; + + 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 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 + RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + + // when + machineCache.getMachines(runtimeId); + + // then + Map 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 + RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + KubernetesMachineImpl machine = machines[0]; + Entry 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 + RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + KubernetesMachineImpl machine = machines[0]; + + // when + machineCache.getServer(runtimeId, machine.getName(), "non-existing"); + } + + @Test + public void shouldUpdateMachineStatusServerStatus() throws Exception { + // given + RuntimeId 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 shouldUpdateMachineStatus() throws Exception { + // given + RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + KubernetesMachineImpl machine = machines[0]; + String machineName = machine.getName(); + + // when + machineCache.updateMachineStatus(runtimeId, machineName, MachineStatus.RUNNING); + + // then + Optional 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 + RuntimeId 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 + RuntimeId runtimeId = runtimeStates[0].getRuntimeId(); + + // when + machineCache.remove(runtimeId); + + // then + assertEquals(machineCache.getMachines(runtimeId).size(), 0); + } +} diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesRuntimeStateCacheTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesRuntimeStateCacheTest.java new file mode 100644 index 00000000000..fe8ba9d9396 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/KubernetesRuntimeStateCacheTest.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * 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.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 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.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; +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.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState.RuntimeId; +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 workspaceTckRepository; + @Inject private TckRepository accountRepository; + @Inject private TckRepository runtimesRepository; + + @Inject private KubernetesRuntimeStateCache runtimesStatesCache; + + 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 identities = runtimesStatesCache.getIdentities(); + + // then + assertEquals(identities.size(), 2); + assertTrue(identities.contains(runtimesStates[0].getRuntimeId())); + assertTrue(identities.contains(runtimesStates[1].getRuntimeId())); + } + + @Test + public void shouldReturnRuntimeStateByRuntimeId() throws Exception { + // given + KubernetesRuntimeState expectedState = runtimesStates[1]; + + // when + Optional 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 fetchedOpt = + runtimesStatesCache.get(nonExisting.getRuntimeId()); + + // then + assertFalse(fetchedOpt.isPresent()); + } + + @Test + public void shouldReturnRuntimeStatus() throws Exception { + // when + WorkspaceStatus status = runtimesStatesCache.getStatus(runtimesStates[0].getRuntimeId()); + + // then + assertEquals(runtimesStates[0].getStatus(), status); + } + + @Test + public void shouldThrowExceptionWhenThereIsNotStateForSpecifiedRuntimeId() throws Exception { + // when + WorkspaceStatus status = runtimesStatesCache.getStatus(runtimesStates[0].getRuntimeId()); + + // then + assertEquals(runtimesStates[0].getStatus(), status); + } + + @Test(dependsOnMethods = "shouldReturnRuntimeStatus") + public void shouldUpdateStatus() throws Exception { + // given + KubernetesRuntimeState stateToUpdate = runtimesStates[0]; + + // when + runtimesStatesCache.updateStatus(stateToUpdate.getRuntimeId(), WorkspaceStatus.STOPPED); + + // then + WorkspaceStatus updatedStatus = runtimesStatesCache.getStatus(stateToUpdate.getRuntimeId()); + assertEquals(updatedStatus, 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); + WorkspaceStatus updatedStatus = runtimesStatesCache.getStatus(stateToUpdate.getRuntimeId()); + assertEquals(updatedStatus, 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); + WorkspaceStatus updatedStatus = runtimesStatesCache.getStatus(stateToUpdate.getRuntimeId()); + assertEquals(updatedStatus, WorkspaceStatus.RUNNING); + assertEquals(stateToUpdate.getStatus(), WorkspaceStatus.RUNNING); + } + + @Test(dependsOnMethods = "shouldReturnRuntimeStateByRuntimeId") + public void shouldPutRuntimeState() throws Exception { + // given + KubernetesRuntimeState runtimeState = createRuntimeState(workspaces[2]); + + // when + boolean isInserted = runtimesStatesCache.putIfAbsent(runtimeState); + + // then + assertTrue(isInserted); + Optional 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 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]); + RuntimeId 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]); + RuntimeId toRemove = runtimeState.getRuntimeId(); + + // when + runtimesStatesCache.remove(toRemove); + + // then + assertFalse(runtimesStatesCache.get(toRemove).isPresent()); + } +} diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/TestObjects.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/TestObjects.java new file mode 100644 index 00000000000..3646ae653e4 --- /dev/null +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/cache/tck/TestObjects.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * 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.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.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; +import org.eclipse.che.workspace.infrastructure.kubernetes.model.KubernetesRuntimeState.RuntimeId; + +/** @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())); + } + + public static KubernetesRuntimeState createRuntimeState(WorkspaceImpl workspace) { + return new KubernetesRuntimeState( + new RuntimeId(workspace.getId(), "defEnv", workspace.getAccount().getId()), + generate("namespace", 5), + WorkspaceStatus.RUNNING); + } + + public static KubernetesMachineImpl createMachine( + String workspaceId, + String machineName, + MachineStatus status, + Map 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))); + } +} diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceTest.java index 01155424028..08dd070e531 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesNamespaceTest.java @@ -79,28 +79,32 @@ public void setUp() throws Exception { when(namespaceOperation.withName(anyString())).thenReturn(serviceAccountResource); when(serviceAccountResource.get()).thenReturn(mock(ServiceAccount.class)); - k8sNamespace = new KubernetesNamespace(WORKSPACE_ID, pods, services, pvcs, ingresses); + k8sNamespace = + new KubernetesNamespace( + clientFactory, WORKSPACE_ID, NAMESPACE, pods, services, pvcs, ingresses); } @Test - public void testKubernetesNamespaceCreationWhenNamespaceExists() throws Exception { + public void testKubernetesNamespacePreparingWhenNamespaceExists() throws Exception { // given prepareNamespace(NAMESPACE); + KubernetesNamespace namespace = new KubernetesNamespace(clientFactory, NAMESPACE, WORKSPACE_ID); // when - new KubernetesNamespace(clientFactory, NAMESPACE, WORKSPACE_ID); + namespace.prepare(); } @Test - public void testKubernetesNamespaceCreationWhenNamespaceDoesNotExist() throws Exception { + public void testKubernetesNamespacePreparingCreationWhenNamespaceDoesNotExist() throws Exception { // given MetadataNested namespaceMeta = prepareCreateNamespaceRequest(); Resource resource = prepareNamespaceResource(NAMESPACE); doThrow(new KubernetesClientException("error", 403, null)).when(resource).get(); + KubernetesNamespace namespace = new KubernetesNamespace(clientFactory, NAMESPACE, WORKSPACE_ID); // when - KubernetesNamespace namespace = new KubernetesNamespace(clientFactory, NAMESPACE, WORKSPACE_ID); + namespace.prepare(); // then verify(namespaceMeta).withName(NAMESPACE); @@ -145,7 +149,7 @@ public void testThrowsInfrastructureExceptionWhenFailedToGetNamespaceServiceAcco doThrow(new KubernetesClientException("error", 403, null)).when(resource).get(); doThrow(KubernetesClientException.class).when(kubernetesClient).serviceAccounts(); - new KubernetesNamespace(clientFactory, NAMESPACE, WORKSPACE_ID); + new KubernetesNamespace(clientFactory, NAMESPACE, WORKSPACE_ID).prepare(); } @Test(expectedExceptions = InfrastructureException.class) @@ -156,7 +160,7 @@ public void testThrowsInfrastructureExceptionWhenServiceAccountEventNotPublished doThrow(new KubernetesClientException("error", 403, null)).when(resource).get(); when(serviceAccountResource.get()).thenReturn(null); - new KubernetesNamespace(clientFactory, NAMESPACE, WORKSPACE_ID); + new KubernetesNamespace(clientFactory, NAMESPACE, WORKSPACE_ID).prepare(); } @Test(expectedExceptions = InfrastructureException.class) @@ -175,7 +179,7 @@ public void testThrowsInfrastructureExceptionWhenWatcherClosed() throws Exceptio .when(serviceAccountResource) .watch(any()); - new KubernetesNamespace(clientFactory, NAMESPACE, WORKSPACE_ID); + new KubernetesNamespace(clientFactory, NAMESPACE, WORKSPACE_ID).prepare(); } @Test @@ -185,16 +189,15 @@ public void testStopsWaitingServiceAccountEventJustAfterEventReceived() throws E doThrow(new KubernetesClientException("error", 403, null)).when(resource).get(); when(serviceAccountResource.get()).thenReturn(null); doAnswer( - (Answer) - invocation -> { - final Watcher watcher = invocation.getArgument(0); - watcher.eventReceived(Action.ADDED, mock(ServiceAccount.class)); - return mock(Watch.class); - }) + invocation -> { + final Watcher watcher = invocation.getArgument(0); + watcher.eventReceived(Action.ADDED, mock(ServiceAccount.class)); + return mock(Watch.class); + }) .when(serviceAccountResource) .watch(any()); - new KubernetesNamespace(clientFactory, NAMESPACE, WORKSPACE_ID); + new KubernetesNamespace(clientFactory, NAMESPACE, WORKSPACE_ID).prepare(); verify(serviceAccountResource).get(); verify(serviceAccountResource).watch(any()); diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java index bae47d34312..ce9b624b215 100644 --- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java +++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntimeTest.java @@ -65,6 +65,8 @@ import org.eclipse.che.api.workspace.shared.dto.event.MachineStatusEvent; import org.eclipse.che.workspace.infrastructure.kubernetes.bootstrapper.KubernetesBootstrapper; import org.eclipse.che.workspace.infrastructure.kubernetes.bootstrapper.KubernetesBootstrapperFactory; +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.namespace.KubernetesPods; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesServices; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.WorkspaceVolumesStrategy; @@ -118,6 +120,8 @@ public class OpenShiftInternalRuntimeTest { @Mock private WorkspaceVolumesStrategy volumesStrategy; @Mock private WorkspaceProbesFactory workspaceProbesFactory; @Mock private ProbeScheduler probesScheduler; + @Mock private KubernetesRuntimeStateCache runtimeStateCache; + @Mock private KubernetesMachineCache machinesCache; @Captor private ArgumentCaptor machineStatusEventCaptor; @@ -141,6 +145,8 @@ public void setup() throws Exception { workspaceProbesFactory, new RuntimeEventsPublisher(eventService), mock(KubernetesSharedPool.class), + runtimeStateCache, + machinesCache, context, project, emptyList()); @@ -151,7 +157,7 @@ public void setup() throws Exception { when(project.services()).thenReturn(services); when(project.routes()).thenReturn(routes); when(project.pods()).thenReturn(pods); - when(bootstrapperFactory.create(any(), anyList(), any())).thenReturn(bootstrapper); + when(bootstrapperFactory.create(any(), anyList(), any(), any())).thenReturn(bootstrapper); doReturn( ImmutableMap.of( M1_NAME, diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/project/OpenShiftProjectTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/project/OpenShiftProjectTest.java index ca3415c424a..90d5eaf112e 100644 --- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/project/OpenShiftProjectTest.java +++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/project/OpenShiftProjectTest.java @@ -81,30 +81,35 @@ public void setUp() throws Exception { when(namespaceOperation.withName(anyString())).thenReturn(serviceAccountResource); when(serviceAccountResource.get()).thenReturn(mock(ServiceAccount.class)); - openShiftProject = new OpenShiftProject(WORKSPACE_ID, pods, services, routes, pvcs, ingresses); + openShiftProject = + new OpenShiftProject( + clientFactory, WORKSPACE_ID, PROJECT_NAME, pods, services, routes, pvcs, ingresses); } @Test - public void testOpenShiftProjectCreationWhenProjectExists() throws Exception { + public void testOpenShiftProjectPreparingWhenProjectExists() throws Exception { // given prepareProject(PROJECT_NAME); + OpenShiftProject openShiftProject = + new OpenShiftProject(clientFactory, PROJECT_NAME, WORKSPACE_ID); // when - new OpenShiftProject(clientFactory, PROJECT_NAME, WORKSPACE_ID); + openShiftProject.prepare(); } @Test - public void testOpenShiftProjectCreationWhenProjectDoesNotExist() throws Exception { + public void testOpenShiftProjectPreparingWhenProjectDoesNotExist() throws Exception { // given MetadataNested projectMetadata = prepareProjectRequest(); Resource resource = prepareProjectResource(PROJECT_NAME); doThrow(new KubernetesClientException("error", 403, null)).when(resource).get(); - - // when OpenShiftProject openShiftProject = new OpenShiftProject(clientFactory, PROJECT_NAME, WORKSPACE_ID); + // when + openShiftProject.prepare(); + // then verify(projectMetadata).withName(PROJECT_NAME); } diff --git a/pom.xml b/pom.xml index 612f60950a7..0595ab47667 100644 --- a/pom.xml +++ b/pom.xml @@ -799,6 +799,12 @@ infrastructure-kubernetes ${che.version} + + org.eclipse.che.infrastructure + infrastructure-kubernetes + ${che.version} + tests + org.eclipse.che.infrastructure infrastructure-openshift diff --git a/wsmaster/integration-tests/postgresql-tck/pom.xml b/wsmaster/integration-tests/postgresql-tck/pom.xml index 8a996950b5c..11844c1eb1e 100644 --- a/wsmaster/integration-tests/postgresql-tck/pom.xml +++ b/wsmaster/integration-tests/postgresql-tck/pom.xml @@ -44,6 +44,15 @@ che-core-api-user tests + + org.eclipse.che.infrastructure + infrastructure-kubernetes + + + org.eclipse.che.infrastructure + infrastructure-kubernetes + tests + org.eclipse.che.multiuser che-multiuser-machine-authentication @@ -253,7 +262,8 @@ che-core-api-ssh, che-core-api-workspace, che-core-api-installer, - che-multiuser-machine-authentication + che-multiuser-machine-authentication, + infrastructure-kubernetes test tests diff --git a/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java b/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java index 0ea15cf1dd1..f50a5a48163 100644 --- a/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java +++ b/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java @@ -17,14 +17,12 @@ import java.util.Collection; import java.util.Map; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; import javax.inject.Inject; import javax.inject.Provider; import javax.persistence.EntityManager; import org.eclipse.che.account.spi.AccountDao; import org.eclipse.che.account.spi.AccountImpl; import org.eclipse.che.account.spi.jpa.JpaAccountDao; -import org.eclipse.che.api.core.model.workspace.Workspace; import org.eclipse.che.api.installer.server.jpa.JpaInstallerDao; import org.eclipse.che.api.installer.server.model.impl.InstallerImpl; import org.eclipse.che.api.installer.server.model.impl.InstallerServerConfigImpl; @@ -77,6 +75,13 @@ import org.eclipse.che.multiuser.machine.authentication.server.signature.spi.SignatureKeyDao; import org.eclipse.che.security.PasswordEncryptor; import org.eclipse.che.security.SHA512PasswordEncryptor; +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.cache.jpa.JpaKubernetesMachineCache; +import org.eclipse.che.workspace.infrastructure.kubernetes.cache.jpa.JpaKubernetesRuntimeStateCache; +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.postgresql.Driver; import org.postgresql.ds.PGSimpleDataSource; import org.slf4j.Logger; @@ -128,7 +133,14 @@ protected void configure() { WorkspaceExpiration.class, VolumeImpl.class, SignatureKeyImpl.class, - SignatureKeyPairImpl.class) + SignatureKeyPairImpl.class, + // k8s-runtimes + KubernetesRuntimeState.class, + KubernetesRuntimeState.RuntimeId.class, + KubernetesMachineImpl.class, + KubernetesMachineImpl.MachineId.class, + KubernetesServerImpl.class, + KubernetesServerImpl.ServerId.class) .addEntityClass( "org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute") .build()); @@ -161,8 +173,6 @@ protected void configure() { // machine bind(new TypeLiteral>() {}) .toInstance(new JpaTckRepository<>(RecipeImpl.class)); - bind(new TypeLiteral>() {}) - .toInstance(new WorkspaceRepoForSnapshots()); // ssh bind(SshDao.class).to(JpaSshDao.class); @@ -187,6 +197,16 @@ protected void configure() { bind(SignatureKeyDao.class).to(JpaSignatureKeyDao.class); bind(new TypeLiteral>() {}) .toInstance(new JpaTckRepository<>(SignatureKeyPairImpl.class)); + + // k8s runtimes + bind(new TypeLiteral>() {}) + .toInstance(new JpaTckRepository<>(KubernetesRuntimeState.class)); + + bind(new TypeLiteral>() {}) + .toInstance(new JpaTckRepository<>(KubernetesMachineImpl.class)); + + bind(KubernetesRuntimeStateCache.class).to(JpaKubernetesRuntimeStateCache.class); + bind(KubernetesMachineCache.class).to(JpaKubernetesMachineCache.class); } private static void waitConnectionIsEstablished(String dbUrl, String dbUser, String dbPassword) { @@ -267,24 +287,6 @@ public void removeAll() throws TckRepositoryException { } } - static class WorkspaceRepoForSnapshots extends JpaTckRepository { - public WorkspaceRepoForSnapshots() { - super(WorkspaceImpl.class); - } - - @Override - public void createAll(Collection entities) throws TckRepositoryException { - super.createAll( - entities - .stream() - .map( - w -> - new WorkspaceImpl( - w, new AccountImpl(w.getNamespace(), w.getNamespace(), "simple"))) - .collect(Collectors.toList())); - } - } - private static class WorkspaceRepository extends JpaTckRepository { public WorkspaceRepository() { super(WorkspaceImpl.class);