All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.simulator.tests.topic.ReliableTopicTest Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2008-2016, Hazelcast, Inc. All Rights Reserved.
 *
 * Licensed 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.
 */
package com.hazelcast.simulator.tests.topic;

import com.hazelcast.cp.IAtomicLong;
import com.hazelcast.nio.ObjectDataInput;
import com.hazelcast.nio.ObjectDataOutput;
import com.hazelcast.nio.serialization.DataSerializableFactory;
import com.hazelcast.nio.serialization.IdentifiedDataSerializable;
import com.hazelcast.simulator.hz.HazelcastTest;
import com.hazelcast.simulator.test.BaseThreadState;
import com.hazelcast.simulator.test.TestException;
import com.hazelcast.simulator.test.annotations.AfterRun;
import com.hazelcast.simulator.test.annotations.BeforeRun;
import com.hazelcast.simulator.test.annotations.Setup;
import com.hazelcast.simulator.test.annotations.TimeStep;
import com.hazelcast.simulator.test.annotations.Verify;
import com.hazelcast.simulator.tests.helpers.KeyLocality;
import com.hazelcast.simulator.utils.ExceptionReporter;
import com.hazelcast.topic.ITopic;
import com.hazelcast.topic.Message;
import com.hazelcast.topic.MessageListener;

import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import static com.hazelcast.simulator.tests.helpers.KeyUtils.generateStringKeys;
import static com.hazelcast.simulator.utils.TestUtils.assertTrueEventually;
import static com.hazelcast.simulator.utils.UuidUtil.newSecureUuidString;
import static java.lang.String.format;
import static org.junit.Assert.assertEquals;

public class ReliableTopicTest extends HazelcastTest {

    // properties
    public int topicCount = 10;
    public int listenersPerTopic = 2;
    public KeyLocality keyLocality = KeyLocality.SHARED;

    private AtomicLong failures = new AtomicLong();
    private IAtomicLong totalMessagesSend;
    private ITopic[] topics;
    private List listeners;

    @Setup
    @SuppressWarnings("unchecked")
    public void setup() {
        totalMessagesSend = getAtomicLong(name + ":TotalExpectedCounter");
        topics = new ITopic[topicCount];
        listeners = new LinkedList<>();

        String[] names = generateStringKeys(name, topicCount, keyLocality, targetInstance);

        int listenerIdCounter = 0;
        for (int i = 0; i < topics.length; i++) {
            ITopic topic = targetInstance.getReliableTopic(names[i]);
            topics[i] = topic;
            for (int l = 0; l < listenersPerTopic; l++) {
                MessageListenerImpl topicListener = new MessageListenerImpl(listenerIdCounter);
                listenerIdCounter++;
                topic.addMessageListener(topicListener);
                listeners.add(topicListener);
            }
        }
    }

    @BeforeRun
    public void beforeRun(ThreadState state) {
        for (ITopic topic : topics) {
            state.counterMap.put(topic, new AtomicLong());
        }
    }

    @TimeStep
    public void timeStep(ThreadState state) throws Exception {
        ITopic topic = state.getRandomTopic();
        AtomicLong counter = state.counterMap.get(topic);
        MessageEntity msg = new MessageEntity(state.id, counter.incrementAndGet());
        state.messagesSend++;
        topic.publish(msg);
    }

    @AfterRun
    public void afterRun(ThreadState state) {
        totalMessagesSend.addAndGet(state.messagesSend);
    }

    public class ThreadState extends BaseThreadState {

        private long messagesSend = 0;
        private final Map counterMap = new HashMap<>();
        private final String id = newSecureUuidString();

        private ITopic getRandomTopic() {
            int index = randomInt(topics.length);
            return topics[index];
        }
    }

    private static class MessageDataSerializableFactory implements DataSerializableFactory {

        public static final int FACTORY_ID = 18;

        @Override
        public IdentifiedDataSerializable create(int i) {
            return new MessageEntity();
        }
    }

    private static class MessageEntity implements IdentifiedDataSerializable {

        private String thread;
        private long value;

        public MessageEntity() {
        }

        public MessageEntity(String thread, long counter) {
            this.thread = thread;
            this.value = counter;
        }

        @Override
        public String toString() {
            return "MessageEntity{"
                    + "thread=" + thread
                    + ", value=" + value
                    + '}';
        }

        @Override
        public void writeData(ObjectDataOutput out) throws IOException {
            out.writeUTF(thread);
            out.writeLong(value);
        }

        @Override
        public void readData(ObjectDataInput in) throws IOException {
            thread = in.readUTF();
            value = in.readLong();
        }

        @Override
        public int getFactoryId() {
            return MessageDataSerializableFactory.FACTORY_ID;
        }

        @Override
        public int getClassId() {
            return 0;
        }
    }

    private class MessageListenerImpl implements MessageListener {

        private final Map values = new HashMap<>();
        private final AtomicLong received = new AtomicLong();

        private final int id;

        public MessageListenerImpl(int id) {
            this.id = id;
        }

        @Override
        public void onMessage(Message message) {
            String threadId = message.getMessageObject().thread;
            Long previousValue = values.get(threadId);
            if (previousValue == null) {
                previousValue = 0L;
            }

            long actualValue = message.getMessageObject().value;
            long expectedValue = previousValue + 1;
            if (expectedValue != actualValue) {
                failures.incrementAndGet();
                ExceptionReporter.report(testContext.getTestId(), new TestException(format(
                        "There is an unexpected gap or equality between values. Expected %d, but was %d",
                        expectedValue, actualValue)));
            }

            values.put(threadId, actualValue);

            if (received.getAndIncrement() % 100000 == 0) {
                logger.info(toString() + " is at " + message.getMessageObject().toString());
            }
        }

        @Override
        public String toString() {
            return "StressMessageListener{"
                    + "id=" + id
                    + '}';
        }
    }

    @Verify(global = true)
    public void verify() {
        final long expectedCount = listenersPerTopic * totalMessagesSend.get();
        assertTrueEventually(() -> {
            long actualCount = 0;
            for (MessageListenerImpl topicListener : listeners) {
                actualCount += topicListener.received.get();
            }
            assertEquals("published messages don't match received messages", expectedCount, actualCount);
        });
        assertEquals("Failures found", 0, failures.get());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy