/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */
#include "unit_test.h"
#include "BrokerFixture.h"
#include "qpid/client/MessageReplayTracker.h"
#include "qpid/sys/Time.h"

namespace qpid {
namespace tests {

QPID_AUTO_TEST_SUITE(MessageReplayTrackerTests)

using namespace qpid::client;
using namespace qpid::sys;
using std::string;

class ReplayBufferChecker
{
  public:

    ReplayBufferChecker(uint from, uint to) : end(to), i(from) {}

    void operator()(const Message& m)
    {
        if (i > end) BOOST_FAIL("Extra message found: " + m.getData());
        BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i++)).str(), m.getData());
    }
  private:
    const uint end;
    uint i;

};

QPID_AUTO_TEST_CASE(testReplay)
{
    SessionFixture fix;
    fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);

    MessageReplayTracker tracker(10);
    tracker.init(fix.session);
    for (uint i = 0; i < 5; i++) {
        Message message((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
        tracker.send(message);
    }
    ReplayBufferChecker checker(1, 10);
    tracker.foreach(checker);

    tracker.replay(fix.session);
    for (uint j = 0; j < 2; j++) {//each message should have been sent twice
        for (uint i = 0; i < 5; i++) {
            Message m;
            BOOST_CHECK(fix.subs.get(m, "my-queue", TIME_SEC));
            BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
        }
    }
    Message m;
    BOOST_CHECK(!fix.subs.get(m, "my-queue"));
}

QPID_AUTO_TEST_CASE(testCheckCompletion)
{
    SessionFixture fix;
    fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);

    MessageReplayTracker tracker(10);
    tracker.init(fix.session);
    for (uint i = 0; i < 5; i++) {
        Message message((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
        tracker.send(message);
    }
    fix.session.sync();//ensures all messages are complete
    tracker.checkCompletion();
    tracker.replay(fix.session);
    Message received;
    for (uint i = 0; i < 5; i++) {
        BOOST_CHECK(fix.subs.get(received, "my-queue"));
        BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), received.getData());
    }
    BOOST_CHECK(!fix.subs.get(received, "my-queue"));
}

QPID_AUTO_TEST_SUITE_END()

}} // namespace qpid::tests
