/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.channel.cc.orchestrator.ui.ws.rs.operation;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import java.util.Collections;
import java.util.List;

import javax.ws.rs.ProcessingException;
import javax.ws.rs.core.Response.Status;

import org.jboss.arquillian.extension.rest.client.ArquillianResteasyResource;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.scytl.products.ov.channel.cc.orchestrator.mixdec.domain.model.BallotBoxStatus;
import com.scytl.products.ov.channel.cc.orchestrator.ui.ws.rs.config.MockMixingNodeListener;
import com.scytl.products.ov.commons.errormanagement.ExecutionPolicy;
import com.scytl.products.ov.commons.errormanagement.ExponentialBackoffExecutionPolicy;
import com.scytl.products.ov.commons.messaging.MessageListener;

/**
 * Test the error recovery workflow when a DTO cannot be processed.
 * <p>
 * WARNING: This test can only be run as part of the MessageBrokerTestSuite.
 */
@RunWith(Arquillian.class)
public class AlwaysFailMixDecArquillian extends MixDecArquillianTestBase {

    @Test
    public void retryOnErrorDTO(@ArquillianResteasyResource("") ResteasyWebTarget webTarget) throws Throwable {
        assertThat(getBallotBoxStatus(webTarget, BALLOT_BOX_ID), is(BallotBoxStatus.STATUS_NOT_FOUND));

        // Start the mock mixing control component nodes
        startUpMixingNodes();

        // Start processing the ballot box.
        List<BallotBoxStatus> ballotBoxStatuses = startMixing(webTarget, BALLOT_BOX_ID);
        ballotBoxStatuses.forEach(bbStatus -> {
            if (bbStatus.getBallotBoxId().equals(BALLOT_BOX_ID)) {
                assertThat(bbStatus.getProcessStatus(), is(BallotBoxStatus.STATUS_CLOSED));
            }
        });

        // Check the ballot box status
        assertThat(getBallotBoxStatus(webTarget, BALLOT_BOX_ID), is(BallotBoxStatus.STATUS_CLOSED));

        // The ballot box should eventually be closed. It will wait for 7
        // seconds (1+2+4).
        ExecutionPolicy policy =
            new ExponentialBackoffExecutionPolicy(3, 1000, Collections.singleton(ProcessingException.class));

        try {
            policy.execute(() -> {
                assertThat(downloadMixingResults(webTarget, BALLOT_BOX_ID).getStatus(), is(Status.OK.getStatusCode()));
                return null;
            });
        } catch (Throwable t) {
            // Expected, let it through.
        }

        assertThat(getBallotBoxStatus(webTarget, BALLOT_BOX_ID), is(BallotBoxStatus.STATUS_ERROR));
    }

    @Override
    protected MessageListener createListener(String nodeName, String requestQueueName, String responseQueueName) {
        MockMixingNodeListener listener =
            new MockMixingNodeListener(messagingService, nodeName, requestQueueName, responseQueueName);
        // Always mark the DTO as failed.
        listener.setDTOProcessor(mixingDTO -> mixingDTO.setError(new RuntimeException("Mock failure")));

        return listener;
    }

}
