cc-cli 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +12 -0
  5. data/Guardfile +24 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +186 -0
  8. data/Rakefile +1 -0
  9. data/bin/cc-cli +5 -0
  10. data/cc-cli.gemspec +28 -0
  11. data/circle.yml +11 -0
  12. data/config/config.yml +31 -0
  13. data/lib/cc/api/explorer.rb +175 -0
  14. data/lib/cc/api/explorer/version.rb +7 -0
  15. data/lib/cc/api/http/http_requestor.rb +50 -0
  16. data/lib/cc/api/parser/arguments_mapper.rb +44 -0
  17. data/lib/cc/api/parser/arguments_parser.rb +65 -0
  18. data/lib/cc/api/parser/json_parser.rb +38 -0
  19. data/lib/cc/api/presentor/presentor.rb +47 -0
  20. data/lib/cc/api/util/config_reader.rb +38 -0
  21. data/lib/cc/api/util/key_chains_getter.rb +80 -0
  22. data/spec/dummy_data/catalog_categories.json +1 -0
  23. data/spec/dummy_data/catalog_product_types.json +1 -0
  24. data/spec/dummy_data/catalog_products.json +1 -0
  25. data/spec/dummy_data/catalog_stores.json +1 -0
  26. data/spec/dummy_data/lattice_offers.json +1 -0
  27. data/spec/dummy_data/lattice_products.json +1 -0
  28. data/spec/dummy_data/lattice_stores.json +1 -0
  29. data/spec/dummy_data/store_products.json +1 -0
  30. data/spec/explorer_spec.rb +238 -0
  31. data/spec/http/http_requestor_spec.rb +54 -0
  32. data/spec/parser/arguments_mapper_spec.rb +78 -0
  33. data/spec/parser/arguments_parser_spec.rb +81 -0
  34. data/spec/parser/json_parser_spec.rb +108 -0
  35. data/spec/spec_helper.rb +49 -0
  36. data/spec/support/arguments_mapper_returning_blank_json.rb +7 -0
  37. data/spec/support/arguments_mapper_returning_json_with_id_and_skus.rb +7 -0
  38. data/spec/support/arguments_mapper_returning_page_params.rb +7 -0
  39. data/spec/support/arguments_parser_returning_expected_result.rb +6 -0
  40. data/spec/support/json_parser.rb +43 -0
  41. data/spec/support/stdout_helper.rb +10 -0
  42. data/spec/support/table_fields_matcher.rb +16 -0
  43. data/spec/utils/utils_spec.rb +90 -0
  44. metadata +194 -0
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cc::Api::Http::HttpRequestor do
4
+ let(:license) { double("License", :username => 'abc', :password => "123")}
5
+
6
+ before(:each) do
7
+ Cc::Api::Util::ConfigReader.stub(:license).and_return(license)
8
+ end
9
+
10
+ context "returns valid JSON response for a post request" do
11
+ let(:param) { {request: { url: "https://abc:123@api.crystalcommerce.com/v1/lattice/offers", :body=>{"search"=>{"skus"=>{"201750"=>["123abc", "456def"]}}}, method: "POST"} } }
12
+
13
+ it "returns valid JSON response for a post request" do
14
+ stub_request(:post, "https://abc:123@api.crystalcommerce.com/v1/lattice/offers").
15
+ with(:body => "{\"search\":{\"skus\":{\"201750\":[\"123abc\",\"456def\"]}}}", :headers => {"Content-Type" => "application/json"}).
16
+ to_return(:status => 200, :body => LATTICE_OFFERS_RESPONSE, :headers => {"Content-Type" => "application/json"})
17
+
18
+ result = subject.request_for_json param
19
+ result.should_not eq nil
20
+
21
+ end
22
+ end
23
+
24
+ context "raises error" do
25
+ let(:param) { {request: { url: "https://abc:123@api.crystalcommerce.com/v1/lattice/offers", :body=>{"search"=>{"skus"=>{"201750"=>["123abc", "456def"]}}}, method: "POST"} } }
26
+
27
+ it "if license keys are not set properly" do
28
+ Cc::Api::Util::ConfigReader.stub(:license).and_raise(Cc::Api::Util::LicenseKeysException)
29
+ expect {
30
+ subject.request_for_json param
31
+ }.to raise_error(Cc::Api::Util::LicenseKeysException)
32
+ end
33
+
34
+ it "if not enough privileges" do
35
+ stub_request(:post, "https://abc:123@api.crystalcommerce.com/v1/lattice/offers").
36
+ with(:body => "{\"search\":{\"skus\":{\"201750\":[\"123abc\",\"456def\"]}}}", :headers => {"Content-Type" => "application/json"}).
37
+ to_return(:status => 401, :body => "", :headers => {"Content-Type" => "application/json"})
38
+
39
+ expect {
40
+ subject.request_for_json param
41
+ }.to raise_error Cc::Api::Http::UnauthorizedAccessException
42
+ end
43
+
44
+ it "if there's a server error" do
45
+ stub_request(:post, "https://abc:123@api.crystalcommerce.com/v1/lattice/offers").
46
+ with(:body => "{\"search\":{\"skus\":{\"201750\":[\"123abc\",\"456def\"]}}}", :headers => {"Content-Type" => "application/json"}).
47
+ to_return(:status => 500, :body => "", :headers => {"Content-Type" => "application/json"})
48
+
49
+ expect {
50
+ subject.request_for_json param
51
+ }.to raise_error Cc::Api::Http::ServerProblemException
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cc::Api::Parser::ArgumentsMapper do
4
+ describe "map" do
5
+ let(:rand) { "123" }
6
+ context "lattice" do
7
+ context "products" do
8
+ let(:args) { {:action => "lattice-products", :params => { :id => rand, :skus => [rand] } } }
9
+ let(:wrong_args) { {:action => "this", :is => "a", :wrong => "argument" } }
10
+
11
+ it_behaves_like "arguments mapper returning json with id and skus"
12
+ end
13
+
14
+ context "stores" do
15
+ let(:args) { { :action => "lattice-stores" } }
16
+
17
+ it_behaves_like "arguments mapper returning blank json"
18
+ end
19
+
20
+ context "offers" do
21
+ let(:rand) { "123" }
22
+ let(:args) { { :action => "lattice-offers", :params => { :id => rand, :skus => [rand] } } }
23
+
24
+ it "matches the args and creates a json object that maps the args" do
25
+ res = Cc::Api::Parser::ArgumentsMapper.map args
26
+ expected_res = {id: rand, skus: [rand]}
27
+ res.should eq expected_res
28
+ end
29
+ end
30
+ end
31
+
32
+ context "catalog" do
33
+ context "products" do
34
+ let(:args) { { :action => "catalog-products", :params => { :page => 1 } } }
35
+
36
+ it_behaves_like "arguments mapper returning page params"
37
+ end
38
+
39
+ context "product types" do
40
+ let(:args) { { :action => "catalog-product_types", :params => { :page => 1 } } }
41
+
42
+ it_behaves_like "arguments mapper returning page params"
43
+ end
44
+
45
+ context "stores" do
46
+ let(:args) { { :action => "catalog-stores" } }
47
+
48
+ it_behaves_like "arguments mapper returning blank json"
49
+ end
50
+
51
+ context "categories" do
52
+ let(:args) { { :action => "catalog-categories", :params => { :page => 1} } }
53
+
54
+ it_behaves_like "arguments mapper returning page params"
55
+ end
56
+ end
57
+
58
+ context "store" do
59
+ context "products" do
60
+ let(:store) { "arux" }
61
+ let(:args) { { :action => "store-products", :params => { :token => "123", :store => store } } }
62
+
63
+ it "matches the args and creates a json object that maps the args" do
64
+ res = Cc::Api::Parser::ArgumentsMapper.map args
65
+ expected_res = {token: rand, store: store}
66
+ res.should eq expected_res
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ describe "get_url" do
73
+ it "gets the correct url for the given action" do
74
+ a = { :url => "https://api.crystalcommerce.com/v1/catalog/products", :target_key_chain=>"products", :ignores=>["descriptors"]}
75
+ Cc::Api::Parser::ArgumentsMapper.get_url( "catalog-products").should eq a
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ #TODO: Dry this up
4
+ describe Cc::Api::Parser::ArgumentsParser do
5
+ before(:each) do
6
+ allow(Cc::Api::Util::ConfigReader).to receive(:pair).and_return "abc:123"
7
+ end
8
+
9
+ describe "parse" do
10
+ context "lattice" do
11
+ let(:url) { "https://api.crystalcommerce.com/v1/lattice/" }
12
+ let(:rand) { "123" }
13
+
14
+ context "products" do
15
+ let(:expected_result) { {request: {url: url + "products/" + rand + "?skus[]=" + rand } } }
16
+ let(:args) { { :action => "lattice-products", :params => { :id => rand, :skus => [ rand ] } } }
17
+
18
+ it_behaves_like "arguments parser returning expected result"
19
+ end
20
+
21
+ context "stores" do
22
+ let(:expected_result) { {request: { url: url + "stores", :target_key_chain => "" } } }
23
+ let(:args) { {:action => "lattice-stores"} }
24
+
25
+ it_behaves_like "arguments parser returning expected result"
26
+ end
27
+
28
+ context "offers" do
29
+ let(:expected_result) { {request: { url: url + "offers", :body=>{"search"=>{"skus"=>{"123"=>["123"]}}}, method: "POST"} } }
30
+ let(:args) { {:action => "lattice-offers", :params => { :id => rand, :skus => [rand] } } }
31
+
32
+ it_behaves_like "arguments parser returning expected result"
33
+ end
34
+ end
35
+
36
+ context "catalog" do
37
+ context "products" do
38
+ let(:url) { "https://api.crystalcommerce.com/v1/catalog/products?page=1" }
39
+ let(:expected_result) { { request: { url: url } } }
40
+ let(:args) { {:action => "catalog-products", :params => {:page => 1} } }
41
+
42
+ it_behaves_like "arguments parser returning expected result"
43
+ end
44
+
45
+ context "product types" do
46
+ let(:url) { "https://api.crystalcommerce.com/v1/catalog/product_types?page=1" }
47
+ let(:expected_result) { { request: { url: url } } }
48
+ let(:args) { { :action => "catalog-product_types", :params => {:page => 1} } }
49
+
50
+ it_behaves_like "arguments parser returning expected result"
51
+ end
52
+
53
+ context "product types" do
54
+ let(:url) { "https://api.crystalcommerce.com/v1/catalog/stores" }
55
+ let(:expected_result) { { request: { url: url, :target_key_chain=>"stores" } } }
56
+ let(:args) { { :action => "catalog-stores" } }
57
+
58
+ it_behaves_like "arguments parser returning expected result"
59
+ end
60
+
61
+ context "categories" do
62
+ let(:url) { "https://api.crystalcommerce.com/v1/catalog/categories?page=1" }
63
+ let(:expected_result) { { request: { url: url } } }
64
+ let(:args) { { :action => "catalog-categories", :params => {:page => 1} } }
65
+
66
+ it_behaves_like "arguments parser returning expected result"
67
+ end
68
+ end
69
+
70
+ context "store" do
71
+ context "products" do
72
+ let(:url) { "https://arux-api.crystalcommerce.com/v1/products?page=2" }
73
+ let(:token) { "123" }
74
+ let(:expected_result) { { request: { url: url, token: token } } }
75
+ let(:args) { { :action => "store-products", :params => { :token => token, :store => "arux", :page => 2 } } }
76
+
77
+ it_behaves_like "arguments parser returning expected result"
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,108 @@
1
+ require 'cc/api/parser/json_parser'
2
+ require 'json'
3
+
4
+ describe Cc::Api::Parser::JsonParser do
5
+ context "'vanilla' reduce" do
6
+ let(:product_id) { nil }
7
+ context "lattice" do
8
+ context "products" do
9
+ let(:json_response) { LATTICE_PRODUCTS_RESPONSE }
10
+ let(:blank_json_response) {'{"product":{"product_id":123,"variants":[]}}'}
11
+ let(:action) { "lattice-products" }
12
+ let(:chosen_columns) { ["store_variant.sku", "store_variant.store_name", "store_variant.store_business_name", "store_variant.sell_price.money.cents"] }
13
+
14
+ it_behaves_like "json parser"
15
+
16
+ end
17
+
18
+ context "offers" do
19
+ let(:product_id) { "201750" }
20
+ let(:json_response) { LATTICE_OFFERS_RESPONSE }
21
+ let(:blank_json_response) {'{"201750" : []}'}
22
+ let(:action) { "lattice-offers" }
23
+ let(:chosen_columns) { ["buy_price.cents", "qty", "product_url", "inventory_qty"] }
24
+
25
+ it_behaves_like "json parser"
26
+ end
27
+
28
+ context "stores" do
29
+ let(:json_response) { LATTICE_STORES_RESPONSE }
30
+ let(:blank_json_response) {'[]'}
31
+ let(:action) { "lattice-stores" }
32
+ let(:chosen_columns) { ["store.id", "store.name", "store.is_active", "store.country"] }
33
+
34
+ it_behaves_like "json parser"
35
+ end
36
+ end
37
+
38
+ context "catalog" do
39
+ context "products" do
40
+ let(:json_response) { CATALOG_PRODUCTS_RESPONSE }
41
+ let(:blank_json_response) {'{"products":[]}'}
42
+ let(:action) { "catalog-products" }
43
+ let(:chosen_columns) { ["name", "seoname", "barcode", "photo.content_type"] }
44
+
45
+ it_behaves_like "json parser"
46
+ end
47
+
48
+ context "product_types" do
49
+ context "valid chosen columns" do
50
+ let(:json_response) { CATALOG_PRODUCT_TYPES_RESPONSE }
51
+ let(:blank_json_response) {'{"product_types":[]}'}
52
+ let(:action) { "catalog-product_types" }
53
+ let(:chosen_columns) { ["name", "default_weight", "variant_dimensions.0.name"] }
54
+
55
+ it_behaves_like "json parser"
56
+ end
57
+
58
+ context "invalid chosen columns having index in variant_diments.<index>.name out of bounds" do
59
+ let(:json_response) { CATALOG_PRODUCT_TYPES_RESPONSE }
60
+ let(:blank_json_response) {'{"product_types":[]}'}
61
+ let(:action) { "catalog-product_types" }
62
+ let(:chosen_columns) { ["name", "default_weight", "variant_dimensions.500.name"] }
63
+
64
+ it_behaves_like "json parser"
65
+ end
66
+ end
67
+
68
+ context "stores" do
69
+ let(:json_response) { CATALOG_STORES_RESPONSE }
70
+ let(:blank_json_response) {'{"stores":[]}'}
71
+ let(:action) { "catalog-stores" }
72
+ let(:chosen_columns) { ["name", "country"] }
73
+
74
+ it_behaves_like "json parser"
75
+ end
76
+
77
+ context "categories" do
78
+ let(:json_response) { CATALOG_CATEGORIES_RESPONSE }
79
+ let(:blank_json_response) {'{"categories":[]}'}
80
+ let(:action) { "catalog-categories" }
81
+ let(:chosen_columns) { ["name", "seoname"] }
82
+
83
+ it_behaves_like "json parser"
84
+ end
85
+ end
86
+
87
+ context "stores" do
88
+ context "valid chosen columns" do
89
+ let(:json_response) { STORE_PRODUCTS_RESPONSE }
90
+ let(:blank_json_response) {'{"paginated_collection": {"entries" : []} }'}
91
+ let(:action) { "store-products" }
92
+ let(:chosen_columns) { ["product.weight", "product.qty", "product.default_variant.variant.descriptors.0.variant_descriptor.name"] }
93
+
94
+ it_behaves_like "json parser"
95
+ end
96
+
97
+ context "invalid chosen columns having index in variant_diments.<index>.name out of bounds" do
98
+ let(:json_response) { STORE_PRODUCTS_RESPONSE }
99
+ let(:blank_json_response) {'{"paginated_collection": {"entries" : []} }'}
100
+ let(:action) { "store-products" }
101
+ let(:chosen_columns) { ["product.weight", "product.qty", "product.default_variant.variant.descriptors.500.variant_descriptor.name"] }
102
+
103
+ it_behaves_like "json parser"
104
+
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,49 @@
1
+ # Require this file using `require "spec_helper"` to ensure that it is only
2
+ # loaded once.
3
+ #
4
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
5
+ require 'webmock/rspec'
6
+ require 'cc/api/explorer'
7
+ require 'pry'
8
+
9
+ def suppress_stdouts config #need to suppress command_line_reporter's output
10
+ original_stderr = $stderr
11
+ original_stdout = $stdout
12
+ config.before(:all) do
13
+ # Redirect stderr and stdout
14
+ $stderr = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w')
15
+ $stdout = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w')
16
+ end
17
+ config.after(:all) do
18
+ $stderr = original_stderr
19
+ $stdout = original_stdout
20
+ end
21
+ end
22
+
23
+ RSpec.configure do |config|
24
+ config.treat_symbols_as_metadata_keys_with_true_values = true
25
+ config.run_all_when_everything_filtered = true
26
+ config.filter_run :focus
27
+ Dir["./spec/support/**/*.rb"].sort.each {|f| require f}
28
+ config.include(StdoutHelper)
29
+
30
+ # Run specs in random order to surface order dependencies. If you find an
31
+ # order dependency and want to debug it, you can fix the order by providing
32
+ # the seed, which is printed after each run.
33
+ # --seed 1234
34
+
35
+ config.order = 'random'
36
+
37
+ #suppress_stdouts config
38
+
39
+ LATTICE_PRODUCTS_RESPONSE = IO.read("spec/dummy_data/lattice_products.json") # sample json response
40
+ LATTICE_STORES_RESPONSE = IO.read("spec/dummy_data/lattice_stores.json") # sample json response
41
+ LATTICE_OFFERS_RESPONSE = IO.read("spec/dummy_data/lattice_offers.json") # sample json response
42
+ CATALOG_PRODUCTS_RESPONSE = IO.read("spec/dummy_data/catalog_products.json") # sample json response
43
+ CATALOG_PRODUCT_TYPES_RESPONSE = IO.read("spec/dummy_data/catalog_product_types.json") # sample json response
44
+ CATALOG_STORES_RESPONSE = IO.read("spec/dummy_data/catalog_stores.json") # sample json response
45
+ CATALOG_CATEGORIES_RESPONSE = IO.read("spec/dummy_data/catalog_categories.json") # sample json response
46
+ STORE_PRODUCTS_RESPONSE = IO.read("spec/dummy_data/store_products.json") # sample json response
47
+ end
48
+
49
+
@@ -0,0 +1,7 @@
1
+ shared_examples "arguments mapper returning blank json" do
2
+ it "matches the args and creates a json object that maps the args" do
3
+ res = Cc::Api::Parser::ArgumentsMapper.map args
4
+ expected_res = {}
5
+ res.should eq expected_res
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ shared_examples "arguments mapper returning json with id and skus" do
2
+ it "matches the args and creates a json object that maps the args" do
3
+ res = Cc::Api::Parser::ArgumentsMapper.map args
4
+ expected_res = {id: rand, skus: [rand]}
5
+ res.should eq expected_res
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ shared_examples "arguments mapper returning page params" do
2
+ it "matches the args and creates a json object that maps the args" do
3
+ res = Cc::Api::Parser::ArgumentsMapper.map args
4
+ expected_res = { :page => 1 }
5
+ res.should eq expected_res
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ shared_examples "arguments parser returning expected result" do
2
+ it "returns json object when arguments are valid" do
3
+ res = Cc::Api::Parser::ArgumentsParser.parse args
4
+ res.should eq expected_result
5
+ end
6
+ end
@@ -0,0 +1,43 @@
1
+ shared_examples "json parser" do
2
+ it "returns json object when arguments are valid" do
3
+ json = JSON.parse(json_response)
4
+ target = Cc::Api::Parser::ArgumentsMapper.get_target_key_chain action
5
+
6
+ array = Cc::Api::Util::KeyChainsGetter.get_target_array json, target, product_id
7
+
8
+ result = Cc::Api::Parser::JsonParser.vanilla_reduce array, chosen_columns
9
+
10
+ chosen_columns.each do |chosen_column|
11
+ result.first[chosen_column].should_not eq nil
12
+ end
13
+ end
14
+
15
+ it "returns blank array if json response is blank" do
16
+ json = JSON.parse(blank_json_response)
17
+ target = Cc::Api::Parser::ArgumentsMapper.get_target_key_chain action
18
+ array = Cc::Api::Util::KeyChainsGetter.get_target_array json, target
19
+
20
+ result = Cc::Api::Parser::JsonParser.vanilla_reduce array, chosen_columns
21
+
22
+ result.should eq []
23
+ end
24
+
25
+ it "returns blank array if json response is nil" do
26
+ json = nil
27
+ target = Cc::Api::Parser::ArgumentsMapper.get_target_key_chain action
28
+ array = Cc::Api::Util::KeyChainsGetter.get_target_array json, target
29
+
30
+ result = Cc::Api::Parser::JsonParser.vanilla_reduce array, chosen_columns
31
+
32
+ result.should eq []
33
+ end
34
+
35
+ it "throws exception whenever chosen_columns are not valid" do
36
+ json = nil
37
+ target = Cc::Api::Parser::ArgumentsMapper.get_target_key_chain action
38
+ array = Cc::Api::Util::KeyChainsGetter.get_target_array json, target
39
+
40
+ result = Cc::Api::Parser::JsonParser.vanilla_reduce array, ["invalid", "columns"]
41
+ end
42
+
43
+ end