Browse Source

Spruce up transition tests

Christopher Mullins 6 years ago
parent
commit
962c896f8c
1 changed files with 163 additions and 49 deletions
  1. 163 49
      test/remote/spec/transition_spec.rb

+ 163 - 49
test/remote/spec/transition_spec.rb

@@ -124,8 +124,10 @@ RSpec.describe 'Transitions' do
 
 
       @mqtt_client.wait_for_listeners
       @mqtt_client.wait_for_listeners
 
 
+      expected_updates = calculate_transition_steps(start_value: 0, end_value: 255, duration: 2000)
+
       expect(last_value).to eq(255)
       expect(last_value).to eq(255)
-      expect(seen_updates).to eq(8) # duration of 2000ms / 300ms period + 1 for initial packet
+      expect(seen_updates).to eq(expected_updates.length)
     end
     end
 
 
     it 'should transition a field downwards' do
     it 'should transition a field downwards' do
@@ -148,8 +150,10 @@ RSpec.describe 'Transitions' do
 
 
       @mqtt_client.wait_for_listeners
       @mqtt_client.wait_for_listeners
 
 
+      expected_updates = calculate_transition_steps(start_value: 0, end_value: 255, duration: 2000)
+
       expect(last_value).to eq(0)
       expect(last_value).to eq(0)
-      expect(seen_updates).to eq(8) # duration of 2000ms / 300ms period + 1 for initial packet
+      expect(seen_updates).to eq(expected_updates.length) # duration of 2000ms / 450ms period + 1 for initial packet
     end
     end
 
 
     it 'should transition two fields at once if received in the same command' do
     it 'should transition two fields at once if received in the same command' do
@@ -170,10 +174,12 @@ RSpec.describe 'Transitions' do
 
 
       @mqtt_client.wait_for_listeners
       @mqtt_client.wait_for_listeners
 
 
+      expected_updates = calculate_transition_steps(start_value: 0, end_value: 250, duration: 2000)
+
       expect(updates['hue'].last).to eq(250)
       expect(updates['hue'].last).to eq(250)
       expect(updates['brightness'].last).to eq(0)
       expect(updates['brightness'].last).to eq(0)
       expect(updates['hue'].length == updates['brightness'].length).to eq(true), "Should have the same number of updates for both fields"
       expect(updates['hue'].length == updates['brightness'].length).to eq(true), "Should have the same number of updates for both fields"
-      expect(updates['hue'].length).to eq(8)
+      expect(updates['hue'].length).to eq(expected_updates.length)
     end
     end
   end
   end
 
 
@@ -205,7 +211,14 @@ RSpec.describe 'Transitions' do
 
 
       @mqtt_client.wait_for_listeners
       @mqtt_client.wait_for_listeners
 
 
-      expect(seen_updates.map { |x| x['brightness'] }).to eq([0, 64, 128, 191, 255])
+      expected_updates = calculate_transition_steps(start_value: 0, end_value: 255, period: 500, duration: 2000)
+
+      transitions_are_equal(
+        expected: expected_updates,
+        seen: seen_updates.map { |x| x['brightness'] },
+        # Allow some variation for the lossy level -> brightness conversion
+        allowed_variation: 2
+      )
       expect((Time.now - start_time)/4).to be >= 0.5 # Don't count the first update
       expect((Time.now - start_time)/4).to be >= 0.5 # Don't count the first update
     end
     end
 
 
@@ -248,7 +261,12 @@ RSpec.describe 'Transitions' do
 
 
       @mqtt_client.wait_for_listeners
       @mqtt_client.wait_for_listeners
 
 
-      expect(seen_updates.map { |x| x['brightness'] }).to eq([0, 64, 128, 191, 255])
+      transitions_are_equal(
+        expected: calculate_transition_steps(start_value: 0, end_value: 255, duration: 2000, period: 500),
+        seen: seen_updates.map { |x| x['brightness'] },
+        # Allow some variation for the lossy level -> brightness conversion
+        allowed_variation: 2
+      )
     end
     end
   end
   end
 
 
@@ -270,7 +288,12 @@ RSpec.describe 'Transitions' do
       @mqtt_client.wait_for_listeners
       @mqtt_client.wait_for_listeners
 
 
       expect(seen_updates['state']).to eq(['ON'])
       expect(seen_updates['state']).to eq(['ON'])
-      expect(seen_updates['brightness']).to eq([0, 64, 128, 191, 255])
+      transitions_are_equal(
+        expected: calculate_transition_steps(start_value: 0, end_value: 255, duration: 1000),
+        seen: seen_updates['brightness'],
+        # Allow some variation for the lossy level -> brightness conversion
+        allowed_variation: 3
+      )
     end
     end
 
 
     it 'should transition from on -> off' do
     it 'should transition from on -> off' do
@@ -290,7 +313,12 @@ RSpec.describe 'Transitions' do
       @mqtt_client.wait_for_listeners
       @mqtt_client.wait_for_listeners
 
 
       expect(seen_updates['state']).to eq(['OFF'])
       expect(seen_updates['state']).to eq(['OFF'])
-      expect(seen_updates['brightness']).to eq([255, 191, 128, 64, 0])
+      transitions_are_equal(
+        expected: calculate_transition_steps(start_value: 255, end_value: 0, duration: 1000),
+        seen: seen_updates['brightness'],
+        # Allow some variation for the lossy level -> brightness conversion
+        allowed_variation: 3
+      )
     end
     end
 
 
     it 'should transition from off -> on with known last brightness' do
     it 'should transition from off -> on with known last brightness' do
@@ -310,7 +338,12 @@ RSpec.describe 'Transitions' do
 
 
       @mqtt_client.wait_for_listeners
       @mqtt_client.wait_for_listeners
 
 
-      expect(seen_updates['brightness']).to eq([99, 140, 181, 222, 255])
+      transitions_are_equal(
+        expected: calculate_transition_steps(start_value: 99, end_value: 255, duration: 1000),
+        seen: seen_updates['brightness'],
+        # Allow some variation for the lossy level -> brightness conversion
+        allowed_variation: 4
+      )
     end
     end
 
 
     it 'should transition from on -> off with known last brightness' do
     it 'should transition from on -> off with known last brightness' do
@@ -329,7 +362,12 @@ RSpec.describe 'Transitions' do
 
 
       @mqtt_client.wait_for_listeners
       @mqtt_client.wait_for_listeners
 
 
-      expect(seen_updates['brightness']).to eq([99, 74, 48, 23, 0])
+      transitions_are_equal(
+        expected: calculate_transition_steps(start_value: 99, end_value: 0, duration: 1000),
+        seen: seen_updates['brightness'],
+        # Allow some variation for the lossy level -> brightness conversion
+        allowed_variation: 3
+      )
     end
     end
   end
   end
 
 
@@ -361,8 +399,11 @@ RSpec.describe 'Transitions' do
 
 
         @mqtt_client.wait_for_listeners
         @mqtt_client.wait_for_listeners
 
 
-        expect(seen_updates.length).to eq(5)
-        expect(seen_updates.last[update_field]).to eq(update_max)
+        transitions_are_equal(
+          expected: calculate_transition_steps(start_value: update_min, end_value: update_max, duration: 1000),
+          seen: seen_updates.map{ |x| x[update_field] },
+          allowed_variation: 3
+        )
       end
       end
 
 
       it "should support field '#{field}' max --> min" do
       it "should support field '#{field}' max --> min" do
@@ -379,8 +420,11 @@ RSpec.describe 'Transitions' do
 
 
         @mqtt_client.wait_for_listeners
         @mqtt_client.wait_for_listeners
 
 
-        expect(seen_updates.length).to eq(5)
-        expect(seen_updates.last[update_field]).to eq(update_min)
+        transitions_are_equal(
+          expected: calculate_transition_steps(start_value: update_max, end_value: update_min, duration: 1000),
+          seen: seen_updates.map{ |x| x[update_field] },
+          allowed_variation: 3
+        )
       end
       end
     end
     end
   end
   end
@@ -400,17 +444,26 @@ RSpec.describe 'Transitions' do
     it 'should smoothly transition from one color to another' do
     it 'should smoothly transition from one color to another' do
       seen_updates = []
       seen_updates = []
 
 
