Class: MQTT::Testing::SubHandler

Inherits:
SubHandler show all
Defined in:
lib/mqtt/sub_testing.rb

Overview

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.

Instance Attribute Summary collapse

Attributes inherited from SubHandler

#jsonifyHashes

Instance Method Summary collapse

Methods inherited from SubHandler

#subscribe_to, #track, #wait_for

Methods inherited from BaseHandler

#destroy!, getTopicMatch, get_topic_split, #lockAndListen, #register_subscription, #unregister_subscription

Constructor Details

#initialize(jsonify: true, test_handler: nil) ⇒ SubHandler

Initialize the test class



129
130
131
132
133
134
135
136
137
138
139
140
# 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

Instance Attribute Details

#message_logObject (readonly)

Returns the value of attribute message_log.



12
13
14
# File 'lib/mqtt/sub_testing.rb', line 12

def message_log
  @message_log
end

#publish_queueObject (readonly)

Returns the value of attribute publish_queue.



13
14
15
# File 'lib/mqtt/sub_testing.rb', line 13

def publish_queue
  @publish_queue
end

#retained_topicsObject

Returns the value of attribute retained_topics.



14
15
16
# File 'lib/mqtt/sub_testing.rb', line 14

def retained_topics
  @retained_topics
end

#test_handlerObject

Returns the value of attribute test_handler.



16
17
18
# File 'lib/mqtt/sub_testing.rb', line 16

def test_handler
  @test_handler
end

Instance Method Details

#assert_garbage_resilientObject



87
88
89
90
91
92
93
94
95
96
# 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_resetObject

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.


119
120
121
122
# File 'lib/mqtt/sub_testing.rb', line 119

def full_reset()
  @callbackList.clear();
  prepare();
end

#prepare(retained: true) ⇒ Object

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

The list of callbacks is not affected


102
103
104
105
106
107
108
109
110
111
112
113
# 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) ⇒ Object

Process all messages until the queue is empty.

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


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# 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_messageObject

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



55
56
57
58
59
# 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) ⇒ Object

Note:

The published data is not immediately processed. Use process_message or process_all

Publish a message to topic.



42
43
44
45
46
47
48
49
50
51
52
# 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