sauce 0.7.2 → 0.8.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.
- data/VERSION +1 -1
- data/bin/sauce +56 -49
- data/lib/sauce.rb +1 -0
- data/lib/sauce/config.rb +6 -0
- data/lib/sauce/connect.rb +58 -0
- data/lib/sauce/integrations.rb +14 -0
- data/spec/other_spec.rb +7 -0
- data/{test → spec}/saucelabs_spec.rb +1 -9
- data/support/sauce_connect +826 -0
- data/support/simplejson/LICENSE.txt +19 -0
- data/support/simplejson/__init__.py +437 -0
- data/support/simplejson/decoder.py +421 -0
- data/support/simplejson/encoder.py +501 -0
- data/support/simplejson/ordered_dict.py +119 -0
- data/support/simplejson/scanner.py +77 -0
- data/support/simplejson/tool.py +39 -0
- data/test/helper.rb +8 -2
- data/test/test_connect.rb +25 -0
- metadata +20 -7
@@ -0,0 +1,119 @@
|
|
1
|
+
"""Drop-in replacement for collections.OrderedDict by Raymond Hettinger
|
2
|
+
|
3
|
+
http://code.activestate.com/recipes/576693/
|
4
|
+
|
5
|
+
"""
|
6
|
+
from UserDict import DictMixin
|
7
|
+
|
8
|
+
# Modified from original to support Python 2.4, see
|
9
|
+
# http://code.google.com/p/simplejson/issues/detail?id=53
|
10
|
+
try:
|
11
|
+
all
|
12
|
+
except NameError:
|
13
|
+
def all(seq):
|
14
|
+
for elem in seq:
|
15
|
+
if not elem:
|
16
|
+
return False
|
17
|
+
return True
|
18
|
+
|
19
|
+
class OrderedDict(dict, DictMixin):
|
20
|
+
|
21
|
+
def __init__(self, *args, **kwds):
|
22
|
+
if len(args) > 1:
|
23
|
+
raise TypeError('expected at most 1 arguments, got %d' % len(args))
|
24
|
+
try:
|
25
|
+
self.__end
|
26
|
+
except AttributeError:
|
27
|
+
self.clear()
|
28
|
+
self.update(*args, **kwds)
|
29
|
+
|
30
|
+
def clear(self):
|
31
|
+
self.__end = end = []
|
32
|
+
end += [None, end, end] # sentinel node for doubly linked list
|
33
|
+
self.__map = {} # key --> [key, prev, next]
|
34
|
+
dict.clear(self)
|
35
|
+
|
36
|
+
def __setitem__(self, key, value):
|
37
|
+
if key not in self:
|
38
|
+
end = self.__end
|
39
|
+
curr = end[1]
|
40
|
+
curr[2] = end[1] = self.__map[key] = [key, curr, end]
|
41
|
+
dict.__setitem__(self, key, value)
|
42
|
+
|
43
|
+
def __delitem__(self, key):
|
44
|
+
dict.__delitem__(self, key)
|
45
|
+
key, prev, next = self.__map.pop(key)
|
46
|
+
prev[2] = next
|
47
|
+
next[1] = prev
|
48
|
+
|
49
|
+
def __iter__(self):
|
50
|
+
end = self.__end
|
51
|
+
curr = end[2]
|
52
|
+
while curr is not end:
|
53
|
+
yield curr[0]
|
54
|
+
curr = curr[2]
|
55
|
+
|
56
|
+
def __reversed__(self):
|
57
|
+
end = self.__end
|
58
|
+
curr = end[1]
|
59
|
+
while curr is not end:
|
60
|
+
yield curr[0]
|
61
|
+
curr = curr[1]
|
62
|
+
|
63
|
+
def popitem(self, last=True):
|
64
|
+
if not self:
|
65
|
+
raise KeyError('dictionary is empty')
|
66
|
+
# Modified from original to support Python 2.4, see
|
67
|
+
# http://code.google.com/p/simplejson/issues/detail?id=53
|
68
|
+
if last:
|
69
|
+
key = reversed(self).next()
|
70
|
+
else:
|
71
|
+
key = iter(self).next()
|
72
|
+
value = self.pop(key)
|
73
|
+
return key, value
|
74
|
+
|
75
|
+
def __reduce__(self):
|
76
|
+
items = [[k, self[k]] for k in self]
|
77
|
+
tmp = self.__map, self.__end
|
78
|
+
del self.__map, self.__end
|
79
|
+
inst_dict = vars(self).copy()
|
80
|
+
self.__map, self.__end = tmp
|
81
|
+
if inst_dict:
|
82
|
+
return (self.__class__, (items,), inst_dict)
|
83
|
+
return self.__class__, (items,)
|
84
|
+
|
85
|
+
def keys(self):
|
86
|
+
return list(self)
|
87
|
+
|
88
|
+
setdefault = DictMixin.setdefault
|
89
|
+
update = DictMixin.update
|
90
|
+
pop = DictMixin.pop
|
91
|
+
values = DictMixin.values
|
92
|
+
items = DictMixin.items
|
93
|
+
iterkeys = DictMixin.iterkeys
|
94
|
+
itervalues = DictMixin.itervalues
|
95
|
+
iteritems = DictMixin.iteritems
|
96
|
+
|
97
|
+
def __repr__(self):
|
98
|
+
if not self:
|
99
|
+
return '%s()' % (self.__class__.__name__,)
|
100
|
+
return '%s(%r)' % (self.__class__.__name__, self.items())
|
101
|
+
|
102
|
+
def copy(self):
|
103
|
+
return self.__class__(self)
|
104
|
+
|
105
|
+
@classmethod
|
106
|
+
def fromkeys(cls, iterable, value=None):
|
107
|
+
d = cls()
|
108
|
+
for key in iterable:
|
109
|
+
d[key] = value
|
110
|
+
return d
|
111
|
+
|
112
|
+
def __eq__(self, other):
|
113
|
+
if isinstance(other, OrderedDict):
|
114
|
+
return len(self)==len(other) and \
|
115
|
+
all(p==q for p, q in zip(self.items(), other.items()))
|
116
|
+
return dict.__eq__(self, other)
|
117
|
+
|
118
|
+
def __ne__(self, other):
|
119
|
+
return not self == other
|
@@ -0,0 +1,77 @@
|
|
1
|
+
"""JSON token scanner
|
2
|
+
"""
|
3
|
+
import re
|
4
|
+
def _import_c_make_scanner():
|
5
|
+
try:
|
6
|
+
from simplejson._speedups import make_scanner
|
7
|
+
return make_scanner
|
8
|
+
except ImportError:
|
9
|
+
return None
|
10
|
+
c_make_scanner = _import_c_make_scanner()
|
11
|
+
|
12
|
+
__all__ = ['make_scanner']
|
13
|
+
|
14
|
+
NUMBER_RE = re.compile(
|
15
|
+
r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?',
|
16
|
+
(re.VERBOSE | re.MULTILINE | re.DOTALL))
|
17
|
+
|
18
|
+
def py_make_scanner(context):
|
19
|
+
parse_object = context.parse_object
|
20
|
+
parse_array = context.parse_array
|
21
|
+
parse_string = context.parse_string
|
22
|
+
match_number = NUMBER_RE.match
|
23
|
+
encoding = context.encoding
|
24
|
+
strict = context.strict
|
25
|
+
parse_float = context.parse_float
|
26
|
+
parse_int = context.parse_int
|
27
|
+
parse_constant = context.parse_constant
|
28
|
+
object_hook = context.object_hook
|
29
|
+
object_pairs_hook = context.object_pairs_hook
|
30
|
+
memo = context.memo
|
31
|
+
|
32
|
+
def _scan_once(string, idx):
|
33
|
+
try:
|
34
|
+
nextchar = string[idx]
|
35
|
+
except IndexError:
|
36
|
+
raise StopIteration
|
37
|
+
|
38
|
+
if nextchar == '"':
|
39
|
+
return parse_string(string, idx + 1, encoding, strict)
|
40
|
+
elif nextchar == '{':
|
41
|
+
return parse_object((string, idx + 1), encoding, strict,
|
42
|
+
_scan_once, object_hook, object_pairs_hook, memo)
|
43
|
+
elif nextchar == '[':
|
44
|
+
return parse_array((string, idx + 1), _scan_once)
|
45
|
+
elif nextchar == 'n' and string[idx:idx + 4] == 'null':
|
46
|
+
return None, idx + 4
|
47
|
+
elif nextchar == 't' and string[idx:idx + 4] == 'true':
|
48
|
+
return True, idx + 4
|
49
|
+
elif nextchar == 'f' and string[idx:idx + 5] == 'false':
|
50
|
+
return False, idx + 5
|
51
|
+
|
52
|
+
m = match_number(string, idx)
|
53
|
+
if m is not None:
|
54
|
+
integer, frac, exp = m.groups()
|
55
|
+
if frac or exp:
|
56
|
+
res = parse_float(integer + (frac or '') + (exp or ''))
|
57
|
+
else:
|
58
|
+
res = parse_int(integer)
|
59
|
+
return res, m.end()
|
60
|
+
elif nextchar == 'N' and string[idx:idx + 3] == 'NaN':
|
61
|
+
return parse_constant('NaN'), idx + 3
|
62
|
+
elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity':
|
63
|
+
return parse_constant('Infinity'), idx + 8
|
64
|
+
elif nextchar == '-' and string[idx:idx + 9] == '-Infinity':
|
65
|
+
return parse_constant('-Infinity'), idx + 9
|
66
|
+
else:
|
67
|
+
raise StopIteration
|
68
|
+
|
69
|
+
def scan_once(string, idx):
|
70
|
+
try:
|
71
|
+
return _scan_once(string, idx)
|
72
|
+
finally:
|
73
|
+
memo.clear()
|
74
|
+
|
75
|
+
return scan_once
|
76
|
+
|
77
|
+
make_scanner = c_make_scanner or py_make_scanner
|
@@ -0,0 +1,39 @@
|
|
1
|
+
r"""Command-line tool to validate and pretty-print JSON
|
2
|
+
|
3
|
+
Usage::
|
4
|
+
|
5
|
+
$ echo '{"json":"obj"}' | python -m simplejson.tool
|
6
|
+
{
|
7
|
+
"json": "obj"
|
8
|
+
}
|
9
|
+
$ echo '{ 1.2:3.4}' | python -m simplejson.tool
|
10
|
+
Expecting property name: line 1 column 2 (char 2)
|
11
|
+
|
12
|
+
"""
|
13
|
+
import sys
|
14
|
+
import simplejson as json
|
15
|
+
|
16
|
+
def main():
|
17
|
+
if len(sys.argv) == 1:
|
18
|
+
infile = sys.stdin
|
19
|
+
outfile = sys.stdout
|
20
|
+
elif len(sys.argv) == 2:
|
21
|
+
infile = open(sys.argv[1], 'rb')
|
22
|
+
outfile = sys.stdout
|
23
|
+
elif len(sys.argv) == 3:
|
24
|
+
infile = open(sys.argv[1], 'rb')
|
25
|
+
outfile = open(sys.argv[2], 'wb')
|
26
|
+
else:
|
27
|
+
raise SystemExit(sys.argv[0] + " [infile [outfile]]")
|
28
|
+
try:
|
29
|
+
obj = json.load(infile,
|
30
|
+
object_pairs_hook=json.OrderedDict,
|
31
|
+
use_decimal=True)
|
32
|
+
except ValueError, e:
|
33
|
+
raise SystemExit(e)
|
34
|
+
json.dump(obj, outfile, sort_keys=True, indent=' ', use_decimal=True)
|
35
|
+
outfile.write('\n')
|
36
|
+
|
37
|
+
|
38
|
+
if __name__ == '__main__':
|
39
|
+
main()
|
data/test/helper.rb
CHANGED
@@ -8,6 +8,12 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
8
8
|
require 'sauce'
|
9
9
|
|
10
10
|
Sauce.config do |config|
|
11
|
-
config.browsers = [
|
12
|
-
|
11
|
+
config.browsers = [
|
12
|
+
["Windows 2003", "firefox", "3.6."],
|
13
|
+
["Windows 2003", "safariproxy", "5."]
|
14
|
+
]
|
15
|
+
config.browser_url = "http://saucelabs.com"
|
16
|
+
|
17
|
+
#config.application_host = "localhost"
|
18
|
+
#config.application_port = "4444"
|
13
19
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestConnect < Test::Unit::TestCase
|
4
|
+
context "Sauce Connect" do
|
5
|
+
should "be running when ready" do
|
6
|
+
connect = Sauce::Connect.new(:host => "saucelabs.com", :port => 80)
|
7
|
+
assert_equal "uninitialized", connect.status
|
8
|
+
connect.wait_until_ready
|
9
|
+
assert_equal "running", connect.status
|
10
|
+
connect.status.should == "running"
|
11
|
+
connect.disconnect
|
12
|
+
end
|
13
|
+
|
14
|
+
should "set error flag if things don't go well" do
|
15
|
+
connect = Sauce::Connect.new(:host => "saucelabs.com", :port => 80, :username => 'fail')
|
16
|
+
start = Time.now
|
17
|
+
while Time.now-start < 20 && !connect.error
|
18
|
+
sleep 1
|
19
|
+
end
|
20
|
+
|
21
|
+
assert connect.error
|
22
|
+
connect.disconnect
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sauce
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 63
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 8
|
9
|
+
- 0
|
10
|
+
version: 0.8.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Sean Grove
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-10-
|
19
|
+
date: 2010-10-26 00:00:00 -07:00
|
20
20
|
default_executable: sauce
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -143,15 +143,26 @@ files:
|
|
143
143
|
- lib/sauce.rb
|
144
144
|
- lib/sauce/client.rb
|
145
145
|
- lib/sauce/config.rb
|
146
|
+
- lib/sauce/connect.rb
|
146
147
|
- lib/sauce/gateway_ext.rb
|
147
148
|
- lib/sauce/heroku.rb
|
148
149
|
- lib/sauce/integrations.rb
|
149
150
|
- lib/sauce/job.rb
|
150
151
|
- lib/sauce/selenium.rb
|
151
152
|
- lib/sauce/tunnel.rb
|
153
|
+
- spec/other_spec.rb
|
154
|
+
- spec/saucelabs_spec.rb
|
155
|
+
- support/sauce_connect
|
156
|
+
- support/simplejson/LICENSE.txt
|
157
|
+
- support/simplejson/__init__.py
|
158
|
+
- support/simplejson/decoder.py
|
159
|
+
- support/simplejson/encoder.py
|
160
|
+
- support/simplejson/ordered_dict.py
|
161
|
+
- support/simplejson/scanner.py
|
162
|
+
- support/simplejson/tool.py
|
152
163
|
- test/helper.rb
|
153
|
-
- test/saucelabs_spec.rb
|
154
164
|
- test/test_config.rb
|
165
|
+
- test/test_connect.rb
|
155
166
|
- test/test_jobs.rb
|
156
167
|
- test/test_selenium.rb
|
157
168
|
- test/test_tunnels.rb
|
@@ -190,9 +201,11 @@ signing_key:
|
|
190
201
|
specification_version: 3
|
191
202
|
summary: Ruby access to Sauce Labs' features
|
192
203
|
test_files:
|
204
|
+
- spec/other_spec.rb
|
205
|
+
- spec/saucelabs_spec.rb
|
193
206
|
- test/helper.rb
|
194
|
-
- test/saucelabs_spec.rb
|
195
207
|
- test/test_config.rb
|
208
|
+
- test/test_connect.rb
|
196
209
|
- test/test_jobs.rb
|
197
210
|
- test/test_selenium.rb
|
198
211
|
- test/test_tunnels.rb
|