leantesting 1.0.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.
- checksums.yaml +7 -0
- data/Gemfile +9 -0
- data/LICENSE +10 -0
- data/README.md +348 -0
- data/Rakefile +9 -0
- data/leantesting.gemspec +20 -0
- data/lib/BaseClass/APIRequest.rb +195 -0
- data/lib/BaseClass/Entity.rb +33 -0
- data/lib/BaseClass/EntityHandler.rb +183 -0
- data/lib/BaseClass/EntityList.rb +188 -0
- data/lib/Entity/Bug/Bug.rb +11 -0
- data/lib/Entity/Bug/BugAttachment.rb +7 -0
- data/lib/Entity/Bug/BugComment.rb +7 -0
- data/lib/Entity/Platform/PlatformBrowser.rb +10 -0
- data/lib/Entity/Platform/PlatformBrowserVersion.rb +7 -0
- data/lib/Entity/Platform/PlatformDevice.rb +7 -0
- data/lib/Entity/Platform/PlatformOS.rb +10 -0
- data/lib/Entity/Platform/PlatformOSVersion.rb +7 -0
- data/lib/Entity/Platform/PlatformType.rb +10 -0
- data/lib/Entity/Project/Project.rb +27 -0
- data/lib/Entity/Project/ProjectBugScheme.rb +7 -0
- data/lib/Entity/Project/ProjectSection.rb +7 -0
- data/lib/Entity/Project/ProjectUser.rb +7 -0
- data/lib/Entity/Project/ProjectVersion.rb +7 -0
- data/lib/Entity/User/UserOrganization.rb +7 -0
- data/lib/Exception/BaseException/SDKException.rb +19 -0
- data/lib/Exception/SDKBadJSONResponseException.rb +15 -0
- data/lib/Exception/SDKDuplicateRequestException.rb +19 -0
- data/lib/Exception/SDKErrorResponseException.rb +13 -0
- data/lib/Exception/SDKIncompleteRequestException.rb +19 -0
- data/lib/Exception/SDKInvalidArgException.rb +15 -0
- data/lib/Exception/SDKMissingArgException.rb +15 -0
- data/lib/Exception/SDKUnexpectedResponseException.rb +15 -0
- data/lib/Exception/SDKUnsupportedRequestException.rb +19 -0
- data/lib/Handler/Attachment/AttachmentsHandler.rb +17 -0
- data/lib/Handler/Auth/OAuth2Handler.rb +118 -0
- data/lib/Handler/Bug/BugAttachmentsHandler.rb +51 -0
- data/lib/Handler/Bug/BugCommentsHandler.rb +20 -0
- data/lib/Handler/Bug/BugsHandler.rb +57 -0
- data/lib/Handler/Platform/PlatformBrowserVersionsHandler.rb +20 -0
- data/lib/Handler/Platform/PlatformBrowsersHandler.rb +23 -0
- data/lib/Handler/Platform/PlatformDevicesHandler.rb +10 -0
- data/lib/Handler/Platform/PlatformHandler.rb +22 -0
- data/lib/Handler/Platform/PlatformOSHandler.rb +23 -0
- data/lib/Handler/Platform/PlatformOSVersionsHandler.rb +20 -0
- data/lib/Handler/Platform/PlatformTypeDevicesHandler.rb +20 -0
- data/lib/Handler/Platform/PlatformTypesHandler.rb +21 -0
- data/lib/Handler/Project/ProjectBugReproducibilitySchemeHandler.rb +20 -0
- data/lib/Handler/Project/ProjectBugSeveritySchemeHandler.rb +20 -0
- data/lib/Handler/Project/ProjectBugStatusSchemeHandler.rb +20 -0
- data/lib/Handler/Project/ProjectBugTypeSchemeHandler.rb +20 -0
- data/lib/Handler/Project/ProjectBugsHandler.rb +67 -0
- data/lib/Handler/Project/ProjectSectionsHandler.rb +39 -0
- data/lib/Handler/Project/ProjectUsersHandler.rb +20 -0
- data/lib/Handler/Project/ProjectVersionsHandler.rb +39 -0
- data/lib/Handler/Project/ProjectsHandler.rb +46 -0
- data/lib/Handler/User/UserHandler.rb +14 -0
- data/lib/Handler/User/UserOrganizationsHandler.rb +14 -0
- data/lib/leantesting.rb +65 -0
- data/lib/loader.rb +18 -0
- data/tests/APIRequestTest.rb +152 -0
- data/tests/BaseClassesTest.rb +96 -0
- data/tests/ClientTest.rb +52 -0
- data/tests/EntitiesTest.rb +97 -0
- data/tests/EntityListTest.rb +51 -0
- data/tests/ExceptionsTest.rb +70 -0
- data/tests/HandlersRequestsTest.rb +215 -0
- data/tests/MockRequestsTest.rb +556 -0
- data/tests/OAuth2HandlerTest.rb +75 -0
- data/tests/res/upload_sample.jpg +0 -0
- metadata +169 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
class Project < Entity
|
2
|
+
attr_reader \
|
3
|
+
:sections,
|
4
|
+
:versions,
|
5
|
+
:users,
|
6
|
+
:bugTypeScheme,
|
7
|
+
:bugStatusScheme,
|
8
|
+
:bugSeverityScheme,
|
9
|
+
:bugReproducibilityScheme,
|
10
|
+
:bugs
|
11
|
+
|
12
|
+
def initialize(origin, data)
|
13
|
+
super
|
14
|
+
|
15
|
+
@sections = ProjectSectionsHandler.new(origin, data['id'])
|
16
|
+
@versions = ProjectVersionsHandler.new(origin, data['id'])
|
17
|
+
@users = ProjectUsersHandler.new(origin, data['id'])
|
18
|
+
|
19
|
+
@bugTypeScheme = ProjectBugTypeSchemeHandler.new(origin, data['id'])
|
20
|
+
@bugStatusScheme = ProjectBugStatusSchemeHandler.new(origin, data['id'])
|
21
|
+
@bugSeverityScheme = ProjectBugSeveritySchemeHandler.new(origin, data['id'])
|
22
|
+
@bugReproducibilityScheme = ProjectBugReproducibilitySchemeHandler.new(origin, data['id'])
|
23
|
+
|
24
|
+
@bugs = ProjectBugsHandler.new(origin, data['id'])
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class SDKException < Exception
|
2
|
+
|
3
|
+
def initialize(message = nil)
|
4
|
+
super
|
5
|
+
|
6
|
+
if !message
|
7
|
+
message = 'Unknown SDK Error'
|
8
|
+
else
|
9
|
+
message = 'SDK Error: ' + message
|
10
|
+
end
|
11
|
+
|
12
|
+
@message = message
|
13
|
+
end
|
14
|
+
|
15
|
+
def message
|
16
|
+
@message
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class SDKBadJSONResponseException < SDKException
|
2
|
+
|
3
|
+
def initialize(message = nil)
|
4
|
+
@baseMessage = 'JSON remote response is inconsistent or invalid'
|
5
|
+
|
6
|
+
if !message
|
7
|
+
message = @baseMessage
|
8
|
+
else
|
9
|
+
message = @baseMessage + ' - ' + message
|
10
|
+
end
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class SDKDuplicateRequestException < SDKException
|
2
|
+
|
3
|
+
def initialize(message = nil)
|
4
|
+
@baseMessage = 'Duplicate request data'
|
5
|
+
|
6
|
+
if message.is_a? Array
|
7
|
+
message = message.map{ |el| '`' + el + '`' }.join(', ')
|
8
|
+
end
|
9
|
+
|
10
|
+
if !message
|
11
|
+
message = @baseMessage
|
12
|
+
else
|
13
|
+
message = @baseMessage + ' - multiple ' + message
|
14
|
+
end
|
15
|
+
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class SDKIncompleteRequestException < SDKException
|
2
|
+
|
3
|
+
def initialize(message = nil)
|
4
|
+
@baseMessage = 'Incomplete request data'
|
5
|
+
|
6
|
+
if message.is_a? Array
|
7
|
+
message = message.map{ |el| '`' + el + '`' }.join(', ')
|
8
|
+
end
|
9
|
+
|
10
|
+
if !message
|
11
|
+
message = @baseMessage
|
12
|
+
else
|
13
|
+
message = @baseMessage + ' - missing required ' + message
|
14
|
+
end
|
15
|
+
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class SDKUnexpectedResponseException < SDKException
|
2
|
+
|
3
|
+
def initialize(message = nil)
|
4
|
+
@baseMessage = 'Got unexpected remote response'
|
5
|
+
|
6
|
+
if !message
|
7
|
+
message = @baseMessage
|
8
|
+
else
|
9
|
+
message = @baseMessage + ' - ' + message
|
10
|
+
end
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class SDKUnsupportedRequestException < SDKException
|
2
|
+
|
3
|
+
def initialize(message = nil)
|
4
|
+
@baseMessage = 'Unsupported request data'
|
5
|
+
|
6
|
+
if message.is_a? Array
|
7
|
+
message = message.map{ |el| '`' + el + '`' }.join(', ')
|
8
|
+
end
|
9
|
+
|
10
|
+
if !message
|
11
|
+
message = @baseMessage
|
12
|
+
else
|
13
|
+
message = @baseMessage + ' - invalid ' + message
|
14
|
+
end
|
15
|
+
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class AttachmentsHandler < EntityHandler
|
2
|
+
|
3
|
+
def find(id)
|
4
|
+
super
|
5
|
+
|
6
|
+
req = APIRequest.new(@origin, '/v1/attachments/' + id.to_s(), 'GET')
|
7
|
+
BugAttachment.new(@origin, req.exec)
|
8
|
+
end
|
9
|
+
|
10
|
+
def delete(id)
|
11
|
+
super
|
12
|
+
|
13
|
+
req = APIRequest.new(@origin, '/v1/attachments/' + id.to_s(), 'DELETE')
|
14
|
+
req.exec
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
#
|
2
|
+
# Handler to manage general authentication routines
|
3
|
+
#
|
4
|
+
# leantesting.com/en/api-docs#oauth-flow
|
5
|
+
#
|
6
|
+
class OAuth2Handler
|
7
|
+
|
8
|
+
#
|
9
|
+
# Constructs an OAuth2Handler instance
|
10
|
+
#
|
11
|
+
# Arguments:
|
12
|
+
# origin Client -- Originating client reference
|
13
|
+
#
|
14
|
+
def initialize(origin)
|
15
|
+
@origin = origin
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Function that generates link for user to follow in order to request authorization code
|
20
|
+
#
|
21
|
+
# Arguments:
|
22
|
+
# clientID String -- client ID given at application registration
|
23
|
+
# redirectURI String -- URL to be redirected to after authorization
|
24
|
+
# scope String -- (optional) comma-separated list of requested scopes (default: 'read')
|
25
|
+
# state String -- (optional) random string for MITM attack prevention
|
26
|
+
#
|
27
|
+
# Exceptions:
|
28
|
+
# SDKInvalidArgException if provided clientID param is not a string
|
29
|
+
# SDKInvalidArgException if provided redirectURI param is not a string
|
30
|
+
# SDKInvalidArgException if provided scope param is not a string
|
31
|
+
# SDKInvalidArgException if provided state param is not a string
|
32
|
+
#
|
33
|
+
# Returns:
|
34
|
+
# String -- returns URL to follow for authorization code request
|
35
|
+
#
|
36
|
+
def generateAuthLink(clientID, redirectURI, scope = 'read', state = nil)
|
37
|
+
if !clientID.is_a? String
|
38
|
+
raise SDKInvalidArgException, '`clientID` must be a string'
|
39
|
+
elsif !redirectURI.is_a? String
|
40
|
+
raise SDKInvalidArgException, '`redirectURI` must be a string'
|
41
|
+
elsif !scope.is_a? String
|
42
|
+
raise SDKInvalidArgException, '`scope` must be a string'
|
43
|
+
elsif state && !state.is_a?(String)
|
44
|
+
raise SDKInvalidArgException, '`state` must be a string'
|
45
|
+
end
|
46
|
+
|
47
|
+
baseURL = 'https://leantesting.com/login/oauth/authorize'
|
48
|
+
|
49
|
+
params = {
|
50
|
+
'client_id' => clientID,
|
51
|
+
'redirect_uri' => redirectURI,
|
52
|
+
'scope' => scope
|
53
|
+
}
|
54
|
+
|
55
|
+
if state
|
56
|
+
params['state'] = state
|
57
|
+
end
|
58
|
+
|
59
|
+
baseURL += '?' + Curl::postalize(params)
|
60
|
+
baseURL
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Generates an access token string from the provided authorization code
|
65
|
+
#
|
66
|
+
# Arguments:
|
67
|
+
# clientID String -- client ID given at application registration
|
68
|
+
# clientSecret String -- client secret given at application registration
|
69
|
+
# grantType String -- oauth specific grant_type value (i.e.: authorization_code)
|
70
|
+
# code String -- authorization code obtained from the generated auth link
|
71
|
+
# redirectURI String -- URL to be redirected to after authorization
|
72
|
+
|
73
|
+
# Exceptions:
|
74
|
+
# SDKInvalidArgException if provided clientID param is not a string
|
75
|
+
# SDKInvalidArgException if provided clientSecret param is not a string
|
76
|
+
# SDKInvalidArgException if provided grantType param is not a string
|
77
|
+
# SDKInvalidArgException if provided code param is not a string
|
78
|
+
# SDKInvalidArgException if provided redirectURI param is not a string
|
79
|
+
#
|
80
|
+
# Returns:
|
81
|
+
# String -- returns obtained access token string
|
82
|
+
#
|
83
|
+
def exchangeAuthCode(clientID, clientSecret, grantType, code, redirectURI)
|
84
|
+
if !clientID.is_a? String
|
85
|
+
raise SDKInvalidArgException, '`clientID` must be a string'
|
86
|
+
elsif !clientSecret.is_a? String
|
87
|
+
raise SDKInvalidArgException, '`clientSecret` must be a string'
|
88
|
+
elsif !grantType.is_a? String
|
89
|
+
raise SDKInvalidArgException, '`grantType` must be a string'
|
90
|
+
elsif !code.is_a? String
|
91
|
+
raise SDKInvalidArgException, '`code` must be a string'
|
92
|
+
elsif !redirectURI.is_a? String
|
93
|
+
raise SDKInvalidArgException, '`redirectURI` must be a string'
|
94
|
+
end
|
95
|
+
|
96
|
+
params = {
|
97
|
+
'grant_type' => grantType,
|
98
|
+
'client_id' => clientID,
|
99
|
+
'client_secret' => clientSecret,
|
100
|
+
'redirect_uri' => redirectURI,
|
101
|
+
'code' => code
|
102
|
+
}
|
103
|
+
|
104
|
+
req = APIRequest.new(
|
105
|
+
@origin,
|
106
|
+
'/login/oauth/access_token',
|
107
|
+
'POST',
|
108
|
+
{
|
109
|
+
'base_uri' => 'https://leantesting.com',
|
110
|
+
'params' => params
|
111
|
+
}
|
112
|
+
)
|
113
|
+
|
114
|
+
resp = req.exec
|
115
|
+
resp['access_token']
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class BugAttachmentsHandler < EntityHandler
|
2
|
+
|
3
|
+
def initialize(origin, bugID)
|
4
|
+
super(origin)
|
5
|
+
|
6
|
+
@bugID = bugID
|
7
|
+
end
|
8
|
+
|
9
|
+
#
|
10
|
+
# Uploads given file as an attachment for specified bug.
|
11
|
+
#
|
12
|
+
# Arguments:
|
13
|
+
# filepath String -- an absolute path of the file to be uploaded
|
14
|
+
# example: /home/path/to/file.txt (Linux), C:\\Users\\Documents\\file.txt (Windows)
|
15
|
+
#
|
16
|
+
# Exceptions:
|
17
|
+
# SDKInvalidArgException if filepath is not a string
|
18
|
+
#
|
19
|
+
# Returns:
|
20
|
+
# BugAttachment -- the newly uploaded attachment
|
21
|
+
#
|
22
|
+
def upload(filepath)
|
23
|
+
if !filepath.is_a? String
|
24
|
+
raise SDKInvalidArgException, '`filepath` must be of type string'
|
25
|
+
end
|
26
|
+
|
27
|
+
req = APIRequest.new(
|
28
|
+
@origin,
|
29
|
+
'/v1/bugs/' + @bugID.to_s() + '/attachments',
|
30
|
+
'POST',
|
31
|
+
{
|
32
|
+
'form_data' => true,
|
33
|
+
'file_path' => filepath
|
34
|
+
}
|
35
|
+
)
|
36
|
+
|
37
|
+
BugAttachment.new(@origin, req.exec)
|
38
|
+
end
|
39
|
+
|
40
|
+
def all(filters = nil)
|
41
|
+
if !filters
|
42
|
+
filters = {}
|
43
|
+
end
|
44
|
+
|
45
|
+
super
|
46
|
+
|
47
|
+
request = APIRequest.new(@origin, '/v1/bugs/' + @bugID.to_s() + '/attachments', 'GET')
|
48
|
+
EntityList.new(@origin, request, BugAttachment, filters)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|