package ru.rsdn.patterns.behavioral.observer.problems.fault;

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;

import org.junit.Assert;
import org.junit.Test;

import ru.rsdn.patterns.behavioral.observer.AbstractPublisher;
import ru.rsdn.patterns.behavioral.observer.ISubscriber;

/**
 * Тестирование работы издателя и отказоустойчивого издателя с подписчиками,
 * среди которых есть один дефектный
 */
public class FaultTolerantPublisherTest extends
		AbstractPublisher<CopyOnWriteArrayList<ISubscriber>> {
	public FaultTolerantPublisherTest() {
		super(new CopyOnWriteArrayList<ISubscriber>());
	}

	/**
	 * Тестирование отказа издателя из-за дефектного подписчика
	 */
	@Test(expected = RuntimeException.class)
	public void crashNotifyTest() {
		subscribe(new FaultySubscriber());
		subscribe(new ISubscriber() {
			public void eventHappen() {
				Assert.fail();
			}
		});
		notifySubscribers();
	}

	/**
	 * Оповещение подписчиков
	 */
	private void notifySubscribers() {
		for (final ISubscriber subscriber : getSubscribers())
			subscriber.eventHappen();
	}

	/**
	 * Тестирование отказоустойчивого издателя
	 */
	@Test
	public void normalNotifyTest() {
		subscribe(new FaultySubscriber());
		final AtomicBoolean notified = new AtomicBoolean();
		subscribe(new ISubscriber() {
			public void eventHappen() {
				notified.set(true);
			}
		});
		faultTolerantNotifyAll();
		Assert.assertTrue(notified.get());
		Assert.assertTrue(getSubscribers().size() == 1);
	}

	/**
	 * Устойчивое к отказам оповещение подписчиков
	 */
	private void faultTolerantNotifyAll() {
		for (final ISubscriber subscriber : getSubscribers())
			try {
				subscriber.eventHappen();
			} catch (final RuntimeException e) {
				System.err.println("Обнаружен дефектный подписчик: " +
						subscriber);
				unsubscribe(subscriber);
			}
	}
}
