package org.bench4q.master.unitTest.infrastructure.ha;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.bench4q.master.domain.RunningAgentInterface;
import org.bench4q.master.domain.entity.Agent;
import org.bench4q.master.domain.entity.TestPlan;
import org.bench4q.master.domain.entity.TestPlanScript;
import org.bench4q.master.infrastructure.highavailable.impl.HighAvailablePoolImpl;
import org.bench4q.master.unitTest.TestBase_MakeUpTestPlan;
import org.bench4q.share.enums.master.AgentStatus;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:mockHttpMesseger-context.xml" })
public class Test_highAvailableWithMockMessenger extends
		TestBase_MakeUpTestPlan {
	private List<Agent> testCase1 = new ArrayList<Agent>();
	{
		testCase1.add(Agent.createAgentWithoutId("127.0.0.1", 6565, 500));

		Agent agent = Agent.createAgentWithoutId("127.0.0.2", 6565, 500);
		agent.setCurrentEnumStatus(AgentStatus.BreakDown);
		testCase1.add(agent);

		Agent agent2 = Agent.createAgentWithoutId("127.0.0.3", 6565, 500);
		agent2.setCurrentEnumStatus(AgentStatus.InRunning);
		agent2.bookTest(10);
		testCase1.add(agent2);
	}

	private List<Agent> testcase2 = new ArrayList<Agent>();
	{
		testcase2.add(Agent.createAgentWithoutId("127.0.0.1", 6565, 500));
		testcase2.add(Agent.createAgentWithoutId("127.0.0.2", 6565, 500));
	}

	@Autowired
	private HighAvailablePoolImpl ha;

	@Test
	public void test_BreakDown() {
		this.prepareWith(this.testcase2);
		synchronized (this.ha) {
			assertEquals(1000, this.ha.getCurrentAvailableLoad());
		}
		this.submitATestPlanWithOneScript();
		TestPlan testPlan = this.getTestPlanRepository().getTestPlanInDomainBy(
				getTestPlanRunIdUuid());
		testPlan.run();
		// Let ha get the agent's runIds
		this.ha.checkAllHeartBeat();
		TestPlanScript runningScript = testPlan
				.extracSpecifiedScript(getScriptId());
		assertEquals(1, runningScript.getRunningAgents().size());
		RunningAgentInterface runningAgentInterface = (RunningAgentInterface) runningScript
				.getRunningAgents().toArray()[0];
		// Kill the agent In run
		runningAgentInterface.getAgent().setCurrentEnumStatus(
				AgentStatus.BreakDown);
		// activate ha ckeckAllHeartBeats
		this.ha.checkAllHeartBeat();
		assertEquals(2, runningScript.getRunningAgents().size());

		this.cleanUpWith(this.testcase2);
	}

	@Test
	public void test_getCurrentAvailableLoad() {
		prepareWith(this.testCase1);
		assertEquals(500, this.ha.getCurrentAvailableLoad());
		assertEquals(Long.valueOf(1000), this.ha.getMaxAvailableLoad());
	}

	private void prepareWith(List<Agent> agents) {
		this.ha.getPool().clear();
		for (Agent agent : agents) {
			this.ha.add(agent);
		}
		this.ha.checkAllHeartBeat();
	}

	private void cleanUpWith(List<Agent> agents) {
		for (Agent agent : agents) {
			this.getAgentRepository().detach(agent.getId());
		}
	}

	@Test
	public void test_applyFor() {
		prepareWith(this.testcase2);
		int loadToApply = 10;
		List<RunningAgentInterface> result = null;
		synchronized (this.ha) {
			assertTrue(this.ha.getCurrentAvailableLoad() > loadToApply);
			result = this.ha.applyFor(loadToApply);
		}
		assertEquals(1, result.size());
		assertEquals(1, result.size());
		assertEquals(loadToApply, result.get(0).getLoadInUse());
		UUID runId = result.get(0).getAgentRunId();
		assertNotNull(runId);
		assertNull(result.get(0).getRunningScript());
		assertEquals(1, this.ha.getAgentRunBlotters().size());
		assertEquals(result.get(0), this.ha.getAgentRunBlotters().get(runId));
		for (RunningAgentInterface runningAgent : result) {
			assertTrue(runningAgent.stop());
		}
	}
}
