cc-cli 0.0.1

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.
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