Package com.salas.bb.domain

Source Code of com.salas.bb.domain.TestDataFeed

// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software Foundation;
// either version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program;
// if not, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: TestDataFeed.java,v 1.27 2008/02/28 15:59:53 spyromus Exp $
//

package com.salas.bb.domain;

import com.salas.bb.utils.parser.Channel;
import com.salas.bb.utils.parser.Item;
import junit.framework.TestCase;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
* This suite contains tests for <code>DataFeed</code> unit.
* It covers:
* <ul>
<li>Initialization of properties upon construction.</li>
<li>Storing of: initialization time, last polling time, number of retrievals,
*      number of articles polled, purge limit, flags for
*      marking articles as read when no keywords found and automatic discovery
*      of links in new articles.</li>
<li>Getting and setting the list of read articles' keys.</li>
<li>Adding, inserting and removing articles.</li>
* </ul>
*/
public class TestDataFeed extends TestCase
{
    private DataFeed feed;

    protected void setUp()
        throws Exception
    {
        feed = new DummyDataFeed();
    }

    // ---------------------------------------------------------------------------------------------
    // Tests
    // ---------------------------------------------------------------------------------------------

    /**
     * Tests initialization of properties after construction.
     */
    public void testConstruction()
    {
        assertEquals("Wrong purge limit setting.",
            NetworkFeed.PURGE_LIMIT_INHERITED, feed.getPurgeLimit());
        assertEquals("Wrong purge limit setting.",
            NetworkFeed.DEFAULT_PURGE_LIMIT, feed.getPurgeLimitCombined());
        assertEquals("Wrong default init time.",
            NetworkFeed.INIT_TIME_UNINITIALIZED, feed.getInitTime());
        assertEquals("Wrong last poll time.",
            NetworkFeed.DEFAULT_LAST_POLL_TIME, feed.getLastPollTime());
        assertEquals("Wrong last update time.",
            NetworkFeed.DEFAULT_LAST_UPDATE_SERVER_TIME, feed.getLastUpdateServerTime());
        assertEquals("Wrong total polled articles counter.",
            NetworkFeed.DEFAULT_TOTAL_POLLED_ARTICLES, feed.getTotalPolledArticles());
        assertEquals("Wrong number of retrievals.",
            NetworkFeed.DEFAULT_RETRIEVALS, feed.getRetrievals());
    }

    /**
     * Tests saving initialization time.
     */
    public void testGetSetInitTime()
    {
        assertEquals("Wrong default init time.",
            NetworkFeed.INIT_TIME_UNINITIALIZED, feed.getInitTime());

        feed.setInitTime(1);
        assertEquals("Wrong init time.", 1, feed.getInitTime());
    }

    /**
     * Tests reporting initialization state. The feed is initialized when it's initialization
     * time is set.
     */
    public void testInitialized()
    {
        assertFalse("Feed should not be initialized.", feed.isInitialized());

        feed.setInitTime(1);
        assertTrue("Feed should be initialized.", feed.isInitialized());
    }

    /**
     * Tests saving time of last poll.
     */
    public void testGetSetLastPollTime()
    {
        assertEquals("Wrong last poll time.",
            NetworkFeed.DEFAULT_LAST_POLL_TIME, feed.getLastPollTime());

        feed.setLastPollTime(1);
        assertEquals("Wrong last poll time.", 1, feed.getLastPollTime());
    }

    /**
     * Tests saving the counter of retrievals.
     */
    public void testGetSetRetrievals()
    {
        assertEquals("Wrong number of retrievals.",
            NetworkFeed.DEFAULT_RETRIEVALS, feed.getRetrievals());

        feed.setRetrievals(1);
        assertEquals("Wrong number of retrievals.", 1, feed.getRetrievals());
    }

    /**
     * Tests saving the counter of polled articles.
     */
    public void testGetSetTotalPolledArticles()
    {
        assertEquals("Wrong total polled articles counter.",
            NetworkFeed.DEFAULT_TOTAL_POLLED_ARTICLES, feed.getTotalPolledArticles());

        feed.setTotalPolledArticles(10);
        assertEquals("Wrong total polled articles counter.", 10, feed.getTotalPolledArticles());
    }

    /**
     * Tests returning the list of keys of read articles.
     * Feed is initialized.
     */
    public void testGetReadArticlesKeysInitialized()
    {
        StandardArticle art1 = article(1);
        art1.setRead(false);
        feed.appendArticle(art1);

        StandardArticle art2 = article(2);
        art2.setRead(false);
        feed.appendArticle(art2);

        // Make feed to be initialized
        feed.setInitTime(1);

        String keys;

        // Nothing marked as read
        keys = feed.getReadArticlesKeys();
        assertEquals("Should be no keys.", "", keys);

        // Situation 1: there's read article present
        art1.setRead(true);
        keys = feed.getReadArticlesKeys();
        assertEquals("Keys should have single key of read article.",
            art1.getSimpleMatchKey(), keys);

        // Situation 2: there are two read articles present
        art2.setRead(true);
        keys = feed.getReadArticlesKeys();
        assertEquals("Keys should have single key of read article.",
            art1.getSimpleMatchKey() + "," + art2.getSimpleMatchKey(), keys);

        // Situation 3: Feed is empty
        feed = new DummyNetworkFeed();
        keys = feed.getReadArticlesKeys();
        assertEquals("Should be no keys.", "", keys);
    }

