tools

various tools I have been using throughout the years
Log | Files | Refs | README | LICENSE

test_helpers.rb (5123B)


      1 # frozen_string_literal: true
      2 
      3 require 'fileutils'
      4 require 'json'
      5 require 'stringio'
      6 require 'tmpdir'
      7 require 'yaml'
      8 
      9 module TestHelpers
     10   TEST_BRIDGE_UUID = 'bc6be180-4c57-0130-8d8f-0018de9ecdd0'
     11   TEST_BRIDGE_URI = 'http://localhost/api'
     12   TEST_APPLICATION_UUID = 'application_uuid'
     13 
     14   TEST_UDP_BRIDGE_UUID = 'aa0be180-4c57-0130-8d8f-0018de9ecdd0'
     15   TEST_UDP_BRIDGE_IP = '10.0.0.42'
     16   TEST_UDP_BRIDGE_URI = "http://#{TEST_UDP_BRIDGE_IP}/api".freeze
     17 
     18   FIXTURE_DIR = File.expand_path('config', __dir__)
     19   JSON_FIXTURE_DIR = File.expand_path('json', __dir__)
     20   EMPTY_CONFIG_FILE = File.join(FIXTURE_DIR, 'empty.yml')
     21 
     22   TEST_TMP_DIR = File.join(Dir.tmpdir, 'hue-spec')
     23   TEST_CONFIG_APPLICATION_PATH = File.join(TEST_TMP_DIR, 'applications.yml')
     24   TEST_CONFIG_BRIDGE_PATH = File.join(TEST_TMP_DIR, 'bridges.yml')
     25 
     26   TEST_CONFIG_APPLICATION = YAML.load_file(File.join(FIXTURE_DIR, 'applications.yml'))
     27   TEST_CONFIG_BRIDGE = YAML.load_file(File.join(FIXTURE_DIR, 'bridges.yml'))
     28 
     29   def mock_application_config_path
     30     FileUtils.mkdir_p(TEST_TMP_DIR)
     31     create_test_application_config
     32     allow(Hue::Config::Application).to receive(:file_path).and_return(TEST_CONFIG_APPLICATION_PATH)
     33   end
     34 
     35   def mock_bridge_config_path
     36     FileUtils.mkdir_p(TEST_TMP_DIR)
     37     create_test_bridge_config
     38     allow(Hue::Config::Bridge).to receive(:file_path).and_return(TEST_CONFIG_BRIDGE_PATH)
     39   end
     40 
     41   def create_test_application_config
     42     FileUtils.mkdir_p(TEST_TMP_DIR)
     43     File.write(TEST_CONFIG_APPLICATION_PATH, YAML.dump(TEST_CONFIG_APPLICATION))
     44   end
     45 
     46   def create_test_bridge_config
     47     FileUtils.mkdir_p(TEST_TMP_DIR)
     48     File.write(TEST_CONFIG_BRIDGE_PATH, YAML.dump(TEST_CONFIG_BRIDGE))
     49   end
     50 
     51   def mock_udp_replies(uuid = TEST_UDP_BRIDGE_UUID, ip = TEST_UDP_BRIDGE_IP)
     52     fake_socket = instance_double(UDPSocket, send: 0)
     53     payload = "HTTP/1.1 200 OK\r\nLOCATION: http://#{ip}/description.xml\r\n" \
     54               "ST: urn:schemas-upnp-org:device:Basic:1\r\nUSN: uuid:#{uuid}::IpBridge\r\n\r\n"
     55     delivered = false
     56     allow(fake_socket).to receive(:recvfrom) do
     57       raise Hue::Error, 'simulated timeout' if delivered
     58 
     59       delivered = true
     60       [payload, [nil, 1900, 'fake.local', ip]]
     61     end
     62     allow(UDPSocket).to receive(:new).and_return(fake_socket)
     63   end
     64 
     65   def mock_udp_no_reply
     66     fake_socket = instance_double(UDPSocket, send: 0)
     67     allow(fake_socket).to receive(:recvfrom) { raise Hue::Error, 'simulated timeout' }
     68     allow(UDPSocket).to receive(:new).and_return(fake_socket)
     69   end
     70 
     71   def mock_nupnp_empty_reply
     72     stub_request(:get, 'https://www.meethue.com/api/nupnp').to_return(body: '[]', status: 200)
     73   end
     74 
     75   def mock_socket_hostname
     76     allow(Socket).to receive(:gethostname).and_return('hostname')
     77   end
     78 
     79   def with_fake_request(path = nil, kind = :get_success)
     80     fixture = kind == :get_success ? (path || :get_success) : kind
     81     stub_request(:get, bridge_request_url(TEST_BRIDGE_URI, path))
     82       .to_return(body: read_json_fixture(fixture), status: 200,
     83                  headers: { 'Content-Type' => 'application/json' })
     84   end
     85 
     86   def with_fake_post(path = nil, body = nil, fixture = 'post_success', host = TEST_BRIDGE_URI)
     87     stub = stub_request(:post, raw_request_url(host, path))
     88     stub = stub.with(body: body) if body
     89     stub.to_return(body: read_json_fixture(fixture), status: 200,
     90                    headers: { 'Content-Type' => 'application/json' })
     91   end
     92 
     93   def with_fake_delete(path = nil, fixture = 'put_success')
     94     stub_request(:delete, bridge_request_url(TEST_BRIDGE_URI, path))
     95       .to_return(body: read_json_fixture(fixture), status: 200,
     96                  headers: { 'Content-Type' => 'application/json' })
     97   end
     98 
     99   def with_fake_update(path = nil, body = nil, fixture = 'put_success')
    100     stub = stub_request(:put, bridge_request_url(TEST_BRIDGE_URI, path))
    101     stub = stub.with(body: body) if body
    102     stub.to_return(body: read_json_fixture(fixture), status: 200,
    103                    headers: { 'Content-Type' => 'application/json' })
    104   end
    105 
    106   def api_reply(name)
    107     JSON.parse(read_json_fixture(name))
    108   end
    109 
    110   def with_temp_config_path(with_default = false)
    111     File.write(TEST_CONFIG_APPLICATION_PATH, YAML.dump(with_default ? TEST_CONFIG_APPLICATION : {}))
    112     yield
    113   ensure
    114     create_test_application_config
    115   end
    116 
    117   def with_stdout(matcher = nil)
    118     original = $stdout
    119     $stdout = StringIO.new
    120     yield
    121     output = $stdout.string
    122     expect(output).to match(matcher) if matcher
    123     output
    124   ensure
    125     $stdout = original
    126   end
    127 
    128   def test_bridge
    129     Hue::Bridge.new(TEST_APPLICATION_UUID, TEST_BRIDGE_URI)
    130   end
    131 
    132   private
    133 
    134   def read_json_fixture(name)
    135     File.read(File.join(JSON_FIXTURE_DIR, "#{name}.json"))
    136   end
    137 
    138   def bridge_request_url(host, path)
    139     base = host.sub(%r{/$}, '')
    140     segments = [base]
    141     segments << TEST_APPLICATION_UUID unless path.to_s.start_with?(TEST_APPLICATION_UUID)
    142     segments << path.to_s if path && !path.to_s.empty?
    143     segments.reject { |s| s.to_s.empty? }.join('/')
    144   end
    145 
    146   def raw_request_url(host, path)
    147     base = host.sub(%r{/$}, '')
    148     path && !path.to_s.empty? ? "#{base}/#{path}" : base
    149   end
    150 end