diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-07-20 15:26:25 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-07-20 15:26:25 +0300 |
commit | a09983ae35713f5a2bbb100981116d31ce99826e (patch) | |
tree | 2ee2af7bd104d57086db360a7e6d8c9d5d43667a /spec/lib/gitlab/json_spec.rb | |
parent | 18c5ab32b738c0b6ecb4d0df3994000482f34bd8 (diff) |
Add latest changes from gitlab-org/gitlab@13-2-stable-ee
Diffstat (limited to 'spec/lib/gitlab/json_spec.rb')
-rw-r--r-- | spec/lib/gitlab/json_spec.rb | 429 |
1 files changed, 322 insertions, 107 deletions
diff --git a/spec/lib/gitlab/json_spec.rb b/spec/lib/gitlab/json_spec.rb index ee7c98a5a54..d7671dda323 100644 --- a/spec/lib/gitlab/json_spec.rb +++ b/spec/lib/gitlab/json_spec.rb @@ -7,189 +7,404 @@ RSpec.describe Gitlab::Json do stub_feature_flags(json_wrapper_legacy_mode: true) end - describe ".parse" do - context "legacy_mode is disabled by default" do - it "parses an object" do - expect(subject.parse('{ "foo": "bar" }')).to eq({ "foo" => "bar" }) - end + shared_examples "json" do + describe ".parse" do + context "legacy_mode is disabled by default" do + it "parses an object" do + expect(subject.parse('{ "foo": "bar" }')).to eq({ "foo" => "bar" }) + end - it "parses an array" do - expect(subject.parse('[{ "foo": "bar" }]')).to eq([{ "foo" => "bar" }]) - end + it "parses an array" do + expect(subject.parse('[{ "foo": "bar" }]')).to eq([{ "foo" => "bar" }]) + end - it "parses a string" do - expect(subject.parse('"foo"', legacy_mode: false)).to eq("foo") - end + it "parses a string" do + expect(subject.parse('"foo"', legacy_mode: false)).to eq("foo") + end - it "parses a true bool" do - expect(subject.parse("true", legacy_mode: false)).to be(true) - end + it "parses a true bool" do + expect(subject.parse("true", legacy_mode: false)).to be(true) + end - it "parses a false bool" do - expect(subject.parse("false", legacy_mode: false)).to be(false) + it "parses a false bool" do + expect(subject.parse("false", legacy_mode: false)).to be(false) + end end - end - context "legacy_mode is enabled" do - it "parses an object" do - expect(subject.parse('{ "foo": "bar" }', legacy_mode: true)).to eq({ "foo" => "bar" }) - end + context "legacy_mode is enabled" do + it "parses an object" do + expect(subject.parse('{ "foo": "bar" }', legacy_mode: true)).to eq({ "foo" => "bar" }) + end - it "parses an array" do - expect(subject.parse('[{ "foo": "bar" }]', legacy_mode: true)).to eq([{ "foo" => "bar" }]) - end + it "parses an array" do + expect(subject.parse('[{ "foo": "bar" }]', legacy_mode: true)).to eq([{ "foo" => "bar" }]) + end - it "raises an error on a string" do - expect { subject.parse('"foo"', legacy_mode: true) }.to raise_error(JSON::ParserError) - end + it "raises an error on a string" do + expect { subject.parse('"foo"', legacy_mode: true) }.to raise_error(JSON::ParserError) + end - it "raises an error on a true bool" do - expect { subject.parse("true", legacy_mode: true) }.to raise_error(JSON::ParserError) + it "raises an error on a true bool" do + expect { subject.parse("true", legacy_mode: true) }.to raise_error(JSON::ParserError) + end + + it "raises an error on a false bool" do + expect { subject.parse("false", legacy_mode: true) }.to raise_error(JSON::ParserError) + end end - it "raises an error on a false bool" do - expect { subject.parse("false", legacy_mode: true) }.to raise_error(JSON::ParserError) + context "feature flag is disabled" do + before do + stub_feature_flags(json_wrapper_legacy_mode: false) + end + + it "parses an object" do + expect(subject.parse('{ "foo": "bar" }', legacy_mode: true)).to eq({ "foo" => "bar" }) + end + + it "parses an array" do + expect(subject.parse('[{ "foo": "bar" }]', legacy_mode: true)).to eq([{ "foo" => "bar" }]) + end + + it "parses a string" do + expect(subject.parse('"foo"', legacy_mode: true)).to eq("foo") + end + + it "parses a true bool" do + expect(subject.parse("true", legacy_mode: true)).to be(true) + end + + it "parses a false bool" do + expect(subject.parse("false", legacy_mode: true)).to be(false) + end end end - context "feature flag is disabled" do - before do - stub_feature_flags(json_wrapper_legacy_mode: false) - end + describe ".parse!" do + context "legacy_mode is disabled by default" do + it "parses an object" do + expect(subject.parse!('{ "foo": "bar" }')).to eq({ "foo" => "bar" }) + end - it "parses an object" do - expect(subject.parse('{ "foo": "bar" }', legacy_mode: true)).to eq({ "foo" => "bar" }) - end + it "parses an array" do + expect(subject.parse!('[{ "foo": "bar" }]')).to eq([{ "foo" => "bar" }]) + end - it "parses an array" do - expect(subject.parse('[{ "foo": "bar" }]', legacy_mode: true)).to eq([{ "foo" => "bar" }]) - end + it "parses a string" do + expect(subject.parse!('"foo"', legacy_mode: false)).to eq("foo") + end - it "parses a string" do - expect(subject.parse('"foo"', legacy_mode: true)).to eq("foo") + it "parses a true bool" do + expect(subject.parse!("true", legacy_mode: false)).to be(true) + end + + it "parses a false bool" do + expect(subject.parse!("false", legacy_mode: false)).to be(false) + end end - it "parses a true bool" do - expect(subject.parse("true", legacy_mode: true)).to be(true) + context "legacy_mode is enabled" do + it "parses an object" do + expect(subject.parse!('{ "foo": "bar" }', legacy_mode: true)).to eq({ "foo" => "bar" }) + end + + it "parses an array" do + expect(subject.parse!('[{ "foo": "bar" }]', legacy_mode: true)).to eq([{ "foo" => "bar" }]) + end + + it "raises an error on a string" do + expect { subject.parse!('"foo"', legacy_mode: true) }.to raise_error(JSON::ParserError) + end + + it "raises an error on a true bool" do + expect { subject.parse!("true", legacy_mode: true) }.to raise_error(JSON::ParserError) + end + + it "raises an error on a false bool" do + expect { subject.parse!("false", legacy_mode: true) }.to raise_error(JSON::ParserError) + end end - it "parses a false bool" do - expect(subject.parse("false", legacy_mode: true)).to be(false) + context "feature flag is disabled" do + before do + stub_feature_flags(json_wrapper_legacy_mode: false) + end + + it "parses an object" do + expect(subject.parse!('{ "foo": "bar" }', legacy_mode: true)).to eq({ "foo" => "bar" }) + end + + it "parses an array" do + expect(subject.parse!('[{ "foo": "bar" }]', legacy_mode: true)).to eq([{ "foo" => "bar" }]) + end + + it "parses a string" do + expect(subject.parse!('"foo"', legacy_mode: true)).to eq("foo") + end + + it "parses a true bool" do + expect(subject.parse!("true", legacy_mode: true)).to be(true) + end + + it "parses a false bool" do + expect(subject.parse!("false", legacy_mode: true)).to be(false) + end end end - end - describe ".parse!" do - context "legacy_mode is disabled by default" do - it "parses an object" do - expect(subject.parse!('{ "foo": "bar" }')).to eq({ "foo" => "bar" }) + describe ".dump" do + it "dumps an object" do + expect(subject.dump({ "foo" => "bar" })).to eq('{"foo":"bar"}') end - it "parses an array" do - expect(subject.parse!('[{ "foo": "bar" }]')).to eq([{ "foo" => "bar" }]) + it "dumps an array" do + expect(subject.dump([{ "foo" => "bar" }])).to eq('[{"foo":"bar"}]') end - it "parses a string" do - expect(subject.parse!('"foo"', legacy_mode: false)).to eq("foo") + it "dumps a string" do + expect(subject.dump("foo")).to eq('"foo"') end - it "parses a true bool" do - expect(subject.parse!("true", legacy_mode: false)).to be(true) + it "dumps a true bool" do + expect(subject.dump(true)).to eq("true") end - it "parses a false bool" do - expect(subject.parse!("false", legacy_mode: false)).to be(false) + it "dumps a false bool" do + expect(subject.dump(false)).to eq("false") end end - context "legacy_mode is enabled" do - it "parses an object" do - expect(subject.parse!('{ "foo": "bar" }', legacy_mode: true)).to eq({ "foo" => "bar" }) + describe ".generate" do + let(:obj) do + { test: true, "foo.bar" => "baz", is_json: 1, some: [1, 2, 3] } end - it "parses an array" do - expect(subject.parse!('[{ "foo": "bar" }]', legacy_mode: true)).to eq([{ "foo" => "bar" }]) - end + it "generates JSON" do + expected_string = <<~STR.chomp + {"test":true,"foo.bar":"baz","is_json":1,"some":[1,2,3]} + STR - it "raises an error on a string" do - expect { subject.parse!('"foo"', legacy_mode: true) }.to raise_error(JSON::ParserError) + expect(subject.generate(obj)).to eq(expected_string) end - it "raises an error on a true bool" do - expect { subject.parse!("true", legacy_mode: true) }.to raise_error(JSON::ParserError) + it "allows you to customise the output" do + opts = { + indent: " ", + space: " ", + space_before: " ", + object_nl: "\n", + array_nl: "\n" + } + + json = subject.generate(obj, opts) + + expected_string = <<~STR.chomp + { + "test" : true, + "foo.bar" : "baz", + "is_json" : 1, + "some" : [ + 1, + 2, + 3 + ] + } + STR + + expect(json).to eq(expected_string) end + end - it "raises an error on a false bool" do - expect { subject.parse!("false", legacy_mode: true) }.to raise_error(JSON::ParserError) + describe ".pretty_generate" do + let(:obj) do + { + test: true, + "foo.bar" => "baz", + is_json: 1, + some: [1, 2, 3], + more: { test: true }, + multi_line_empty_array: [], + multi_line_empty_obj: {} + } + end + + it "generates pretty JSON" do + expected_string = <<~STR.chomp + { + "test": true, + "foo.bar": "baz", + "is_json": 1, + "some": [ + 1, + 2, + 3 + ], + "more": { + "test": true + }, + "multi_line_empty_array": [ + + ], + "multi_line_empty_obj": { + } + } + STR + + expect(subject.pretty_generate(obj)).to eq(expected_string) + end + + it "allows you to customise the output" do + opts = { + space_before: " " + } + + json = subject.pretty_generate(obj, opts) + + expected_string = <<~STR.chomp + { + "test" : true, + "foo.bar" : "baz", + "is_json" : 1, + "some" : [ + 1, + 2, + 3 + ], + "more" : { + "test" : true + }, + "multi_line_empty_array" : [ + + ], + "multi_line_empty_obj" : { + } + } + STR + + expect(json).to eq(expected_string) end end - context "feature flag is disabled" do + context "the feature table is missing" do before do - stub_feature_flags(json_wrapper_legacy_mode: false) + allow(Feature::FlipperFeature).to receive(:table_exists?).and_return(false) end - it "parses an object" do - expect(subject.parse!('{ "foo": "bar" }', legacy_mode: true)).to eq({ "foo" => "bar" }) + it "skips legacy mode handling" do + expect(Feature).not_to receive(:enabled?).with(:json_wrapper_legacy_mode, default_enabled: true) + + subject.send(:handle_legacy_mode!, {}) end - it "parses an array" do - expect(subject.parse!('[{ "foo": "bar" }]', legacy_mode: true)).to eq([{ "foo" => "bar" }]) + it "skips oj feature detection" do + expect(Feature).not_to receive(:enabled?).with(:oj_json, default_enabled: true) + + subject.send(:enable_oj?) end + end - it "parses a string" do - expect(subject.parse!('"foo"', legacy_mode: true)).to eq("foo") + context "the database is missing" do + before do + allow(Feature::FlipperFeature).to receive(:table_exists?).and_raise(PG::ConnectionBad) end - it "parses a true bool" do - expect(subject.parse!("true", legacy_mode: true)).to be(true) + it "still parses json" do + expect(subject.parse("{}")).to eq({}) end - it "parses a false bool" do - expect(subject.parse!("false", legacy_mode: true)).to be(false) + it "still generates json" do + expect(subject.dump({})).to eq("{}") end end end - describe ".dump" do - it "dumps an object" do - expect(subject.dump({ "foo" => "bar" })).to eq('{"foo":"bar"}') + context "oj gem" do + before do + stub_feature_flags(oj_json: true) end - it "dumps an array" do - expect(subject.dump([{ "foo" => "bar" }])).to eq('[{"foo":"bar"}]') - end + it_behaves_like "json" - it "dumps a string" do - expect(subject.dump("foo")).to eq('"foo"') + describe "#enable_oj?" do + it "returns true" do + expect(subject.enable_oj?).to be(true) + end end + end - it "dumps a true bool" do - expect(subject.dump(true)).to eq("true") + context "json gem" do + before do + stub_feature_flags(oj_json: false) end - it "dumps a false bool" do - expect(subject.dump(false)).to eq("false") + it_behaves_like "json" + + describe "#enable_oj?" do + it "returns false" do + expect(subject.enable_oj?).to be(false) + end end end - describe ".generate" do - it "delegates to the adapter" do - args = [{ foo: "bar" }] + describe Gitlab::Json::GrapeFormatter do + subject { described_class.call(obj, env) } + + let(:obj) { { test: true } } + let(:env) { {} } + let(:result) { "{\"test\":true}" } + + context "oj is enabled" do + before do + stub_feature_flags(oj_json: true) + end + + context "grape_gitlab_json flag is enabled" do + before do + stub_feature_flags(grape_gitlab_json: true) + end + + it "generates JSON" do + expect(subject).to eq(result) + end + + it "uses Gitlab::Json" do + expect(Gitlab::Json).to receive(:dump).with(obj) + + subject + end + end + + context "grape_gitlab_json flag is disabled" do + before do + stub_feature_flags(grape_gitlab_json: false) + end + + it "generates JSON" do + expect(subject).to eq(result) + end - expect(JSON).to receive(:generate).with(*args) + it "uses Grape::Formatter::Json" do + expect(Grape::Formatter::Json).to receive(:call).with(obj, env) - subject.generate(*args) + subject + end + end end - end - describe ".pretty_generate" do - it "delegates to the adapter" do - args = [{ foo: "bar" }] + context "oj is disabled" do + before do + stub_feature_flags(oj_json: false) + end - expect(JSON).to receive(:pretty_generate).with(*args) + it "generates JSON" do + expect(subject).to eq(result) + end + + it "uses Grape::Formatter::Json" do + expect(Grape::Formatter::Json).to receive(:call).with(obj, env) - subject.pretty_generate(*args) + subject + end end end end |