-      fields = @client.get('/settings')['group_state_fields']
-      @client.put(
-        '/settings',
-        group_state_fields: fields + %w(oh_color),
-        mqtt_state_rate_limit: 1000
-      )
+      end_color = '0,255,0'
+      end_hs = rgb_to_hs(end_color)
+
+      last_hue = nil
+      last_sat = nil
+
+      @mqtt_client.on_update(@id_params) do |id, message|
+        field, value = message.first
+
+        if field == 'hue'
+          last_hue = value
+        elsif field == 'saturation'
+          last_sat = value
+        end
 
 
-      @mqtt_client.on_state(@id_params) do |id, message|
-        color = message['color']
-        seen_updates << color
-        color == '0,255,0'
+        if !last_hue.nil? && !last_sat.nil?
+          seen_updates << {hue: last_hue, saturation: last_sat}
+        end
+
+        last_hue == end_hs[:hue] && last_sat == end_hs[:saturation]
       end
       end
 
 
       response = @client.schedule_transition(@id_params, {
       response = @client.schedule_transition(@id_params, {
@@ -423,9 +476,7 @@ RSpec.describe 'Transitions' do
 
 
       @mqtt_client.wait_for_listeners
       @mqtt_client.wait_for_listeners
 
 
-      parts = seen_updates.map { |x| x.split(',').map(&:to_i) }
-
-      # This is less even than you'd expect because RGB -> Hue/Sat is lossy.
+      # This ends up being less even than you'd expect because RGB -> Hue/Sat is lossy.
       # Raw logs show that the right thing is happening:
       # Raw logs show that the right thing is happening:
       #
       #
       #     >>> stepSizes = (-64,64,0)
       #     >>> stepSizes = (-64,64,0)
@@ -435,42 +486,105 @@ RSpec.describe 'Transitions' do
       #     >>> current color = (127,128,0)
       #     >>> current color = (127,128,0)
       #     >>> current color = (63,192,0)
       #     >>> current color = (63,192,0)
       #     >>> current color = (0,255,0)
       #     >>> current color = (0,255,0)
-      expect(parts).to eq([
-        [255, 0, 0],
-        [255, 84, 0],
-        [250, 255, 0],
-        [84, 255, 0],
-        [0, 255, 0]
-      ])
+      expected_updates = calculate_color_transition_steps(start_color: '255,0,0', end_color: '0,255,0', duration: 4000, period: 1000)
+
+      color_transitions_are_equal(
+        expected: expected_updates,
+        seen: seen_updates
+      )
     end
     end
 
 
     it 'should handle color transitions from known state' do
     it 'should handle color transitions from known state' do
       seen_updates = []
       seen_updates = []
 
 
-      fields = @client.get('/settings')['group_state_fields']
-      @client.put(
-        '/settings',
-        group_state_fields: fields + %w(oh_color),
-        mqtt_state_rate_limit: 1000
-      )
       @client.patch_state({status: 'ON', color: '255,0,0'}, @id_params)
       @client.patch_state({status: 'ON', color: '255,0,0'}, @id_params)
+      end_color = '0,0,255'
+      end_hs = rgb_to_hs(end_color)
+
+      last_hue = nil
+      last_sat = nil
 
 
-      @mqtt_client.on_state(@id_params) do |id, message|
-        color = message['color']
-        seen_updates << color if color
-        color == '0,0,255'
+      @mqtt_client.on_update(@id_params) do |id, message|
+        field, value = message.first
+
+        if field == 'hue'
+          last_hue = value
+        elsif field == 'saturation'
+          last_sat = value
+        end
+
+        if !last_hue.nil? && !last_sat.nil?
+          seen_updates << {hue: last_hue, saturation: last_sat}
+        end
+
+        last_hue == end_hs[:hue] && last_sat == end_hs[:saturation]
       end
       end
 
 
       @client.patch_state({color: '0,0,255', transition: 2.0}, @id_params)
       @client.patch_state({color: '0,0,255', transition: 2.0}, @id_params)
+
       @mqtt_client.wait_for_listeners
       @mqtt_client.wait_for_listeners
 
 
-      parts = seen_updates.map { |x| x.split(',').map(&:to_i) }
+      expected_updates = calculate_color_transition_steps(start_color: '255,0,0', end_color: '0,0,255', duration: 2000)
+
+      color_transitions_are_equal(
+        expected: expected_updates,
+        seen: seen_updates
+      )
+    end
+  end
+
+  context 'computed parameters' do
+    # it 'should accept no length parameters' do
+    #   result = @client.schedule_transition(@id_params, field: 'kelvin', end_value: 100)
+
+    #   puts @transition_defaults
+
+    #   expect(result).to eq({'success' => true})
+    # end
+
+    (@transition_defaults = {
+      duration: {default: 4.5, test: 2},
+      num_periods: {default: 10, test: 5},
+      period: {default: 450, test: 225}
+    }).each do |k, params|
+      it "it should compute other parameters given only #{k}" do
+        seen_values = 0
+        gap = 0
+
+        @mqtt_client.on_update(@id_params) do |id, msg|
+          val = msg['brightness']
 
 
-      expect(parts).to eq([
-        [255,0,0],
-        [161,0,255],
-        [0,0,255]
-      ])
+          if val > 0
+            seen_values += 1
+            last_seen = val
+          end
+
+          if seen_values == 3
+            gap = last_seen/seen_values
+          end
+
+          val == 255
+        end
+
+        t_params = {field: 'level', start_value: 0, end_value: 100}.merge({k => params[:test]})
+
+        start_time = Time.now
+
+        @client.schedule_transition(@id_params, t_params)
+        transitions = @client.transitions
+
+        @mqtt_client.wait_for_listeners
+        duration = Time.now - start_time
+
+        expect(transitions.length).to eq(1), "Should only be one active transition"
+
+        period = transitions.first['period']
+        expected_duration = (k == :duration ? params[:test] : (TransitionHelpers::Defaults::DURATION/1000.0))
+        num_periods = (expected_duration/period.to_f)*1000
+
+        expect(duration).to be_within(1.5).of(expected_duration)
+        expect(gap).to be_within(10).of((255/num_periods).ceil)
+      end
     end
     end
   end
   end
 end
 end