pisoni 1.29.1 → 1.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4bc480ca255fad3679c652ee5913824d543c7f4e5d51b0866f3919d4d1a496c3
4
- data.tar.gz: d5b36dd8d28242573d3e476ae4420c93dfd30275848ea16c4526ad61db1a386e
3
+ metadata.gz: 5804502f649cd2bb89c6a7e696684c4226c53430e4c132e4f82fd755d4e1a96d
4
+ data.tar.gz: 354583b6d17ebdf0a5ed15c7121ab5b550ce008e3383c1fab17ac5f8a66c8a97
5
5
  SHA512:
6
- metadata.gz: ffb11b5ae16138162d9fbb2c5b0784618b94d478cbbfd6e8edc377ae05b3554471ffd360db902ba5e569b0c90b96ceca3005860d53f57cfdab744cb48f019716
7
- data.tar.gz: 5ff19f326743a8e56b8cb2df1ab37bbef54bafbd075a4e8d6a90ee729b51e8950e7248d331724982fbf7f42c5e6ceb265f13767bd4c9b7d4c09633ab982b3eca
6
+ metadata.gz: a25cc7464fe34178899e3239fc39d0ce394e70dfb68f9cc6f4ebe0c062dfe3f72975d2158132df9fadb65d488f18fb6f19b0fc3d0d803fb0093fb3f5f976a100
7
+ data.tar.gz: 8343b9dae4eac7195396cc48563a3df20c07b5402dd4ef5010a100bda895833664845131e91c0838d7788f32258cdb6763989c8cf02ed45e337c4748e3236e6b
data/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  Notable changes to Pisoni will be tracked in this document.
4
4
 
5
+ ## 1.31.0 - 2026-07-03
6
+
7
+ ### Added
8
+
9
+ - Batch update support for applications via `Application.save_batch`. [#37](https://github.com/3scale/pisoni/pull/37)
10
+ - Qlty integration for code quality and coverage reporting, replacing codeclimate. [#39](https://github.com/3scale/pisoni/pull/39)
11
+
12
+ ### Changed
13
+
14
+ - Updated Faraday dependency to allow >= 2.14.3 (removed <= 2.9 cap). [#36](https://github.com/3scale/pisoni/pull/36)
15
+ - Minimum Ruby version bumped from 2.6 to 3.0 (required by Faraday >= 2.9). [#36](https://github.com/3scale/pisoni/pull/36)
16
+ - CircleCI now requires manual approval before running builds. [#38](https://github.com/3scale/pisoni/pull/38)
17
+ - Pinned minitest to ~> 5.0 to prevent breakage from minitest 6. [#36](https://github.com/3scale/pisoni/pull/36)
18
+
19
+ ## 1.30.0 - 2024-02-29
20
+
21
+ ### Changed
22
+
23
+ - Fixed the issue with fetching utilization and managing referrer filters for applications with special characters in the
24
+ application IDs by escaping them. [#33](https://github.com/3scale/pisoni/pull/33)
25
+ - Upgrade dependencies, specifically `faraday` and `json`, making Ruby 2.6 the minimum supported version. [#34](https://github.com/3scale/pisoni/pull/34)
26
+
5
27
  ## 1.29.1 - 2023-11-30
6
28
 
7
29
  ### Changed
data/Gemfile CHANGED
@@ -3,8 +3,9 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  group :test do
6
- gem 'minitest'
7
- gem "codeclimate-test-reporter", require: nil
6
+ gem 'minitest', '~> 5.0'
7
+ gem 'simplecov', require: false
8
+ gem 'simplecov_json_formatter', require: false
8
9
  end
9
10
 
10
11
  group :development, :test do
data/Makefile CHANGED
@@ -1,78 +1,24 @@
1
- MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
2
- PROJECT_PATH := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
1
+ COMPOSE ?= podman-compose
3
2
 
4
- include $(PROJECT_PATH)/.env
3
+ .PHONY: deps_up
4
+ deps_up:
5
+ $(COMPOSE) up -d
5
6
 
6
- include $(PROJECT_PATH)/mk/compose.mk
7
- COMPOSE ?= $(COMPOSE_BIN) -f $(PROJECT_PATH)/docker/docker-compose.yml -f $(PROJECT_PATH)/docker/docker-compose.apisonator.yml
8
-
9
- CI_IMAGE_REPO ?= quay.io/3scale
10
- CI_IMAGE_NAME ?= pisoni-ci
11
- CI_IMAGE ?= $(CI_IMAGE_REPO)/$(CI_IMAGE_NAME)
12
- CI_DOCKERFILE ?= $(PROJECT_PATH)/docker/Dockerfile.ci
13
-
14
- include $(PROJECT_PATH)/mk/ci-image.mk
15
- include $(PROJECT_PATH)/mk/ci.mk
16
-
17
- all: clean pull build test
18
-
19
- $(call ci_build_target,ci-pull,pull)
20
- $(call ci_build_target,ci-test,test)
21
- $(call ci_build_target,ci-compose-config,compose-config)
7
+ .PHONY: deps_down
8
+ deps_down:
9
+ - $(COMPOSE) down
22
10
 
23
- .PHONY: compose-config
24
- compose-config: compose
25
- $(COMPOSE) config
11
+ .PHONY: run_test
12
+ run_test:
13
+ THREESCALE_CORE_INTERNAL_API=http://user:password@localhost:3001 bundle exec rake test
26
14
 
27
15
  .PHONY: test
28
- test: run_test clean
29
-
30
- .PHONY: bash
31
- bash: run clean
32
-
33
- .PHONY: dev
34
- dev: run
35
-
36
- .PHONY: run
37
- run: compose
38
- $(COMPOSE) run --rm test /bin/bash
39
-
40
- .PHONY: run_test
41
- run_test: compose
42
- $(COMPOSE) run --rm -e COVERAGE=$(COVERAGE) test
16
+ test: deps_up run_test deps_down
43
17
 
44
18
  .PHONY: license_finder
45
- license_finder: compose
46
- $(COMPOSE) run --rm -e COVERAGE=$(COVERAGE) test bundle exec rake license_finder:check
47
-
48
- .PHONY: build
49
- build: compose
50
- $(COMPOSE) build
51
-
52
- .PHONY: pull
53
- pull: compose
54
- $(COMPOSE) pull
19
+ license_finder:
20
+ $(COMPOSE) run --rm -e COVERAGE=$(COVERAGE) pisoni bundle exec rake license_finder:check
55
21
 
56
22
  .PHONY: stop
57
- stop: compose
23
+ stop:
58
24
  $(COMPOSE) stop
59
-
60
- .PHONY: clean
61
- clean: stop
62
- - $(COMPOSE) rm -f -v
63
-
64
- .PHONY: up
65
- up: compose
66
- $(COMPOSE) up --abort-on-container-exit --exit-code-from test -t 2 --remove-orphans
67
-
68
- .PHONY: down
69
- down: clean
70
- - $(COMPOSE) down
71
-
72
- .PHONY: destroy
73
- destroy: clean
74
- $(COMPOSE) down -v --remove-orphans --rmi local
75
-
76
- .PHONY: destroy-all
77
- destroy-all: clean
78
- $(COMPOSE) down -v --remove-orphans --rmi all
data/README.md CHANGED
@@ -23,22 +23,16 @@ where x.y.z is the version you aim for.
23
23
 
24
24
  ## Development
25
25
 
26
- ### Environment set up
26
+ ### Running tests with `make` and `podman-compose`
27
27
 
28
- We are using [Docker Compose](https://docs.docker.com/compose/) to run the tests
29
- in an isolated environment.
28
+ We are using [podman-compose](https://github.com/containers/podman-compose) to run the dependencies (redis and apisonator) for the tests.
29
+ You need to have it installed locally.
30
30
 
31
- You should first `make pull build` to download the needed images and build the
32
- one used for actual testing and development.
31
+ You can run the test suite (with the required dependencies) by executing `make test`.
33
32
 
34
- You can then run `make test` to run the test suite, and `make dev` to enter
35
- a container in which the code is sync'ed back to your host.
33
+ For cleaning up the dependencies containers, you can run `make deps_down`.
36
34
 
37
- For cleaning up containers, volumes and networks you can run `make clean` and
38
- `make destroy`. If you want to also get rid of pulled images, run `make
39
- destroy-all`.
40
-
41
- ### Running tests
35
+ ### Running tests locally
42
36
 
43
37
  You can run both tests & specs with:
44
38
 
@@ -63,6 +63,11 @@ module ThreeScale
63
63
  api_do_delete(attributes, api_options, &blk)[:ok]
64
64
  end
65
65
 
66
+ def api_update_batch(attributes, api_options = {}, &blk)
67
+ ret = api_do_put(attributes, api_options.merge(prefix: ''), &blk)
68
+ ret[:response_json]
69
+ end
70
+
66
71
  # Helpers
67
72
 
68
73
  def api_do_get(attributes, api_options = {}, &blk)
@@ -106,7 +111,7 @@ module ThreeScale
106
111
  else
107
112
  Core.faraday.send method, uri, attributes.to_json
108
113
  end
109
- rescue Faraday::Error::ClientError, SystemCallError => e
114
+ rescue Faraday::ClientError, SystemCallError => e
110
115
  raise ConnectionError, e
111
116
  end
112
117
  private :api_http
@@ -1,3 +1,5 @@
1
+ require 'erb'
2
+
1
3
  module ThreeScale
2
4
  module Core
3
5
  module APIClient
@@ -38,6 +40,10 @@ module ThreeScale
38
40
  @default_prefix = prefix
39
41
  end
40
42
 
43
+ def url_encode(str)
44
+ ERB::Util.url_encode(str)
45
+ end
46
+
41
47
  private
42
48
 
43
49
  def internal_api_error(status)
@@ -1,5 +1,3 @@
1
- require 'cgi'
2
-
3
1
  module ThreeScale
4
2
  module Core
5
3
  class Application < APIClient::Resource
@@ -18,19 +16,20 @@ module ThreeScale
18
16
  private_class_method :base_uri
19
17
 
20
18
  def self.app_uri(service_id, id)
21
- escaped_id = CGI::escape(id.to_s)
22
-
23
- "#{base_uri(service_id)}#{escaped_id}"
19
+ "#{base_uri(service_id)}#{url_encode(id)}"
24
20
  end
25
21
  private_class_method :app_uri
26
22
 
27
23
  def self.key_uri(service_id, key)
28
- escaped_key = CGI::escape(key.to_s)
29
-
30
- "#{base_uri(service_id)}key/#{escaped_key}"
24
+ "#{base_uri(service_id)}key/#{url_encode(key)}"
31
25
  end
32
26
  private_class_method :key_uri
33
27
 
28
+ def self.batch_uri(service_id)
29
+ "#{base_uri(service_id)}batch"
30
+ end
31
+ private_class_method :batch_uri
32
+
34
33
  def self.load(service_id, id)
35
34
  api_read({}, uri: app_uri(service_id, id))
36
35
  end
@@ -44,6 +43,10 @@ module ThreeScale
44
43
  api_delete({}, uri: app_uri(service_id, id))
45
44
  end
46
45
 
46
+ def self.save_batch(service_id, applications)
47
+ api_update_batch({ applications: applications }, uri: batch_uri(service_id))
48
+ end
49
+
47
50
  def initialize(attributes = {})
48
51
  @state = :active
49
52
  super(attributes)
@@ -77,8 +80,7 @@ module ThreeScale
77
80
 
78
81
  def self.save_id_by_key(service_id, user_key, id)
79
82
  raise ApplicationHasInconsistentData.new(id, user_key) if (service_id.nil? || id.nil? || user_key.nil? || service_id=="" || id=="" || user_key=="")
80
- escaped_key = CGI::escape(user_key)
81
- ret = api_do_put({}, uri: "#{app_uri(service_id, id)}/key/#{escaped_key}")
83
+ ret = api_do_put({}, uri: "#{app_uri(service_id, id)}/key/#{url_encode(user_key)}")
82
84
  ret[:ok]
83
85
  end
84
86
 
@@ -1,5 +1,3 @@
1
- require 'cgi'
2
-
3
1
  module ThreeScale
4
2
  module Core
5
3
  class ApplicationKey < APIClient::Resource
@@ -23,12 +21,12 @@ module ThreeScale
23
21
  end
24
22
 
25
23
  def self.base_uri(service_id, application_id)
26
- "#{default_uri}#{service_id}/applications/#{CGI::escape(application_id.to_s)}/keys/"
24
+ "#{default_uri}#{service_id}/applications/#{url_encode(application_id)}/keys/"
27
25
  end
28
26
  private_class_method :base_uri
29
27
 
30
28
  def self.application_key_uri(service_id, application_id, value = '')
31
- "#{base_uri(service_id, application_id)}#{CGI::escape(value.to_s)}"
29
+ "#{base_uri(service_id, application_id)}#{url_encode(value)}"
32
30
  end
33
31
  private_class_method :application_key_uri
34
32
  end
@@ -25,7 +25,7 @@ module ThreeScale
25
25
  end
26
26
 
27
27
  def self.base_uri(service_id, application_id)
28
- "#{default_uri}#{service_id}/applications/#{application_id}/referrer_filters"
28
+ "#{default_uri}#{service_id}/applications/#{url_encode(application_id)}/referrer_filters"
29
29
  end
30
30
  private_class_method :base_uri
31
31
  end
@@ -6,7 +6,7 @@ module ThreeScale
6
6
  default_uri '/internal/services/'
7
7
 
8
8
  def self.utilization_uri(service_id, app_id)
9
- "#{default_uri}#{service_id}/applications/#{app_id}/utilization/"
9
+ "#{default_uri}#{service_id}/applications/#{url_encode(app_id)}/utilization/"
10
10
  end
11
11
  private_class_method :utilization_uri
12
12
 
@@ -1,5 +1,5 @@
1
1
  module ThreeScale
2
2
  module Core
3
- VERSION = '1.29.1'
3
+ VERSION = '1.31.0'
4
4
  end
5
5
  end
data/lib/3scale/core.rb CHANGED
@@ -1,14 +1,7 @@
1
1
  require 'uri'
2
2
  require 'json'
3
3
  require 'faraday'
4
- require 'net/http/persistent'
5
-
6
- # Warn that Faraday < 0.13 and Net::HTTP::Persistent >= 3.0.0 don't mix well
7
- if Faraday::VERSION =~ /0\.([0-9]|1[012])\.\d+/ &&
8
- Net::HTTP::Persistent::VERSION =~ /^[^012]\.\d+\.\d+/
9
- warn 'The combination of faraday < 0.13 and net-http-persistent 3.0+ is ' \
10
- 'known to have issues. See https://github.com/lostisland/faraday/issues/617'
11
- end
4
+ require 'faraday/net_http_persistent'
12
5
 
13
6
  require '3scale/core/version'
14
7
  require '3scale/core/logger'
@@ -56,7 +49,7 @@ module ThreeScale
56
49
  @password = uri.password
57
50
  end
58
51
 
59
- @faraday.basic_auth(@username, @password) if @username || @password
52
+ @faraday.set_basic_auth(@username, @password) if @username || @password
60
53
  @faraday
61
54
  end
62
55
 
data/pisoni.gemspec CHANGED
@@ -18,12 +18,12 @@ Gem::Specification.new do |s|
18
18
  s.description = 'Client for the Apisonator internal API for model data.'
19
19
  s.license = 'Apache-2.0'
20
20
 
21
- s.add_dependency 'faraday', '>= 0.9.1'
22
- s.add_dependency 'json', '>= 1.8.1'
23
- s.add_dependency 'injectedlogger', '>= 0.0.13'
24
- s.add_dependency 'net-http-persistent'
21
+ s.add_runtime_dependency 'faraday', '~> 2.0', '>= 2.14.3'
22
+ s.add_runtime_dependency 'json', '~> 2.7', '>= 2.7.1'
23
+ s.add_runtime_dependency 'injectedlogger', '0.0.13'
24
+ s.add_runtime_dependency 'faraday-net_http_persistent', '~> 2.1'
25
25
 
26
- s.add_development_dependency 'rake'
26
+ s.add_development_dependency 'rake', '~> 13.1'
27
27
 
28
28
  s.files = `git ls-files`.split($/).reject do |f| [
29
29
  %r{^\.[^\/]},
@@ -39,5 +39,5 @@ Gem::Specification.new do |s|
39
39
 
40
40
  s.rdoc_options = ["--charset=UTF-8"]
41
41
 
42
- s.required_ruby_version = '>= 2.3.0'
42
+ s.required_ruby_version = '>= 3.0.0'
43
43
  end
@@ -0,0 +1,19 @@
1
+ version: '3'
2
+ services:
3
+
4
+ redis:
5
+ image: redis:6.2-alpine
6
+
7
+ apisonator:
8
+ image: quay.io/3scale/apisonator:latest
9
+ ports:
10
+ - "3001:3001"
11
+ environment:
12
+ CONFIG_INTERNAL_API_USER: user
13
+ CONFIG_INTERNAL_API_PASSWORD: password
14
+ CONFIG_QUEUES_MASTER_NAME: redis://redis:6379
15
+ CONFIG_REDIS_PROXY: redis://redis:6379
16
+ RACK_ENV: test
17
+ command: 3scale_backend start -p 3001
18
+ depends_on:
19
+ - redis
@@ -59,7 +59,7 @@ module ThreeScale
59
59
  end
60
60
 
61
61
  describe 'with a key that contains special chars (*, _, etc.)' do
62
- let(:key) { '#$*' }
62
+ let(:key) { SPECIAL_CHARACTERS }
63
63
 
64
64
  before do
65
65
  ApplicationKey.delete(service_id, app_id, key)
@@ -74,8 +74,8 @@ module ThreeScale
74
74
  end
75
75
 
76
76
  describe 'with app ID that contains special characters ({, $, ? etc.)' do
77
- let(:app_id) { 'abc{1}$3?' }
78
- let(:key) { 'z#$*' }
77
+ let(:app_id) { SPECIAL_CHARACTERS }
78
+ let(:key) { SPECIAL_CHARACTERS }
79
79
 
80
80
  before do
81
81
  ApplicationKey.delete(service_id, app_id, key)
@@ -119,7 +119,7 @@ module ThreeScale
119
119
  end
120
120
 
121
121
  describe 'with a key that contains special chars (*, _, etc.)' do
122
- let(:key_with_special_chars) { '#$*' }
122
+ let(:key_with_special_chars) { SPECIAL_CHARACTERS }
123
123
 
124
124
  before do
125
125
  ApplicationKey.save(service_id, app_id, key)
@@ -3,7 +3,7 @@ module ThreeScale
3
3
  module Core
4
4
  describe ApplicationReferrerFilter do
5
5
  let(:service_id) { 10 }
6
- let(:app_id) { 100 }
6
+ let(:app_id) { SPECIAL_CHARACTERS }
7
7
  let(:filters) { %w(foo bar doopah) }
8
8
  let(:application) do
9
9
  { service_id: service_id,
@@ -24,6 +24,8 @@ module ThreeScale
24
24
  end
25
25
 
26
26
  describe '.load_all' do
27
+ subject { ApplicationReferrerFilter.load_all(service_id, app_id) }
28
+
27
29
  describe 'Getting all referrer filters' do
28
30
  let(:ref_filters) { %w(foo bar) }
29
31
 
@@ -32,14 +34,13 @@ module ThreeScale
32
34
  end
33
35
 
34
36
  it 'returns a sorted list of filters' do
35
- filters = ApplicationReferrerFilter.load_all(service_id, app_id)
36
- filters.must_equal ref_filters.sort
37
+ subject.must_equal ref_filters.sort
37
38
  end
38
39
  end
39
40
 
40
41
  describe 'when there are no referrer filters' do
41
42
  it 'returns an empty list' do
42
- ApplicationReferrerFilter.load_all(service_id, app_id).must_equal []
43
+ subject.must_equal []
43
44
  end
44
45
  end
45
46
  end
@@ -47,7 +47,7 @@ module ThreeScale
47
47
 
48
48
  describe 'with an app ID that contains special characters' do
49
49
  let(:service_id) { 2001 }
50
- let(:app_id) { '#$*' }
50
+ let(:app_id) { SPECIAL_CHARACTERS }
51
51
 
52
52
  before do
53
53
  Application.save service_id: service_id, id: app_id, state: 'suspended',
@@ -90,7 +90,7 @@ module ThreeScale
90
90
 
91
91
  describe 'with an app ID that contains special characters' do
92
92
  let(:service_id) { 2001 }
93
- let(:app_id) { '#$*' }
93
+ let(:app_id) { SPECIAL_CHARACTERS }
94
94
 
95
95
  before do
96
96
  Application.save service_id: service_id, id: app_id, state: 'suspended',
@@ -157,7 +157,7 @@ module ThreeScale
157
157
 
158
158
  describe 'with an app ID that contains special characters' do
159
159
  let(:service_id) { 2001 }
160
- let(:app_id) { '#$*' }
160
+ let(:app_id) { SPECIAL_CHARACTERS }
161
161
 
162
162
  before do
163
163
  Application.delete(service_id, app_id)
@@ -269,9 +269,102 @@ module ThreeScale
269
269
  end
270
270
  end
271
271
 
272
+ describe '.save_batch' do
273
+ let(:service_id) { 2001 }
274
+
275
+ before do
276
+ Application.delete(service_id, 'batch_app_1')
277
+ Application.delete(service_id, 'batch_app_2')
278
+ Application.delete(service_id, 'batch_app_3')
279
+ end
280
+
281
+ it 'creates multiple applications in a single request' do
282
+ apps = [
283
+ { id: 'batch_app_1', state: 'active', plan_id: '100', plan_name: 'Gold',
284
+ redirect_url: 'http://example.com', user_key: 'uk_batch_1' },
285
+ { id: 'batch_app_2', state: 'suspended', plan_id: '101', plan_name: 'Silver' }
286
+ ]
287
+
288
+ result = Application.save_batch(service_id, apps)
289
+
290
+ result[:status].must_equal 'completed'
291
+ result[:total].must_equal 2
292
+ result[:successful].must_equal 2
293
+ result[:failed].must_equal 0
294
+
295
+ app1 = Application.load(service_id, 'batch_app_1')
296
+ app1.wont_be_nil
297
+ app1.plan_name.must_equal 'Gold'
298
+
299
+ app2 = Application.load(service_id, 'batch_app_2')
300
+ app2.wont_be_nil
301
+ app2.plan_name.must_equal 'Silver'
302
+ end
303
+
304
+ it 'reports failures for invalid applications without blocking valid ones' do
305
+ apps = [
306
+ { id: 'batch_app_1', state: 'active', plan_id: '100', plan_name: 'Gold' },
307
+ { id: 'batch_app_3', plan_id: '102', plan_name: 'Bronze' }
308
+ ]
309
+
310
+ result = Application.save_batch(service_id, apps)
311
+
312
+ result[:status].must_equal 'completed'
313
+ result[:total].must_equal 2
314
+ result[:successful].must_equal 1
315
+ result[:failed].must_equal 1
316
+
317
+ result[:failures].wont_be_nil
318
+ result[:failures].size.must_equal 1
319
+ result[:failures][0][:id].must_equal 'batch_app_3'
320
+
321
+ Application.load(service_id, 'batch_app_1').wont_be_nil
322
+ end
323
+
324
+ it 'returns modified status for existing applications' do
325
+ Application.save(service_id: service_id, id: 'batch_app_1',
326
+ state: 'active', plan_id: '100', plan_name: 'Old')
327
+
328
+ apps = [
329
+ { id: 'batch_app_1', state: 'active', plan_id: '200', plan_name: 'New' }
330
+ ]
331
+
332
+ result = Application.save_batch(service_id, apps)
333
+
334
+ result[:successful].must_equal 1
335
+ result[:applications][0][:status].must_equal 'modified'
336
+
337
+ app = Application.load(service_id, 'batch_app_1')
338
+ app.plan_name.must_equal 'New'
339
+ end
340
+
341
+ it 'handles empty applications array' do
342
+ result = Application.save_batch(service_id, [])
343
+
344
+ result[:status].must_equal 'completed'
345
+ result[:total].must_equal 0
346
+ result[:successful].must_equal 0
347
+ result[:failed].must_equal 0
348
+ end
349
+
350
+ it 'saves user keys and application keys' do
351
+ apps = [
352
+ { id: 'batch_app_1', state: 'active', plan_id: '100', plan_name: 'Gold',
353
+ user_key: 'uk_batch_test', application_keys: ['ak1', 'ak2'] }
354
+ ]
355
+
356
+ result = Application.save_batch(service_id, apps)
357
+
358
+ result[:successful].must_equal 1
359
+ result[:applications][0][:application][:user_key].must_equal 'uk_batch_test'
360
+ result[:applications][0][:application][:application_keys].must_include 'ak1'
361
+ result[:applications][0][:application][:application_keys].must_include 'ak2'
362
+ end
363
+ end
364
+
272
365
  describe 'by_key' do
273
366
  let(:key) { 'a_key' }
274
- let(:key_with_special_chars) { '#$*' }
367
+ let(:key_with_special_chars) { SPECIAL_CHARACTERS }
275
368
  let(:service_id) { 2001 }
276
369
  let(:app_id) { 8011 }
277
370
 
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,11 @@
1
1
  if ENV['COVERAGE'] && !ENV['COVERAGE'].empty?
2
- require 'codeclimate-test-reporter'
2
+ require 'simplecov'
3
+ require 'simplecov_json_formatter'
3
4
  SimpleCov.start do
4
- formatter ENV['CODECLIMATE_REPO_TOKEN'] ?
5
- CodeClimate::TestReporter::Formatter :
5
+ formatter SimpleCov::Formatter::MultiFormatter.new([
6
+ SimpleCov::Formatter::JSONFormatter,
6
7
  SimpleCov::Formatter::HTMLFormatter
8
+ ])
7
9
  add_filter '/spec/'
8
10
  end
9
11
  end
@@ -13,3 +15,5 @@ $:.unshift(File.dirname(__FILE__) + '/../lib')
13
15
  require 'minitest/autorun'
14
16
  require 'bundler/setup'
15
17
  Bundler.require(:default, :development, :test)
18
+
19
+ SPECIAL_CHARACTERS = "! \"#$%&'()*+,-.:;<=>?@[]^_`{|}~\\/".freeze
@@ -105,6 +105,16 @@ module ThreeScale
105
105
  Utilization.load(service_id, non_existing_app_id).must_be_nil
106
106
  end
107
107
  end
108
+
109
+ describe 'with an application ID with special characters' do
110
+ let(:app_id) { SPECIAL_CHARACTERS }
111
+
112
+ subject { Utilization.load(service_id, app_id) }
113
+
114
+ it 'gets expected results' do
115
+ subject.wont_be_empty
116
+ end
117
+ end
108
118
  end
109
119
  end
110
120
  end
metadata CHANGED
@@ -1,85 +1,96 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pisoni
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.29.1
4
+ version: 1.31.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alejandro Martinez Ruiz
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-12-12 00:00:00.000000000 Z
10
+ date: 2026-07-03 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: faraday
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
17
19
  - - ">="
18
20
  - !ruby/object:Gem::Version
19
- version: 0.9.1
21
+ version: 2.14.3
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
23
25
  requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '2.0'
24
29
  - - ">="
25
30
  - !ruby/object:Gem::Version
26
- version: 0.9.1
31
+ version: 2.14.3
27
32
  - !ruby/object:Gem::Dependency
28
33
  name: json
29
34
  requirement: !ruby/object:Gem::Requirement
30
35
  requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '2.7'
31
39
  - - ">="
32
40
  - !ruby/object:Gem::Version
33
- version: 1.8.1
41
+ version: 2.7.1
34
42
  type: :runtime
35
43
  prerelease: false
36
44
  version_requirements: !ruby/object:Gem::Requirement
37
45
  requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '2.7'
38
49
  - - ">="
39
50
  - !ruby/object:Gem::Version
40
- version: 1.8.1
51
+ version: 2.7.1
41
52
  - !ruby/object:Gem::Dependency
42
53
  name: injectedlogger
43
54
  requirement: !ruby/object:Gem::Requirement
44
55
  requirements:
45
- - - ">="
56
+ - - '='
46
57
  - !ruby/object:Gem::Version
47
58
  version: 0.0.13
48
59
  type: :runtime
49
60
  prerelease: false
50
61
  version_requirements: !ruby/object:Gem::Requirement
51
62
  requirements:
52
- - - ">="
63
+ - - '='
53
64
  - !ruby/object:Gem::Version
54
65
  version: 0.0.13
55
66
  - !ruby/object:Gem::Dependency
56
- name: net-http-persistent
67
+ name: faraday-net_http_persistent
57
68
  requirement: !ruby/object:Gem::Requirement
58
69
  requirements:
59
- - - ">="
70
+ - - "~>"
60
71
  - !ruby/object:Gem::Version
61
- version: '0'
72
+ version: '2.1'
62
73
  type: :runtime
63
74
  prerelease: false
64
75
  version_requirements: !ruby/object:Gem::Requirement
65
76
  requirements:
66
- - - ">="
77
+ - - "~>"
67
78
  - !ruby/object:Gem::Version
68
- version: '0'
79
+ version: '2.1'
69
80
  - !ruby/object:Gem::Dependency
70
81
  name: rake
71
82
  requirement: !ruby/object:Gem::Requirement
72
83
  requirements:
73
- - - ">="
84
+ - - "~>"
74
85
  - !ruby/object:Gem::Version
75
- version: '0'
86
+ version: '13.1'
76
87
  type: :development
77
88
  prerelease: false
78
89
  version_requirements: !ruby/object:Gem::Requirement
79
90
  requirements:
80
- - - ">="
91
+ - - "~>"
81
92
  - !ruby/object:Gem::Version
82
- version: '0'
93
+ version: '13.1'
83
94
  description: Client for the Apisonator internal API for model data.
84
95
  email:
85
96
  - alex@3scale.net
@@ -119,6 +130,7 @@ files:
119
130
  - lib/3scale_core.rb
120
131
  - lib/pisoni.rb
121
132
  - pisoni.gemspec
133
+ - podman-compose.yml
122
134
  - spec/alert_limit_spec.rb
123
135
  - spec/application_key_spec.rb
124
136
  - spec/application_referrer_filter_spec.rb
@@ -137,7 +149,6 @@ homepage: https://github.com/3scale/pisoni
137
149
  licenses:
138
150
  - Apache-2.0
139
151
  metadata: {}
140
- post_install_message:
141
152
  rdoc_options:
142
153
  - "--charset=UTF-8"
143
154
  require_paths:
@@ -146,15 +157,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
146
157
  requirements:
147
158
  - - ">="
148
159
  - !ruby/object:Gem::Version
149
- version: 2.3.0
160
+ version: 3.0.0
150
161
  required_rubygems_version: !ruby/object:Gem::Requirement
151
162
  requirements:
152
163
  - - ">="
153
164
  - !ruby/object:Gem::Version
154
165
  version: '0'
155
166
  requirements: []
156
- rubygems_version: 3.1.6
157
- signing_key:
167
+ rubygems_version: 4.0.4
158
168
  specification_version: 4
159
169
  summary: Client for the Apisonator internal API for model data
160
170
  test_files: