<|start_filename|>src/test/java/com/iexec/core/workflow/WorkflowToJson.java<|end_filename|>
/*
 * Copyright 2020 IEXEC BLOCKCHAIN TECH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iexec.core.workflow;

import org.junit.Test;

public class WorkflowToJson {

    /*
     * This updates the json files when transitions
     * or actions are modified. 
     */
    @Test
    public void workflowToJson() {
        String transitionsFilePath = "src/main/resources/workflow/replicate-transitions.json";
        String actionsFilePath = "src/main/resources/workflow/replicate-actions.json";
        ReplicateWorkflow rw = ReplicateWorkflow.getInstance();
        
        rw.saveWorkflowAsJsonFile(transitionsFilePath, rw.getTransitions());
        rw.saveWorkflowAsJsonFile(actionsFilePath, rw.getActionMap());
    }
}

<|start_filename|>src/test/java/com/iexec/core/replicate/ReplicateTests.java<|end_filename|>
/*
 * Copyright 2020 IEXEC BLOCKCHAIN TECH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iexec.core.replicate;

import com.iexec.common.replicate.ReplicateStatus;
import com.iexec.common.replicate.ReplicateStatusModifier;
import com.iexec.common.replicate.ReplicateStatusUpdate;

import org.junit.Test;

import java.util.Collections;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import static org.assertj.core.api.Assertions.assertThat;

public class ReplicateTests {

    @Test
    public void shouldInitializeStatusProperly(){
        Replicate replicate = new Replicate("worker", "taskId");
        assertThat(replicate.getStatusUpdateList().size()).isEqualTo(1);

        ReplicateStatusUpdate statusChange = replicate.getStatusUpdateList().get(0);
        assertThat(statusChange.getStatus()).isEqualTo(ReplicateStatus.CREATED);

        Date now = new Date();
        long duration = now.getTime() - statusChange.getDate().getTime();
        long diffInSeconds = TimeUnit.MILLISECONDS.toSeconds(duration);
        assertThat(diffInSeconds).isLessThan(1);
    }

    @Test
    public void shouldUpdateReplicateStatus(){
        Replicate replicate = new Replicate("worker", "taskId");
        assertThat(replicate.getStatusUpdateList().size()).isEqualTo(1);

        // only pool manager sets date of the update
        replicate.updateStatus(ReplicateStatus.STARTING, ReplicateStatusModifier.POOL_MANAGER);
        assertThat(replicate.getStatusUpdateList().size()).isEqualTo(2);

        ReplicateStatusUpdate initialStatus = replicate.getStatusUpdateList().get(0);
        assertThat(initialStatus.getStatus()).isEqualTo(ReplicateStatus.CREATED);

        ReplicateStatusUpdate updatedStatus = replicate.getStatusUpdateList().get(1);
        assertThat(updatedStatus.getStatus()).isEqualTo(ReplicateStatus.STARTING);

        Date now = new Date();
        long duration = now.getTime() - updatedStatus.getDate().getTime();
        long diffInSeconds = TimeUnit.MILLISECONDS.toSeconds(duration);
        assertThat(diffInSeconds).isLessThan(1);
    }

    @Test
    public void shouldGetProperLatestStatus(){
        Replicate replicate = new Replicate("worker", "taskId");
        assertThat(replicate.getStatusUpdateList().size()).isEqualTo(1);
        assertThat(replicate.getCurrentStatus()).isEqualTo(ReplicateStatus.CREATED);

        replicate.updateStatus(ReplicateStatus.STARTING, ReplicateStatusModifier.WORKER);
        assertThat(replicate.getStatusUpdateList().size()).isEqualTo(2);
        assertThat(replicate.getCurrentStatus()).isEqualTo(ReplicateStatus.STARTING);
    }


    @Test
    public void shouldReturnTrueWhenContributed(){
        Replicate replicate = new Replicate("0x1", "taskId");
        replicate.updateStatus(ReplicateStatus.STARTING, ReplicateStatusModifier.WORKER);
        replicate.updateStatus(ReplicateStatus.CONTRIBUTING, ReplicateStatusModifier.WORKER);
        replicate.updateStatus(ReplicateStatus.CONTRIBUTED, ReplicateStatusModifier.WORKER);
        replicate.updateStatus(ReplicateStatus.REVEALING, ReplicateStatusModifier.WORKER);
        replicate.updateStatus(ReplicateStatus.REVEALED, ReplicateStatusModifier.WORKER);

        assertThat(replicate.containsContributedStatus()).isTrue();
    }

    @Test
    public void shouldReturnFalseWhenContributedMissing(){
        Replicate replicate = new Replicate("0x1", "taskId");
        replicate.updateStatus(ReplicateStatus.STARTING, ReplicateStatusModifier.WORKER);
        replicate.updateStatus(ReplicateStatus.CONTRIBUTING, ReplicateStatusModifier.WORKER);
        replicate.updateStatus(ReplicateStatus.REVEALING, ReplicateStatusModifier.WORKER);
        replicate.updateStatus(ReplicateStatus.REVEALED, ReplicateStatusModifier.WORKER);

        assertThat(replicate.containsContributedStatus()).isFalse();
    }

    @Test
    public void shouldBeCreatedLongAgo(){
        final long maxExecutionTime = 60000;
        Date now = new Date();
        Replicate replicate = new Replicate("0x1", "taskId");
        ReplicateStatusUpdate oldCreationDate = replicate.getStatusUpdateList().get(0);
        oldCreationDate.setDate(new Date(now.getTime() - 3 * maxExecutionTime));
        replicate.setStatusUpdateList(Collections.singletonList(oldCreationDate));

        assertThat(replicate.isCreatedMoreThanNPeriodsAgo(2, maxExecutionTime)).isTrue();
    }

    @Test
    public void shouldNotBeCreatedLongAgo(){
        final long maxExecutionTime = 60000;
        Date now = new Date();
        Replicate replicate = new Replicate("0x1", "taskId");
        ReplicateStatusUpdate oldCreationDate = replicate.getStatusUpdateList().get(0);
        oldCreationDate.setDate(new Date(now.getTime() - maxExecutionTime));
        replicate.setStatusUpdateList(Collections.singletonList(oldCreationDate));

        assertThat(replicate.isCreatedMoreThanNPeriodsAgo(2, maxExecutionTime)).isFalse();
    }

    @Test
    public void shouldBeBusyComputing() {
        Replicate replicate = new Replicate("worker", "taskId");
        assertThat(replicate.isBusyComputing()).isTrue();
        replicate.updateStatus(ReplicateStatus.STARTING, ReplicateStatusModifier.WORKER);
        assertThat(replicate.isBusyComputing()).isTrue();
        replicate.updateStatus(ReplicateStatus.APP_DOWNLOADING, ReplicateStatusModifier.WORKER);
        assertThat(replicate.isBusyComputing()).isTrue();
        replicate.updateStatus(ReplicateStatus.APP_DOWNLOADED, ReplicateStatusModifier.WORKER);
        assertThat(replicate.isBusyComputing()).isTrue();
        replicate.updateStatus(ReplicateStatus.COMPUTING, ReplicateStatusModifier.WORKER);
        assertThat(replicate.isBusyComputing()).isTrue();

        replicate.updateStatus(ReplicateStatus.COMPUTED, ReplicateStatusModifier.WORKER);
        assertThat(replicate.isBusyComputing()).isFalse();
        replicate.updateStatus(ReplicateStatus.CONTRIBUTING, ReplicateStatusModifier.WORKER);
        assertThat(replicate.isBusyComputing()).isFalse();
        replicate.updateStatus(ReplicateStatus.CONTRIBUTED, ReplicateStatusModifier.WORKER);
        assertThat(replicate.isBusyComputing()).isFalse();
        replicate.updateStatus(ReplicateStatus.REVEALING, ReplicateStatusModifier.WORKER);
        assertThat(replicate.isBusyComputing()).isFalse();
        replicate.updateStatus(ReplicateStatus.REVEALED, ReplicateStatusModifier.WORKER);
        assertThat(replicate.isBusyComputing()).isFalse();
        replicate.updateStatus(ReplicateStatus.COMPLETED, ReplicateStatusModifier.WORKER);
        assertThat(replicate.isBusyComputing()).isFalse();
    }
}


<|start_filename|>src/test/java/com/iexec/core/metric/MetricServiceTests.java<|end_filename|>
/*
 * Copyright 2020 IEXEC BLOCKCHAIN TECH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iexec.core.metric;

import com.iexec.core.task.TaskService;
import com.iexec.core.task.TaskStatus;
import com.iexec.core.worker.Worker;
import com.iexec.core.worker.WorkerService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

public class MetricServiceTests {

    @Mock
    private WorkerService workerService;
    @Mock
    private TaskService taskService;

    @InjectMocks
    private MetricService metricService;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void shouldGetPlatformMetrics() {
        List<Worker> aliveWorkers = List.of(new Worker());
        when(workerService.getAliveWorkers()).thenReturn(aliveWorkers);
        when(workerService.getAliveTotalCpu()).thenReturn(1);
        when(workerService.getAliveAvailableCpu()).thenReturn(1);
        when(workerService.getAliveTotalGpu()).thenReturn(1);
        when(workerService.getAliveAvailableGpu()).thenReturn(1);
        when(taskService.findByCurrentStatus(TaskStatus.COMPLETED))
                .thenReturn(List.of());

        PlatformMetric metric = metricService.getPlatformMetrics();
        assertThat(metric.getAliveWorkers()).isEqualTo(aliveWorkers.size());
        assertThat(metric.getAliveTotalCpu()).isEqualTo(1);
        assertThat(metric.getAliveAvailableCpu()).isEqualTo(1);
        assertThat(metric.getAliveTotalGpu()).isEqualTo(1);
        assertThat(metric.getAliveAvailableGpu()).isEqualTo(1);
        assertThat(metric.getCompletedTasks()).isZero();
    }

}


<|start_filename|>src/main/java/com/iexec/core/contribution/ContributionService.java<|end_filename|>
/*
 * Copyright 2020 IEXEC BLOCKCHAIN TECH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iexec.core.contribution;

import com.iexec.common.replicate.ReplicateStatus;
import com.iexec.core.replicate.Replicate;
import com.iexec.core.replicate.ReplicatesService;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

@Service
public class ContributionService {

    private final ReplicatesService replicatesService;

    public ContributionService(ReplicatesService replicatesService) {
        this.replicatesService = replicatesService;
    }

    /*
     *
     * Get weight of a contributed
     *
     * */
    int getContributedWeight(String chainTaskId, String contribution) {
        int groupWeight = 0;
        for (Replicate replicate : replicatesService.getReplicates(chainTaskId)) {

            Optional<ReplicateStatus> lastRelevantStatus = replicate.getLastRelevantStatus();
            if (!lastRelevantStatus.isPresent()) {
                continue;
            }

            boolean isContributed = lastRelevantStatus.get().equals(ReplicateStatus.CONTRIBUTED);
            boolean haveSameContribution = contribution.equals(replicate.getContributionHash());
            boolean hasWeight = replicate.getWorkerWeight() > 0;

            if (isContributed && haveSameContribution && hasWeight) {
                groupWeight = Math.max(groupWeight, 1) * replicate.getWorkerWeight();
            }
        }
        return groupWeight;
    }

    /*
     *
     * Should exclude workers that have not CONTRIBUTED yet after t=date(CREATED)+1T
     *
     * */
    int getPendingWeight(String chainTaskId, long maxExecutionTime) {
        int pendingGroupWeight = 0;

        for (Replicate replicate : replicatesService.getReplicates(chainTaskId)) {

            Optional<ReplicateStatus> lastRelevantStatus = replicate.getLastRelevantStatus();
            if (!lastRelevantStatus.isPresent()) {
                continue;
            }

            boolean isCreatedLessThanOnePeriodAgo = !replicate.isCreatedMoreThanNPeriodsAgo(1, maxExecutionTime);
            boolean isNotContributed = !lastRelevantStatus.get().equals(ReplicateStatus.CONTRIBUTED);
            boolean isNotFailed = !lastRelevantStatus.get().equals(ReplicateStatus.FAILED);
            boolean hasWeight = replicate.getWorkerWeight() > 0;

            if (isCreatedLessThanOnePeriodAgo && isNotContributed && isNotFailed && hasWeight) {
                pendingGroupWeight = Math.max(pendingGroupWeight, 1) * replicate.getWorkerWeight();
            }
        }
        return pendingGroupWeight;
    }

    /*
     *
     * Retrieves distinct contributions
     *
     * */
    Set<String> getDistinctContributions(String chainTaskId) {

        Set<String> distinctContributions = new HashSet<>();

        for (Replicate replicate : replicatesService.getReplicates(chainTaskId)) {

            Optional<ReplicateStatus> lastRelevantStatus = replicate.getLastRelevantStatus();
            if (!lastRelevantStatus.isPresent()) {
                continue;
            }

            if (lastRelevantStatus.get().equals(ReplicateStatus.CONTRIBUTED)) {
                distinctContributions.add(replicate.getContributionHash());
            }
        }
        return distinctContributions;
    }


}

<|start_filename|>src/test/java/com/iexec/core/sms/SmsServiceTests.java<|end_filename|>
package com.iexec.core.sms;

import com.iexec.common.utils.BytesUtils;
import com.iexec.core.feign.SmsClient;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.mockito.Mockito.*;

public class SmsServiceTests {

    private static final String CHAIN_TASK_ID = "chainTaskId";

    @Mock
    private SmsClient smsClient;

    @InjectMocks
    private SmsService smsService;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void shouldGetEnclaveChallengeForTeeTask() {
        String expected = "challenge";
        when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenReturn(expected);
        
        String received = smsService.getEnclaveChallenge(CHAIN_TASK_ID, true);
        verify(smsClient).generateTeeChallenge(CHAIN_TASK_ID);
        Assertions.assertThat(received).isEqualTo(expected);
    }

    @Test
    public void shouldNotGetEnclaveChallengeForTeeTaskWhenNullSmsResponse() {
        when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenReturn(null);
        
        String received = smsService.getEnclaveChallenge(CHAIN_TASK_ID, true);
        verify(smsClient).generateTeeChallenge(CHAIN_TASK_ID);
        Assertions.assertThat(received).isEmpty();
    }

    @Test
    public void shouldGetEmptyAddressForStandardTask() {
        Assertions.assertThat(smsService.getEnclaveChallenge(CHAIN_TASK_ID, false))
                .isEqualTo(BytesUtils.EMPTY_ADDRESS);
        verify(smsClient, never()).generateTeeChallenge(anyString());
    }
}

