test: added tests for exception handling in NamespaceProvisioner
Signed-off-by: xbaran4 <pbaran@redhat.com>pull/117/head
parent
bd46d1c218
commit
3d3cbee7e1
|
|
@ -22,6 +22,7 @@ import io.fabric8.kubernetes.client.KubernetesClientException;
|
|||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
|
|
@ -46,9 +47,9 @@ public class NamespaceProvisioner implements EventSubscriber<PostUserPersistedEv
|
|||
private static final String USER_PREFERENCES_SECRET_MOUNT_PATH = "/config/user/preferences";
|
||||
|
||||
private final KubernetesNamespaceFactory namespaceFactory;
|
||||
private final PreferenceManager preferenceManager;
|
||||
private final KubernetesClientFactory clientFactory;
|
||||
private final UserManager userManager;
|
||||
private final PreferenceManager preferenceManager;
|
||||
|
||||
@Inject
|
||||
public NamespaceProvisioner(
|
||||
|
|
@ -80,24 +81,32 @@ public class NamespaceProvisioner implements EventSubscriber<PostUserPersistedEv
|
|||
createOrUpdateSecrets(event.getUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates k8s user profile and user preferences k8s secrets. This serves as a way for
|
||||
* DevWorkspaces to acquire information about the user.
|
||||
*
|
||||
* @param user from its data are the secrets created
|
||||
*/
|
||||
private void createOrUpdateSecrets(User user) {
|
||||
|
||||
Secret userProfileSecret = prepareProfileSecret(user);
|
||||
Secret userPreferencesSecret = preparePreferencesSecret(user);
|
||||
Optional<Secret> userPreferencesSecret = preparePreferencesSecret(user);
|
||||
|
||||
try {
|
||||
String namespace =
|
||||
namespaceFactory.evaluateNamespaceName(
|
||||
new NamespaceResolutionContext(null, user.getId(), user.getName()));
|
||||
namespaceFactory.evaluateNamespaceName(
|
||||
new NamespaceResolutionContext(null, user.getId(), user.getName()));
|
||||
|
||||
clientFactory.create().secrets().inNamespace(namespace).createOrReplace(userProfileSecret);
|
||||
if (userPreferencesSecret != null) {
|
||||
clientFactory.create().secrets().inNamespace(namespace).createOrReplace(userPreferencesSecret);
|
||||
if (userPreferencesSecret.isPresent()) {
|
||||
clientFactory
|
||||
.create()
|
||||
.secrets()
|
||||
.inNamespace(namespace)
|
||||
.createOrReplace(userPreferencesSecret.get());
|
||||
}
|
||||
} catch (InfrastructureException | KubernetesClientException e) {
|
||||
LOG.error("There was a failure while creating user information secrets.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Secret prepareProfileSecret(User user) {
|
||||
|
|
@ -118,7 +127,7 @@ public class NamespaceProvisioner implements EventSubscriber<PostUserPersistedEv
|
|||
.build();
|
||||
}
|
||||
|
||||
private Secret preparePreferencesSecret(User user) {
|
||||
private Optional<Secret> preparePreferencesSecret(User user) {
|
||||
Base64.Encoder enc = Base64.getEncoder();
|
||||
Map<String, String> preferences;
|
||||
try {
|
||||
|
|
@ -126,39 +135,42 @@ public class NamespaceProvisioner implements EventSubscriber<PostUserPersistedEv
|
|||
} catch (ServerException e) {
|
||||
LOG.error(
|
||||
"Could not find user preferences. Skipping creation of user preferences secrets.", e);
|
||||
return null;
|
||||
return Optional.empty();
|
||||
}
|
||||
if (preferences == null || preferences.isEmpty()){
|
||||
LOG.error(
|
||||
"User preferences are empty. Skipping creation of user preferences secrets.");
|
||||
return null;
|
||||
if (preferences == null || preferences.isEmpty()) {
|
||||
LOG.error("User preferences are empty. Skipping creation of user preferences secrets.");
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Map<String, String> preferencesEncoded = new HashMap<>();
|
||||
preferences.forEach(
|
||||
(key, value) ->
|
||||
preferencesEncoded.put(normalizeDataKey(key), enc.encodeToString(value.getBytes())));
|
||||
preferencesEncoded.put(
|
||||
normalizePreferenceName(key), enc.encodeToString(value.getBytes())));
|
||||
|
||||
return new SecretBuilder()
|
||||
.addToData(preferencesEncoded)
|
||||
.withNewMetadata()
|
||||
.withName(USER_PREFERENCES_SECRET_NAME)
|
||||
.addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true")
|
||||
.addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file")
|
||||
.addToAnnotations(DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PREFERENCES_SECRET_MOUNT_PATH)
|
||||
.endMetadata()
|
||||
.build();
|
||||
return Optional.of(
|
||||
new SecretBuilder()
|
||||
.addToData(preferencesEncoded)
|
||||
.withNewMetadata()
|
||||
.withName(USER_PREFERENCES_SECRET_NAME)
|
||||
.addToLabels(DEV_WORKSPACE_MOUNT_LABEL, "true")
|
||||
.addToAnnotations(DEV_WORKSPACE_MOUNT_AS_ANNOTATION, "file")
|
||||
.addToAnnotations(
|
||||
DEV_WORKSPACE_MOUNT_PATH_ANNOTATION, USER_PREFERENCES_SECRET_MOUNT_PATH)
|
||||
.endMetadata()
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Some preferences names are not compatible with k8s restrictions on key field in secret. This
|
||||
* method replaces illegal characters with "-" (dash).
|
||||
* Some preferences names are not compatible with k8s restrictions on key field in secret. The
|
||||
* keys of data must consist of alphanumeric characters, -, _ or . This method replaces illegal
|
||||
* characters with -
|
||||
*
|
||||
* @param name original preference name
|
||||
* @return k8s compatible preference name used as a key field in Secret
|
||||
*/
|
||||
@VisibleForTesting
|
||||
String normalizeDataKey(String name) {
|
||||
String normalizePreferenceName(String name) {
|
||||
return name.replaceAll("[^-._a-zA-Z0-9]+", "-").replaceAll("-+", "-");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,126 @@
|
|||
*/
|
||||
package org.eclipse.che.workspace.infrastructure.kubernetes.provision;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Secret;
|
||||
import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.user.server.PreferenceManager;
|
||||
import org.eclipse.che.api.user.server.UserManager;
|
||||
import org.eclipse.che.api.user.server.model.impl.UserImpl;
|
||||
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
|
||||
import org.eclipse.che.api.workspace.server.spi.NamespaceResolutionContext;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientFactory;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.api.server.impls.KubernetesNamespaceMetaImpl;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class NamespaceProvisionerTest {
|
||||
|
||||
@Mock private KubernetesNamespaceFactory namespaceFactory;
|
||||
@Mock private KubernetesClientFactory clientFactory;
|
||||
@Mock private UserManager userManager;
|
||||
@Mock private PreferenceManager preferenceManager;
|
||||
@InjectMocks private NamespaceProvisioner namespaceProvisioner;
|
||||
|
||||
private static final String USER_ID = "user-id";
|
||||
private static final String USER_NAME = "user-name";
|
||||
private static final String USER_EMAIL = "user-email";
|
||||
private static final String USER_NAMESPACE = "user-namespace";
|
||||
|
||||
private KubernetesServer kubernetesServer;
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() throws InfrastructureException, NotFoundException, ServerException {
|
||||
kubernetesServer = new KubernetesServer(true, true);
|
||||
kubernetesServer.before();
|
||||
|
||||
Map<String, String> preferences = new HashMap<>();
|
||||
preferences.put("preference-name", "preference");
|
||||
|
||||
lenient().when(clientFactory.create()).thenReturn(kubernetesServer.getClient());
|
||||
lenient()
|
||||
.when(namespaceFactory.provision(any()))
|
||||
.thenReturn(new KubernetesNamespaceMetaImpl(USER_NAMESPACE, Collections.emptyMap()));
|
||||
lenient()
|
||||
.when(userManager.getById(USER_ID))
|
||||
.thenReturn(new UserImpl(USER_ID, USER_EMAIL, USER_NAME));
|
||||
lenient().when(namespaceFactory.evaluateNamespaceName(any())).thenReturn(USER_NAMESPACE);
|
||||
lenient().when(preferenceManager.find(USER_ID)).thenReturn(preferences);
|
||||
}
|
||||
|
||||
@AfterMethod
|
||||
public void cleanUp() {
|
||||
kubernetesServer.after();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalizePreferenceNameTest() {}
|
||||
public void shouldCreateSecretsOnNamespaceProvision() throws InfrastructureException {
|
||||
namespaceProvisioner.provision(new NamespaceResolutionContext(null, USER_ID, USER_NAME));
|
||||
List<Secret> createdSecrets =
|
||||
kubernetesServer.getClient().secrets().inNamespace(USER_NAMESPACE).list().getItems();
|
||||
assertEquals(createdSecrets.size(), 2);
|
||||
assertTrue(
|
||||
createdSecrets
|
||||
.stream()
|
||||
.anyMatch(secret -> secret.getMetadata().getName().equals("user-profile")));
|
||||
assertTrue(
|
||||
createdSecrets
|
||||
.stream()
|
||||
.anyMatch(secret -> secret.getMetadata().getName().equals("user-preferences")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateOnlyProfileSecret() throws InfrastructureException, ServerException {
|
||||
when(preferenceManager.find(USER_ID)).thenReturn(Collections.emptyMap());
|
||||
namespaceProvisioner.provision(new NamespaceResolutionContext(null, USER_ID, USER_NAME));
|
||||
List<Secret> createdSecrets =
|
||||
kubernetesServer.getClient().secrets().inNamespace(USER_NAMESPACE).list().getItems();
|
||||
assertEquals(createdSecrets.size(), 1);
|
||||
assertEquals(createdSecrets.get(0).getMetadata().getName(), "user-profile");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateNoSecretOnException() throws InfrastructureException, NotFoundException, ServerException {
|
||||
when(userManager.getById(USER_ID)).thenThrow(new ServerException("Test server exception"));
|
||||
namespaceProvisioner.provision(new NamespaceResolutionContext(null, USER_ID, USER_NAME));
|
||||
assertTrue(kubernetesServer.getClient().secrets().inNamespace(USER_NAMESPACE).list().getItems().isEmpty());
|
||||
verifyNoInteractions(clientFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNormalizePreferenceName() {
|
||||
assertEquals(namespaceProvisioner.normalizePreferenceName("codename:bond"), "codename-bond");
|
||||
assertEquals(namespaceProvisioner.normalizePreferenceName("some--:pref"), "some-pref");
|
||||
assertEquals(namespaceProvisioner.normalizePreferenceName("pref[name].sub"), "pref-name-.sub");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldKeepPreferenceName() {
|
||||
assertEquals(namespaceProvisioner.normalizePreferenceName("codename.bond"), "codename.bond");
|
||||
assertEquals(namespaceProvisioner.normalizePreferenceName("pref_name"), "pref_name");
|
||||
assertEquals(
|
||||
namespaceProvisioner.normalizePreferenceName("some-name.over_rainbow"),
|
||||
"some-name.over_rainbow");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue