From aa1f86b5893644f55a7aacba5b3f9b0ddae19c0a Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Tue, 6 Feb 2018 17:41:29 +0100 Subject: [PATCH 01/11] Add Usage module This will allow us to add usages independently of the implementation. --- gateway/src/apicast/usage.lua | 64 +++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 gateway/src/apicast/usage.lua diff --git a/gateway/src/apicast/usage.lua b/gateway/src/apicast/usage.lua new file mode 100644 index 000000000..60e4f68ff --- /dev/null +++ b/gateway/src/apicast/usage.lua @@ -0,0 +1,64 @@ +--- Usage +-- @module usage +-- Usage to be authorized and reported against 3scale's backend. + +local setmetatable = setmetatable +local ipairs = ipairs +local insert = table.insert + +local _M = {} + +local mt = { __index = _M } + +--- Initialize a usage. +-- @return usage New usage. +function _M.new() + local self = setmetatable({}, mt) + + -- table where the keys are metrics and the values their deltas. + self.deltas = {} + + -- table that contains the metrics that have a delta associated. + -- It's useful to iterate over the deltas without using '.pairs'. + -- That's what we are doing in .merge(). + -- We want to avoid using '.pairs' because is not jitted, '.ipairs' is. + self.metrics = {} + + return self +end + +--- Add a metric usage. +-- Increases the usage of the given metric by the given value. If the metric +-- is not in the usage, it will be included. +-- Note that this mutates self. +-- @tparam string metric Metric. +-- @tparam integer value Value. +function _M:add(metric, value) + if self.deltas[metric] then + self.deltas[metric] = self.deltas[metric] + value + else + self.deltas[metric] = value + insert(self.metrics, metric) + end +end + +--- Merge usages +-- Merges two usages. This means that: +-- +-- 1) When a metric appears in both usages, its delta is updated in self by +-- adding the two values. +-- 2) When a metric does not appear in self, it is added in self. +-- +-- Note that this mutates self. +-- @tparam another_usage Usage Usage. +function _M:merge(another_usage) + local another_usage_metrics = another_usage.metrics + local another_usage_deltas = another_usage.deltas + + for _, metric in ipairs(another_usage_metrics) do + local delta = another_usage_deltas[metric] + self:add(metric, delta) + end +end + +return _M From 52c74f2b385aea72548bd234fa38b194fd9ab4c5 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Tue, 6 Feb 2018 17:42:33 +0100 Subject: [PATCH 02/11] spec: add specs for Usage module --- spec/usage_spec.lua | 90 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 spec/usage_spec.lua diff --git a/spec/usage_spec.lua b/spec/usage_spec.lua new file mode 100644 index 000000000..b70b76346 --- /dev/null +++ b/spec/usage_spec.lua @@ -0,0 +1,90 @@ +local Usage = require('apicast.usage') + +describe('usage', function() + describe('.add', function() + describe('when the metric is already present in the usage', function() + it('adds the given value to the existing one', function() + local usage = Usage.new() + + usage:add('hits', 1) + assert.same({ hits = 1 }, usage.deltas ) + + usage:add('hits', 1) + assert.same({ hits = 2 }, usage.deltas) + end) + end) + + describe('when the metric is not in the usage', function() + it('adds it with the given value', function() + local usage = Usage.new() + usage:add('hits', 1) + + assert.same({ hits = 1 }, usage.deltas) + end) + end) + end) + + describe('.merge', function() + describe('when a metric appears in both usages', function() + it('mutates self adding the deltas', function() + local a_usage = Usage.new() + a_usage:add('a', 1) + a_usage:add('b', 1) + + local another_usage = Usage.new() + another_usage:add('a', 2) + another_usage:add('b', 2) + + a_usage:merge(another_usage) + + assert.same({ a = 3, b = 3 }, a_usage.deltas) + end) + end) + + describe('when a metric of the given usage is not in self', function() + it('adds the metric in self', function() + local a_usage = Usage.new() + a_usage:add('a', 1) + + local another_usage = Usage.new() + another_usage:add('b', 1) + + a_usage:merge(another_usage) + + assert.same({ a = 1, b = 1 }, a_usage.deltas) + end) + end) + + describe('when the other usage does not contain any deltas', function() + it('leaves self unchanged', function() + local a_usage = Usage.new() + a_usage:add('a', 1) + + a_usage:merge(Usage.new()) + + assert.same({ a = 1 }, a_usage.deltas) + end) + end) + end) + + describe('.metrics', function() + it('returns a table without duplicates with all the metrics that have a delta', function() + local usage = Usage.new() + usage:add('hits', 1) + usage:add('hits', 1) -- try adding a metric that already exists + usage:add('some_metric', 1) + + -- Try merging with a usage with the same metrics. + local another_usage = Usage.new() + another_usage:add('hits', 1) + another_usage:add('some_metric', 1) + usage:merge(another_usage) + + local metrics = usage.metrics + + -- The method does not guarantee any order in the result + assert.is_true((metrics[1] == 'hits' and metrics[2] == 'some_metric') or + (metrics[1] == 'some_metric' and metrics[2] == 'hits')) + end) + end) +end) From 24a88148fafa1b25e122520799e12532a3d94d19 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Tue, 6 Feb 2018 18:01:48 +0100 Subject: [PATCH 03/11] Add MappingRulesMatcher module --- gateway/src/apicast/mapping_rules_matcher.lua | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 gateway/src/apicast/mapping_rules_matcher.lua diff --git a/gateway/src/apicast/mapping_rules_matcher.lua b/gateway/src/apicast/mapping_rules_matcher.lua new file mode 100644 index 000000000..e83846fed --- /dev/null +++ b/gateway/src/apicast/mapping_rules_matcher.lua @@ -0,0 +1,53 @@ +--- Mapping rules matcher +-- @module mapping_rules_matcher +-- Matches a request against a set of mapping rules and calculates the usage +-- that needs to be authorized and reported according to the rules that match. + +local ipairs = ipairs +local insert = table.insert +local Usage = require('apicast.usage') + +local _M = {} + +--- Calculate usage from matching mapping rules. +-- Matches a request against a set of mapping rules and returns the resulting +-- usage and the matched rules. +-- @tparam string method HTTP method. +-- @tparam string uri URI. +-- @tparam table args Request arguments. +-- @tparam table rules Mapping rules to be matched. +-- @treturn Usage Calculated usage. +-- @treturn table Matched rules. +function _M.get_usage_from_matches(method, uri, args, rules) + local usage = Usage.new() + local matched_rules = {} + + for _, rule in ipairs(rules) do + if rule:matches(method, uri, args) then + -- Some rules have no delta. Send 0 in that case. + usage:add(rule.system_name, rule.delta or 0) + insert(matched_rules, rule) + end + end + + return usage, matched_rules +end + +--- Check if there is a mapping rule that matches. +-- @tparam string method HTTP method. +-- @tparam string uri URI. +-- @tparam table args Request arguments. +-- @tparam table rules Mapping rules to be matched. +-- @treturn boolean Whether there is a match. +-- @treturn integer|nil Index of the first matched rule. +function _M.matches(method, uri, args, rules) + for i, rule in ipairs(rules) do + if rule:matches(method, uri, args) then + return true, i + end + end + + return false +end + +return _M From 570e9a555b39e86468d1e76a5e4e9400c09d951d Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Tue, 6 Feb 2018 18:24:04 +0100 Subject: [PATCH 04/11] spec: add specs for MappingRulesMatcher --- spec/mapping_rules_matcher_spec.lua | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 spec/mapping_rules_matcher_spec.lua diff --git a/spec/mapping_rules_matcher_spec.lua b/spec/mapping_rules_matcher_spec.lua new file mode 100644 index 000000000..355dc937a --- /dev/null +++ b/spec/mapping_rules_matcher_spec.lua @@ -0,0 +1,52 @@ +local mapping_rules_matcher = require('apicast.mapping_rules_matcher') + +describe('mapping_rules_matcher', function() + local func_true = function() return true end + local func_false = function() return false end + + -- Test rules. Instead of instantiating mapping rules, we just mock the + -- methods and attributes we are interested in, for simplicity. + local rule_1 = { matches = func_true, system_name = 'hits', delta = 1 } + local rule_2 = { matches = func_false, system_name = 'hits', delta = 2 } + local rule_3 = { matches = func_true, system_name = 'hits', delta = 3 } + local rules = { rule_1, rule_2, rule_3 } + + describe('.get_usage_from_matches', function() + local usage, matched_rules = mapping_rules_matcher.get_usage_from_matches( + 'GET', '/', {}, rules) + + it('returns the usage from matching the mapping rules', function() + assert.same({ hits = 4 }, usage.deltas) + end) + + it('returns the rules that matched', function() + assert.same({ rule_1, rule_3 } , matched_rules) + end) + end) + + describe('.matches', function() + describe('when there is a match', function() + local not_maching_rule = { matches = func_false } + local matching_rule = { matches = func_true } + + it('returns true and the index of the first rule that matches', function() + local matches, index = mapping_rules_matcher.matches( + 'GET', '/', {}, { not_maching_rule, matching_rule }) + + assert.is_true(matches) + assert.equals(2, index) + end) + end) + + describe('when there is not a match', function() + local not_matching_rule = { matches = func_false } + + it('returns false', function() + local matches = mapping_rules_matcher.matches( + 'GET', '/', {}, { not_matching_rule }) + + assert.is_false(matches) + end) + end) + end) +end) From c5efbe4b7d0a161e98cbcba1452f6060aeb79b64 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Tue, 6 Feb 2018 18:28:15 +0100 Subject: [PATCH 05/11] policy/find_policy: use new MappingRulesMatcher --- gateway/src/apicast/policy/find_service/policy.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/gateway/src/apicast/policy/find_service/policy.lua b/gateway/src/apicast/policy/find_service/policy.lua index 9ea9bb56a..a55ebe0e3 100644 --- a/gateway/src/apicast/policy/find_service/policy.lua +++ b/gateway/src/apicast/policy/find_service/policy.lua @@ -1,8 +1,7 @@ -local next = next - local policy = require('apicast.policy') local _M = policy.new('Find Service Policy') local configuration_store = require 'apicast.configuration_store' +local mapping_rules_matcher = require 'apicast.mapping_rules_matcher' local new = _M.new local function find_service_strict(configuration, host) @@ -39,10 +38,14 @@ local function find_service_cascade(configuration, host) if hosts[h] == host then local name = service.system_name or service.id ngx.log(ngx.DEBUG, 'service ', name, ' matched host ', hosts[h]) - local usage, matched_patterns = service:get_usage(method, uri) - if next(usage) and matched_patterns ~= '' then - ngx.log(ngx.DEBUG, 'service ', name, ' matched patterns ', matched_patterns) + local matches = mapping_rules_matcher.matches(method, uri, {}, service.rules) + -- matches() also returns the index of the first rule that matched. + -- As a future optimization, in the part of the code that calculates + -- the usage, we could use this to avoid trying to match again all the + -- rules before the one that matched. + + if matches then found = service break end From 8a08e8d4a72d46b4ccb803c421edd7de4c579206 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Tue, 6 Feb 2018 18:29:22 +0100 Subject: [PATCH 06/11] service: use new MappingRulesMatcher This simplifies the Service module because it no longer needs to be responsible for matching mapping rules and collecting the usage. --- gateway/src/apicast/configuration/service.lua | 32 ++----------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/gateway/src/apicast/configuration/service.lua b/gateway/src/apicast/configuration/service.lua index e5ef8d90c..45a4e1e99 100644 --- a/gateway/src/apicast/configuration/service.lua +++ b/gateway/src/apicast/configuration/service.lua @@ -8,13 +8,12 @@ local rawget = rawget local lower = string.lower local gsub = string.gsub local select = select -local concat = table.concat -local insert = table.insert local re = require 'ngx.re' local http_authorization = require 'resty.http_authorization' local oauth = require('apicast.oauth') +local mapping_rules_matcher = require('apicast.mapping_rules_matcher') local _M = { } local mt = { __index = _M } @@ -163,21 +162,6 @@ function backend_version_credentials.version_oauth(config) return setmetatable({ access_token, access_token = access_token }, credentials_oauth_mt) end -local function set_or_inc(t, name, delta) - return (t[name] or 0) + (delta or 0) -end - -local function check_rule(req, rule, usage_t, matched_rules, params) - if rule:matches(req.method, req.path, req.args) then - local system_name = rule.system_name - local value = set_or_inc(usage_t, system_name, rule.delta) - - usage_t[system_name] = value - params['usage[' .. system_name .. ']'] = value - insert(matched_rules, rule.pattern) - end -end - local function get_auth_params(method) local params = ngx.req.get_uri_args() @@ -238,22 +222,12 @@ function _M:oauth() end local function extract_usage_v2(config, method, path) - local usage_t = {} - local matched_rules = {} - local params = {} local rules = config.rules - local args = get_auth_params(method) - ngx.log(ngx.DEBUG, '[mapping] service ', config.id, ' has ', #rules, ' rules') - for i = 1, #rules do - check_rule({path=path, method=method, args=args}, rules[i], usage_t, matched_rules, params) - end - - -- if there was no match, usage is set to nil and it will respond a 404, this - -- behavior can be changed - return usage_t, concat(matched_rules, ", "), params + local args = get_auth_params(method) + return mapping_rules_matcher.get_usage_from_matches(method, path, args, rules) end -- Deprecated From fbcd1e9786cdcdeef7fc2a2d227cb96d09f2d6f1 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Wed, 7 Feb 2018 10:23:33 +0100 Subject: [PATCH 07/11] proxy: work with new Usage module The .parsed_usage() method will be moved to the backend client in a future refactor. --- gateway/src/apicast/proxy.lua | 40 +++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/gateway/src/apicast/proxy.lua b/gateway/src/apicast/proxy.lua index 0c86fa1be..d6c66be04 100644 --- a/gateway/src/apicast/proxy.lua +++ b/gateway/src/apicast/proxy.lua @@ -21,6 +21,7 @@ local concat = table.concat local gsub = string.gsub local tonumber = tonumber local setmetatable = setmetatable +local ipairs = ipairs local encode_args = ngx.encode_args local resty_resolver = require 'resty.resolver' local semaphore = require('ngx.semaphore') @@ -126,6 +127,31 @@ local function output_debug_headers(service, usage, credentials) end end +-- Converts a usage to the format expected by the 3scale backend client. +local function format_usage(usage) + local res = {} + + local usage_metrics = usage.metrics + local usage_deltas = usage.deltas + + for _, metric in ipairs(usage_metrics) do + local delta = usage_deltas[metric] + res['usage[' .. metric .. ']'] = delta + end + + return res +end + +local function matched_patterns(matched_rules) + local patterns = {} + + for _, rule in ipairs(matched_rules) do + insert(patterns, rule.pattern) + end + + return patterns +end + function _M:authorize(service, usage, credentials, ttl) if not usage or not credentials then return nil, 'missing usage or credentials' end @@ -243,7 +269,7 @@ function _M:rewrite(service) return error_no_credentials(service) end - local _, matched_patterns, usage_params = service:get_usage(ngx.req.get_method(), ngx.var.uri) + local usage, matched_rules = service:get_usage(ngx.req.get_method(), ngx.var.uri) local cached_key = { service.id } -- remove integer keys for serialization @@ -263,16 +289,22 @@ function _M:rewrite(service) local ctx = ngx.ctx local var = ngx.var + local parsed_usage = format_usage(usage) + -- save those tables in context so they can be used in the backend client - ctx.usage = usage_params + ctx.usage = parsed_usage ctx.credentials = credentials - ctx.matched_patterns = matched_patterns self.credentials = credentials - self.usage = usage_params + self.usage = parsed_usage var.cached_key = concat(cached_key, ':') + if debug_header_enabled(service) then + local patterns = matched_patterns(matched_rules) + ctx.matched_patterns = concat(patterns, ', ') + end + local ttl if self.oauth then From 65f0d466ad71b6facec28489d2895cde6f078d88 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Wed, 7 Feb 2018 10:37:38 +0100 Subject: [PATCH 08/11] CHANGELOG: add entry for Usage and MappingRulesMatcher --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e7141e66..df92bc931 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Extract `mapping_rule` module from the `configuration` module [PR #571](https://github.com/3scale/apicast/pull/571) - Renamed `apicast/policy/policy.lua` to `apicast/policy.lua` [PR #569](https://github.com/3scale/apicast/pull/569) - Sandbox loading policies [PR #566](https://github.com/3scale/apicast/pull/566) +- Extracted `usage` and `mapping_rules_matcher` modules so they can be used from policies [PR #580](https://github.com/3scale/apicast/pull/580) ## [3.2.0-alpha2] - 2017-11-30 From a574d5473e203b8da1ec0cf22cea19f8106e9e7b Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Wed, 7 Feb 2018 12:12:43 +0100 Subject: [PATCH 09/11] spec/proxy: fix tests that expect wrong key in the cache These tests were passing just because proxy:authorize was being called with the wrong arguments. We were sending a table with usages, but in reality, this method expects a string with the usage formatted. --- spec/proxy_spec.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/spec/proxy_spec.lua b/spec/proxy_spec.lua index 53b847409..1371bac9a 100644 --- a/spec/proxy_spec.lua +++ b/spec/proxy_spec.lua @@ -3,6 +3,7 @@ local lrucache = require('resty.lrucache') local configuration_store = require 'apicast.configuration_store' local Service = require 'apicast.configuration.service' +local Usage = require 'apicast.usage' describe('Proxy', function() local configuration, proxy @@ -63,9 +64,10 @@ describe('Proxy', function() stub(proxy, 'cache_handler').returns(true) - proxy:authorize(service, { foo = 0 }, { client_id = 'blah' }, ttl) + proxy:authorize(service, { ['usage[foo]'] = 0 }, { client_id = 'blah' }, ttl) - assert.spy(proxy.cache_handler).was.called_with(proxy.cache, 'client_id=blah:foo=0', response, ttl) + assert.spy(proxy.cache_handler).was.called_with( + proxy.cache, 'client_id=blah:usage%5Bfoo%5D=0', response, ttl) end) it('works with no ttl', function() @@ -75,9 +77,10 @@ describe('Proxy', function() stub(ngx_backend, 'send', function() return response end) stub(proxy, 'cache_handler').returns(true) - proxy:authorize(service, { foo = 0 }, { client_id = 'blah' }) + proxy:authorize(service, { ['usage[foo]'] = 0 }, { client_id = 'blah' }) - assert.spy(proxy.cache_handler).was.called_with(proxy.cache, 'client_id=blah:foo=0', response, nil) + assert.spy(proxy.cache_handler).was.called_with( + proxy.cache, 'client_id=blah:usage%5Bfoo%5D=0', response, nil) end) end) From b63c83bc1a593fbf4f53778b8670a76df36d4c96 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Wed, 7 Feb 2018 12:32:57 +0100 Subject: [PATCH 10/11] proxy: receive context in .rewrite() --- gateway/src/apicast/policy/apicast/policy.lua | 2 +- gateway/src/apicast/proxy.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gateway/src/apicast/policy/apicast/policy.lua b/gateway/src/apicast/policy/apicast/policy.lua index 3e4b51669..887c77e51 100644 --- a/gateway/src/apicast/policy/apicast/policy.lua +++ b/gateway/src/apicast/policy/apicast/policy.lua @@ -56,7 +56,7 @@ function _M:rewrite(context) ngx.ctx.service = service -- it is possible that proxy:rewrite will terminate the request - p:rewrite(service) + p:rewrite(service, context) end p.set_upstream(service) diff --git a/gateway/src/apicast/proxy.lua b/gateway/src/apicast/proxy.lua index d6c66be04..437fb821a 100644 --- a/gateway/src/apicast/proxy.lua +++ b/gateway/src/apicast/proxy.lua @@ -254,7 +254,7 @@ local function handle_oauth(service) return oauth end -function _M:rewrite(service) +function _M:rewrite(service, context) service = _M.set_service(service or ngx.ctx.service) -- handle_oauth can terminate the request From ac5605f4ffe78a3e54570225a1ffab556ae7da61 Mon Sep 17 00:00:00 2001 From: David Ortiz Date: Wed, 7 Feb 2018 12:49:07 +0100 Subject: [PATCH 11/11] proxy: merge usage with the one in the context This allows other policies to add to the usage that will be authorized and reported against 3scale's backend. --- gateway/src/apicast/proxy.lua | 22 ++++++++++++++-------- spec/proxy_spec.lua | 8 ++++++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/gateway/src/apicast/proxy.lua b/gateway/src/apicast/proxy.lua index 437fb821a..55c1f2351 100644 --- a/gateway/src/apicast/proxy.lua +++ b/gateway/src/apicast/proxy.lua @@ -11,6 +11,7 @@ local custom_config = env.get('APICAST_CUSTOM_CONFIG') local util = require('apicast.util') local resty_lrucache = require('resty.lrucache') local backend_cache_handler = require('apicast.backend.cache_handler') +local Usage = require('apicast.usage') local resty_url = require 'resty.url' @@ -155,7 +156,9 @@ end function _M:authorize(service, usage, credentials, ttl) if not usage or not credentials then return nil, 'missing usage or credentials' end - local encoded_usage = encode_args(usage) + local formatted_usage = format_usage(usage) + + local encoded_usage = encode_args(formatted_usage) if encoded_usage == '' then return error_no_match(service) end @@ -178,7 +181,7 @@ function _M:authorize(service, usage, credentials, ttl) ngx.var.cached_key = nil local backend = assert(backend_client:new(service, http_ng_ngx), 'missing backend') - local res = backend:authrep(usage, credentials) + local res = backend:authrep(formatted_usage, credentials) local authorized, rejection_reason = self:handle_backend_response(cached_key, res, ttl) if not authorized then @@ -289,14 +292,15 @@ function _M:rewrite(service, context) local ctx = ngx.ctx local var = ngx.var - local parsed_usage = format_usage(usage) - -- save those tables in context so they can be used in the backend client - ctx.usage = parsed_usage + context.usage = context.usage or Usage.new() + context.usage:merge(usage) + + ctx.usage = usage ctx.credentials = credentials self.credentials = credentials - self.usage = parsed_usage + self.usage = usage var.cached_key = concat(cached_key, ':') @@ -351,7 +355,8 @@ end local function capture_post_action(self, cached_key, service) local backend = assert(backend_client:new(service, http_ng_ngx), 'missing backend') - local res = backend:authrep(self.usage, self.credentials, response_codes_data()) + local formatted_usage = format_usage(self.usage) + local res = backend:authrep(formatted_usage, self.credentials, response_codes_data()) self:handle_backend_response(cached_key, res) end @@ -364,7 +369,8 @@ local function timer_post_action(self, cached_key, service) if ok then -- TODO: try to do this in different phase and use semaphore to limit number of background threads -- TODO: Also it is possible to use sets in shared memory to enqueue work - ngx.timer.at(0, post_action, self, cached_key, backend, self.usage, self.credentials, response_codes_data()) + local formatted_usage = format_usage(self.usage) + ngx.timer.at(0, post_action, self, cached_key, backend, formatted_usage, self.credentials, response_codes_data()) else ngx.log(ngx.ERR, 'failed to acquire timer: ', err) return capture_post_action(self, cached_key, service) diff --git a/spec/proxy_spec.lua b/spec/proxy_spec.lua index 1371bac9a..8afd5ded2 100644 --- a/spec/proxy_spec.lua +++ b/spec/proxy_spec.lua @@ -64,7 +64,9 @@ describe('Proxy', function() stub(proxy, 'cache_handler').returns(true) - proxy:authorize(service, { ['usage[foo]'] = 0 }, { client_id = 'blah' }, ttl) + local usage = Usage.new() + usage:add('foo', 0) + proxy:authorize(service, usage, { client_id = 'blah' }, ttl) assert.spy(proxy.cache_handler).was.called_with( proxy.cache, 'client_id=blah:usage%5Bfoo%5D=0', response, ttl) @@ -77,7 +79,9 @@ describe('Proxy', function() stub(ngx_backend, 'send', function() return response end) stub(proxy, 'cache_handler').returns(true) - proxy:authorize(service, { ['usage[foo]'] = 0 }, { client_id = 'blah' }) + local usage = Usage.new() + usage:add('foo', 0) + proxy:authorize(service, usage, { client_id = 'blah' }) assert.spy(proxy.cache_handler).was.called_with( proxy.cache, 'client_id=blah:usage%5Bfoo%5D=0', response, nil)