class MQTT::Testing::SubHandler

This class is meant purely for testing.

It completely removes the need for a external MQTT broker, and captures errors.
Message processing can be done step-by-step, for better analysis of errors.
Its interface is identical to the main class, making it indistinguishable.

Attributes

message_log[R]
publish_queue[R]
retained_topics[RW]
test_handler[RW]

Public Class Methods

new(jsonify: true, test_handler: nil) click to toggle source

Initialize the test class @param jsonify [Boolean] Whether or not Hashes and Arrays should be

converted to JSON before sending.

@param test_handler [nil, MiniTest::Test] The test handler to use to report

errors or pass sanity checks. Must support flunk and pass!
# File lib/mqtt/sub_testing.rb, line 129
def initialize(jsonify: true, test_handler: nil)
        @callbackList    = Array.new();
        @retained_topics = Hash.new();
        @publish_queue   = Queue.new();
        @message_log          = Hash.new() do |h, key| h = Array.new() end;

        @trackerHash = Hash.new();

        @jsonifyHashes = jsonify;

        @test_handler = test_handler;
end

Public Instance Methods

assert_garbage_resilient() click to toggle source
# File lib/mqtt/sub_testing.rb, line 87
def assert_garbage_resilient()
        @callbackList.each do |c|
                t = Array.new() {|a,k| a[k] = SecureRandom.random_bytes(100)}
                c.offer(t, SecureRandom.random_bytes(100));
        end

        if(@test_handler)
                @test_handler.pass("No garbage message problem detected.");
        end
end
full_reset() click to toggle source

Perform a complete reset of the testing unit, clearing out all

queues and removing all callbacks. This should mainly be used
inside the teardown or setup routines, before creating a new
testing instance, to prevent uncleaned garbage.
# File lib/mqtt/sub_testing.rb, line 119
def full_reset()
        @callbackList.clear();
        prepare();
end
prepare(retained: true) click to toggle source

Prepare the code for the next test by cleaning out all queues.

The list of callbacks is not affected

@param retained [Boolean, Hash<String, String>] Either a bool whether or not to clear retained messages,

or a Hash with Topic-Keys containing String-Data to use.
# File lib/mqtt/sub_testing.rb, line 102
def prepare(retained: true)
        @publish_queue.clear();
        if(retained.is_a? Hash)
                @retained_topics = retained.clone
                @retained_topics.each do |topic, data|
                        publish_to(topic, data);
                end
        elsif(retained)
                @retained_topics = Hash.new();
        end
        @message_log.clear()
end
process_all(max_loops: 500, error_on_loop: true) click to toggle source

Process all messages until the queue is empty.

Do remember that the callbacks can publish new data, which then gets processed again!

@param max_loops [Integer] Amount of loops to do before aborting @param error_on_loop [Boolean] Raise an error if too many loops happened?

# File lib/mqtt/sub_testing.rb, line 65
def process_all(max_loops: 500, error_on_loop: true)
        until @publish_queue.empty?
                process_message
                max_loops -= 1;

                if(max_loops == 0)
                        if(error_on_loop)
                                if(@test_handler)
                                        @test_handler.flunk("MQTT Loop recursion detected")
                                else
                                        raise RuntimeError, "MQTT Loop recursion detected"
                                end
                        end
                        return
                end
        end

        if(error_on_loop and @test_handler)
                @test_handler.pass("No MQTT Loop recursion.");
        end
end
process_message() click to toggle source

Process a single MQTT message in queue, recording errors etc.

# File lib/mqtt/sub_testing.rb, line 55
def process_message
        return if @publish_queue.empty?
        packet = @publish_queue.pop
        call_interested(packet[0], packet[1]);
end
publish_to(topic, data, qos: nil, retain: false) click to toggle source

Publish a message to topic. @param topic [String] The topic to push to. @param data [String] The data to be transmitted. @note The published data is not immediately processed.

Use process_message or process_all
# File lib/mqtt/sub_testing.rb, line 42
def publish_to(topic, data, qos: nil, retain: false)
        if(@jsonifyHashes and (data.is_a? Array or data.is_a? Hash))
                data = data.to_json
        else
                data = data.to_s;
        end

        @publish_queue              << [topic, data];
        @message_log[topic]         << data;
        @retained_topics[topic] = data if retain;
end

Private Instance Methods

call_interested(topic, data) click to toggle source
# File lib/mqtt/sub_testing.rb, line 18
def call_interested(topic, data)
        @callbackList.each do |h|
                tMatch = SubHandler.getTopicMatch(topic, h.topic_split);
                if tMatch then
                        h.offer(tMatch, data)
                end
        end
end
raw_subscribe_to(topic, qos: nil) click to toggle source
# File lib/mqtt/sub_testing.rb, line 28
def raw_subscribe_to(topic, qos: nil)
        @retained_topics.each do |retTopic, retData|
                if SubHandler.getTopicMatch(retTopic, SubHandler.get_topic_split(topic))
                        publish_to(retTopic, retData)
                end
        end
end