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

core.apiCore.helpers.MessageQueueHelper Maven / Gradle / Ivy

package core.apiCore.helpers;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.StringUtils;
import org.apache.http.util.TextUtils;

import core.apiCore.ServiceManager;
import core.apiCore.interfaces.KafkaInterface;
import core.apiCore.interfaces.RabbitMqInterface;
import core.apiCore.interfaces.ServiceBusInterface;
import core.helpers.Helper;
import core.helpers.StopWatchHelper;
import core.support.configReader.Config;
import core.support.logger.TestLog;
import core.support.objects.KeyValue;
import core.support.objects.MessageObject;
import core.support.objects.MessageObject.messageType;
import core.support.objects.ServiceObject;

public class MessageQueueHelper {

	public static final String RESPONSE_IDENTIFIER = "response.identifier";

	
	/**
	 * 1) gets messages, adds them to the outboundMessages 2) filters based on the
	 * message key 3) validates based on expected response requirements
	 * 
	 * @param messageId
	 * @throws Exception
	 */
	public static void receiveAndValidateMessages(ServiceObject serviceObject, String messageId, messageType messageType) throws Exception {

		// evaluate options
		evaluateOption(serviceObject);
		
		// return if no validation required
		if(serviceObject.getExpectedResponse().isEmpty())
			return;
		
		CopyOnWriteArrayList filteredMessages = new CopyOnWriteArrayList<>();
		List errorMessages = new ArrayList();

		// message queue will run for maxRetrySeconds to retrieve matching outbound message
		int maxRetrySeconds = Config.getIntValue(ServiceManager.SERVICE_RESPONSE_TIMEOUT_SECONDS);
		StopWatchHelper watch = StopWatchHelper.start();
		long passedTimeInSeconds = 0;
		long lastLogged = 0;
		int interval = 10; // log every 10 seconds

		do {
			lastLogged = MessageQueueHelper.logPerInterval(interval, watch, lastLogged, filteredMessages.size());

			// gets messages and stores them in outboundMessages hashmap
			getOutboundMessages(messageType);

			// filters based on message id
			filteredMessages.addAll(MessageQueueHelper.filterOutboundMessage(messageId));

			// validate message count
			errorMessages = validateExpectedMessageCount(serviceObject.getExpectedResponse(),
					getMessageList(filteredMessages));

			// validates messages. will retry on error if expected number of messages not set
			if (errorMessages.isEmpty()) {
				printAllFilteredMessages(filteredMessages);
				errorMessages.addAll((validateMessages(serviceObject, filteredMessages)));
				
				// if expected fixed number of messages, at this point we have met that requirement
				if(isExpectingMessageCount(serviceObject.getExpectedResponse()))
					break;
			}

			passedTimeInSeconds = watch.time(TimeUnit.SECONDS);

		} while (!errorMessages.isEmpty() && passedTimeInSeconds < maxRetrySeconds);

		// save matching filtered messages to variable specified
		saveOutBoundValues(serviceObject, filteredMessages, errorMessages);
		
		if (!errorMessages.isEmpty()) {
			String errorString = StringUtils.join(errorMessages, "\n error: ");
			TestLog.ConsoleLog(errorString);
			Helper.assertFalse(StringUtils.join(errorMessages, "\n error: "));
		}
	}
	
	public static void saveOutBoundValues(ServiceObject serviceObject, CopyOnWriteArrayList filteredMessages,  List errorMessages) {
		if (filteredMessages.isEmpty() || !errorMessages.isEmpty() || serviceObject.getOutputParams().isEmpty())
			return;
		
		// get all the filtered messages
		ArrayList messages = new ArrayList();
		for(MessageObject message : filteredMessages) {
			messages.add(message.getMessage());
		}
		
		String outputParam = serviceObject.getOutputParams();
		// replace parameters for outputParam
		outputParam = DataHelper.replaceParameters(outputParam);

		List keywords = DataHelper.getValidationMap(outputParam);
		for (KeyValue keyword : keywords) {

			// fail if value is wrong format
			if (!keyword.key.toString().startsWith("<") || !keyword.key.toString().contains("$")
					|| !keyword.key.toString().endsWith(">"))
				Helper.assertFalse("variable placement must of format path: <$variable>. invalid value: "
						+ keyword.key.toString());

			String key = (String) keyword.key;
			key = key.replace("$", "").replace("<", "").replace(">", "").trim();
			// gets json value. if list, returns string separated by comma
			String value = Helper.convertListToString(messages);

			Config.putValue(key, value, false);
			TestLog.logPass("output parameter: " + key + " value: " + value);
		}
		
	}
	
