Skip to content
GmsClientTest.java 8.79 KiB
Newer Older
package it.inaf.ia2.gms.client;

import it.inaf.ia2.gms.client.call.HttpClientWrapper;
import it.inaf.ia2.gms.client.call.MockedHttpClientWrapper;
import it.inaf.ia2.gms.client.model.Permission;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodySubscriber;
import java.net.http.HttpResponse.BodySubscribers;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Flow;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.AdditionalMatchers;
import org.mockito.ArgumentMatcher;
import org.mockito.ArgumentMatchers;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class GmsClientTest {

    private static final String BASE_URL = "http://base-url";

    private HttpClient httpClient;
    private GmsClient client;

    @Before
    public void setUp() {

        httpClient = mock(HttpClient.class);
        HttpClientWrapper clientWrapper = new MockedHttpClientWrapper(BASE_URL, httpClient);
        clientWrapper.setAccessToken("foo");
        client = new GmsClient(clientWrapper);
    public void testGetMyGroups() {

        String body = "LBT.INAF\n"
                + "LBT.AZ";
        CompletableFuture response = CompletableFuture.completedFuture(getMockedResponse(200, body));
        when(httpClient.sendAsync(any(), any())).thenReturn(response);
        List<String> groups = client.getMyGroups("LBT.");
        verify(httpClient, times(1)).sendAsync(endpointEq("GET", "search"), any());
        assertEquals(2, groups.size());
        assertEquals("INAF", groups.get(0));
        assertEquals("AZ", groups.get(1));
    public void testListGroups() {

        String body = "INAF\n"
                + "AZ";
        CompletableFuture response = CompletableFuture.completedFuture(getMockedResponse(200, body));
        when(httpClient.sendAsync(any(), any())).thenReturn(response);
        List<String> groups = client.listGroups("LBT.");
        verify(httpClient, times(1)).sendAsync(endpointEq("GET", "list/LBT."), any());
        assertEquals(2, groups.size());
        assertEquals("INAF", groups.get(0));
        assertEquals("AZ", groups.get(1));
    public void testCreateGroup() {
        CompletableFuture response = CompletableFuture.completedFuture(getMockedResponse(201));
        when(httpClient.sendAsync(any(), any())).thenReturn(response);
        client.createGroup("LBT.INAF", false);
        verify(httpClient, times(1)).sendAsync(endpointEq("POST", "LBT.INAF"), any());
    }
    @Test
    public void testDeleteGroup() {

        CompletableFuture response = CompletableFuture.completedFuture(getMockedResponse(204));
        when(httpClient.sendAsync(any(), any())).thenReturn(response);
        client.deleteGroup("LBT.INAF");
        verify(httpClient, times(1)).sendAsync(endpointEq("DELETE", "LBT.INAF"), any());
    public void testAddMember() {
        CompletableFuture response = CompletableFuture.completedFuture(getMockedResponse(200));
        when(httpClient.sendAsync(any(), any())).thenReturn(response);
        client.addMember("LBT.INAF", "user");
        verify(httpClient, times(1)).sendAsync(endpointEq("POST", "membership/LBT.INAF"), any());
    public void testRemoveMember() {
        CompletableFuture response = CompletableFuture.completedFuture(getMockedResponse(204));
        when(httpClient.sendAsync(any(), any())).thenReturn(response);
        client.removeMember("LBT.INAF", "user");
        verify(httpClient, times(1)).sendAsync(endpointEq("DELETE", "membership/LBT.INAF?user_id=user"), any());
    }
    @Test
    public void testAddPermission() {

        CompletableFuture response = CompletableFuture.completedFuture(getMockedResponse(200));
        when(httpClient.sendAsync(any(), any())).thenReturn(response);
        client.addPermission("LBT.INAF", "user", Permission.ADMIN);
        verify(httpClient, times(1)).sendAsync(endpointEq("POST", "permission/LBT.INAF"), any());
    public void testRemovePermission() {
        CompletableFuture response = CompletableFuture.completedFuture(getMockedResponse(204));
        when(httpClient.sendAsync(any(), any())).thenReturn(response);
        client.removePermission("LBT.INAF", "user");
        verify(httpClient, times(1)).sendAsync(endpointEq("DELETE", "permission/LBT.INAF?user_id=user"), any());
    }
    @Test
    public void testInvitedRegistration() {

        CompletableFuture response = CompletableFuture.completedFuture(getMockedResponse(201));

        when(httpClient.sendAsync(any(), any())).thenReturn(response);
        Map<String, Permission> permissionsMap = new HashMap<>();
        permissionsMap.put("group1", Permission.MANAGE_MEMBERS);
        permissionsMap.put("group2", Permission.MANAGE_MEMBERS);
        client.addInvitedRegistration("bvjsgqu423", "email", permissionsMap);
        // hash = AOyojiwaRR7BHPde6Tomg3+BMoQQggNM3wUHEarXuNQ=

        verify(httpClient, times(1)).sendAsync(
                AdditionalMatchers.and(
                        endpointEq("POST", "invited-registration"),
                        ArgumentMatchers.argThat(req -> {
                            String reqbody = req.bodyPublisher().map(p -> {
                                var bodySubscriber = BodySubscribers.ofString(StandardCharsets.UTF_8);
                                var flowSubscriber = new StringSubscriber(bodySubscriber);
                                p.subscribe(flowSubscriber);
                                return bodySubscriber.getBody().toCompletableFuture().join();
                            }).get();

                            // If the resulting hash contains a + symbol it has to be encoded to %2B,
                            // otherwise it will be interpreted as a space and wrong value will be
                            // stored into the database
                            String expectedBody = "token_hash=AOyojiwaRR7BHPde6Tomg3%2BBMoQQggNM3wUHEarXuNQ="
                                    + "&email=email&groups=group2 MANAGE_MEMBERS\n"
                                    + "group1 MANAGE_MEMBERS";

                            return reqbody.equals(expectedBody);
                        })), any());
    }

    /**
     * Credit: https://stackoverflow.com/a/55816685/771431
     */
    static final class StringSubscriber implements Flow.Subscriber<ByteBuffer> {

        final BodySubscriber<String> wrapped;

        StringSubscriber(BodySubscriber<String> wrapped) {
            this.wrapped = wrapped;
        }

        @Override
        public void onSubscribe(Flow.Subscription subscription) {
            wrapped.onSubscribe(subscription);
        }

        @Override
        public void onNext(ByteBuffer item) {
            wrapped.onNext(List.of(item));
        }

        @Override
        public void onError(Throwable throwable) {
            wrapped.onError(throwable);
        }

        @Override
        public void onComplete() {
            wrapped.onComplete();
        }
    }

    private HttpResponse getMockedResponse(int statusCode, String body) {
        HttpResponse response = getMockedResponse(statusCode);
        InputStream in = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8));
        when(response.body()).thenReturn(in);
        return response;
    private HttpResponse getMockedResponse(int statusCode) {
        HttpResponse response = mock(HttpResponse.class);
        when(response.statusCode()).thenReturn(statusCode);
        return response;
    private HttpRequest endpointEq(String expectedMethod, String expectedEndpoint) {
        return ArgumentMatchers.argThat(endpointEqArgumentMatcher(expectedMethod, expectedEndpoint));
    }

    private ArgumentMatcher<HttpRequest> endpointEqArgumentMatcher(String expectedMethod, String expectedEndpoint) {

        return new ArgumentMatcher<HttpRequest>() {

            private final String expectedUri = BASE_URL + "/" + expectedEndpoint;

            @Override
            public boolean matches(HttpRequest request) {
                return expectedMethod.equals(request.method()) && expectedUri.equals(request.uri().toString());
            }

            @Override
            public String toString() {
                return expectedMethod + " " + expectedUri;
            }
        };