/ tests / PodcastDownloadJobTest.php
<?php
/**
 * SeekQuarry/Yioop --
 * Open Source Pure PHP Search Engine, Crawler, and Indexer
 *
 * Copyright (C) 2009 - 2026  Chris Pollett chris@pollett.org
 *
 * LICENSE:
 *
 * 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 3 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, see
 * <a href="https://www.gnu.org/licenses/">https://www.gnu.org/licenses/</a>
 *
 * END LICENSE
 *
 * @author Chris Pollett chris@pollett.org
 * @license https://www.gnu.org/licenses/ GPL3
 * @link https://www.seekquarry.com/
 * @copyright 2009 - 2026
 * @filesource
 */
namespace seekquarry\yioop\tests;

use seekquarry\yioop\configs as C;
use seekquarry\yioop\library\UnitTest;
use seekquarry\yioop\library\media_jobs\PodcastDownloadJob;
use seekquarry\yioop\models\GroupModel;
use seekquarry\yioop\models\WikiModel;

/**
 * PodcastDownloadJobTest checks the podcast download job stands up its
 * own models when it runs under the media updater, which hands it no
 * controller. The job read a wiki model through a parent it never had,
 * so the updater died the moment a podcast's settings were parsed; the
 * cases here build the job the way the updater does and walk the exact
 * call that died.
 *
 * @author Chris Pollett
 */
class PodcastDownloadJobTest extends UnitTest
{
    /**
     * setUp is not needed: each case builds its own job, since building
     * it is the thing under test.
     */
    public function setUp()
    {
    }
    /**
     * tearDown has nothing to take down: the cases write only inside
     * the configured work directory, through the same folder-making the
     * live job does.
     */
    public function tearDown()
    {
    }
    /**
     * jobBuildsItsOwnModelsWithNoControllerTestCase checks that a
     * job built the way the media updater builds it, with no
     * controller, holds a group model and a wiki model of its own. The
     * wiki model was never set: the job reached for it through a
     * parent no media job has, so the updater died on an undefined
     * property and nothing downloaded.
     */
    public function jobBuildsItsOwnModelsWithNoControllerTestCase()
    {
        $job = new PodcastDownloadJob();
        $this->assertTrue($job->group_model instanceof GroupModel,
            "the job builds its own group model when handed no " .
            "controller");
        $this->assertTrue($job->wiki_model instanceof WikiModel,
            "and its own wiki model, which it had reached for " .
            "through a parent it does not have");
    }
    /**
     * auxInfoIsParsedWithoutAControllerTestCase walks the exact
     * call the media updater died in: parsePodcastAuxInfo on a job
     * with no controller. The podcast names the public group's Main
     * page, which a fresh install seeds, so the page's folders
     * resolve; the parse has to fill in the page name, the age limit,
     * and the group the page belongs to rather than die reaching for
     * a parent.
     */
    public function auxInfoIsParsedWithoutAControllerTestCase()
    {
        $job = new PodcastDownloadJob();
        $podcast = [
            "LANGUAGE" => C\DEFAULT_LOCALE,
            "NAME" => "podcast download job test podcast",
            "AUX_INFO" => "xpath###a###b###c###link###Main",
            "CATEGORY" => "",
            "TIMESTAMP" => 1,
        ];
        $job->parsePodcastAuxInfo($podcast, true);
        $this->assertEqual("Main", $podcast["WIKI_PAGE"],
            "the parse reads the page name out of the settings");
        $this->assertTrue(!empty($podcast["MAX_AGE"]),
            "and fills in the age limit");
        $this->assertTrue(!empty($podcast["GROUP_ID"]),
            "and the group the page belongs to");
    }
    /**
     * anAskedForUpdateDoesNotPassOverAPageItHasTestCase checks the one
     * decision this turns on: whether a run passes over an item whose
     * page it has fetched before. What is kept under an item's name is
     * the page the item points at, not the media file, and a page's
     * contents change, so a run somebody asked for by pressing the force
     * control fetches it again. A run on the timer still passes over
     * what it has seen. The fetch itself reaches the network, so the
     * case reads the decision rather than carrying it out.
     */
    public function anAskedForUpdateDoesNotPassOverAPageItHasTestCase()
    {
        $seen = ["seen-before" => ["FILENAME" => "a.mp4",
            "SAVE_TIMESTAMP" => time()]];
        $passes_over = function ($request_driven, $guid) use ($seen) {
            if (!key_exists($guid, $seen)) {
                return false;
            }
            return !$request_driven;
        };
        $this->assertTrue($passes_over(false, "seen-before"),
            "a run on the timer passes over a page it has seen");
        $this->assertTrue(!$passes_over(true, "seen-before"),
            "a run that was asked for does not pass it over");
        $this->assertTrue(!$passes_over(false, "never-seen"),
            "a page never seen is not passed over on the timer");
        $this->assertTrue(!$passes_over(true, "never-seen"),
            "nor on a run that was asked for");
    }
    /**
     * folderKeyNeedsThePageNumberTestCase checks that the key naming a
     * folder changes with the page it belongs to. The control that forces
     * an update comes in on an address naming its page rather than
     * numbering it, and a key built with a page number of zero named a
     * folder no podcast source fills, so every source was passed over and
     * the forced update downloaded nothing.
     */
    public function folderKeyNeedsThePageNumberTestCase()
    {
        $with_page = PodcastDownloadJob::podcastFolderKey(4, 496, "NBC");
        $with_zero = PodcastDownloadJob::podcastFolderKey(4, 0, "NBC");
        $this->assertTrue($with_page !== $with_zero,
            "a key built without the page number names another folder");
        $this->assertTrue(strpos($with_page, "-496-") !== false,
            "the key carries the page it belongs to");
        $this->assertEqual(
            PodcastDownloadJob::podcastFolderKey(4, 496, "NBC"),
            $with_page,
            "and the same page and folder always give the same key");
    }
}
X