<|start_filename|>src/main/java/com/iexec/core/contribution/ConsensusService.java<|end_filename|>
/*
 * Copyright 2020 IEXEC BLOCKCHAIN TECH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iexec.core.contribution;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class ConsensusService {

    private PredictionService predictionService;

    public ConsensusService(PredictionService predictionService) {
        this.predictionService = predictionService;
    }


    /*
     *
     * Estimating pending workers are going to contribute to the best prediction
     *
     * Return true means a consensus is not possible now, a new worker is welcome to add more weight
     * Return false means a consensus is possible now, no need to add new workers
     *
     */
    public boolean doesTaskNeedMoreContributionsForConsensus(String chainTaskId, int trust, long maxExecutionTime) {
        trust = Math.max(trust, 1);//ensure trust equals 1

        int bestPredictionWeight = predictionService.getBestPredictionWeight(chainTaskId, maxExecutionTime);
        int worstPredictionsWeight = predictionService.getWorstPredictionsWeight(chainTaskId);

        int allPredictionsWeight = worstPredictionsWeight + bestPredictionWeight;

        boolean needsMoreContributions = !isConsensusPossibleNow(trust, bestPredictionWeight, allPredictionsWeight);

        if (needsMoreContributions){
            log.info("More contributions needed [chainTaskId:{}, trust:{}, bestPredictionWeight:{}, " +
                            "allPredictionsWeight:{}]", chainTaskId, trust, bestPredictionWeight, allPredictionsWeight);
        }

        return needsMoreContributions;
    }

    private boolean isConsensusPossibleNow(int trust, int pendingAndContributedBestPredictionWeight, int allPredictionsWeight) {
        return pendingAndContributedBestPredictionWeight * trust > (1 + allPredictionsWeight) * (trust - 1);
    }






}

<|start_filename|>src/test/java/com/iexec/core/metric/MetricControllerTests.java<|end_filename|>
/*
 * Copyright 2020 IEXEC BLOCKCHAIN TECH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iexec.core.metric;

import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpStatus;

import static org.mockito.Mockito.when;

public class MetricControllerTests {

    @Mock
    private MetricService metricService;

    @InjectMocks
    private MetricController metricController;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void shouldGetMetrics() {
        PlatformMetric metric = PlatformMetric.builder()
                .aliveAvailableCpu(1)
                .aliveAvailableGpu(1)
                .build();
        when(metricService.getPlatformMetrics()).thenReturn(metric);
        Assertions.assertThat(
                metricController.getPlatformMetric().getStatusCode())
        .isEqualTo(HttpStatus.OK);
        Assertions.assertThat(
                metricController.getPlatformMetric().getBody())
        .isEqualTo(metric);
    }
}


<|start_filename|>src/test/java/com/iexec/core/chain/adapter/BlockchainAdapterServiceTests.java<|end_filename|>
/*
 * Copyright 2021 IEXEC BLOCKCHAIN TECH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iexec.core.chain.adapter;

import com.iexec.common.chain.adapter.CommandStatus;
import com.iexec.common.chain.adapter.args.TaskFinalizeArgs;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.ResponseEntity;

import java.util.Optional;

import static org.mockito.Mockito.when;

public class BlockchainAdapterServiceTests {

    public static final String CHAIN_TASK_ID = "CHAIN_TASK_ID";
    public static final String CHAIN_DEAL_ID = "CHAIN_DEAL_ID";
    public static final int TASK_INDEX = 0;
    public static final String LINK = "link";
    public static final String CALLBACK = "callback";
    public static final int PERIOD = 10;
    public static final int MAX_ATTEMPTS = 3;
    public static final int ATTEMPT = 0;

    @Mock
    private BlockchainAdapterClient blockchainAdapterClient;

    @InjectMocks
    private BlockchainAdapterService blockchainAdapterService;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    //Initialize

    @Test
    public void requestInitialize() {
        when(blockchainAdapterClient.requestInitializeTask(CHAIN_DEAL_ID, TASK_INDEX))
                .thenReturn(ResponseEntity.ok(CHAIN_TASK_ID));

        Assertions.assertThat(blockchainAdapterService.requestInitialize(CHAIN_DEAL_ID, TASK_INDEX))
                .isPresent();
    }

    @Test
    public void requestInitializeFailedSinceNot200() {
        when(blockchainAdapterClient.requestInitializeTask(CHAIN_DEAL_ID, TASK_INDEX))
                .thenReturn(ResponseEntity.badRequest().build());

        Assertions.assertThat(blockchainAdapterService.requestInitialize(CHAIN_DEAL_ID, TASK_INDEX))
                .isEmpty();
    }

    @Test
    public void requestInitializeFailedSinceNoBody() {
        when(blockchainAdapterClient.requestInitializeTask(CHAIN_DEAL_ID, TASK_INDEX))
                .thenReturn(ResponseEntity.ok().build());

        Assertions.assertThat(blockchainAdapterService.requestInitialize(CHAIN_DEAL_ID, TASK_INDEX))
                .isEmpty();
    }

    @Test
    public void isInitialized() {
        when(blockchainAdapterClient.getStatusForInitializeTaskRequest(CHAIN_TASK_ID))
                .thenReturn(ResponseEntity.ok(CommandStatus.SUCCESS));
        Assertions.assertThat(blockchainAdapterService.isInitialized(CHAIN_TASK_ID))
                .isEqualTo(Optional.of(true));
    }

    // Finalize

    @Test
    public void requestFinalize() {
        when(blockchainAdapterClient.requestFinalizeTask(CHAIN_TASK_ID, new TaskFinalizeArgs(LINK, CALLBACK)))
                .thenReturn(ResponseEntity.ok(CHAIN_TASK_ID));

        Assertions.assertThat(blockchainAdapterService.requestFinalize(CHAIN_TASK_ID, LINK, CALLBACK))
                .isPresent();
    }

    @Test
    public void requestFinalizeFailedSinceNot200() {
        when(blockchainAdapterClient.requestFinalizeTask(CHAIN_TASK_ID, new TaskFinalizeArgs(LINK, CALLBACK)))
                .thenReturn(ResponseEntity.ok().build());

        Assertions.assertThat(blockchainAdapterService.requestFinalize(CHAIN_TASK_ID, LINK, CALLBACK))
                .isEmpty();
    }

    @Test
    public void requestFinalizeFailedSinceNoBody() {
        when(blockchainAdapterClient.requestFinalizeTask(CHAIN_TASK_ID, new TaskFinalizeArgs(LINK, CALLBACK)))
                .thenReturn(ResponseEntity.badRequest().build());

        Assertions.assertThat(blockchainAdapterService.requestFinalize(CHAIN_TASK_ID, LINK, CALLBACK))
                .isEmpty();
    }

    @Test
    public void isFinalized() {
        when(blockchainAdapterClient.getStatusForFinalizeTaskRequest(CHAIN_TASK_ID))
                .thenReturn(ResponseEntity.ok(CommandStatus.SUCCESS));
        Assertions.assertThat(blockchainAdapterService.isFinalized(CHAIN_TASK_ID))
                .isEqualTo(Optional.of(true));
    }

    // Testing ability to pull & wait

    @Test
    public void isCommandCompletedWithSuccess() {
        when(blockchainAdapterClient.getStatusForInitializeTaskRequest(CHAIN_TASK_ID))
                .thenReturn(ResponseEntity.ok(CommandStatus.RECEIVED))
                .thenReturn(ResponseEntity.ok(CommandStatus.PROCESSING))
                .thenReturn(ResponseEntity.ok(CommandStatus.SUCCESS));

        Optional<Boolean> commandCompleted = blockchainAdapterService
                .isCommandCompleted(blockchainAdapterClient::getStatusForInitializeTaskRequest,
                CHAIN_TASK_ID, PERIOD, MAX_ATTEMPTS, ATTEMPT);
        Assertions.assertThat(commandCompleted.isPresent()).isTrue();
        Assertions.assertThat(commandCompleted.get()).isTrue();
    }

    @Test
    public void isCommandCompletedWithFailure() {
        when(blockchainAdapterClient.getStatusForInitializeTaskRequest(CHAIN_TASK_ID))
                .thenReturn(ResponseEntity.ok(CommandStatus.RECEIVED))
                .thenReturn(ResponseEntity.ok(CommandStatus.PROCESSING))
                .thenReturn(ResponseEntity.ok(CommandStatus.FAILURE));

        Optional<Boolean> commandCompleted = blockchainAdapterService
                .isCommandCompleted(blockchainAdapterClient::getStatusForInitializeTaskRequest,
                CHAIN_TASK_ID, PERIOD, MAX_ATTEMPTS, ATTEMPT);
        Assertions.assertThat(commandCompleted.isPresent()).isTrue();
        Assertions.assertThat(commandCompleted.get()).isFalse();
    }


}

<|start_filename|>src/test/java/com/iexec/core/pubsub/NotificationServiceTests.java<|end_filename|>
/*
 * Copyright 2020 IEXEC BLOCKCHAIN TECH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iexec.core.pubsub;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.springframework.messaging.simp.SimpMessagingTemplate;

import com.iexec.common.notification.TaskNotification;

public class NotificationServiceTests {

    @Mock
    private SimpMessagingTemplate sender;

    @Spy
    @InjectMocks
    private NotificationService notificationService;

    @Before
    public void init() { MockitoAnnotations.initMocks(this); }

    @Test
    public void shouldSendTaskNotification() {
        String chainTaskId = "chainTaskId";
        TaskNotification taskNotification = TaskNotification.builder()
            .chainTaskId(chainTaskId)
            .build();

        notificationService.sendTaskNotification(taskNotification);

        String destination = "/topic/task/" + taskNotification.getChainTaskId();

        Mockito.verify(sender, Mockito.times(1))
            .convertAndSend(destination, taskNotification);
    }
}

<|start_filename|>src/main/java/com/iexec/core/contribution/PredictionService.java<|end_filename|>
/*
 * Copyright 2020 IEXEC BLOCKCHAIN TECH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iexec.core.contribution;

import org.springframework.stereotype.Service;

import java.util.Set;

@Service
public class PredictionService {

    private ContributionService contributionService;

    public PredictionService(ContributionService contributionService) {
        this.contributionService = contributionService;
    }

    Prediction getContributedBestPrediction(String chainTaskId) {
        Set<String> distinctContributions = contributionService.getDistinctContributions(chainTaskId);
        Prediction bestPrediction = Prediction.builder().contribution("").weight(0).build();

        for (String predictionContribution : distinctContributions) {
            int predictionWeight = contributionService.getContributedWeight(chainTaskId, predictionContribution);

            if (predictionWeight >= bestPrediction.getWeight()) {
                bestPrediction.setContribution(predictionContribution);
                bestPrediction.setWeight(predictionWeight);
            }
        }
        return bestPrediction;
    }

    private int getContributedBestPredictionWeight(String chainTaskId) {
        return this.getContributedBestPrediction(chainTaskId).getWeight();
    }

    /*
     *
     * Considering pending workers are going to contribute to the best prediction
     * Counting pending and contributed
     *
     * */
    int getBestPredictionWeight(String chainTaskId, long maxExecutionTime) {
        int contributedBestPredictionWeight = getContributedBestPredictionWeight(chainTaskId);
        int pendingWeight = contributionService.getPendingWeight(chainTaskId, maxExecutionTime);

        int bestPredictionWeight;
        if (pendingWeight == 0 && contributedBestPredictionWeight == 0) {
            bestPredictionWeight = 0;
        } else if (pendingWeight > 0 && contributedBestPredictionWeight == 0) {
            bestPredictionWeight = pendingWeight;
        } else if (pendingWeight == 0 && contributedBestPredictionWeight > 0) {
            bestPredictionWeight = contributedBestPredictionWeight;
        } else {
            bestPredictionWeight = contributedBestPredictionWeight * pendingWeight;
        }
        return bestPredictionWeight;
    }

    /*
     *
     * Sum all prediction weights but exclude contributed best prediction weight
     *
     * */
    int getWorstPredictionsWeight(String chainTaskId) {
        Set<String> distinctContributions = contributionService.getDistinctContributions(chainTaskId);
        String bestPredictionContribution = this.getContributedBestPrediction(chainTaskId).getContribution();

        int allOtherPredictionsWeight = 0;

        for (String contribution : distinctContributions) {
            int predictionWeight = contributionService.getContributedWeight(chainTaskId, contribution);

            if (!contribution.equals(bestPredictionContribution)) {
                allOtherPredictionsWeight = allOtherPredictionsWeight + predictionWeight;
            }
        }
        return allOtherPredictionsWeight;
    }

}

<|start_filename|>src/test/java/com/iexec/core/stdout/StdoutCronServiceTests.java<|end_filename|>
package com.iexec.core.stdout;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.List;

import com.iexec.core.task.TaskService;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class StdoutCronServiceTests {

    @Mock
    private StdoutService stdoutService;

    @Mock
    private TaskService taskService;

    @InjectMocks
    private StdoutCronService stdoutCronService;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void shouldCleanStdout() {
        List<String> ids = List.of("id1", "id2");
        when(taskService.getChainTaskIdsOfTasksExpiredBefore(any()))
                .thenReturn(ids);
        stdoutCronService.purgeStdout();
        verify(stdoutService).delete(ids);
    }
}


<|start_filename|>src/main/java/com/iexec/core/chain/adapter/BlockchainAdapterService.java<|end_filename|>
/*
 * Copyright 2021 IEXEC BLOCKCHAIN TECH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iexec.core.chain.adapter;

import com.iexec.common.chain.adapter.CommandStatus;
import com.iexec.common.chain.adapter.args.TaskFinalizeArgs;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.function.Function;

import static java.util.concurrent.TimeUnit.SECONDS;

@Slf4j
@Service
public class BlockchainAdapterService {

    public static final int WATCH_PERIOD_SECONDS = 1;//To tune
    public static final int MAX_ATTEMPTS = 50;
    private final BlockchainAdapterClient blockchainAdapterClient;

    public BlockchainAdapterService(BlockchainAdapterClient blockchainAdapterClient) {
        this.blockchainAdapterClient = blockchainAdapterClient;
    }

    /**
     * Request on-chain initialization of the task.
     *
     * @param chainDealId ID of the deal
     * @param taskIndex   index of the task in the deal
     * @return chain task ID is initialization is properly requested
     */
    public Optional<String> requestInitialize(String chainDealId, int taskIndex) {
        try {
            ResponseEntity<String> initializeResponseEntity =
                    blockchainAdapterClient.requestInitializeTask(chainDealId, taskIndex);
            if (initializeResponseEntity.getStatusCode().is2xxSuccessful()
                    && !StringUtils.isEmpty(initializeResponseEntity.getBody())) {
                String chainTaskId = initializeResponseEntity.getBody();
                log.info("Requested initialize [chainTaskId:{}, chainDealId:{}, " +
                        "taskIndex:{}]", chainTaskId, chainDealId, taskIndex);
                return Optional.of(chainTaskId);
            }
        } catch (Throwable e) {
            log.error("Failed to requestInitialize [chainDealId:{}, " +
                    "taskIndex:{}]", chainDealId, taskIndex, e);
        }
        return Optional.empty();
    }

    /**
     * Verify if the initialize task command is completed on-chain.
     *
     * @param chainTaskId ID of the task
     * @return true if the tx is mined, false if reverted or empty for other
     * cases (too long since still RECEIVED or PROCESSING, adapter error)
     */
    public Optional<Boolean> isInitialized(String chainTaskId) {
        return isCommandCompleted(blockchainAdapterClient::getStatusForInitializeTaskRequest,
                chainTaskId, SECONDS.toMillis(WATCH_PERIOD_SECONDS), MAX_ATTEMPTS, 0);
    }

    /**
     * Request on-chain finalization of the task.
     *
     * @param chainTaskId  ID of the deal
     * @param resultLink   link of the result to be published on-chain
     * @param callbackData optional data for on-chain callback
     * @return chain task ID is initialization is properly requested
     */
    public Optional<String> requestFinalize(String chainTaskId,
                                            String resultLink,
                                            String callbackData) {
        try {
            ResponseEntity<String> finalizeResponseEntity =
                    blockchainAdapterClient.requestFinalizeTask(chainTaskId,
                            new TaskFinalizeArgs(resultLink, callbackData));
            if (finalizeResponseEntity.getStatusCode().is2xxSuccessful()
                    && !StringUtils.isEmpty(finalizeResponseEntity.getBody())) {
                log.info("Requested finalize [chainTaskId:{}, resultLink:{}, " +
                        "callbackData:{}]", chainTaskId, resultLink, callbackData);
                return Optional.of(chainTaskId);
            }
        } catch (Throwable e) {
            log.error("Failed to requestFinalize [chainTaskId:{}, resultLink:{}, " +
                    "callbackData:{}]", chainTaskId, resultLink, callbackData, e);
        }
        return Optional.empty();
    }

    /**
     * Verify if the finalize task command is completed on-chain.
     *
     * @param chainTaskId ID of the task
     * @return true if the tx is mined, false if reverted or empty for other
     * cases (too long since still RECEIVED or PROCESSING, adapter error)
     */
    public Optional<Boolean> isFinalized(String chainTaskId) {
        return isCommandCompleted(blockchainAdapterClient::getStatusForFinalizeTaskRequest,
                chainTaskId, SECONDS.toMillis(WATCH_PERIOD_SECONDS), MAX_ATTEMPTS, 0);
    }

    /**
     * Verify if a command sent to the adapter is completed on-chain.
     *
     * @param getCommandStatusFunction method for checking the command is completed
     * @param chainTaskId              ID of the task
     * @param period                   period in ms between checks
     * @param maxAttempts              maximum number of attempts for checking
     * @param attempt                  current attempt number
     * @return true if the tx is mined, false if reverted or empty for other
     * cases (too long since still RECEIVED or PROCESSING, adapter error)
     */
    Optional<Boolean> isCommandCompleted(
            Function<String, ResponseEntity<CommandStatus>> getCommandStatusFunction,
            String chainTaskId,
            long period, int maxAttempts, int attempt) {
        if (attempt >= maxAttempts) {
            log.error("Reached max retry while waiting command completion " +
                            "[chainTaskId:{}, maxAttempts:{}]",
                    chainTaskId, maxAttempts);
            return Optional.empty();
        }
        ResponseEntity<CommandStatus> commandStatusEntity;
        try {
            commandStatusEntity = getCommandStatusFunction.apply(chainTaskId);
            if (!commandStatusEntity.getStatusCode().is2xxSuccessful()
                    || commandStatusEntity.getBody() == null) {
                return Optional.empty();
            }
            CommandStatus status = commandStatusEntity.getBody();
            if (CommandStatus.SUCCESS.equals(status)
                    || CommandStatus.FAILURE.equals(status)) {
                return Optional.of(status.equals(CommandStatus.SUCCESS));
            }
            // RECEIVED, PROCESSING
            log.warn("Waiting command completion [chainTaskId:{}, " +
                            "status:{}, period:{}ms, attempt:{}, maxAttempts:{}]",
                    chainTaskId, status, period, attempt, maxAttempts);
            Thread.sleep(period);
            return isCommandCompleted(getCommandStatusFunction, chainTaskId,
                    period, maxAttempts, attempt + 1);
        } catch (Throwable e) {
            log.error("Unexpected error while waiting command completion " +
                            "[chainTaskId:{}, period:{}ms, attempt:{}, maxAttempts:{}]",
                    chainTaskId, period, attempt, maxAttempts, e);
        }
        return Optional.empty();
    }

}

<|start_filename|>src/test/java/com/iexec/core/contribution/ContributionServiceTests.java<|end_filename|>
/*
 * Copyright 2020 IEXEC BLOCKCHAIN TECH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iexec.core.contribution;

import com.iexec.common.replicate.ReplicateStatus;
import com.iexec.core.replicate.Replicate;
import com.iexec.core.replicate.ReplicatesService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.*;

import static org.assertj.core.api.Java6Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;


public class ContributionServiceTests {

    private final static String CHAIN_TASK_ID = "0xtaskId";
    private final static String A = "0xA";
    private final static String B = "0xB";
    private final static long MAX_EXECUTION_TIME = 60000;

    @Mock
    private ReplicatesService replicatesService;

    @InjectMocks
    private ContributionService contributionService;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void shouldGetContributedWeight() {
        Replicate replicate1 = mock(Replicate.class);
        when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
        when(replicate1.getContributionHash()).thenReturn(A);
        when(replicate1.getWorkerWeight()).thenReturn(3);

        Replicate replicate2 = mock(Replicate.class);
        when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
        when(replicate2.getContributionHash()).thenReturn(A);
        when(replicate2.getWorkerWeight()).thenReturn(5);

        Replicate replicate3 = mock(Replicate.class);
        when(replicate3.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
        when(replicate3.getContributionHash()).thenReturn(B);
        when(replicate3.getWorkerWeight()).thenReturn(10);

        List<Replicate> replicates = Arrays.asList(replicate1, replicate2, replicate3);

        when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(replicates);

        assertThat(contributionService.getContributedWeight(CHAIN_TASK_ID, A)).isEqualTo(15);
        assertThat(contributionService.getContributedWeight(CHAIN_TASK_ID, B)).isEqualTo(10);
    }

    @Test
    public void shouldNotGetContributedWeightSinceNoContribution() {
        Replicate replicate1 = mock(Replicate.class);
        when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
        when(replicate1.getContributionHash()).thenReturn("");
        when(replicate1.getWorkerWeight()).thenReturn(3);

        List<Replicate> replicates = Collections.singletonList(replicate1);

        when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(replicates);

        assertThat(contributionService.getContributedWeight(CHAIN_TASK_ID, A)).isEqualTo(0);
    }

    @Test
    public void shouldNotGetContributedWeightSinceNoWeight() {
        Replicate replicate1 = mock(Replicate.class);
        when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
        when(replicate1.getContributionHash()).thenReturn(A);
        when(replicate1.getWorkerWeight()).thenReturn(0);

        List<Replicate> replicates = Collections.singletonList(replicate1);

        when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(replicates);

        assertThat(contributionService.getContributedWeight(CHAIN_TASK_ID, A)).isEqualTo(0);
    }

    @Test
    public void shouldNotGetContributedWeightSinceNoTContributed() {
        Replicate replicate1 = mock(Replicate.class);
        when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTING));
        when(replicate1.getContributionHash()).thenReturn(A);
        when(replicate1.getWorkerWeight()).thenReturn(3);

        List<Replicate> replicates = Collections.singletonList(replicate1);

        when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(replicates);

        assertThat(contributionService.getContributedWeight(CHAIN_TASK_ID, A)).isEqualTo(0);
    }

    @Test
    public void shouldGetPendingWeight() {
        Replicate replicate1 = mock(Replicate.class);
        when(replicate1.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
        when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
        when(replicate1.getWorkerWeight()).thenReturn(3);

        Replicate replicate2 = mock(Replicate.class);
        when(replicate2.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
        when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
        when(replicate2.getWorkerWeight()).thenReturn(5);

        List<Replicate> replicates = Arrays.asList(replicate1, replicate2);

        when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(replicates);

        assertThat(contributionService.getPendingWeight(CHAIN_TASK_ID, MAX_EXECUTION_TIME)).isEqualTo(15);
    }

    @Test
    public void shouldCount0PendingWeightSinceContributed() {
        Replicate replicate1 = mock(Replicate.class);
        when(replicate1.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
        when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
        when(replicate1.getWorkerWeight()).thenReturn(3);

        List<Replicate> replicates = Collections.singletonList(replicate1);

        when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(replicates);

        assertThat(contributionService.getPendingWeight(CHAIN_TASK_ID, MAX_EXECUTION_TIME)).isEqualTo(0);
    }

    @Test
    public void shouldCountOnlyPendingWeightForOneSinceOtherFailed() {
        Replicate replicate1 = mock(Replicate.class);
        when(replicate1.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
        when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
        when(replicate1.getWorkerWeight()).thenReturn(3);

        Replicate replicate2 = mock(Replicate.class);
        when(replicate2.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
        when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.FAILED));
        when(replicate2.getWorkerWeight()).thenReturn(5);

        List<Replicate> replicates = Arrays.asList(replicate1, replicate2);

        when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(replicates);

        assertThat(contributionService.getPendingWeight(CHAIN_TASK_ID, MAX_EXECUTION_TIME)).isEqualTo(3);
    }

    @Test
    public void shouldCountOnlyPendingWeightForOneSinceOtherContributed() {
        Replicate replicate1 = mock(Replicate.class);
        when(replicate1.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
        when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
        when(replicate1.getWorkerWeight()).thenReturn(3);

        Replicate replicate2 = mock(Replicate.class);
        when(replicate2.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
        when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
        when(replicate2.getWorkerWeight()).thenReturn(5);

        List<Replicate> replicates = Arrays.asList(replicate1, replicate2);

        when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(replicates);

        assertThat(contributionService.getPendingWeight(CHAIN_TASK_ID, MAX_EXECUTION_TIME)).isEqualTo(3);
    }

    @Test
    public void shouldCountOnlyPendingWeightForOneSinceOtherVeryOld() {
        Replicate replicate1 = mock(Replicate.class);
        when(replicate1.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
        when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
        when(replicate1.getWorkerWeight()).thenReturn(3);

        Replicate replicate2 = mock(Replicate.class);
        when(replicate2.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(true);
        when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
        when(replicate2.getWorkerWeight()).thenReturn(5);

        List<Replicate> replicates = Arrays.asList(replicate1, replicate2);

        when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(replicates);

        assertThat(contributionService.getPendingWeight(CHAIN_TASK_ID, MAX_EXECUTION_TIME)).isEqualTo(3);
    }

    @Test
    public void shouldCountOnlyPendingWeightForOneSinceOtherNoWeight() {
        Replicate replicate1 = mock(Replicate.class);
        when(replicate1.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
        when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
        when(replicate1.getWorkerWeight()).thenReturn(3);

        Replicate replicate2 = mock(Replicate.class);
        when(replicate2.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
        when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
        when(replicate2.getWorkerWeight()).thenReturn(0);

        List<Replicate> replicates = Arrays.asList(replicate1, replicate2);

        when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(replicates);

        assertThat(contributionService.getPendingWeight(CHAIN_TASK_ID, MAX_EXECUTION_TIME)).isEqualTo(3);
    }

    @Test
    public void shouldGetDistinctContributions() {
        Replicate replicate1 = mock(Replicate.class);
        when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
        when(replicate1.getContributionHash()).thenReturn(A);
        when(replicate1.getWorkerWeight()).thenReturn(3);

        Replicate replicate2 = mock(Replicate.class);
        when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
        when(replicate2.getContributionHash()).thenReturn(A);
        when(replicate2.getWorkerWeight()).thenReturn(5);

        Replicate replicate3 = mock(Replicate.class);
        when(replicate3.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
        when(replicate3.getContributionHash()).thenReturn(B);
        when(replicate3.getWorkerWeight()).thenReturn(10);


        List<Replicate> replicates = Arrays.asList(replicate1, replicate2, replicate3);

        when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(replicates);

        assertThat(contributionService.getDistinctContributions(CHAIN_TASK_ID)).isEqualTo(new HashSet<>(Arrays.asList(A, B)));
    }

    @Test
    public void shouldNotGetDistinctContributionsSinceNotContributed() {
        Replicate replicate1 = mock(Replicate.class);
        when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));

        List<Replicate> replicates = Collections.singletonList(replicate1);

        when(replicatesService.getReplicates(CHAIN_TASK_ID)).thenReturn(replicates);

        assertThat(contributionService.getDistinctContributions(CHAIN_TASK_ID)).isEmpty();
    }

}

<|start_filename|>Dockerfile<|end_filename|>
FROM openjdk:11.0.7-jre-slim

COPY build/libs/iexec-core-@projectversion@.jar iexec-core.jar

ENTRYPOINT ["java", "-jar", "/iexec-core.jar"]

<|start_filename|>src/test/java/com/iexec/core/stdout/TaskStdoutServiceTests.java<|end_filename|>
/*
 * Copyright 2020 IEXEC BLOCKCHAIN TECH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iexec.core.stdout;

import static com.iexec.common.utils.TestUtils.CHAIN_TASK_ID;
import static com.iexec.common.utils.TestUtils.WORKER_ADDRESS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.List;
import java.util.Optional;

import com.iexec.core.task.TaskService;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class TaskStdoutServiceTests {

    private static final String STDOUT = "This is an stdout string";

    @Mock
    private StdoutRepository stdoutRepository;
    @Mock
    private TaskService taskService;
    @InjectMocks
    private StdoutService stdoutService;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void shouldAddReplicateStdout() {
        ArgumentCaptor<TaskStdout> argumentCaptor = ArgumentCaptor.forClass(TaskStdout.class);
        stdoutService.addReplicateStdout(CHAIN_TASK_ID, WORKER_ADDRESS, STDOUT);
        verify(stdoutRepository, times(1)).save(argumentCaptor.capture());
        TaskStdout capturedEvent = argumentCaptor.getAllValues().get(0);
        assertThat(capturedEvent.getReplicateStdoutList().get(0).getStdout()).isEqualTo(STDOUT);
        assertThat(capturedEvent.getReplicateStdoutList().get(0).getWalletAddress()).isEqualTo(WORKER_ADDRESS);
    }

    @Test
    public void shouldGetReplicateStdout() {
        ReplicateStdout replicateStdout = new ReplicateStdout(WORKER_ADDRESS, STDOUT);
        TaskStdout taskStdout = TaskStdout.builder()
                .chainTaskId(CHAIN_TASK_ID)
                .replicateStdoutList(List.of(replicateStdout))
                .build();
        when(stdoutRepository.findByChainTaskIdAndWalletAddress(CHAIN_TASK_ID, WORKER_ADDRESS))
                .thenReturn(Optional.of(taskStdout));
        Optional<ReplicateStdout> optional = stdoutService.getReplicateStdout(CHAIN_TASK_ID, WORKER_ADDRESS);
        assertThat(optional.get().getStdout()).isEqualTo(STDOUT);
    }
}