	/**
	 * generate message id if the request body is set
	 * 
	 * @param requestBody
	 * @return
	 * @return
	 */
	public static String generateMessageId(ServiceObject serviceObject, String messageIdPrefix) {
		String messageId = StringUtils.EMPTY;

		// get unique identifier for request body to match outbound message
		if (!serviceObject.getRequestBody().isEmpty())
			messageId = messageIdPrefix + "-" + UUID.randomUUID().toString();

		return messageId;
	}

	/**
	 * log per interval stating the wait time for a message from message queue
	 * 
	 * @param interval
	 * @param watch
	 * @param lastLogged
	 * @return
	 */
	public static long logPerInterval(int interval, StopWatchHelper watch, long lastLogged, int receivedMessageCount) {
		long passedTimeInSeconds = watch.time(TimeUnit.SECONDS);
		if (passedTimeInSeconds > interval && passedTimeInSeconds - lastLogged > interval) {
			TestLog.logPass("waiting: " + watch.time(TimeUnit.SECONDS) + " seconds");
			TestLog.logPass("received: " + receivedMessageCount + " relevant message(s)");

			Helper.waitForSeconds(1);
			lastLogged = passedTimeInSeconds;
		}
		return lastLogged;
	}

	/**
	 * validate expected message count from received message format:
	 * EXPECTED_MESSAGE_COUNT:1;
	 * 
	 * @param request
	 * @param filteredMessages
	 * @return
	 */
	public static List validateExpectedMessageCount(String request, List filteredMessages) {
		List errorMessages = new ArrayList();

		if (filteredMessages.isEmpty()) {
			errorMessages.add("no messages received");
			return errorMessages;
		}

		int expectedMessageCount = -1;

		// get a map of key values in request
		Map params = getKeyValueFromString(request, ";", ":");

		// get expected message count if set
		if (params.containsKey(DataHelper.EXPECTED_MESSAGE_COUNT)) {
			expectedMessageCount = Helper.getIntFromString(params.get(DataHelper.EXPECTED_MESSAGE_COUNT), true);
		}

		// get actual message count
		int actualMessageCount = filteredMessages.size();

		// compare expected with actual message count
		// TestLog.logPass("verifying message count: " + "Response message count
		// received " + filteredMessages.size() + " out of " + expectedMessageCount + "
		// expected messages");
		if (expectedMessageCount != -1 && expectedMessageCount != actualMessageCount) {
			String errorMessage = "Response received " + filteredMessages.size() + " out of " + expectedMessageCount
					+ ".\n Received messages: \n";
			errorMessages.add(errorMessage + String.join("\n ", filteredMessages));
		}
		return errorMessages;
	}
	
	/**
	 * is fixed messaged count expected
	 * eg. EXPECTED_MESSAGE_COUNT:2
	 * @param expectedResponse
	 * @return
	 */
	public static boolean isExpectingMessageCount(String expectedResponse) {
		int expectedMessageCount = -1;

		// get a map of key values in request
		Map params = getKeyValueFromString(expectedResponse, ";", ":");

		// get expected message count if set
		if (params.containsKey(DataHelper.EXPECTED_MESSAGE_COUNT)) {
			expectedMessageCount = Helper.getIntFromString(params.get(DataHelper.EXPECTED_MESSAGE_COUNT), true);
		}
		if(expectedMessageCount != -1)
			return true;
		
		return false;
	}

	/**
	 * separated based on key value if key value exists eg. key:value; key1:value1
	 * 
	 * @param value
	 * @param entriesSeparator eg. ";"
	 * @param separator        eg ":"
	 * @return
	 */
	public static Map getKeyValueFromString(String value, String entriesSeparator, String separator) {
		Map map = new HashMap();

		// remove all spaces
		value = value.replaceAll("\\s+", "");

		String[] entries = value.split(entriesSeparator);
		for (String entry : entries) {
			if (!TextUtils.isEmpty(entry) && entry.contains(separator)) {
				String[] keyValue = entry.split(separator);
				map.put(keyValue[0], keyValue[1]);
			}
		}
		return map;
	}

	/**
	 * find message based on unique identifier passed in through options
	 * identifiers are separated by comma 
	 * separators have And relationship
	 * @param messageId
	 * @return
	 */
	public static CopyOnWriteArrayList findMessagesBasedOnResponseIdentifier() {
		CopyOnWriteArrayList filteredMessages = new CopyOnWriteArrayList();
		List identifierList = Config.getValueList(MessageQueueHelper.RESPONSE_IDENTIFIER);

		// return if identifier is empty
		if (identifierList.isEmpty())
			return filteredMessages;

		for (Entry entry : MessageObject.outboundMessages.entrySet()) {
			String receiveMessage = Optional.ofNullable(entry.getKey().getMessage()).orElse("");

			boolean isMessageMatch = isIdentifierMatch(receiveMessage, identifierList);
			if (entry.getValue().equals(true) && isMessageMatch) {

				filteredMessages.add(entry.getKey());
				MessageObject.outboundMessages.put(entry.getKey(), false);
			}

		}

		return filteredMessages;
	}
	
