itunes_store_transporter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ require "spec_helper"
2
+
3
+ describe ITunes::Store::Transporter::TransporterMessage do
4
+ subject { ITunes::Store::Transporter::TransporterMessage.new("some message", 1) }
5
+ its(:code) { should == 1 }
6
+ its(:message) { should == "some message" }
7
+
8
+ describe "#to_s" do
9
+ it "includes the code and message" do
10
+ subject.to_s.should == "some message (1)"
11
+ end
12
+ end
13
+
14
+ describe "error predicate methods" do
15
+ method_codes = {
16
+ :bad_data? => [3000, 3999],
17
+ :invalid_data? => [4000, 4999],
18
+ :missing_data? => [5000, 5999],
19
+ :unsupported_feature? => [6000, 6999],
20
+ :schema_error? => [8000, 8999],
21
+ :asset_error? => [9000, 9999]
22
+ }
23
+
24
+ method_codes.each do |method, codes|
25
+ [codes.first, codes.last].each do |code|
26
+
27
+ context "code #{code}" do
28
+ subject { described_class.new("", code) }
29
+ its(method) { should be_true }
30
+ its(:validation_error?) { should be_true }
31
+
32
+ (method_codes.keys - [method]).each do |other|
33
+ its(other) { should be_false }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ describe ITunes::Store::Transporter::ExecutionError do
42
+ subject { described_class.new(messages, 1) }
43
+ let(:messages) { 2.times.inject([]) { |err, i| err << ITunes::Store::Transporter::TransporterMessage.new("message #{i}", i) } }
44
+ its(:exitstatus) { should == 1 }
45
+ its(:errors) { should == messages }
46
+
47
+ describe "#to_s" do
48
+ it "includes each messages and its code" do
49
+ subject.to_s.should == "message 0 (0), message 1 (1)"
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,71 @@
1
+ require "spec_helper"
2
+
3
+ describe ITunes::Store::Transporter::OutputParser do
4
+ describe "parsing errors" do
5
+ # TODO: test various error message/code formats handled by the parser
6
+
7
+ context "without an error code" do
8
+ before(:all) { @parser = described_class.new(fixture("errors_and_warnings.no_error_number")) }
9
+
10
+ subject { @parser }
11
+ its(:warnings) { should be_empty }
12
+ its(:errors) { should have(2).items }
13
+
14
+ describe "the first error" do
15
+ subject { @parser.errors.first }
16
+ its(:code) { should be_nil }
17
+ its(:message) { should == "An error occurred while doing fun stuff" }
18
+ end
19
+
20
+ describe "the second error" do
21
+ subject { @parser.errors.last }
22
+ its(:code) { should be_nil }
23
+ its(:message) { should == "An exception has occurred: network timeout" }
24
+ end
25
+ end
26
+
27
+ context "with an error code" do
28
+ before(:all) { @parser = described_class.new(fixture("errors_and_warnings.with_error_number")) }
29
+
30
+ subject { @parser }
31
+ its(:warnings) { should be_empty }
32
+ its(:errors) { should have(2).items }
33
+
34
+
35
+ describe "the first error" do
36
+ subject { @parser.errors.first }
37
+ its(:code) { should == 4000 }
38
+ its(:message) { should == "This is error 4000" }
39
+ end
40
+
41
+ describe "the second error" do
42
+ subject { @parser.errors.last }
43
+ its(:code) { should == 5000 }
44
+ its(:message) { should == "This is error 5000" }
45
+ end
46
+ end
47
+
48
+ context "with duplicate messages" do
49
+ before(:all) { @parser = described_class.new(fixture("errors_and_warnings.duplicate_errors")) }
50
+
51
+ it "does not include duplicates" do
52
+ errors = @parser.errors.map { |e| e.message }
53
+ errors.should == ["Error 1", "Error 2", "Error 3"]
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "parsing warnings" do
59
+ before(:all) { @parser = described_class.new(fixture("errors_and_warnings.single_warning")) }
60
+
61
+ subject { @parser }
62
+ its(:errors) { should be_empty }
63
+ its(:warnings) { should have(1).item }
64
+
65
+ describe "the warning" do
66
+ subject { @parser.warnings.first }
67
+ its(:code) { should == 4010 }
68
+ its(:message) { should == "You've been warned!" }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,52 @@
1
+ require "spec_helper"
2
+ require "rbconfig"
3
+
4
+ describe ITunes::Store::Transporter::Shell do
5
+ it "yields stdout and stderr as they become available" do
6
+ ruby = File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["ruby_install_name"])
7
+ temp = Tempfile.new ""
8
+ # sleep else poll() (select) can favor the 1st FD in the read array, causing the
9
+ # test to fail on some platforms
10
+ temp.write(<<-CODE)
11
+ $stdout.puts "OUT 1"
12
+ $stdout.flush
13
+ sleep 1
14
+ $stderr.puts "ERR 1"
15
+ $stderr.flush
16
+ sleep 1
17
+ $stdout.puts "OUT 2"
18
+ $stdout.flush
19
+ sleep 1
20
+ $stderr.puts "ERR 2"
21
+ CODE
22
+
23
+ temp.flush
24
+
25
+ output = []
26
+ expect = [ [ :stdout, "OUT 1" ],
27
+ [ :stderr, "ERR 1" ],
28
+ [ :stdout, "OUT 2" ],
29
+ [ :stderr, "ERR 2" ] ]
30
+
31
+ described_class.new(ruby).exec([temp.path]) do |line, stream|
32
+ output << [ stream, line.chomp! ]
33
+ end
34
+
35
+ output.should == expect
36
+ end
37
+
38
+ context "when on Windows" do
39
+ before(:all) { ENV["PROGRAMFILES"] = "C:\\" }
40
+ it "selects the Windows executable" do
41
+ described_class.stub(:windows? => true)
42
+ described_class.new.path.should match /#{described_class::WINDOWS_EXE}\Z/
43
+ end
44
+ end
45
+
46
+ context "when on anything but Windows" do
47
+ it "selects the right executable" do
48
+ described_class.stub(:windows? => false)
49
+ described_class.new.path.should match /#{described_class::EXE_NAME}\Z/
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,75 @@
1
+ require "rspec"
2
+ require "yaml"
3
+ require "tempfile"
4
+ require "fileutils"
5
+ require "itunes/store/transporter"
6
+
7
+ module SpecHelper
8
+ def create_options(options = {})
9
+ { :username => "uzer",
10
+ :password => "_Gcod3" }.merge(options)
11
+ end
12
+
13
+ # TODO: options for package contents?
14
+ def create_package(options = {})
15
+ Dir.mktmpdir ["",".itmsp"]
16
+ end
17
+
18
+ def expect_shell_args(*expected)
19
+ ITunes::Store::Transporter::Shell.any_instance.stub(:exec) { |*arg| arg.first.should include(*expected) }
20
+ end
21
+
22
+ def fixture(path)
23
+ Fixture.for(path)
24
+ end
25
+
26
+ # Set up output streams and exit code
27
+ def mock_output(options = {})
28
+ outputs = []
29
+ exitcode = options[:exit] || 0
30
+
31
+ # Load a fixture for the given stream
32
+ [:stderr, :stdout].each do |fd|
33
+ fixture = options[fd]
34
+ next unless fixture
35
+ lines = Array === fixture ? fixture : Fixture.for(fixture)
36
+ outputs << [ lines, fd ]
37
+ end
38
+
39
+ ITunes::Store::Transporter::Shell.any_instance.stub(:exec) do |*options|
40
+ block = options.pop
41
+ outputs.each do |lines, fd|
42
+ lines.each { |line| block.call(line, fd) }
43
+ end
44
+ exitcode
45
+ end
46
+ end
47
+
48
+ module Fixture
49
+ class << self
50
+ def for(path)
51
+ type, name = path.split ".", 2
52
+ raise "Unknown fixture '#{path}'" unless fixtures[type].include?(name)
53
+ fixtures[type][name].split("\n")
54
+ end
55
+
56
+ private
57
+ def fixtures
58
+ @fixtures ||= load_fixtures
59
+ end
60
+
61
+ def load_fixtures
62
+ init = Hash.new { |h, k| h[k] = {} }
63
+ Dir[File.join(File.expand_path(File.dirname(__FILE__)), "fixtures", "*.yml")].inject(init) do |fixtures, path|
64
+ name = File.basename(path, ".yml")
65
+ fixtures[name] = YAML.load_file(path)
66
+ fixtures
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ RSpec.configure do |config|
74
+ config.include(SpecHelper)
75
+ end
@@ -0,0 +1,106 @@
1
+ require "spec_helper"
2
+ require "itunes/store/transporter"
3
+
4
+ shared_examples_for "a transporter method" do
5
+ it "uses the default options" do
6
+ defaults = create_options
7
+ config = {
8
+ :path => "/",
9
+ :print_stderr => true,
10
+ :print_stdout => true
11
+ }
12
+
13
+ s = stub(command)
14
+ s.should_receive(:run)
15
+
16
+ klass = ITunes::Store::Transporter::Command.const_get(command)
17
+ klass.should_receive(:new).with(config, defaults).and_return(s)
18
+
19
+ described_class.new(config.merge(defaults)).send(method, options)
20
+ end
21
+ end
22
+
23
+ shared_examples_for "a transporter method without a package argument" do
24
+ it_behaves_like "a transporter method"
25
+
26
+ it "executes the underlying command" do
27
+ ITunes::Store::Transporter::Command.const_get(command).any_instance.should_receive(:run).with(options)
28
+ subject.send(method, options)
29
+ end
30
+ end
31
+
32
+ shared_examples_for "a transporter method with a package argument" do
33
+ it_behaves_like "a transporter method"
34
+
35
+ it "executes the underlying command" do
36
+ ITunes::Store::Transporter::Command.const_get(command).any_instance.should_receive(:run).with(:package => "package.itmsp")
37
+ subject.send(method, "package.itmsp")
38
+ end
39
+ end
40
+
41
+
42
+ describe ITunes::Store::Transporter do
43
+ let(:options) { {} }
44
+
45
+ describe "#new" do
46
+ context "when the options are not a Hash or nil" do
47
+ it "raises an ArgumentError" do
48
+ lambda { described_class.new(123) }.should raise_exception(ArgumentError, /must be/)
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "#lookup" do
54
+ let(:method) { :lookup }
55
+ let(:command) { "Lookup" }
56
+
57
+ it_behaves_like "a transporter method without a package argument"
58
+
59
+ it "executes the underlying command" do
60
+ ITunes::Store::Transporter::Command::Lookup.any_instance.should_receive(:run)
61
+ subject.lookup
62
+ end
63
+ end
64
+
65
+ describe "#providers" do
66
+ let(:method) { :providers }
67
+ let(:command) { "Providers" }
68
+
69
+ it_behaves_like "a transporter method without a package argument"
70
+ end
71
+
72
+ describe "#schema" do
73
+ let(:method) { :schema }
74
+ let(:command) { "Schema" }
75
+
76
+ it_behaves_like "a transporter method without a package argument"
77
+ end
78
+
79
+ describe "#status" do
80
+ let(:method) { :status }
81
+ let(:command) { "Status" }
82
+
83
+ it_behaves_like "a transporter method without a package argument"
84
+ end
85
+
86
+ describe "#upload" do
87
+ let(:method) { :upload }
88
+ let(:command) { "Upload" }
89
+
90
+ it_behaves_like "a transporter method with a package argument"
91
+ end
92
+
93
+ describe "#verify" do
94
+ let(:method) { :verify }
95
+ let(:command) { "Verify" }
96
+
97
+ it_behaves_like "a transporter method with a package argument"
98
+ end
99
+
100
+ describe "#version" do
101
+ let(:method) { :version }
102
+ let(:command) { "Version" }
103
+
104
+ it_behaves_like "a transporter method without a package argument"
105
+ end
106
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: itunes_store_transporter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Skye Shaw
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-10 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: childprocess
16
+ requirement: &70193863731280 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.3.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70193863731280
25
+ - !ruby/object:Gem::Dependency
26
+ name: optout
27
+ requirement: &70193863730780 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.0.2
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70193863730780
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &70193863730320 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.9.2
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70193863730320
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: &70193863729860 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 2.8.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70193863729860
58
+ description: ! " iTunes::Store::Transporter is a wrapper around Apple's iTMSTransporter
59
+ program. It allows you to upload packages to the \n Apple Store, validate them,
60
+ retrieve status information, lookup metadata, and more!\n"
61
+ email: sshaw@lucas.cis.temple.edu
62
+ executables:
63
+ - itms
64
+ extensions: []
65
+ extra_rdoc_files:
66
+ - README.rdoc
67
+ files:
68
+ - lib/itunes/store/transporter/command/lookup.rb
69
+ - lib/itunes/store/transporter/command/option.rb
70
+ - lib/itunes/store/transporter/command/providers.rb
71
+ - lib/itunes/store/transporter/command/schema.rb
72
+ - lib/itunes/store/transporter/command/status.rb
73
+ - lib/itunes/store/transporter/command/upload.rb
74
+ - lib/itunes/store/transporter/command/verify.rb
75
+ - lib/itunes/store/transporter/command/version.rb
76
+ - lib/itunes/store/transporter/command.rb
77
+ - lib/itunes/store/transporter/errors.rb
78
+ - lib/itunes/store/transporter/output_parser.rb
79
+ - lib/itunes/store/transporter/shell.rb
80
+ - lib/itunes/store/transporter/version.rb
81
+ - lib/itunes/store/transporter.rb
82
+ - README.rdoc
83
+ - spec/command_spec.rb
84
+ - spec/errors_spec.rb
85
+ - spec/output_parser_spec.rb
86
+ - spec/shell_spec.rb
87
+ - spec/spec_helper.rb
88
+ - spec/transporter_spec.rb
89
+ - bin/itms
90
+ homepage: http://github.com/sshaw/itunes_store_transporter
91
+ licenses:
92
+ - MIT
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 1.8.10
112
+ signing_key:
113
+ specification_version: 3
114
+ summary: Upload and manage your assets in the iTunes Store using the iTunes Store's
115
+ Transporter (iTMSTransporter).
116
+ test_files:
117
+ - spec/command_spec.rb
118
+ - spec/errors_spec.rb
119
+ - spec/output_parser_spec.rb
120
+ - spec/shell_spec.rb
121
+ - spec/spec_helper.rb
122
+ - spec/transporter_spec.rb
123
+ has_rdoc: