Class: MockGCM::Server

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/mock_gcm/server.rb

Constant Summary collapse

DEFAULT_HOST =
'localhost'

Instance Method Summary collapse

Constructor Details

#initialize(api_key, port) ⇒ Server

Returns a new instance of Server.



22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/mock_gcm/server.rb', line 22

def initialize(api_key, port)
  @api_key = api_key

  @received_messages = []
  @mutex = Mutex.new

  @server = HttpServer.new(self, port, DEFAULT_HOST, 1, File.open("/dev/null"), false, false)

  # Configurable error behaviour
  @next_request_failure = nil
  @canonicals        = {}
  @errors            = {}
end

Instance Method Details

#add_received(reg_id, collapse_key, time_to_live, delay_while_idle, data, dry_run, restrict_package_name) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/mock_gcm/server.rb', line 77

def add_received(reg_id, collapse_key, time_to_live, delay_while_idle, data, dry_run, restrict_package_name)
  hsh = {
    'registration_id'       => reg_id.freeze,
    'collapse_key'          => collapse_key.freeze,
    'time_to_live'          => time_to_live.freeze,
    'delay_while_idle'      => delay_while_idle.freeze,
    'data'                  => data.freeze,
    'dry_run'               => dry_run.freeze,
    'restrict_package_name' => restrict_package_name.freeze
  }.freeze
  @mutex.synchronize { @received_messages << hsh }
end

#canonical_id_for(reg_id) ⇒ Object



67
68
69
# File 'lib/mock_gcm/server.rb', line 67

def canonical_id_for(reg_id)
  @mutex.synchronize { @canonicals[reg_id] }
end

#check_authorization_header(request, response, req_data) ⇒ Object



106
107
108
109
110
111
112
113
# File 'lib/mock_gcm/server.rb', line 106

def check_authorization_header(request, response, req_data)
  if request.header['Authorization'] == "key=#{@api_key}"
    true
  else
    response.status = 401
    false
  end
end

#check_content_type(request, response, req_data) ⇒ Object



115
116
117
118
119
120
121
122
# File 'lib/mock_gcm/server.rb', line 115

def check_content_type(request, response, req_data)
  if request.header['Content-Type'] == "application/json"
    true
  else
    response.status = 400
    false
  end
end

#check_data_format(request, response, req_data) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/mock_gcm/server.rb', line 124

def check_data_format(request, response, req_data)
  fail = Proc.new do
    response.status = 400
    return false
  end
  json = JSON.parse(req_data) rescue fail.call

  # Required
  fail.call unless json["data"].is_a?(Hash)
  fail.call unless json["registration_ids"].is_a?(Array) && json["registration_ids"].all? { |reg_id| reg_id.is_a?(String) } && json["registration_ids"].size <= 1000
  # Optional
  fail.call unless json.fetch("collapse_key", "").is_a?(String)
  fail.call unless json.fetch("time_to_live", 1).is_a?(Integer)
  fail.call unless json.fetch("restrict_package_name", "").is_a?(String)
  fail.call unless [true,false].include?(json.fetch("dry_run", false))
  fail.call unless [true,false].include?(json.fetch("delay_while_idle", false))

  valid_fields = ["data", "registration_ids", "collapse_key", "time_to_live", "delay_while_idle", "dry_run", "restrict_package_name"]
  json.keys.each do |key|
    fail.call unless valid_fields.include?(key)
  end

  true
end

#check_fail_next_request(request, response, req_data) ⇒ Object

Check stuff



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/mock_gcm/server.rb', line 92

def check_fail_next_request(request, response, req_data)
  return true unless next_request_failure = @mutex.synchronize do
    @next_request_failure.tap { @next_request_failure = nil }
  end

  response.status = next_request_failure[:errno]

  next_request_failure[:retry_after].tap do |retry_after|
    response.header['Retry-After'] = retry_after if retry_after
  end

  false
end

#error_for(reg_id) ⇒ Object

Check server state from request thread



57
58
59
60
61
62
63
64
65
# File 'lib/mock_gcm/server.rb', line 57

def error_for(reg_id)
  @mutex.synchronize {
    return unless hsh = @errors[reg_id]
    return unless hsh[:times] != 0

    hsh[:times] -= 1 if hsh[:times] >= 1
    hsh[:error]
  }
end

#handle_req_data(req_data) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/mock_gcm/server.rb', line 149

def handle_req_data(req_data)
  req_json = JSON.parse(req_data)

  success, failure, canonical_ids, results = 0, 0, 0, []

  reg_ids = req_json['registration_ids']
  reg_ids.each do |reg_id|
    results << {}.tap do |result|
      if error = error_for(reg_id)
        result['error'] = error
        failure += 1
        next
      end

      if canonical_id = canonical_id_for(reg_id)
        result['registration_id'] = canonical_id
        canonical_ids += 1
      end

      result['message_id'] = rand(100_000_000)
      success += 1

      add_received(reg_id, req_json['collapse_key'], req_json['time_to_live'],
                   req_json['delay_while_idle'], req_json.fetch('data'),
                   req_json['dry_run'], req_json['restrict_package_name'])
    end
  end

  return success, failure, canonical_ids, results
end

#ip_auth_handler(io) ⇒ Object

HttpServer handlers



182
183
184
# File 'lib/mock_gcm/server.rb', line 182

def ip_auth_handler(io)
  true
end

#mock_canonical_id(reg_id, canonical_reg_id) ⇒ Object



47
48
49
# File 'lib/mock_gcm/server.rb', line 47

def mock_canonical_id(reg_id, canonical_reg_id)
  @mutex.synchronize { @canonicals[reg_id] = canonical_reg_id }
end

#mock_error(reg_id, error, options = {}) ⇒ Object



51
52
53
# File 'lib/mock_gcm/server.rb', line 51

def mock_error(reg_id, error, options = {})
  @mutex.synchronize { @errors[reg_id] = { :error => error, :times => options[:times] || -1 } }
end

#mock_next_request_failure(errno, retry_after = nil) ⇒ Object



40
41
42
43
44
45
# File 'lib/mock_gcm/server.rb', line 40

def mock_next_request_failure(errno, retry_after = nil)
  @mutex.synchronize do
    @next_request_failure = {:errno => Integer(errno)}
    @next_request_failure[:retry_after] = retry_after if retry_after
  end
end

#received_messagesObject

Message log



73
74
75
# File 'lib/mock_gcm/server.rb', line 73

def received_messages
  @mutex.synchronize { @received_messages.dup }
end

#request_handler(request, response) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/mock_gcm/server.rb', line 186

def request_handler(request, response)
  req_data = request.data.read(request.content_length)

  return unless check_fail_next_request(request, response, req_data)
  return unless check_authorization_header(request, response, req_data)
  return unless check_content_type(request, response, req_data)
  return unless check_data_format(request, response, req_data)

  success, failure, canonical_ids, results = handle_req_data(req_data)

  response.header['Content-Type'] = 'application/json'
  response.body = {
    'multicast_id'  => rand(100_000_000),
    'success'       => success,
    'failure'       => failure,
    'canonical_ids' => canonical_ids,
    'results'       => results
  }.to_json
end