    /**
     * Tests returning the list of keys of read articles.
     * Feed is not initialized
     */
    public void testGetReadArticlesKeys()
    {
        StandardArticle art1 = article(1);
        art1.setRead(false);
        feed.appendArticle(art1);

        StandardArticle art2 = article(2);
        art2.setRead(false);
        feed.appendArticle(art2);

        String keys;

        // Nothing marked as read
        keys = feed.getReadArticlesKeys();
        assertEquals("Should be no keys.", "", keys);

        feed.setReadArticlesKeys("12345678,87654321");
        keys = feed.getReadArticlesKeys();
        assertEquals("Keys should be returned as is.", "12345678,87654321", keys);
    }

    /**
     * Tests setting the list of keys of read articles. The articles which are
     * currently in the feed and have the keys mentioned in the list should be
     * marked as read immediately. Also the list of keys should be recorded.
     */
    public void testSetReadArticlesKeys()
    {
        StandardArticle art1 = article(1);
        art1.setRead(false);
        feed.appendArticle(art1);

        StandardArticle art2 = article(2);
        art2.setRead(false);
        feed.appendArticle(art2);

        // Set the key of the first article as read
        String keys = art1.getSimpleMatchKey();
        feed.setReadArticlesKeys(keys);
        assertTrue("Should be marked as read.", art1.isRead());
    }

    /**
     * Tests the clearing of list of read articles keys.
     */
    public void testSetReadArticlesKeysClear()
    {
        String keys;
        feed.setReadArticlesKeys("12345678,87654321");
        keys = feed.getReadArticlesKeys();
        assertEquals("Keys should be returned as is.", "12345678,87654321", keys);

        feed.setReadArticlesKeys(null);
        keys = feed.getReadArticlesKeys();
        assertEquals("Should be no keys.", "", keys);
    }

    /**
     * Tests inheritance of the flag.
     */
    public void testGetSetAutoFeedsDiscoveryInheritance()
    {
        assertEquals("Wrong default setting.", false, feed.isAutoFeedsDiscovery());

        IGuide guide = new StandardGuide();
        feed.addParentGuide(guide);

        guide.setAutoFeedsDiscovery(true);
        assertEquals("Wrong setting.", true, feed.isAutoFeedsDiscovery());

        guide.setAutoFeedsDiscovery(false);
        assertEquals("Wrong setting.", false, feed.isAutoFeedsDiscovery());
    }

    /**
     * Tests saving of the purge limit property.
     */
    public void testGetSetPurgeLimit()
    {
        assertEquals("Wrong purge limit setting.",
            NetworkFeed.PURGE_LIMIT_INHERITED, feed.getPurgeLimit());

        feed.setPurgeLimit(1);
        assertEquals("Wrong purge limit setting.", 1, feed.getPurgeLimit());
    }

    /**
     * Tests appending the article to the tail of feed.
     */
    public void testAppendArticle()
    {
        feed = new DummyNetworkFeed();
        assertEquals("Shoud be no articles.", 0, feed.getArticlesCount());

        StandardArticle art1 = article(1);
        StandardArticle art2 = article(2);

        feed.appendArticle(art1);
        assertEquals("Wrong article number.", 1, feed.getArticlesCount());
        assertTrue("Wrong article added.", art1 == feed.getArticleAt(0));
        assertTrue("Wrong feed.", feed == art1.getFeed());

        feed.appendArticle(art2);
        assertEquals("Wrong article number.", 2, feed.getArticlesCount());
        assertTrue("Wrong article added.", art2 == feed.getArticleAt(1));
    }

    /**
     * Tests appending duplicate article to the tail of feed.
     */
    public void testAppendArticleDuplicate()
    {
        feed = new DummyNetworkFeed();
        assertEquals("Shoud be no articles.", 0, feed.getArticlesCount());

        StandardArticle art1 = new StandardArticle("");

        feed.appendArticle(art1);
        assertEquals("Wrong article number.", 1, feed.getArticlesCount());

        try
        {
            feed.appendArticle(art1);
            fail("The article is already in the feed. ISE is expected.");
        } catch (IllegalStateException e)
        {
            // Expected
        }
    }

    /**
     * Tests appending articles with the same Link-Title-Pubdates.
     */
    public void testAppendWikiArticlesDuplicate()
    {
        // wiki feed
        feed = new DummyNetworkFeed();
        feed.setHandlingType(FeedHandlingType.LINK_TITLE_PUBDATE);

        Date today = new Date();
        StandardArticle art1 = article("1", "http://localhost/1", today);
        StandardArticle art2 = article("1", "http://localhost/1", today);

        feed.appendArticle(art1);
        assertEquals("Should add article", 1, feed.getArticlesCount());

        feed.appendArticle(art2);
        assertEquals("Should not add duplicate", 1, feed.getArticlesCount());
    }

    /**
     * Tests appending articles with the same Link-Title but different Pubdates.
     */
    public void testAppendWikiArticlesNonDuplicate()
    {
        // wiki feed
        feed = new DummyNetworkFeed();
        feed.setHandlingType(FeedHandlingType.LINK_TITLE_PUBDATE);

        Date today = new Date();
        Date yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
        StandardArticle art1 = article("1", "http://localhost/1", yesterday);
        StandardArticle art2 = article("1", "http://localhost/1", today);

        feed.appendArticle(art1);
        assertEquals("Should add article", 1, feed.getArticlesCount());

        feed.appendArticle(art2);
        assertEquals("Should add non-duplicate", 2, feed.getArticlesCount());
    }

    /**
     * Tests handling of addition of NULL.
     */
    public void testAppendArticleNull()
    {
        try
        {
            feed.appendArticle(null);
            fail("NPE is expected.");
        } catch (NullPointerException e)
        {
            // Expected
        }
    }

    /**
     * Tests inserting the article to the tail of feed.
     */
    public void testInsertArticle()
    {
        feed = new DummyNetworkFeed();
        assertEquals("Shoud be no articles.", 0, feed.getArticlesCount());

        StandardArticle art1 = article(1);
        StandardArticle art2 = article(2);

        feed.insertArticle(0, art1);
        assertEquals("Wrong article number.", 1, feed.getArticlesCount());
        assertTrue("Wrong article added.", art1 == feed.getArticleAt(0));

        feed.insertArticle(0, art2);
        assertEquals("Wrong article number.", 2, feed.getArticlesCount());
        assertTrue("Wrong article added.", art2 == feed.getArticleAt(0));
    }

    /**
     * Tests appending duplicate article to the tail of feed.
     */
    public void testInsertArticleDuplicate()
    {
        feed = new DummyNetworkFeed();
        assertEquals("Shoud be no articles.", 0, feed.getArticlesCount());

        StandardArticle art1 = new StandardArticle("");

        feed.insertArticle(0, art1);
        assertEquals("Wrong article number.", 1, feed.getArticlesCount());

        try
        {
            feed.insertArticle(0, art1);
            fail("The article is already in the feed. ISE is expected.");
        } catch (IllegalStateException e)
        {
            // Expected
        }
    }

    /**
     * Tests handling of insertion of NULL.
     */
    public void testInsertArticleNull()
    {
        try
        {
            feed.insertArticle(0, null);
            fail("NPE is expected.");
        } catch (NullPointerException e)
        {
            // Expected
        }
    }

    /**
     * Tests firing IOB exection when inserting article to some missing position.
     */
    public void testInsertArticleAIOB()
    {
        feed = new DummyNetworkFeed();
        assertEquals("Shoud be no articles.", 0, feed.getArticlesCount());

        try
        {
            feed.insertArticle(1, new StandardArticle(""));
            fail("IOB expected.");
        } catch (IndexOutOfBoundsException e)
        {
            // Expected
        }
    }

    /**
     * Tests removing article from feed.
     */
    public void testRemoveArticle()
    {
        feed = new DummyNetworkFeed();
        assertEquals("Shoud be no articles.", 0, feed.getArticlesCount());

        StandardArticle art1 = new StandardArticle("");
        feed.insertArticle(0, art1);

        assertTrue("Should report successful removal.", feed.removeArticle(art1));
        assertEquals("Shoud be no articles.", 0, feed.getArticlesCount());
    }

    /**
     * Tests duplicate removing of articles.
     */
    public void testRemoveArticleDuplicate()
    {
        feed = new DummyNetworkFeed();
        assertEquals("Shoud be no articles.", 0, feed.getArticlesCount());

        StandardArticle art1 = new StandardArticle("");
        feed.insertArticle(0, art1);

        assertTrue("Should report successful removal.", feed.removeArticle(art1));
        assertFalse("Shouldn't report successful removal.", feed.removeArticle(art1));
    }

    /**
     * Tests handling of removing NULL-articles.
     */
    public void testRemoveArticleNull()
    {
        try
        {
            feed.removeArticle(null);
            fail("NPE is expected.");
        } catch (NullPointerException e)
        {
            // Expected
        }
    }

    /**
     * Tests that articles added are being marked as read automatically if their
     * keys are in the list of read articles' keys.
     */
    public void testAutoReadOnAdding()
    {
        String keys;

        feed = new DummyNetworkFeed();
        StandardArticle art1 = article(1);
        StandardArticle art2 = article(2);

        keys = art1.getSimpleMatchKey();

        feed.setReadArticlesKeys(keys);

        feed.appendArticle(art1);
        assertTrue("Should be marked as read.", art1.isRead());
        assertEquals("Wrong unread count.", 0, feed.getUnreadArticlesCount());

        feed.appendArticle(art2);
        assertFalse("Should not be marked as read.", art2.isRead());
        assertEquals("Wrong unread count.", 1, feed.getUnreadArticlesCount());
    }

    /**
     * Tests getting format of the feed from its handle.
     */
    public void testGetFormat()
    {
        assertNull("Format is not known.", feed.getFormat());

        feed.setFormat("A");
        assertEquals("Format is known.", "A", feed.getFormat());
    }

    /**
     * Tests getting language of the feed from its handle.
     */
    public void testGetLanguage()
    {
        assertNull("Language is not known.", feed.getLanguage());

        feed.setLanguage("A");
        assertEquals("Language is known.", "A", feed.getLanguage());
    }

    /**
     * Tests reporting of updatable status by feed when it's invalid.
     */
    public void testIsUpdatableInvalid()
    {
        feed.setInvalidnessReason(null);
        feed.setID(1);
        assertTrue("Feed is valid. It can be updatable.", feed.isUpdatable(false));
        assertTrue("Feed is valid. It can be updatable.", feed.isUpdatable(true));

        feed.setInvalidnessReason(null);
        feed.setID(-1);
        assertFalse("Feed isn't persisted. It cannot be updatable.", feed.isUpdatable(false, true));
        assertFalse("Feed isn't persisted. It cannot be updatable.", feed.isUpdatable(true, true));

        feed.setInvalidnessReason("A");
        feed.setID(1);
        assertFalse("Feed is invalid. It cannot be updatable.", feed.isUpdatable(false));
        assertTrue("Feed is invalid, but questioned manually. It can be updatable.",
            feed.isUpdatable(true));

        feed.setInvalidnessReason("A");
        feed.setID(-1);
        assertFalse("Feed isn't persisted. It cannot be updatable.", feed.isUpdatable(false, true));
        assertFalse("Feed isn't persisted. It cannot be updatable.", feed.isUpdatable(true, true));
    }

    /**
     * Tests getting and setting update period and inheritance of the values.
     */
    public void testGetSetUpdatePeriod()
    {
        feed.setUpdatePeriod(1);
        assertEquals("Wrong period.", 1, feed.getUpdatePeriod());

        feed.setUpdatePeriod(DataFeed.UPDATE_PERIOD_INHERITED);
        assertEquals("Wrong period.", DataFeed.getGlobalUpdatePeriod(),
            feed.getUpdatePeriodCombined());
    }

    /**
     * Tests that the feed is reported to be not updatable if it's not time yet.
     */
    public void testIsUpdatableNotTime()
    {
        // Setting the last update time to a second ago
        long base = System.currentTimeMillis();
        feed.setLastPollTime(base - 1000);
        feed.setID(1);

        // Setting five seconds period -- not time
        feed.setUpdatePeriod(5000);
        assertFalse("Too early for updates.", feed.isUpdatable(false));
        assertTrue("Direct updates are allowed at any moment.", feed.isUpdatable(true));

        // Setting half second period -- time has come
        feed.setUpdatePeriod(500);
        assertTrue("Time of updates has come.", feed.isUpdatable(false));
        assertTrue("Direct updates are allowed at any moment.", feed.isUpdatable(true));
    }

    /** Tests manual-mode updates reporting. */
    public void testIsUpdatableManual()
    {
        // Setting the last update time to yesterday
        long base = System.currentTimeMillis();
        feed.setLastPollTime(base - 24*60*60*1000);
        feed.setID(1);

        // Setting manual period
        feed.setUpdatePeriod(0);
        assertFalse("In manual mode, can't be auto-updated.", feed.isUpdatable(false));
        assertTrue("Direct updates are allowed at any moment.", feed.isUpdatable(true));
    }

    /**
     * Tests updating the feed data from parsed channel object.
     */
    public void testUpdateFeed()
    {
        Channel channel = new Channel();

        // The parsed channel has information about format and language,
        // the feed we have -- has not. The information should be moved.
        channel.setFormat("A");
        channel.setLanguage("B");

        feed.updateFeed(channel);
        assertEquals("Wrong format.", "A", feed.getFormat());
        assertEquals("Wrong language.", "B", feed.getLanguage());

        // The parsed channel has no information about format and language,
        // the feed we already have -- has. There should be no updates.
        channel.setFormat(null);
        channel.setLanguage(null);

        feed.updateFeed(channel);
        assertEquals("Wrong format.", "A", feed.getFormat());
        assertEquals("Wrong language.", "B", feed.getLanguage());
    }

    /**
     * Tests updating the articles list from parsed empty channel object.
     */
    public void testUpdateArticlesEmpty()
    {
        // Channel has no articles
        feed.updateArticles(new StandardArticle[0]);
        assertEquals("Wrong number of articles.", 0, feed.getArticlesCount());
    }

    /**
     * Tests updating the articles list from parsed channel object.
     */
    public void testUpdateArticles()
    {
        StandardArticle[] incArticles = {article(1)};

        feed.updateArticles(incArticles);
        assertEquals("Wrong number of articles.", 1, feed.getArticlesCount());

        // Continued updates should not add the same item
        feed.updateArticles(incArticles);
        assertEquals("Wrong number of articles.", 1, feed.getArticlesCount());
    }

    /**
     * Tests the updates with detection of existing articles.
     */
    public void testUpdateArticlesOld()
    {
        // First update -- single item
        StandardArticle[] incArticles1 = new StandardArticle[]
        {
            article(2)
        };

        feed.updateArticles(incArticles1);
        assertEquals("Wrong number of articles.", 1, feed.getArticlesCount());
        assertEquals("Wrong article added.", "2", feed.getArticleAt(0).getHtmlText());

        // Second update -- one new item and one old
        StandardArticle[] incArticles2 = new StandardArticle[]
        {
                article(1), article(2), article(3)
        };

        feed.updateArticles(incArticles2);
        assertEquals("Wrong number of articles.", 3, feed.getArticlesCount());
        assertEquals("Wrong article added.", "3", feed.getArticleAt(0).getHtmlText());
        assertEquals("Wrong article added.", "1", feed.getArticleAt(1).getHtmlText());
        assertEquals("Wrong article added.", "2", feed.getArticleAt(2).getHtmlText());
    }

    /**
     * Tests the scenario when there are more articles in the parsed channel then
     * it's allowed by local limits. In this case the older articles should be skipped.
     */
    public void testUpdateArticlesGreaterThanLimit()
    {
        // Configure incoming articles
        StandardArticle[] incArticles = new StandardArticle[]
        {
                article(1), article(2), article(3)
        };

        feed.setPurgeLimit(2);

        // Channel has 3 articles, the limit is 2
        feed.updateArticles(incArticles);
        assertEquals("Wrong number of articles.", 2, feed.getArticlesCount());
        assertEquals("Wrong article added.", "2", feed.getArticleAt(0).getHtmlText());
        assertEquals("Wrong article added.", "1", feed.getArticleAt(1).getHtmlText());
    }

    /**
     * Tests the scenario when the feed contains several articles "from the future" in
     * the top of the articles list. Normally, it will prevent to load the articles
     * following them because they will be treated as "old" because the seen article
     * (the one with future date) is on top of them. To avoid this behaviour it's proposed
     * to continue reading channel after the future article has been seen.
     */
    public void testUpdateArticlesFromFuture()
    {
        // Configure incoming articles
        StandardArticle art1 = article(1);
        StandardArticle art2 = article(2);
        StandardArticle art3 = article(3);

        // Set future date to the first article
        GregorianCalendar cal = new GregorianCalendar();
        cal.roll(Calendar.YEAR, 1);
        Date futureDate = cal.getTime();
        art1.setPublicationDate(futureDate);

        // Add the "future" article during the first update
        feed.updateArticles(new StandardArticle[] { art1 });
        assertEquals("Wrong number of articles.", 1, feed.getArticlesCount());

        // Now add more articles to the channel and run another update
        feed.updateArticles(new StandardArticle[] { art1, art2, art3 });
        assertEquals("Wrong number of articles.", 3, feed.getArticlesCount());
        assertEquals("Wrong order of articles.", "3", feed.getArticleAt(0).getHtmlText());
        assertEquals("Wrong order of articles.", "2", feed.getArticleAt(1).getHtmlText());
        assertEquals("Wrong order of articles.", "1", feed.getArticleAt(2).getHtmlText());
    }

    /**
     * This test ensures that the above test {@link #testUpdateArticlesFromFuture()}
     * doesn't break anything.
     */
    public void testUpdateArticlesFromFutureDuplicate()
    {
        // Configure incoming articles
        StandardArticle art1 = article(1);
        StandardArticle art1_1 = article(1);
        StandardArticle art2 = article(2);
        StandardArticle art3 = article(3);

        // Set future date to the first article
        GregorianCalendar cal = new GregorianCalendar();
        cal.roll(Calendar.YEAR, 1);
        Date futureDate = cal.getTime();
        art1.setPublicationDate(futureDate);

        // Set the dates so that the art2 is newer than art3
        art2.setPublicationDate(new Date(3));
        art3.setPublicationDate(new Date(2));

        // Add the "future" article during the first update
        feed.updateArticles(new StandardArticle[] { art1, art1_1, art2, art3 });

        assertEquals("Wrong number of articles.", 3, feed.getArticlesCount());
        assertEquals("Wrong order of articles.", "3", feed.getArticleAt(0).getHtmlText());
        assertEquals("Wrong order of articles.", "2", feed.getArticleAt(1).getHtmlText());
        assertEquals("Wrong order of articles.", "1", feed.getArticleAt(2).getHtmlText());
    }

    /**
     * There are several feeds with an advertisement article (or articles) in the head of
     * the articles list. There are tests to ensure that the article "from the future" never
     * stops the processing, but there are several registered occasions when the first
     * article is from the far past or has no date at all, but still usually appears at
     * the top. We have to deal with this situation gracefully as well.
     */
    public void testUpdateArticlesAdvert()
    {
        // Configure incoming articles
        StandardArticle artAdvert = article(1);
        StandardArticle art2 = article(2);
        StandardArticle art3 = article(3);

        // We have a feed with advert at first
        feed.updateArticles(new StandardArticle[] { artAdvert });

        assertEquals("Wrong number of articles.", 1, feed.getArticlesCount());
        assertEquals("Wrong article.", "1", feed.getArticleAt(0).getHtmlText());

        // Then the item1 is added to the feed
        feed.updateArticles(new StandardArticle[] { artAdvert, art2 });

        assertEquals("Wrong number of articles.", 2, feed.getArticlesCount());
        assertEquals("Wrong article.", "2", feed.getArticleAt(0).getHtmlText());
        assertEquals("Wrong article.", "1", feed.getArticleAt(1).getHtmlText());

        // And now the item2 is added in front the item1 but after the advert, like this:
        // advert -> item2 -> item1
        feed.updateArticles(new StandardArticle[] { artAdvert, art3, art2 });

        assertEquals("Wrong number of articles.", 3, feed.getArticlesCount());
        assertEquals("Wrong article.", "3", feed.getArticleAt(0).getHtmlText());
        assertEquals("Wrong article.", "2", feed.getArticleAt(1).getHtmlText());
        assertEquals("Wrong article.", "1", feed.getArticleAt(2).getHtmlText());
    }

    /**
     * Tests updating sequence when NULL feed is returned from <code>fetchFeed</code>.
     */
    public void testUpdateNull()
    {
        DummyDataFeed feed = new DummyDataFeed();
        feed.setChannel(null);

        feed.update();
        assertTrue("Feed should update time and counters in any case.",
            feed.getLastPollTime() > DataFeed.DEFAULT_LAST_POLL_TIME);
        assertEquals("Time of initialization should change accordingly.",
            feed.getLastPollTime(), feed.getInitTime());
        assertEquals("Retrieval count should grow.", 1, feed.getRetrievals());
    }

    /**
     * Tests normal update sequence with updates to times and retrieval counts.
     */
    public void testUpdateNotNull()
    {
        Channel channel = new Channel();
        channel.addItem(new Item("1"));

        DummyDataFeed feed = new DummyDataFeed();
        feed.setChannel(channel);

        long base = System.currentTimeMillis();
        feed.update();
        long initTime = feed.getInitTime();
        assertTrue("Time should be updated.", feed.getLastPollTime() >= base);
        assertTrue("Time should be updated.", initTime >= base);
        assertEquals("Wrong retrievals count.", 1, feed.getRetrievals());
        assertEquals("Wrong total articles counter.", 1, feed.getTotalPolledArticles());
        assertTrue("Update method wasn't called.", feed.isUpdateArticlesCalled());
        assertTrue("Update method wasn't called.", feed.isUpdateFeedCalled());

        // Another update
        base = System.currentTimeMillis();
        feed.update();
        assertTrue("Time should be updated.", feed.getLastPollTime() >= base);
        assertEquals("Time should not be updated.", initTime, feed.getInitTime());
        assertEquals("Wrong retrievals count.", 2, feed.getRetrievals());
        assertEquals("Wrong total articles counter.", 1, feed.getTotalPolledArticles());
        assertTrue("Update method wasn't called.", feed.isUpdateArticlesCalled());
        assertTrue("Update method wasn't called.", feed.isUpdateFeedCalled());
    }

    /**
     * Tests work of cleaner.
     *
     * @throws Exception if something goes wrong.
     */
    public void testClean() throws Exception
    {
        // There's nothing to clean
        feed.clean();
        assertEquals("Wrong number of articles.", 0, feed.getArticlesCount());

        // Adding two articles one by one (two updates) while having limit of 1
        // The second update should call cleaner and remove the last article
        DummyDataFeed feed = new DummyDataFeed();
        feed.setPurgeLimit(1);
        Channel channel1 = new Channel();
        channel1.addItem(new Item("1"));

        // First update
        feed.setChannel(channel1);
        feed.update();

        // A little pause to create a gap between items
        Thread.sleep(100);

        Channel channel2 = new Channel();
        Item item = new Item("2");
        channel2.addItem(item);

        // Second update
        feed.setChannel(channel2);
        feed.update();

        assertEquals("Wrong number of articles.", 1, feed.getArticlesCount());
        assertEquals("Wrong article is left.", "2", feed.getArticleAt(0).getHtmlText());
    }

    /**
     * Tests work of cleaner.
     */
    public void testCleanPinned()
    {
        // There's nothing to clean
        feed.clean();
        assertEquals("Wrong number of articles.", 0, feed.getArticlesCount());

        // Adding two articles one by one (two updates) while having limit of 1
        // The second update should call cleaner but the first article should be
        // removed because of a pin.
        DummyDataFeed feed = new DummyDataFeed();
        feed.setPurgeLimit(1);
        DataFeed.setGlobalPurgeUnread(false);
        Channel channel1 = new Channel();
        channel1.addItem(new Item("1"));

        // First update
        feed.setChannel(channel1);
        feed.update();
        feed.getArticleAt(0).setPinned(true);

        Channel channel2 = new Channel();
        Item item = new Item("2");
        channel2.addItem(item);

        // Second update
        feed.setChannel(channel2);
        feed.update();

        assertEquals("Wrong number of articles.", 2, feed.getArticlesCount());
    }

    /**
     * Assume there are 6 articles: 3 pinned and 3 not pinned.
     * When we set the purge limit to 3 (and we know that pinned articles aren't removed)
     * the 3 not pinned articles should stay as otherwise there will be no new articles
     * once the number of pinned articles reaches the purge limit.
     */
    public void testCleanNotCountPinned()
    {
        // Create a sample feed
        DirectFeed feed = new DirectFeed();
        DirectFeed.setGlobalPurgeUnread(true);
        feed.setPurgeLimit(Integer.MAX_VALUE);

        // Generate articles and add them to the feed
        // First 3 are pinned
        for (int i = 0; i < 6; i++)
        {
            String txt = Integer.toString(i);

            StandardArticle article = new StandardArticle(txt);
            article.setRead(false);
            article.setTitle(txt);
            article.setPinned(i < 3);

            feed.appendArticle(article);
        }

        // Set purge limit to 3 and see if articles stay
        feed.setPurgeLimit(3);
        assertEquals("3 unpinned articles should stay", 6, feed.getArticlesCount());
    }

    /**
     * Tests removal of correct items.
     */
    public void testComplexClean()
    {
        DummyDataFeed feed = new DummyDataFeed();

        long time = System.currentTimeMillis();
        IArticle article0 = articleWithTime(time);
        IArticle article1 = articleWithTime(time + 1000);
        IArticle article2 = articleWithTime(time + 2000);
        IArticle article3 = articleWithTime(time + 3000);
        IArticle articlem1 = articleWithTime(time - 1000);
        IArticle articlem2 = articleWithTime(time - 2000);
        IArticle articlem3 = articleWithTime(time - 3000);

        feed.appendArticle(articlem3);
        feed.appendArticle(articlem2);
        feed.appendArticle(articlem1);
        feed.appendArticle(article0);
        feed.appendArticle(article1);
        feed.appendArticle(article2);
        feed.appendArticle(article3);

        feed.setPurgeLimit(2);
        assertEquals(2, feed.getArticlesCount());
        assertTrue(article2 == feed.getArticleAt(0));
        assertTrue(article3 == feed.getArticleAt(1));
    }

    /**
     * Creates a simple test article with the title and text equal to the given index.
     *
     * @param index index.
     *
     * @return article object.
     */
    private static StandardArticle article(long index)
    {
        String text = Long.toString(index);
        StandardArticle article = new StandardArticle(text);
        article.setTitle(text);

        return article;
    }

    /**
     * Creates an article and initializes it with the time given.
     *
     * @param time time of pubication.
     *
     * @return article.
     */
    private static StandardArticle articleWithTime(long time)
    {
        StandardArticle article = article(time);
        article.setPublicationDate(new Date(time));
        return article;
    }

    /**
     * Tests the case when <code>purgeUnread</code> is FALSE meaning that the
     * feed should not remove unread articles during cleanup.
     */
    public void testCleanNoPurgeUnread()
    {
        // Disable purgin unread globally
        boolean globalPurgeUnead = DataFeed.isGlobalPurgeUnread();
        DataFeed.setGlobalPurgeUnread(false);

        try
        {
            // Set purge limit to 1 article
            DummyDataFeed feed = new DummyDataFeed();
            feed.setPurgeLimit(1);

            // Create unread articles and add them to the feed
            StandardArticle art1 = article(1);
            art1.setRead(false);
            feed.appendArticle(art1);

            StandardArticle art2 = article(2);
            art2.setRead(false);
            feed.appendArticle(art2);

            // Clean and check
            feed.clean();
            assertEquals("Unread articles should not be purged.", 2, feed.getArticlesCount());
        } finally
        {
            DataFeed.setGlobalPurgeUnread(globalPurgeUnead);
        }
    }

    /**
     * Tests the case when <code>purgeUnread</code> is FALSE meaning that the
     * feed should not remove unread articles during cleanup. There will be another article
     * which is read. It should be removed.
     */
    public void testCleanNoPurgeUnread2()
    {
        // Disable purgin unread globally
        boolean globalPurgeUnead = DataFeed.isGlobalPurgeUnread();
        DataFeed.setGlobalPurgeUnread(false);

        try
        {
            // Set purge limit to 1 article
            DummyDataFeed feed = new DummyDataFeed();
            feed.setPurgeLimit(1);

            // Create 2 unread articles and one read and add them to the feed
            StandardArticle art1 = article(1);
            art1.setRead(false);
            feed.appendArticle(art1);

            StandardArticle art2 = article(2);
            art2.setRead(true);
            feed.appendArticle(art2);

            StandardArticle art3 = article(3);
            art3.setRead(false);
            feed.appendArticle(art3);

            // Clean and check
            feed.clean();
            assertEquals("Unread articles should not be purged.", 2, feed.getArticlesCount());
            assertTrue("Wrong article.", art1 == feed.getArticleAt(0));
            assertTrue("Wrong article.", art3 == feed.getArticleAt(1));
        } finally
        {
            DataFeed.setGlobalPurgeUnread(globalPurgeUnead);
        }
    }