	private static boolean isIdentifierMatch(String receiveMessage, List identifierList) {
		// return if identifier is empty
		if (identifierList.isEmpty())
			return false;

		for (String identifier : identifierList) {
			if (!receiveMessage.contains(identifier))
				return false;
		}
		return true;
	}

	/**
	 * find message based on record id
	 * 
	 * @param messageId
	 * @return
	 */
	public static CopyOnWriteArrayList findMessagesBasedOnMessageId(String messageId) {
		CopyOnWriteArrayList filteredMessages = new CopyOnWriteArrayList();

		// return if message id is not set. message id is empty when no message is sent
		if (messageId.isEmpty())
			return filteredMessages;

		for (Entry entry : MessageObject.outboundMessages.entrySet()) {
			String receivedMessageId = Optional.ofNullable(entry.getKey().getMessageId()).orElse("");
			String receivedCorrelationId = Optional.ofNullable(entry.getKey().getCorrelationId()).orElse("");

			boolean isMessageMatch = receivedMessageId.contains(messageId) || receivedCorrelationId.contains(messageId);
			if (entry.getValue().equals(true) && isMessageMatch) {

				filteredMessages.add(entry.getKey());
				MessageObject.outboundMessages.put(entry.getKey(), false);
			}
		}

		return filteredMessages;
	}

	/**
	 * filter outbound message based on messageId
	 * 
	 * @param msgId
	 * @return
	 */
	public static CopyOnWriteArrayList filterOutboundMessage(String messageId) {

		// filter messages for the current test
		CopyOnWriteArrayList filteredMessages = new CopyOnWriteArrayList();

		// filter based on message Id
		CopyOnWriteArrayList filterByMessageId = MessageQueueHelper
				.findMessagesBasedOnMessageId(messageId);

		// if message id set (message is sent in same test), use filtered by message id,
		// else use identifier from options
		if (!filterByMessageId.isEmpty())
			filteredMessages.addAll(filterByMessageId);
		else {
			CopyOnWriteArrayList filterByMessageIdentifier = MessageQueueHelper
					.findMessagesBasedOnResponseIdentifier();
			filteredMessages.addAll(filterByMessageIdentifier);
		}

		return filteredMessages;
	}

	public static void getOutboundMessages(messageType messageType) throws Exception {
		switch (messageType) {
		case KAFKA:
			KafkaInterface.getOutboundMessages();
			break;
		case RABBITMQ:
			RabbitMqInterface.getOutboundMessages();
			break;
		case SERVICEBUS:
			ServiceBusInterface.getOutboundMessages();
			break;
		case TEST:
			break;
		default:
		}

	}

	/**
	 * print all messages ids
	 */
	public static void printAllMessages() {
		TestLog.ConsoleLog("Printing All received messages");
		for (Entry entry : MessageObject.outboundMessages.entrySet()) {
			String messageId = entry.getKey().getMessageId();
			Boolean messageAvailable = entry.getValue();

			TestLog.ConsoleLog("received messagesId: '" + messageId + "'. was message read: " + !messageAvailable);
		}
	}

	public static void printAllFilteredMessages(CopyOnWriteArrayList filteredMessages) {
		for (MessageObject message : filteredMessages) {
			String messageId = message.getMessageId();
			String messageContent = message.getMessage();
			if(!message.isLogged) {
				TestLog.logPass("Printing relevant received messages");
				TestLog.logPass("received messagesId: '" + messageId + "' with message content: \n" +  messageContent );
			}
			message.isLogged = true;
		}
	}

	/**
	 * inserts filtered messages to array list of strings
	 * 
	 * @param filteredMessages
	 * @return
	 */
	public static List getMessageList(CopyOnWriteArrayList filteredMessages) {
		List messages = new ArrayList();
		for (MessageObject message : filteredMessages) {
			messages.add(message.getMessage());
		}
		return messages;
	}

	/**
	 * inserts filtered headers to array list of strings
	 * 
	 * @param filteredMessages
	 * @return
	 */
	public static List getHeaderList(CopyOnWriteArrayList filteredMessages) {
		List messages = new ArrayList();
		for (MessageObject message : filteredMessages) {
			messages.addAll(message.getHeader());
		}
		return messages;
	}

	/**
	 * inserts filtered topics to array list of strings
	 * 
	 * @param filteredMessages
	 * @return
	 */
	public static List getTopicList(CopyOnWriteArrayList filteredMessages) {
		List messages = new ArrayList();
		for (MessageObject message : filteredMessages) {
			messages.add(message.getTopic());
		}
		return messages;
	}

	/**
	 * validate message based on message, header, or topic valites json, xml, or
	 * text response
	 * 
	 * @return
	 * 
	 */
	public static List validateMessages(ServiceObject serviceObject,
			CopyOnWriteArrayList filteredMessages) {

		List errorMessages = new ArrayList();
		if (filteredMessages.isEmpty()) {
			errorMessages.add("no messages received");
			return errorMessages;
		}

		List messageList = getMessageList(filteredMessages);
		List headerList = getHeaderList(filteredMessages);
		List topicList = getTopicList(filteredMessages);

		// separate expected response to each section we want to validate: messageBody,
		// header, topic
		String expectedMessage = DataHelper.removeSectionFromExpectedResponse(DataHelper.VERIFY_HEADER_PART_INDICATOR,
				serviceObject.getExpectedResponse());
		expectedMessage = DataHelper.removeSectionFromExpectedResponse(DataHelper.VERIFY_TOPIC_PART_INDICATOR,
				expectedMessage);
		expectedMessage = DataHelper.removeSectionFromExpectedResponse(DataHelper.EXPECTED_MESSAGE_COUNT,
				expectedMessage);
		String expectedHeader = DataHelper.getSectionFromExpectedResponse(DataHelper.VERIFY_HEADER_PART_INDICATOR,
				serviceObject.getExpectedResponse());
		String expectedTopic = DataHelper.getSectionFromExpectedResponse(DataHelper.VERIFY_TOPIC_PART_INDICATOR,
				serviceObject.getExpectedResponse());

		if (!expectedMessage.isEmpty()) {
			//TestLog.logPass("validating message list:"); TODO: will appear per retry
			errorMessages = DataHelper.validateExpectedValues(messageList, expectedMessage);
		}

		if (!expectedHeader.isEmpty()) {
			//TestLog.logPass("validating header list:");
			errorMessages.addAll(DataHelper.validateExpectedValues(headerList, expectedHeader));
		}

		if (!expectedTopic.isEmpty()) {
			//TestLog.logPass("validating topic list:");
			errorMessages.addAll(DataHelper.validateExpectedValues(topicList, expectedTopic));
		}

		return errorMessages;
	}

	public static void evaluateOption(ServiceObject serviceObject) {

		// reset validation timeout. will be overwritten by option value if set
		resetValidationTimeout();

		// if no option specified
		if (serviceObject.getOption().isEmpty()) {
			return;
		}


		// replace parameters for request body
		serviceObject.withOption(DataHelper.replaceParameters(serviceObject.getOption()));

		// get key value mapping of header parameters
		List keywords = DataHelper.getValidationMap(serviceObject.getOption());

		// iterate through key value pairs for headers, separated by ";"
		for (KeyValue keyword : keywords) {

			// if additional options
			switch (keyword.key) {
			case ServiceManager.OPTION_NO_VALIDATION_TIMEOUT:
				Config.putValue(ServiceManager.SERVICE_TIMEOUT_VALIDATION_ENABLED, false);
				break;
			case ServiceManager.OPTION_WAIT_FOR_RESPONSE:
				Config.putValue(ServiceManager.SERVICE_TIMEOUT_VALIDATION_ENABLED, true);
				Config.putValue(ServiceManager.SERVICE_TIMEOUT_VALIDATION_SECONDS, keyword.value);
				break;
			default:
				break;
			}
		}
	}

	/**
	 * reset validation timeout
	 */
	private static void resetValidationTimeout() {
		// reset validation timeout option
		String defaultValidationTimeoutIsEnabled = Config
				.getGlobalValue(ServiceManager.SERVICE_TIMEOUT_VALIDATION_ENABLED);
		String defaultValidationTimeoutIsSeconds = Config
				.getGlobalValue(ServiceManager.SERVICE_TIMEOUT_VALIDATION_SECONDS);

		Config.putValue(ServiceManager.SERVICE_TIMEOUT_VALIDATION_ENABLED, defaultValidationTimeoutIsEnabled);
		Config.putValue(ServiceManager.SERVICE_TIMEOUT_VALIDATION_SECONDS, defaultValidationTimeoutIsSeconds);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy