package com.ctrip.xpipe.redis.console.controller.consoleportal.migration;

import com.ctrip.xpipe.api.command.CommandFuture;
import com.ctrip.xpipe.api.sso.UserInfoHolder;
import com.ctrip.xpipe.command.DefaultCommandFuture;
import com.ctrip.xpipe.redis.console.AbstractConsoleTest;
import com.ctrip.xpipe.redis.console.config.ConsoleConfig;
import com.ctrip.xpipe.redis.console.config.impl.DefaultConsoleConfig;
import com.ctrip.xpipe.redis.console.controller.api.migrate.MigrationApi4Beacon;
import com.ctrip.xpipe.redis.console.controller.api.migrate.meta.BeaconMigrationRequest;
import com.ctrip.xpipe.redis.console.controller.api.migrate.meta.BeaconMigrationResponse;
import com.ctrip.xpipe.redis.console.service.migration.BeaconMigrationService;
import com.ctrip.xpipe.redis.console.spring.XPipeMvcRegistrations;
import com.ctrip.xpipe.spring.RestTemplateFactory;
import com.ctrip.xpipe.sso.DefaultUserInfoHolder;
import com.ctrip.xpipe.testutils.SpringApplicationStarter;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestOperations;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertEquals;

/**
 * @author Slight
 * <p>
 * Mar 18, 2022 7:51 PM
 */
public class ExclusiveThreadsForMigrationTest extends AbstractConsoleTest {

    private RestOperations restOperations;
    private SpringApplicationStarter springApplicationStarter;
    private int port = 8080;

    @SpringBootApplication
    @RestController
    @RequestMapping("/api")
    public static class SlowController {

        @GetMapping(value = "/sleep")
        public int syncMigrate() throws InterruptedException {
            TimeUnit.SECONDS.sleep(60);
            return 0;
        }

    }

    public static class TestDependency implements XPipeMvcRegistrations {

        @Bean
        public BeaconMigrationService beaconMigrationService() {
            return new BeaconMigrationService() {

                @Override
                public CommandFuture<?> migrate(BeaconMigrationRequest migrationRequest) {
                    CommandFuture<String> future = new DefaultCommandFuture<>();
                    future.setSuccess("OK");
                    return future;
                }
            };
        }

        @Bean
        public ConsoleConfig consoleConfig() {
            return new DefaultConsoleConfig();
        }

        @Bean
        public UserInfoHolder userInfoHolder() {
            return new DefaultUserInfoHolder();
        }
    }

    @Before
    public void beforeRestTemplateFactoryTest() throws Exception {

        restOperations = RestTemplateFactory.createCommonsHttpRestTemplate();

        springApplicationStarter = new SpringApplicationStarter(port, 1, TestDependency.class, SlowController.class, MigrationApi4Beacon.class);
        springApplicationStarter.start();
    }

    @After
    public void afterRestTemplateFactoryTest() throws Exception {
        springApplicationStarter.stop();
    }


    @Test
    public void testMigrationApiWorkProperlyDespiteSlowMethods() throws Exception {

        /* remove implements XPipeMvcRegistrations from TestDependency, this test will fail. */

        BeaconMigrationRequest migrationReq = new BeaconMigrationRequest();
        migrationReq.setClusterName("TEST_CLUSTER");
        migrationReq.setIsForced(true);
        migrationReq.setTargetIDC("OY");

        CountDownLatch latch = new CountDownLatch(1);
        Executors.newSingleThreadExecutor().execute(()->{
            latch.countDown();
            restOperations.getForObject("http://localhost:" + port + "/api/sleep", Integer.class);
        });

        latch.await();
        TimeUnit.MILLISECONDS.sleep(50);
        BeaconMigrationResponse response = restOperations.postForObject("http://localhost:" + port + "/api/beacon/migration/sync", migrationReq, BeaconMigrationResponse.class);
        assertEquals("success", response.getMsg());
    }
}
@@ -1571,16 +1571,59 @@
 tEquals;
+%0Aimport static org.junit.Assert.assertTrue;
 %0A%0A/**%0A *
@@ -1886,16 +1886,71 @@
  8080;%0A%0A
+    private static volatile CountDownLatch stopSleep;%0A%0A
     @Spr
@@ -2175,35 +2175,81 @@
     
-TimeUnit.SECONDS.sleep(60);
+if (stopSleep != null) %7B%0A                stopSleep.await();%0A            %7D
 %0A   
@@ -3130,33 +3130,32 @@
 ows Exception %7B%0A
-%0A
         restOper
@@ -3213,16 +3213,33 @@
 emplate(
+2, 2, 1200, 60000
 );%0A%0A    
@@ -3311,44 +3311,44 @@
  1, 
-TestDependency.class, SlowController
+SlowController.class, TestDependency
 .cla
@@ -3553,16 +3553,136 @@
 %0A    %7D%0A%0A
+    @Test%0A    public void testEnvStartupTime() throws Exception %7B%0A        //do nothing%0A        assertTrue(true);%0A    %7D%0A%0A
 %0A    @Te
@@ -4104,38 +4104,231 @@
 tch 
-latch = new CountDownLatch(1);
+threadCreated = new CountDownLatch(1);%0A        /* the 2 latches below are used to reduce time cost of test */%0A        CountDownLatch sleepResponseReceived = new CountDownLatch(1);%0A        stopSleep = new CountDownLatch(1);%0A
 %0A   
@@ -4394,21 +4394,29 @@
         
-latch
+threadCreated
 .countDo
@@ -4532,26 +4532,81 @@
     
-%7D);%0A%0A        latch
+    sleepResponseReceived.countDown();%0A        %7D);%0A%0A        threadCreated
 .awa
@@ -4881,15 +4881,85 @@
 Msg());%0A
+        stopSleep.countDown();%0A        sleepResponseReceived.await();%0A
     %7D%0A%7D

enhance permence of ExclusiveThreadsForMigrationTest