    /**
     * Tests the case when <code>purgeUnread</code> is FALSE meaning that the
     * feed should not remove unread articles during cleanup.
     *
     * Covers the case when there're two read articles, one unread and purge limit set to 1.
     * Unread article should stay.
     */
    public void testCleanNoPurgeUnread3()
    {
        // Disable purgin unread globally
        boolean globalPurgeUnead = DataFeed.isGlobalPurgeUnread();
        DataFeed.setGlobalPurgeUnread(false);

        try
        {
            // Set purge limit to 1 article
            DummyDataFeed feed = new DummyDataFeed();
            feed.setPurgeLimit(1);

            // Create 2 unread articles and one read and add them to the feed
            StandardArticle art1 = article(1);
            art1.setRead(true);
            feed.appendArticle(art1);

            StandardArticle art2 = article(2);
            art2.setRead(false);
            feed.appendArticle(art2);

            StandardArticle art3 = article(3);
            art3.setRead(true);
            feed.appendArticle(art3);

            // Clean and check
            feed.clean();
            assertEquals("Unread articles should not be purged.", 1, feed.getArticlesCount());
            assertTrue("Wrong article.", art2 == feed.getArticleAt(0));
        } finally
        {
            DataFeed.setGlobalPurgeUnread(globalPurgeUnead);
        }
    }

    /**
     * Tests the computation of number of articles for removal.
     */
    public void testCalcArticlesRemove()
    {
        assertEquals("Nothing, because the total is 0.",
            0, DataFeed.calcArticlesToRemove(0, 0, 0, 3, false));
        assertEquals("Nothing, because the total is 0.",
            0, DataFeed.calcArticlesToRemove(0, 0, 0, 3, true));

        assertEquals("Only one article can be removed because the rest are unread.",
            1, DataFeed.calcArticlesToRemove(5, 4, 0, 3, false));
        assertEquals("2 articles, because only two are unread and it's below the limit.",
            2, DataFeed.calcArticlesToRemove(5, 2, 0, 3, false));
        assertEquals("Nothing can be removed as total equals the limit.",
            0, DataFeed.calcArticlesToRemove(3, 3, 0, 3, false));
        assertEquals("Nothing can be removed as total equals the limit.",
            0, DataFeed.calcArticlesToRemove(3, 2, 0, 3, false));

        assertEquals("2 articles, because removing unread is allowed.",
            2, DataFeed.calcArticlesToRemove(5, 4, 0, 3, true));
        assertEquals("2 articles, because removing unread is allowed.",
            2, DataFeed.calcArticlesToRemove(5, 2, 0, 3, true));
        assertEquals("Nothing can be removed as total equals the limit.",
            0, DataFeed.calcArticlesToRemove(3, 3, 0, 3, true));
        assertEquals("Nothing can be removed as total equals the limit.",
            0, DataFeed.calcArticlesToRemove(3, 2, 0, 3, true));

        // Pinned articles never count
        assertEquals("Pinned articles never count",
            0, DataFeed.calcArticlesToRemove(6, 0, 3, 3, true));
        assertEquals("Pinned articles never count",
            1, DataFeed.calcArticlesToRemove(6, 0, 2, 3, true));
    }

    /**
     * Tests how the last update server time field is populated during updates.
     */
    public void testSavingLastUpdateServerTime()
    {
        Channel chan = new Channel();
        chan.setLastUpdateServerTime(-1);
        chan.addItem(new Item("1"));

        DummyDataFeed feed = new DummyDataFeed();
        feed.setChannel(chan);
        feed.update();

        assertEquals("Wrong last update server time.", -1, feed.getLastUpdateServerTime());

        chan.setLastUpdateServerTime(1);
        chan.addItem(new Item("2"));
        feed.update();

        assertEquals("Wrong last update server time.", 1, feed.getLastUpdateServerTime());
    }

    /**
     * BUG: When pinned articles were being set, read articles list was being reset.
     */
    public void testSettingKeysSeparately()
    {
        String readKeys = "12345";
        String pinnedKeys = "67890";

        DummyDataFeed feed = new DummyDataFeed();
        feed.setReadArticlesKeys(readKeys);
        feed.setPinnedArticlesKeys(pinnedKeys);

        assertEquals(readKeys, feed.getReadArticlesKeys());
        assertEquals(pinnedKeys, feed.getPinnedArticlesKeys());
    }

    /** Article factory.
     *
     * @param title title.
     * @param link  link.
     * @param date  date.
     *
     * @return article
     */
    private static StandardArticle article(String title, String link, Date date)
    {
        StandardArticle art = new StandardArticle("");
        try
        {
            art.setLink(new URL(link));
            art.setTitle(title);
            art.setPublicationDate(date);
        } catch (MalformedURLException e)
        {
            fail("Bad link: " + link);
        }

        return art;
    }

}
TOP

Related Classes of com.salas.bb.domain.TestDataFeed

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.