Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
gitlab-ce
Commits
b6f2f738
Commit
b6f2f738
authored
Oct 17, 2018
by
Rémy Coutable
Committed by
Douglas Barbosa Alexandre
Oct 17, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
First iteration to allow creating QA resources using the API
parent
ab9cf561
Changes
34
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
1246 additions
and
205 deletions
+1246
-205
qa/qa.rb
qa/qa.rb
+1
-0
qa/qa/factory/README.md
qa/qa/factory/README.md
+476
-0
qa/qa/factory/api_fabricator.rb
qa/qa/factory/api_fabricator.rb
+97
-0
qa/qa/factory/base.rb
qa/qa/factory/base.rb
+68
-13
qa/qa/factory/dependency.rb
qa/qa/factory/dependency.rb
+10
-21
qa/qa/factory/product.rb
qa/qa/factory/product.rb
+30
-10
qa/qa/factory/repository/project_push.rb
qa/qa/factory/repository/project_push.rb
+2
-7
qa/qa/factory/resource/fork.rb
qa/qa/factory/resource/fork.rb
+1
-1
qa/qa/factory/resource/group.rb
qa/qa/factory/resource/group.rb
+27
-0
qa/qa/factory/resource/issue.rb
qa/qa/factory/resource/issue.rb
+3
-4
qa/qa/factory/resource/merge_request.rb
qa/qa/factory/resource/merge_request.rb
+2
-7
qa/qa/factory/resource/project.rb
qa/qa/factory/resource/project.rb
+29
-4
qa/qa/factory/resource/project_imported_from_github.rb
qa/qa/factory/resource/project_imported_from_github.rb
+1
-3
qa/qa/factory/resource/project_milestone.rb
qa/qa/factory/resource/project_milestone.rb
+1
-1
qa/qa/factory/resource/sandbox.rb
qa/qa/factory/resource/sandbox.rb
+33
-4
qa/qa/factory/resource/ssh_key.rb
qa/qa/factory/resource/ssh_key.rb
+3
-11
qa/qa/factory/resource/user.rb
qa/qa/factory/resource/user.rb
+4
-4
qa/qa/factory/resource/wiki.rb
qa/qa/factory/resource/wiki.rb
+10
-7
qa/qa/page/README.md
qa/qa/page/README.md
+1
-1
qa/qa/runtime/api/client.rb
qa/qa/runtime/api/client.rb
+15
-14
qa/qa/runtime/env.rb
qa/qa/runtime/env.rb
+8
-2
qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb
...es/browser_ui/1_manage/project/add_project_member_spec.rb
+2
-1
qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
...atures/browser_ui/1_manage/project/create_project_spec.rb
+2
-4
qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
...er_ui/3_create/merge_request/rebase_merge_request_spec.rb
+1
-0
qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb
...ecs/features/browser_ui/3_create/repository/clone_spec.rb
+2
-1
qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
...res/browser_ui/3_create/web_ide/add_file_template_spec.rb
+1
-0
qa/spec/factory/api_fabricator_spec.rb
qa/spec/factory/api_fabricator_spec.rb
+161
-0
qa/spec/factory/base_spec.rb
qa/spec/factory/base_spec.rb
+102
-47
qa/spec/factory/dependency_spec.rb
qa/spec/factory/dependency_spec.rb
+15
-8
qa/spec/factory/product_spec.rb
qa/spec/factory/product_spec.rb
+58
-16
qa/spec/runtime/api/client_spec.rb
qa/spec/runtime/api/client_spec.rb
+17
-8
qa/spec/runtime/api/request_spec.rb
qa/spec/runtime/api/request_spec.rb
+12
-6
qa/spec/runtime/api_request_spec.rb
qa/spec/runtime/api_request_spec.rb
+0
-0
qa/spec/runtime/env_spec.rb
qa/spec/runtime/env_spec.rb
+51
-0
No files found.
qa/qa.rb
View file @
b6f2f738
...
@@ -36,6 +36,7 @@ module QA
...
@@ -36,6 +36,7 @@ module QA
# GitLab QA fabrication mechanisms
# GitLab QA fabrication mechanisms
#
#
module
Factory
module
Factory
autoload
:ApiFabricator
,
'qa/factory/api_fabricator'
autoload
:Base
,
'qa/factory/base'
autoload
:Base
,
'qa/factory/base'
autoload
:Dependency
,
'qa/factory/dependency'
autoload
:Dependency
,
'qa/factory/dependency'
autoload
:Product
,
'qa/factory/product'
autoload
:Product
,
'qa/factory/product'
...
...
qa/qa/factory/README.md
0 → 100644
View file @
b6f2f738
This diff is collapsed.
Click to expand it.
qa/qa/factory/api_fabricator.rb
0 → 100644
View file @
b6f2f738
# frozen_string_literal: true
require
'airborne'
require
'active_support/core_ext/object/deep_dup'
require
'capybara/dsl'
module
QA
module
Factory
module
ApiFabricator
include
Airborne
include
Capybara
::
DSL
HTTP_STATUS_OK
=
200
HTTP_STATUS_CREATED
=
201
ResourceNotFoundError
=
Class
.
new
(
RuntimeError
)
ResourceFabricationFailedError
=
Class
.
new
(
RuntimeError
)
ResourceURLMissingError
=
Class
.
new
(
RuntimeError
)
attr_reader
:api_resource
,
:api_response
def
api_support?
respond_to?
(
:api_get_path
)
&&
respond_to?
(
:api_post_path
)
&&
respond_to?
(
:api_post_body
)
end
def
fabricate_via_api!
unless
api_support?
raise
NotImplementedError
,
"Factory
#{
self
.
class
.
name
}
does not support fabrication via the API!"
end
resource_web_url
(
api_post
)
end
def
eager_load_api_client!
api_client
.
tap
do
|
client
|
# Eager-load the API client so that the personal token creation isn't
# taken in account in the actual resource creation timing.
client
.
personal_access_token
end
end
private
attr_writer
:api_resource
,
:api_response
def
resource_web_url
(
resource
)
resource
.
fetch
(
:web_url
)
do
raise
ResourceURLMissingError
,
"API resource for
#{
self
.
class
.
name
}
does not expose a `web_url` property: `
#{
resource
}
`."
end
end
def
api_get
url
=
Runtime
::
API
::
Request
.
new
(
api_client
,
api_get_path
).
url
response
=
get
(
url
)
unless
response
.
code
==
HTTP_STATUS_OK
raise
ResourceNotFoundError
,
"Resource at
#{
url
}
could not be found (
#{
response
.
code
}
): `
#{
response
}
`."
end
process_api_response
(
parse_body
(
response
))
end
def
api_post
response
=
post
(
Runtime
::
API
::
Request
.
new
(
api_client
,
api_post_path
).
url
,
api_post_body
)
unless
response
.
code
==
HTTP_STATUS_CREATED
raise
ResourceFabricationFailedError
,
"Fabrication of
#{
self
.
class
.
name
}
using the API failed (
#{
response
.
code
}
) with `
#{
response
}
`."
end
process_api_response
(
parse_body
(
response
))
end
def
api_client
@api_client
||=
begin
Runtime
::
API
::
Client
.
new
(
:gitlab
,
is_new_session:
!
current_url
.
start_with?
(
'http'
))
end
end
def
parse_body
(
response
)
JSON
.
parse
(
response
.
body
,
symbolize_names:
true
)
end
def
process_api_response
(
parsed_response
)
self
.
api_response
=
parsed_response
self
.
api_resource
=
transform_api_resource
(
parsed_response
.
deep_dup
)
end
def
transform_api_resource
(
resource
)
resource
end
end
end
end
qa/qa/factory/base.rb
View file @
b6f2f738
# frozen_string_literal: true
require
'forwardable'
require
'forwardable'
require
'capybara/dsl'
module
QA
module
QA
module
Factory
module
Factory
class
Base
class
Base
extend
SingleForwardable
extend
SingleForwardable
include
ApiFabricator
extend
Capybara
::
DSL
def_delegators
:evaluator
,
:dependency
,
:dependencies
def_delegators
:evaluator
,
:dependency
,
:dependencies
def_delegators
:evaluator
,
:product
,
:attributes
def_delegators
:evaluator
,
:product
,
:attributes
...
@@ -12,46 +17,96 @@ module QA
...
@@ -12,46 +17,96 @@ module QA
raise
NotImplementedError
raise
NotImplementedError
end
end
def
self
.
fabricate!
(
*
args
)
def
self
.
fabricate!
(
*
args
,
&
prepare_block
)
new
.
tap
do
|
factory
|
fabricate_via_api!
(
*
args
,
&
prepare_block
)
yield
factory
if
block_given?
rescue
NotImplementedError
fabricate_via_browser_ui!
(
*
args
,
&
prepare_block
)
end
def
self
.
fabricate_via_browser_ui!
(
*
args
,
&
prepare_block
)
options
=
args
.
extract_options!
factory
=
options
.
fetch
(
:factory
)
{
new
}
parents
=
options
.
fetch
(
:parents
)
{
[]
}
do_fabricate!
(
factory:
factory
,
prepare_block:
prepare_block
,
parents:
parents
)
do
log_fabrication
(
:browser_ui
,
factory
,
parents
,
args
)
{
factory
.
fabricate!
(
*
args
)
}
current_url
end
end
def
self
.
fabricate_via_api!
(
*
args
,
&
prepare_block
)
options
=
args
.
extract_options!
factory
=
options
.
fetch
(
:factory
)
{
new
}
parents
=
options
.
fetch
(
:parents
)
{
[]
}
raise
NotImplementedError
unless
factory
.
api_support?
factory
.
eager_load_api_client!
do_fabricate!
(
factory:
factory
,
prepare_block:
prepare_block
,
parents:
parents
)
do
log_fabrication
(
:api
,
factory
,
parents
,
args
)
{
factory
.
fabricate_via_api!
}
end
end
def
self
.
do_fabricate!
(
factory
:,
prepare_block
:,
parents:
[])
prepare_block
.
call
(
factory
)
if
prepare_block
dependencies
.
each
do
|
name
,
signature
|
dependencies
.
each
do
|
signature
|
Factory
::
Dependency
.
new
(
name
,
factory
,
signature
).
build!
Factory
::
Dependency
.
new
(
factory
,
signature
).
build!
(
parents:
parents
+
[
self
])
end
end
factory
.
fabricate!
(
*
args
)
resource_web_url
=
yield
Factory
::
Product
.
populate!
(
factory
,
resource_web_url
)
end
private_class_method
:do_fabricate!
def
self
.
log_fabrication
(
method
,
factory
,
parents
,
args
)
return
yield
unless
Runtime
::
Env
.
verbose?
start
=
Time
.
now
prefix
=
"==
#{
'='
*
parents
.
size
}
>"
msg
=
[
prefix
]
msg
<<
"Built a
#{
name
}
"
msg
<<
"as a dependency of
#{
parents
.
last
}
"
if
parents
.
any?
msg
<<
"via
#{
method
}
with args
#{
args
}
"
break
Factory
::
Product
.
populate!
(
factory
)
yield
.
tap
do
msg
<<
"in
#{
Time
.
now
-
start
}
seconds"
puts
msg
.
join
(
' '
)
puts
if
parents
.
empty?
end
end
end
end
private_class_method
:log_fabrication
def
self
.
evaluator
def
self
.
evaluator
@evaluator
||=
Factory
::
Base
::
DSL
.
new
(
self
)
@evaluator
||=
Factory
::
Base
::
DSL
.
new
(
self
)
end
end
private_class_method
:evaluator
class
DSL
class
DSL
attr_reader
:dependencies
,
:attributes
attr_reader
:dependencies
,
:attributes
def
initialize
(
base
)
def
initialize
(
base
)
@base
=
base
@base
=
base
@dependencies
=
{}
@dependencies
=
[]
@attributes
=
{}
@attributes
=
[]
end
end
def
dependency
(
factory
,
as
:,
&
block
)
def
dependency
(
factory
,
as
:,
&
block
)
as
.
tap
do
|
name
|
as
.
tap
do
|
name
|
@base
.
class_eval
{
attr_accessor
name
}
@base
.
class_eval
{
attr_accessor
name
}
Dependency
::
Signature
.
new
(
factory
,
block
).
tap
do
|
signature
|
Dependency
::
Signature
.
new
(
name
,
factory
,
block
).
tap
do
|
signature
|
@dependencies
.
store
(
name
,
signature
)
@dependencies
<<
signature
end
end
end
end
end
end
def
product
(
attribute
,
&
block
)
def
product
(
attribute
,
&
block
)
Product
::
Attribute
.
new
(
attribute
,
block
).
tap
do
|
signature
|
Product
::
Attribute
.
new
(
attribute
,
block
).
tap
do
|
signature
|
@attributes
.
store
(
attribute
,
signature
)
@attributes
<<
signature
end
end
end
end
end
end
...
...
qa/qa/factory/dependency.rb
View file @
b6f2f738
module
QA
module
QA
module
Factory
module
Factory
class
Dependency
class
Dependency
Signature
=
Struct
.
new
(
:factory
,
:block
)
Signature
=
Struct
.
new
(
:
name
,
:
factory
,
:block
)
def
initialize
(
name
,
factory
,
signature
)
def
initialize
(
caller_factory
,
dependency_signature
)
@name
=
name
@caller_factory
=
caller_factory
@factory
=
factory
@dependency_signature
=
dependency_signature
@signature
=
signature
end
end
def
overridden?
def
overridden?
!!
@
factory
.
public_send
(
@
name
)
!!
@
caller_factory
.
public_send
(
@dependency_signature
.
name
)
end
end
def
build!
def
build!
(
parents:
[])
return
if
overridden?
return
if
overridden?
Builder
.
new
(
@signature
,
@factory
).
fabricate!
.
tap
do
|
product
|
dependency
=
@dependency_signature
.
factory
.
fabricate!
(
parents:
parents
)
do
|
factory
|
@factory
.
public_send
(
"
#{
@name
}
="
,
product
)
@dependency_signature
.
block
&
.
call
(
factory
,
@caller_factory
)
end
end
class
Builder
def
initialize
(
signature
,
caller_factory
)
@factory
=
signature
.
factory
@block
=
signature
.
block
@caller_factory
=
caller_factory
end
end
def
fabricate!
dependency
.
tap
do
|
dependency
|
@factory
.
fabricate!
do
|
factory
|
@caller_factory
.
public_send
(
"
#{
@dependency_signature
.
name
}
="
,
dependency
)
@block
&
.
call
(
factory
,
@caller_factory
)
end
end
end
end
end
end
end
...
...
qa/qa/factory/product.rb
View file @
b6f2f738
...
@@ -5,26 +5,46 @@ module QA
...
@@ -5,26 +5,46 @@ module QA
class
Product
class
Product
include
Capybara
::
DSL
include
Capybara
::
DSL
NoValueError
=
Class
.
new
(
RuntimeError
)
attr_reader
:factory
,
:web_url
Attribute
=
Struct
.
new
(
:name
,
:block
)
Attribute
=
Struct
.
new
(
:name
,
:block
)
def
initialize
def
initialize
(
factory
,
web_url
)
@location
=
current_url
@factory
=
factory
@web_url
=
web_url
populate_attributes!
end
end
def
visit!
def
visit!
visit
@location
visit
(
web_url
)
end
end
def
self
.
populate!
(
factory
)
def
self
.
populate!
(
factory
,
web_url
)
new
.
tap
do
|
product
|
new
(
factory
,
web_url
)
factory
.
class
.
attributes
.
each_value
do
|
attribute
|
product
.
instance_exec
(
factory
,
attribute
.
block
)
do
|
factory
,
block
|
value
=
block
.
call
(
factory
)
product
.
define_singleton_method
(
attribute
.
name
)
{
value
}
end
end
private
def
populate_attributes!
factory
.
class
.
attributes
.
each
do
|
attribute
|
instance_exec
(
factory
,
attribute
.
block
)
do
|
factory
,
block
|
value
=
attribute_value
(
attribute
,
block
)
raise
NoValueError
,
"No value was computed for product
#{
attribute
.
name
}
of factory
#{
factory
.
class
.
name
}
."
unless
value
define_singleton_method
(
attribute
.
name
)
{
value
}
end
end
end
end
end
end
def
attribute_value
(
attribute
,
block
)
factory
.
api_resource
&
.
dig
(
attribute
.
name
)
||
(
block
&&
block
.
call
(
factory
))
||
(
factory
.
respond_to?
(
attribute
.
name
)
&&
factory
.
public_send
(
attribute
.
name
))
end
end
end
end
end
end
end
qa/qa/factory/repository/project_push.rb
View file @
b6f2f738
...
@@ -7,13 +7,8 @@ module QA
...
@@ -7,13 +7,8 @@ module QA
project
.
description
=
'Project with repository'
project
.
description
=
'Project with repository'
end
end
product
:output
do
|
factory
|
product
:output
factory
.
output
product
:project
end
product
:project
do
|
factory
|
factory
.
project
end
def
initialize
def
initialize
@file_name
=
'file.txt'
@file_name
=
'file.txt'
...
...
qa/qa/factory/resource/fork.rb
View file @
b6f2f738
...
@@ -11,7 +11,7 @@ module QA
...
@@ -11,7 +11,7 @@ module QA
end
end
end
end
product
(
:user
)
{
|
factory
|
factory
.
user
}
product
:user
def
visit_project_with_retry
def
visit_project_with_retry
# The user intermittently fails to stay signed in after visiting the
# The user intermittently fails to stay signed in after visiting the
...
...
qa/qa/factory/resource/group.rb
View file @
b6f2f738
...
@@ -6,6 +6,10 @@ module QA
...
@@ -6,6 +6,10 @@ module QA
dependency
Factory
::
Resource
::
Sandbox
,
as: :sandbox
dependency
Factory
::
Resource
::
Sandbox
,
as: :sandbox
product
:id
do
true
# We don't retrieve the Group ID when using the Browser UI
end
def
initialize
def
initialize
@path
=
Runtime
::
Namespace
.
name
@path
=
Runtime
::
Namespace
.
name
@description
=
"QA test run at
#{
Runtime
::
Namespace
.
time
}
"
@description
=
"QA test run at
#{
Runtime
::
Namespace
.
time
}
"
...
@@ -35,6 +39,29 @@ module QA
...
@@ -35,6 +39,29 @@ module QA
end
end
end
end
end
end
def
fabricate_via_api!
resource_web_url
(
api_get
)
rescue
ResourceNotFoundError
super
end
def
api_get_path
"/groups/
#{
CGI
.
escape
(
"
#{
sandbox
.
path
}
/
#{
path
}
"
)
}
"
end
def
api_post_path
'/groups'
end
def
api_post_body
{
parent_id:
sandbox
.
id
,
path:
path
,
name:
path
,
visibility:
'public'
}
end
end
end
end
end
end
end
...
...
qa/qa/factory/resource/issue.rb
View file @
b6f2f738
...
@@ -2,16 +2,15 @@ module QA
...
@@ -2,16 +2,15 @@ module QA
module
Factory
module
Factory
module
Resource
module
Resource
class
Issue
<
Factory
::
Base
class
Issue
<
Factory
::
Base
attr_
write
r
:title
,
:description
,
:project
attr_
accesso
r
:title
,
:description
,
:project
dependency
Factory
::
Resource
::
Project
,
as: :project
do
|
project
|
dependency
Factory
::
Resource
::
Project
,
as: :project
do
|
project
|
project
.
name
=
'project-for-issues'
project
.
name
=
'project-for-issues'
project
.
description
=
'project for adding issues'
project
.
description
=
'project for adding issues'
end
end
product
:title
do
product
:project
Page
::
Project
::
Issue
::
Show
.
act
{
issue_title
}
product
:title
end
def
fabricate!
def
fabricate!
project
.
visit!
project
.
visit!
...
...
qa/qa/factory/resource/merge_request.rb
View file @
b6f2f738
...
@@ -12,13 +12,8 @@ module QA
...
@@ -12,13 +12,8 @@ module QA
:milestone
,
:milestone
,
:labels
:labels
product
:project
do
|
factory
|
product
:project
factory
.
project
product
:source_branch
end
product
:source_branch
do
|
factory
|
factory
.
source_branch
end
dependency
Factory
::
Resource
::
Project
,
as: :project
do
|
project
|
dependency
Factory
::
Resource
::
Project
,
as: :project
do
|
project
|
project
.
name
=
'project-with-merge-request'
project
.
name
=
'project-with-merge-request'
...
...
qa/qa/factory/resource/project.rb
View file @
b6f2f738
...
@@ -4,14 +4,13 @@ module QA
...
@@ -4,14 +4,13 @@ module QA
module
Factory
module
Factory
module
Resource
module
Resource
class
Project
<
Factory
::
Base
class
Project
<
Factory
::
Base
attr_
write
r
:description
attr_
accesso
r
:description
attr_reader
:name
attr_reader
:name
dependency
Factory
::
Resource
::
Group
,
as: :group
dependency
Factory
::
Resource
::
Group
,
as: :group
product
:name
do
|
factory
|
product
:group
factory
.
name
product
:name
end
product
:repository_ssh_location
do
product
:repository_ssh_location
do
Page
::
Project
::
Show
.
act
do
Page
::
Project
::
Show
.
act
do
...
@@ -48,6 +47,32 @@ module QA
...
@@ -48,6 +47,32 @@ module QA
page
.
create_new_project
page
.
create_new_project
end
end
end
end
def
api_get_path
"/projects/
#{
name
}
"
end
def
api_post_path
'/projects'
end
def
api_post_body
{
namespace_id:
group
.
id
,
path:
name
,
name:
name
,
description:
description
,
visibility:
'public'
}
end
private
def
transform_api_resource
(
resource
)
resource
[
:repository_ssh_location
]
=
Git
::
Location
.
new
(
resource
[
:ssh_url_to_repo
])
resource
[
:repository_http_location
]
=
Git
::
Location
.
new
(
resource
[
:http_url_to_repo
])
resource
end
end
end
end
end
end
end
...
...
qa/qa/factory/resource/project_imported_from_github.rb
View file @
b6f2f738
...
@@ -8,9 +8,7 @@ module QA
...
@@ -8,9 +8,7 @@ module QA
dependency
Factory
::
Resource
::
Group
,
as: :group
dependency
Factory
::
Resource
::
Group
,
as: :group
product
:name
do
|
factory
|
product
:name
factory
.
name
end
def
fabricate!
def
fabricate!
group
.
visit!
group
.
visit!
...
...
qa/qa/factory/resource/project_milestone.rb
View file @
b6f2f738
...
@@ -7,7 +7,7 @@ module QA
...
@@ -7,7 +7,7 @@ module QA
dependency
Factory
::
Resource
::
Project
,
as: :project
dependency
Factory
::
Resource
::
Project
,
as: :project
product
(
:title
)
{
|
factory
|
factory
.
title
}
product
:title
def
title
=
(
title
)
def
title
=
(
title
)
@title
=
"
#{
title
}
-
#{
SecureRandom
.
hex
(
4
)
}
"
@title
=
"
#{
title
}
-
#{
SecureRandom
.
hex
(
4
)
}
"
...
...
qa/qa/factory/resource/sandbox.rb
View file @
b6f2f738
...
@@ -6,21 +6,28 @@ module QA
...
@@ -6,21 +6,28 @@ module QA
# creating it if it doesn't yet exist.
# creating it if it doesn't yet exist.
#
#
class
Sandbox
<
Factory
::
Base
class
Sandbox
<
Factory
::
Base
attr_reader
:path
product
:id
do
true
# We don't retrieve the Group ID when using the Browser UI
end
product
:path
def
initialize
def
initialize
@
name
=
Runtime
::
Namespace
.
sandbox_name
@
path
=
Runtime
::
Namespace
.
sandbox_name
end
end
def
fabricate!
def
fabricate!
Page
::
Main
::
Menu
.
act
{
go_to_groups
}
Page
::
Main
::
Menu
.
act
{
go_to_groups
}
Page
::
Dashboard
::
Groups
.
perform
do
|
page
|
Page
::
Dashboard
::
Groups
.
perform
do
|
page
|
if
page
.
has_group?
(
@name
)
if
page
.
has_group?
(
path
)
page
.
go_to_group
(
@name
)
page
.
go_to_group
(
path
)
else
else
page
.
go_to_new_group
page
.
go_to_new_group
Page
::
Group
::
New
.
perform
do
|
group
|
Page
::
Group
::
New
.
perform
do
|
group
|
group
.
set_path
(
@name
)
group
.
set_path
(
path
)
group
.
set_description
(
'GitLab QA Sandbox Group'
)
group
.
set_description
(
'GitLab QA Sandbox Group'
)
group
.
set_visibility
(
'Public'
)
group
.
set_visibility
(
'Public'
)
group
.
create
group
.
create
...
@@ -28,6 +35,28 @@ module QA
...
@@ -28,6 +35,28 @@ module QA
end
end
end
end
end
end
def
fabricate_via_api!
resource_web_url
(
api_get
)
rescue
ResourceNotFoundError
super
end
def
api_get_path
"/groups/
#{
path
}
"
end
def
api_post_path
'/groups'
end
def
api_post_body
{
path:
path
,
name:
path
,
visibility:
'public'
}
end
end
end
end
end
end
end
...
...
qa/qa/factory/resource/ssh_key.rb
View file @
b6f2f738
...
@@ -10,17 +10,9 @@ module QA
...
@@ -10,17 +10,9 @@ module QA
attr_reader
:private_key
,
:public_key
,
:fingerprint
attr_reader
:private_key
,
:public_key
,
:fingerprint
def_delegators
:key
,
:private_key
,
:public_key
,
:fingerprint
def_delegators
:key
,
:private_key
,
:public_key
,
:fingerprint
product
:private_key
do
|
factory
|
product
:private_key
factory
.
private_key
product
:title
end
product
:fingerprint
product
:title
do
|
factory
|
factory
.
title
end
product
:fingerprint
do
|
factory
|
factory
.
fingerprint
end
def
key
def
key
@key
||=
Runtime
::
Key
::
RSA
.
new
@key
||=
Runtime
::
Key
::
RSA
.
new
...
...
qa/qa/factory/resource/user.rb
View file @
b6f2f738
...
@@ -31,10 +31,10 @@ module QA
...
@@ -31,10 +31,10 @@ module QA
defined?
(
@username
)
&&
defined?
(
@password
)
defined?
(
@username
)
&&
defined?
(
@password
)
end
end
product
(
:name
)
{
|
factory
|
factory
.
name
}
product
:name
product
(
:username
)
{
|
factory
|
factory
.
username
}
product
:username
product
(
:email
)
{
|
factory
|
factory
.
email
}
product
:email
product
(
:password
)
{
|
factory
|
factory
.
password
}
product
:password
def
fabricate!
def
fabricate!
# Don't try to log-out if we're not logged-in
# Don't try to log-out if we're not logged-in
...
...
qa/qa/factory/resource/wiki.rb
View file @
b6f2f738
...
@@ -10,13 +10,16 @@ module QA
...
@@ -10,13 +10,16 @@ module QA
end
end
def
fabricate!
def
fabricate!
Page
::
Project
::
Menu
.
act
{
click_wiki
}
project
.
visit!
Page
::
Project
::
Wiki
::
New
.
perform
do
|
page
|
page
.
go_to_create_first_page
Page
::
Project
::
Menu
.
perform
{
|
menu_side
|
menu_side
.
click_wiki
}
page
.
set_title
(
@title
)
page
.
set_content
(
@content
)
Page
::
Project
::
Wiki
::
New
.
perform
do
|
wiki_new
|
page
.
set_message
(
@message
)
wiki_new
.
go_to_create_first_page
page
.
create_new_page
wiki_new
.
set_title
(
@title
)
wiki_new
.
set_content
(
@content
)
wiki_new
.
set_message
(
@message
)
wiki_new
.
create_new_page
end
end
end
end
end
end
...
...
qa/qa/page/README.md
View file @
b6f2f738
...
@@ -131,4 +131,4 @@ If you need more information, ask for help on `#quality` channel on Slack
...
@@ -131,4 +131,4 @@ If you need more information, ask for help on `#quality` channel on Slack
(internal, GitLab Team only).
(internal, GitLab Team only).
If you are not a Team Member, and you still need help to contribute, please
If you are not a Team Member, and you still need help to contribute, please
open an issue in GitLab
QA issue tracker
.
open an issue in GitLab
CE issue tracker with the
`~QA`
label
.
qa/qa/runtime/api/client.rb
View file @
b6f2f738
...
@@ -6,34 +6,35 @@ module QA
...
@@ -6,34 +6,35 @@ module QA
class
Client
class
Client
attr_reader
:address
attr_reader
:address
def
initialize
(
address
=
:gitlab
,
personal_access_token:
nil
)
def
initialize
(
address
=
:gitlab
,
personal_access_token:
nil
,
is_new_session:
true
)
@address
=
address
@address
=
address
@personal_access_token
=
personal_access_token
@personal_access_token
=
personal_access_token
@is_new_session
=
is_new_session
end
end
def
personal_access_token
def
personal_access_token
@personal_access_token
||=
get_personal_access_token
@personal_access_token
||=
begin
end
def
get_personal_access_token
# you can set the environment variable PERSONAL_ACCESS_TOKEN
# you can set the environment variable PERSONAL_ACCESS_TOKEN
# to use a specific access token rather than create one from the UI
# to use a specific access token rather than create one from the UI
if
Runtime
::
Env
.
personal_access_token
Runtime
::
Env
.
personal_access_token
||=
create_personal_access_token
Runtime
::
Env
.
personal_access_token
else
create_personal_access_token
end
end
end
end
private
private
def
create_personal_access_token
def
create_personal_access_token
Runtime
::
Browser
.
visit
(
@address
,
Page
::
Main
::
Login
)
do
if
@is_new_session
Runtime
::
Browser
.
visit
(
@address
,
Page
::
Main
::
Login
)
{
do_create_personal_access_token
}
else
do_create_personal_access_token
end
end
def
do_create_personal_access_token
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Factory
::
Resource
::
PersonalAccessToken
.
fabricate!
.
access_token
Factory
::
Resource
::
PersonalAccessToken
.
fabricate!
.
access_token
end
end
end
end
end
end
end
end
end
end
end
qa/qa/runtime/env.rb
View file @
b6f2f738
...
@@ -3,6 +3,12 @@ module QA
...
@@ -3,6 +3,12 @@ module QA
module
Env
module
Env
extend
self
extend
self
attr_writer
:personal_access_token
def
verbose?
enabled?
(
ENV
[
'VERBOSE'
],
default:
false
)
end
# set to 'false' to have Chrome run visibly instead of headless
# set to 'false' to have Chrome run visibly instead of headless
def
chrome_headless?
def
chrome_headless?
enabled?
(
ENV
[
'CHROME_HEADLESS'
])
enabled?
(
ENV
[
'CHROME_HEADLESS'
])
...
@@ -22,7 +28,7 @@ module QA
...
@@ -22,7 +28,7 @@ module QA
# specifies token that can be used for the api
# specifies token that can be used for the api
def
personal_access_token
def
personal_access_token
ENV
[
'PERSONAL_ACCESS_TOKEN'
]
@personal_access_token
||=
ENV
[
'PERSONAL_ACCESS_TOKEN'
]
end
end
def
user_username
def
user_username
...
@@ -42,7 +48,7 @@ module QA
...
@@ -42,7 +48,7 @@ module QA
end
end
def
forker?
def
forker?
forker_username
&&
forker_password
!!
(
forker_username
&&
forker_password
)
end
end
def
forker_username
def
forker_username
...
...
qa/qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb
View file @
b6f2f738
...
@@ -11,9 +11,10 @@ module QA
...
@@ -11,9 +11,10 @@ module QA
Page
::
Main
::
Menu
.
perform
{
|
main
|
main
.
sign_out
}
Page
::
Main
::
Menu
.
perform
{
|
main
|
main
.
sign_out
}
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Factory
::
Resource
::
Project
.
fabricate!
do
|
resource
|
project
=
Factory
::
Resource
::
Project
.
fabricate!
do
|
resource
|
resource
.
name
=
'add-member-project'
resource
.
name
=
'add-member-project'
end
end
project
.
visit!
Page
::
Project
::
Menu
.
act
{
click_members_settings
}
Page
::
Project
::
Menu
.
act
{
click_members_settings
}
Page
::
Project
::
Settings
::
Members
.
perform
do
|
page
|
Page
::
Project
::
Settings
::
Members
.
perform
do
|
page
|
...
...
qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
View file @
b6f2f738
...
@@ -7,17 +7,15 @@ module QA
...
@@ -7,17 +7,15 @@ module QA
Runtime
::
Browser
.
visit
(
:gitlab
,
Page
::
Main
::
Login
)
Runtime
::
Browser
.
visit
(
:gitlab
,
Page
::
Main
::
Login
)
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
created_project
=
Factory
::
Resource
::
Project
.
fabricate!
do
|
project
|
created_project
=
Factory
::
Resource
::
Project
.
fabricate
_via_browser_ui
!
do
|
project
|
project
.
name
=
'awesome-project'
project
.
name
=
'awesome-project'
project
.
description
=
'create awesome project test'
project
.
description
=
'create awesome project test'
end
end
expect
(
created_project
.
name
).
to
match
/^awesome-project-\h{16}$/
expect
(
page
).
to
have_content
(
created_project
.
name
)
expect
(
page
).
to
have_content
(
expect
(
page
).
to
have_content
(
/Project \S?awesome-project\S+ was successfully created/
/Project \S?awesome-project\S+ was successfully created/
)
)
expect
(
page
).
to
have_content
(
'create awesome project test'
)
expect
(
page
).
to
have_content
(
'create awesome project test'
)
expect
(
page
).
to
have_content
(
'The repository for this project is empty'
)
expect
(
page
).
to
have_content
(
'The repository for this project is empty'
)
end
end
...
...
qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
View file @
b6f2f738
...
@@ -10,6 +10,7 @@ module QA
...
@@ -10,6 +10,7 @@ module QA
project
=
Factory
::
Resource
::
Project
.
fabricate!
do
|
project
|
project
=
Factory
::
Resource
::
Project
.
fabricate!
do
|
project
|
project
.
name
=
"only-fast-forward"
project
.
name
=
"only-fast-forward"
end
end
project
.
visit!
Page
::
Project
::
Menu
.
act
{
go_to_settings
}
Page
::
Project
::
Menu
.
act
{
go_to_settings
}
Page
::
Project
::
Settings
::
MergeRequest
.
act
{
enable_ff_only
}
Page
::
Project
::
Settings
::
MergeRequest
.
act
{
enable_ff_only
}
...
...
qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb
View file @
b6f2f738
...
@@ -14,10 +14,11 @@ module QA
...
@@ -14,10 +14,11 @@ module QA
Runtime
::
Browser
.
visit
(
:gitlab
,
Page
::
Main
::
Login
)
Runtime
::
Browser
.
visit
(
:gitlab
,
Page
::
Main
::
Login
)
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Factory
::
Resource
::
Project
.
fabricate!
do
|
scenario
|
project
=
Factory
::
Resource
::
Project
.
fabricate!
do
|
scenario
|
scenario
.
name
=
'project-with-code'
scenario
.
name
=
'project-with-code'
scenario
.
description
=
'project for git clone tests'
scenario
.
description
=
'project for git clone tests'
end
end
project
.
visit!
Git
::
Repository
.
perform
do
|
repository
|
Git
::
Repository
.
perform
do
|
repository
|
repository
.
uri
=
location
.
uri
repository
.
uri
=
location
.
uri
...
...
qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
View file @
b6f2f738
...
@@ -17,6 +17,7 @@ module QA
...
@@ -17,6 +17,7 @@ module QA
project
.
name
=
'file-template-project'
project
.
name
=
'file-template-project'
project
.
description
=
'Add file templates via the Web IDE'
project
.
description
=
'Add file templates via the Web IDE'
end
end
@project
.
visit!
# Add a file via the regular Files view because the Web IDE isn't
# Add a file via the regular Files view because the Web IDE isn't
# available unless there is a file present
# available unless there is a file present
...
...
qa/spec/factory/api_fabricator_spec.rb
0 → 100644
View file @
b6f2f738
# frozen_string_literal: true
describe
QA
::
Factory
::
ApiFabricator
do
let
(
:factory_without_api_support
)
do
Class
.
new
do
def
self
.
name
'FooBarFactory'
end
end
end
let
(
:factory_with_api_support
)
do
Class
.
new
do
def
self
.
name
'FooBarFactory'
end
def
api_get_path
'/foo'
end
def
api_post_path
'/bar'
end
def
api_post_body
{
name:
'John Doe'
}
end
end
end
before
do
allow
(
subject
).
to
receive
(
:current_url
).
and_return
(
''
)
end
subject
{
factory
.
tap
{
|
f
|
f
.
include
(
described_class
)
}.
new
}
describe
'#api_support?'
do
let
(
:api_client
)
{
spy
(
'Runtime::API::Client'
)
}
let
(
:api_client_instance
)
{
double
(
'API Client'
)
}
context
'when factory does not support fabrication via the API'
do
let
(
:factory
)
{
factory_without_api_support
}
it
'returns false'
do
expect
(
subject
).
not_to
be_api_support
end
end
context
'when factory supports fabrication via the API'
do
let
(
:factory
)
{
factory_with_api_support
}
it
'returns false'
do
expect
(
subject
).
to
be_api_support
end
end
end
describe
'#fabricate_via_api!'
do
let
(
:api_client
)
{
spy
(
'Runtime::API::Client'
)
}
let
(
:api_client_instance
)
{
double
(
'API Client'
)
}
before
do
stub_const
(
'QA::Runtime::API::Client'
,
api_client
)
allow
(
api_client
).
to
receive
(
:new
).
and_return
(
api_client_instance
)
allow
(
api_client_instance
).
to
receive
(
:personal_access_token
).
and_return
(
'foo'
)
end
context
'when factory does not support fabrication via the API'
do
let
(
:factory
)
{
factory_without_api_support
}
it
'raises a NotImplementedError exception'
do
expect
{
subject
.
fabricate_via_api!
}.
to
raise_error
(
NotImplementedError
,
"Factory FooBarFactory does not support fabrication via the API!"
)
end
end
context
'when factory supports fabrication via the API'
do
let
(
:factory
)
{
factory_with_api_support
}
let
(
:api_request
)
{
spy
(
'Runtime::API::Request'
)
}
let
(
:resource_web_url
)
{
'http://example.org/api/v4/foo'
}
let
(
:resource
)
{
{
id:
1
,
name:
'John Doe'
,
web_url:
resource_web_url
}
}
let
(
:raw_post
)
{
double
(
'Raw POST response'
,
code:
201
,
body:
resource
.
to_json
)
}
before
do
stub_const
(
'QA::Runtime::API::Request'
,
api_request
)
allow
(
api_request
).
to
receive
(
:new
).
and_return
(
double
(
url:
resource_web_url
))
end
context
'when creating a resource'
do
before
do
allow
(
subject
).
to
receive
(
:post
).
with
(
resource_web_url
,
subject
.
api_post_body
).
and_return
(
raw_post
)
end
it
'returns the resource URL'
do
expect
(
api_request
).
to
receive
(
:new
).
with
(
api_client_instance
,
subject
.
api_post_path
).
and_return
(
double
(
url:
resource_web_url
))
expect
(
subject
).
to
receive
(
:post
).
with
(
resource_web_url
,
subject
.
api_post_body
).
and_return
(
raw_post
)
expect
(
subject
.
fabricate_via_api!
).
to
eq
(
resource_web_url
)
end
it
'populates api_resource with the resource'
do
subject
.
fabricate_via_api!
expect
(
subject
.
api_resource
).
to
eq
(
resource
)
end
context
'when the POST fails'
do
let
(
:post_response
)
{
{
error:
"Name already taken."
}
}
let
(
:raw_post
)
{
double
(
'Raw POST response'
,
code:
400
,
body:
post_response
.
to_json
)
}
it
'raises a ResourceFabricationFailedError exception'
do
expect
(
api_request
).
to
receive
(
:new
).
with
(
api_client_instance
,
subject
.
api_post_path
).
and_return
(
double
(
url:
resource_web_url
))
expect
(
subject
).
to
receive
(
:post
).
with
(
resource_web_url
,
subject
.
api_post_body
).
and_return
(
raw_post
)
expect
{
subject
.
fabricate_via_api!
}.
to
raise_error
(
described_class
::
ResourceFabricationFailedError
,
"Fabrication of FooBarFactory using the API failed (400) with `
#{
raw_post
}
`."
)
expect
(
subject
.
api_resource
).
to
be_nil
end
end
end
context
'#transform_api_resource'
do
let
(
:factory
)
do
Class
.
new
do
def
self
.
name
'FooBarFactory'
end
def
api_get_path
'/foo'
end
def
api_post_path
'/bar'
end
def
api_post_body
{
name:
'John Doe'
}
end
def
transform_api_resource
(
resource
)
resource
[
:new
]
=
'foobar'
resource
end
end
end
let
(
:resource
)
{
{
existing:
'foo'
,
web_url:
resource_web_url
}
}
let
(
:transformed_resource
)
{
{
existing:
'foo'
,
new:
'foobar'
,
web_url:
resource_web_url
}
}
it
'transforms the resource'
do
expect
(
subject
).
to
receive
(
:post
).
with
(
resource_web_url
,
subject
.
api_post_body
).
and_return
(
raw_post
)
expect
(
subject
).
to
receive
(
:transform_api_resource
).
with
(
resource
).
and_return
(
transformed_resource
)
subject
.
fabricate_via_api!
end
end
end
end
end
qa/spec/factory/base_spec.rb
View file @
b6f2f738
# frozen_string_literal: true
describe
QA
::
Factory
::
Base
do
describe
QA
::
Factory
::
Base
do
include
Support
::
StubENV
let
(
:factory
)
{
spy
(
'factory'
)
}
let
(
:factory
)
{
spy
(
'factory'
)
}
let
(
:product
)
{
spy
(
'product'
)
}
let
(
:product
)
{
spy
(
'product'
)
}
let
(
:product_location
)
{
'http://product_location'
}
describe
'.fabricate!'
do
shared_context
'fabrication context'
do
subject
{
Class
.
new
(
described_class
)
}
subject
do
Class
.
new
(
described_class
)
do
def
self
.
name
'MyFactory'
end
end
end
before
do
before
do
allow
(
QA
::
Factory
::
Product
).
to
receive
(
:new
).
and_return
(
product
)
allow
(
subject
).
to
receive
(
:current_url
).
and_return
(
product_location
)
allow
(
QA
::
Factory
::
Product
).
to
receive
(
:populate!
).
and_return
(
product
)
allow
(
subject
).
to
receive
(
:new
).
and_return
(
factory
)
allow
(
QA
::
Factory
::
Product
).
to
receive
(
:populate!
).
with
(
factory
,
product_location
).
and_return
(
product
)
end
end
end
it
'instantiates the factory and calls factory method'
do
shared_examples
'fabrication method'
do
|
fabrication_method_called
,
actual_fabrication_method
=
nil
|
expect
(
subject
).
to
receive
(
:new
).
and_return
(
factory
)
let
(
:fabrication_method_used
)
{
actual_fabrication_method
||
fabrication_method_called
}
subject
.
fabricate!
(
'something'
)
it
'yields factory before calling factory method'
do
expect
(
factory
).
to
receive
(
:something!
).
ordered
expect
(
factory
).
to
receive
(
fabrication_method_used
).
ordered
.
and_return
(
product_location
)
expect
(
factory
).
to
have_received
(
:fabricate!
).
with
(
'something'
)
subject
.
public_send
(
fabrication_method_called
,
factory:
factory
)
do
|
factory
|
factory
.
something!
end
end
end
it
'returns fabrication product'
do
it
'does not log the factory and build method when VERBOSE=false'
do
allow
(
subject
).
to
receive
(
:new
).
and_return
(
factory
)
stub_env
(
'VERBOSE'
,
'false'
)
expect
(
factory
).
to
receive
(
fabrication_method_used
).
and_return
(
product_location
)
result
=
subject
.
fabricate!
(
'something'
)
expect
{
subject
.
public_send
(
fabrication_method_called
,
'something'
,
factory:
factory
)
}
.
not_to
output
.
to_stdout
end
end
expect
(
result
).
to
eq
product
describe
'.fabricate!'
do
context
'when factory does not support fabrication via the API'
do
before
do
expect
(
described_class
).
to
receive
(
:fabricate_via_api!
).
and_raise
(
NotImplementedError
)
end
end
it
'yields factory before calling factory method
'
do
it
'calls .fabricate_via_browser_ui!
'
do
allow
(
subject
).
to
receive
(
:new
).
and_return
(
factory
)
expect
(
described_class
).
to
receive
(
:fabricate_via_browser_ui!
)
subject
.
fabricate!
do
|
factory
|
described_class
.
fabricate!
factory
.
something!
end
end
end
expect
(
factory
).
to
have_received
(
:something!
).
ordered
context
'when factory supports fabrication via the API'
do
expect
(
factory
).
to
have_received
(
:fabricate!
).
ordered
it
'calls .fabricate_via_browser_ui!'
do
expect
(
described_class
).
to
receive
(
:fabricate_via_api!
)
described_class
.
fabricate!
end
end
end
describe
'.fabricate_via_api!'
do
include_context
'fabrication context'
it_behaves_like
'fabrication method'
,
:fabricate_via_api!
it
'instantiates the factory, calls factory method returns fabrication product'
do
expect
(
factory
).
to
receive
(
:fabricate_via_api!
).
and_return
(
product_location
)
result
=
subject
.
fabricate_via_api!
(
factory:
factory
,
parents:
[])
expect
(
result
).
to
eq
(
product
)
end
it
'logs the factory and build method when VERBOSE=true'
do
stub_env
(
'VERBOSE'
,
'true'
)
expect
(
factory
).
to
receive
(
:fabricate_via_api!
).
and_return
(
product_location
)
expect
{
subject
.
fabricate_via_api!
(
factory:
factory
,
parents:
[])
}
.
to
output
(
/==> Built a MyFactory via api with args \[\] in [\d\w\.\-]+/
)
.
to_stdout
end
end
describe
'.fabricate_via_browser_ui!'
do
include_context
'fabrication context'
it_behaves_like
'fabrication method'
,
:fabricate_via_browser_ui!
,
:fabricate!
it
'instantiates the factory and calls factory method'
do
subject
.
fabricate_via_browser_ui!
(
'something'
,
factory:
factory
,
parents:
[])
expect
(
factory
).
to
have_received
(
:fabricate!
).
with
(
'something'
)
end
it
'returns fabrication product'
do
result
=
subject
.
fabricate_via_browser_ui!
(
'something'
,
factory:
factory
,
parents:
[])
expect
(
result
).
to
eq
(
product
)
end
it
'logs the factory and build method when VERBOSE=true'
do
stub_env
(
'VERBOSE'
,
'true'
)
expect
{
subject
.
fabricate_via_browser_ui!
(
'something'
,
factory:
factory
,
parents:
[])
}
.
to
output
(
/==> Built a MyFactory via browser_ui with args \["something"\] in [\d\w\.\-]+/
)
.
to_stdout
end
end
end
end
...
@@ -75,9 +152,9 @@ describe QA::Factory::Base do
...
@@ -75,9 +152,9 @@ describe QA::Factory::Base do
stub_const
(
'Some::MyDependency'
,
dependency
)
stub_const
(
'Some::MyDependency'
,
dependency
)
allow
(
subject
).
to
receive
(
:new
).
and_return
(
instance
)
allow
(
subject
).
to
receive
(
:new
).
and_return
(
instance
)
allow
(
subject
).
to
receive
(
:current_url
).
and_return
(
product_location
)
allow
(
instance
).
to
receive
(
:mydep
).
and_return
(
nil
)
allow
(
instance
).
to
receive
(
:mydep
).
and_return
(
nil
)
allow
(
QA
::
Factory
::
Product
).
to
receive
(
:new
)
expect
(
QA
::
Factory
::
Product
).
to
receive
(
:populate!
)
allow
(
QA
::
Factory
::
Product
).
to
receive
(
:populate!
)
end
end
it
'builds all dependencies first'
do
it
'builds all dependencies first'
do
...
@@ -89,44 +166,22 @@ describe QA::Factory::Base do
...
@@ -89,44 +166,22 @@ describe QA::Factory::Base do
end
end
describe
'.product'
do
describe
'.product'
do
include_context
'fabrication context'
subject
do
subject
do
Class
.
new
(
described_class
)
do
Class
.
new
(
described_class
)
do
def
fabricate!
def
fabricate!
"any"
"any"
end
end
# Defined only to be stubbed
product
:token
def
self
.
find_page
end
product
:token
do
find_page
.
do_something_on_page!
'resulting value'
end
end
end
end
end
it
'appends new product attribute'
do
it
'appends new product attribute'
do
expect
(
subject
.
attributes
).
to
be_one
expect
(
subject
.
attributes
).
to
be_one
expect
(
subject
.
attributes
).
to
have_key
(
:token
)
expect
(
subject
.
attributes
[
0
]).
to
be_a
(
QA
::
Factory
::
Product
::
Attribute
)
end
expect
(
subject
.
attributes
[
0
].
name
).
to
eq
(
:token
)
describe
'populating fabrication product with data'
do
let
(
:page
)
{
spy
(
'page'
)
}
before
do
allow
(
factory
).
to
receive
(
:class
).
and_return
(
subject
)
allow
(
QA
::
Factory
::
Product
).
to
receive
(
:new
).
and_return
(
product
)
allow
(
product
).
to
receive
(
:page
).
and_return
(
page
)
allow
(
subject
).
to
receive
(
:find_page
).
and_return
(
page
)
end
it
'populates product after fabrication'
do
subject
.
fabricate!
expect
(
product
.
token
).
to
eq
'resulting value'
expect
(
page
).
to
have_received
(
:do_something_on_page!
)
end
end
end
end
end
end
end
qa/spec/factory/dependency_spec.rb
View file @
b6f2f738
...
@@ -4,11 +4,11 @@ describe QA::Factory::Dependency do
...
@@ -4,11 +4,11 @@ describe QA::Factory::Dependency do
let
(
:block
)
{
spy
(
'block'
)
}
let
(
:block
)
{
spy
(
'block'
)
}
let
(
:signature
)
do
let
(
:signature
)
do
double
(
'signature'
,
factory:
dependency
,
block:
block
)
double
(
'signature'
,
name: :mydep
,
factory:
dependency
,
block:
block
)
end
end
subject
do
subject
do
described_class
.
new
(
:mydep
,
factory
,
signature
)
described_class
.
new
(
factory
,
signature
)
end
end
describe
'#overridden?'
do
describe
'#overridden?'
do
...
@@ -55,16 +55,23 @@ describe QA::Factory::Dependency do
...
@@ -55,16 +55,23 @@ describe QA::Factory::Dependency do
expect
(
factory
).
to
have_received
(
:mydep
=
).
with
(
dependency
)
expect
(
factory
).
to
have_received
(
:mydep
=
).
with
(
dependency
)
end
end
context
'when receives a caller factory as block argument'
do
let
(
:dependency
)
{
QA
::
Factory
::
Base
}
it
'calls given block with dependency factory and caller factory'
do
it
'calls given block with dependency factory and caller factory'
do
allow_any_instance_of
(
QA
::
Factory
::
Base
).
to
receive
(
:fabricate!
).
and_return
(
factory
)
expect
(
dependency
).
to
receive
(
:fabricate!
).
and_yield
(
dependency
)
allow
(
QA
::
Factory
::
Product
).
to
receive
(
:populate!
).
and_return
(
spy
(
'any'
))
subject
.
build!
subject
.
build!
expect
(
block
).
to
have_received
(
:call
).
with
(
an_instance_of
(
QA
::
Factory
::
Base
),
factory
)
expect
(
block
).
to
have_received
(
:call
).
with
(
dependency
,
factory
)
end
context
'with no block given'
do
let
(
:signature
)
do
double
(
'signature'
,
name: :mydep
,
factory:
dependency
,
block:
nil
)
end
it
'does not error'
do
subject
.
build!
expect
(
dependency
).
to
have_received
(
:fabricate!
)
end
end
end
end
end
end
...
...
qa/spec/factory/product_spec.rb
View file @
b6f2f738
describe
QA
::
Factory
::
Product
do
describe
QA
::
Factory
::
Product
do
let
(
:factory
)
do
let
(
:factory
)
do
QA
::
Factory
::
Base
.
new
Class
.
new
(
QA
::
Factory
::
Base
)
do
def
foo
'bar'
end
end
end
.
new
let
(
:attributes
)
do
{
test:
QA
::
Factory
::
Product
::
Attribute
.
new
(
:test
,
proc
{
'returned'
})
}
end
end
let
(
:product
)
{
spy
(
'product'
)
}
let
(
:product
)
{
spy
(
'product'
)
}
let
(
:product_location
)
{
'http://product_location'
}
subject
{
described_class
.
new
(
factory
,
product_location
)
}
describe
'.populate!'
do
before
do
before
do
allow
(
QA
::
Factory
::
Base
).
to
receive
(
:attributes
).
and_return
(
attributes
)
expect
(
factory
.
class
).
to
receive
(
:attributes
).
and_return
(
attributes
)
end
end
describe
'.populate!'
do
context
'when the product attribute is populated via a block'
do
it
'returns a fabrication product and define factory attributes as its methods'
do
let
(
:attributes
)
do
expect
(
described_class
).
to
receive
(
:new
).
and_return
(
product
)
[
QA
::
Factory
::
Product
::
Attribute
.
new
(
:test
,
proc
{
'returned'
})]
end
it
'returns a fabrication product and defines factory attributes as its methods'
do
result
=
described_class
.
populate!
(
factory
,
product_location
)
result
=
described_class
.
populate!
(
factory
)
do
|
instance
|
expect
(
result
).
to
be_a
(
described_class
)
instance
.
something
=
'string'
expect
(
result
.
test
).
to
eq
(
'returned'
)
end
end
end
expect
(
result
).
to
be
product
context
'when the product attribute is populated via the api'
do
let
(
:attributes
)
do
[
QA
::
Factory
::
Product
::
Attribute
.
new
(
:test
)]
end
it
'returns a fabrication product and defines factory attributes as its methods'
do
expect
(
factory
).
to
receive
(
:api_resource
).
and_return
({
test:
'returned'
})
result
=
described_class
.
populate!
(
factory
,
product_location
)
expect
(
result
).
to
be_a
(
described_class
)
expect
(
result
.
test
).
to
eq
(
'returned'
)
expect
(
result
.
test
).
to
eq
(
'returned'
)
end
end
end
end
context
'when the product attribute is populated via a factory attribute'
do
let
(
:attributes
)
do
[
QA
::
Factory
::
Product
::
Attribute
.
new
(
:foo
)]
end
it
'returns a fabrication product and defines factory attributes as its methods'
do
result
=
described_class
.
populate!
(
factory
,
product_location
)
expect
(
result
).
to
be_a
(
described_class
)
expect
(
result
.
foo
).
to
eq
(
'bar'
)
end
end
context
'when the product attribute has no value'
do
let
(
:attributes
)
do
[
QA
::
Factory
::
Product
::
Attribute
.
new
(
:bar
)]
end
it
'returns a fabrication product and defines factory attributes as its methods'
do
expect
{
described_class
.
populate!
(
factory
,
product_location
)
}
.
to
raise_error
(
described_class
::
NoValueError
,
"No value was computed for product bar of factory
#{
factory
.
class
.
name
}
."
)
end
end
end
describe
'.visit!'
do
describe
'.visit!'
do
it
'makes it possible to visit fabrication product'
do
it
'makes it possible to visit fabrication product'
do
allow_any_instance_of
(
described_class
)
.
to
receive
(
:current_url
).
and_return
(
'some url'
)
allow_any_instance_of
(
described_class
)
allow_any_instance_of
(
described_class
)
.
to
receive
(
:visit
).
and_return
(
'visited some url'
)
.
to
receive
(
:visit
).
and_return
(
'visited some url'
)
...
...
qa/spec/runtime/api/client_spec.rb
View file @
b6f2f738
...
@@ -13,18 +13,27 @@ describe QA::Runtime::API::Client do
...
@@ -13,18 +13,27 @@ describe QA::Runtime::API::Client do
end
end
end
end
describe
'#get_personal_access_token'
do
describe
'#personal_access_token'
do
context
'when QA::Runtime::Env.personal_access_token is present'
do
before
do
allow
(
QA
::
Runtime
::
Env
).
to
receive
(
:personal_access_token
).
and_return
(
'a_token'
)
end
it
'returns specified token from env'
do
it
'returns specified token from env'
do
stub_env
(
'PERSONAL_ACCESS_TOKEN'
,
'a_token'
)
expect
(
described_class
.
new
.
personal_access_token
).
to
eq
'a_token'
end
end
expect
(
described_class
.
new
.
get_personal_access_token
).
to
eq
'a_token'
context
'when QA::Runtime::Env.personal_access_token is nil'
do
before
do
allow
(
QA
::
Runtime
::
Env
).
to
receive
(
:personal_access_token
).
and_return
(
nil
)
end
end
it
'returns a created token'
do
it
'returns a created token'
do
allow_any_instance_of
(
described_class
)
expect
(
subject
).
to
receive
(
:create_personal_access_token
).
and_return
(
'created_token'
)
.
to
receive
(
:create_personal_access_token
).
and_return
(
'created_token'
)
expect
(
described_class
.
new
.
get_personal_access_token
).
to
eq
'created_token'
expect
(
subject
.
personal_access_token
).
to
eq
'created_token'
end
end
end
end
end
end
end
qa/spec/runtime/api/request_spec.rb
View file @
b6f2f738
describe
QA
::
Runtime
::
API
::
Request
do
describe
QA
::
Runtime
::
API
::
Request
do
include
Support
::
StubENV
let
(
:client
)
{
QA
::
Runtime
::
API
::
Client
.
new
(
'http://example.com'
)
}
let
(
:request
)
{
described_class
.
new
(
client
,
'/users'
)
}
before
do
before
do
stub_env
(
'PERSONAL_ACCESS_TOKEN'
,
'a_token'
)
allow
(
client
).
to
receive
(
:personal_access_token
).
and_return
(
'a_token'
)
end
end
let
(
:client
)
{
QA
::
Runtime
::
API
::
Client
.
new
(
'http://example.com'
)
}
let
(
:request
)
{
described_class
.
new
(
client
,
'/users'
)
}
describe
'#url'
do
describe
'#url'
do
it
'returns the full
api
request url'
do
it
'returns the full
API
request url'
do
expect
(
request
.
url
).
to
eq
'http://example.com/api/v4/users?private_token=a_token'
expect
(
request
.
url
).
to
eq
'http://example.com/api/v4/users?private_token=a_token'
end
end
context
'when oauth_access_token is passed in the query string'
do
let
(
:request
)
{
described_class
.
new
(
client
,
'/users'
,
{
oauth_access_token:
'foo'
})
}
it
'does not adds a private_token query string'
do
expect
(
request
.
url
).
to
eq
'http://example.com/api/v4/users?oauth_access_token=foo'
end
end
end
end
describe
'#request_path'
do
describe
'#request_path'
do
...
...
qa/spec/runtime/api_request_spec.rb
deleted
100644 → 0
View file @
ab9cf561
qa/spec/runtime/env_spec.rb
View file @
b6f2f738
...
@@ -34,6 +34,10 @@ describe QA::Runtime::Env do
...
@@ -34,6 +34,10 @@ describe QA::Runtime::Env do
end
end
end
end
describe
'.verbose?'
do
it_behaves_like
'boolean method'
,
:verbose?
,
'VERBOSE'
,
false
end
describe
'.signup_disabled?'
do
describe
'.signup_disabled?'
do
it_behaves_like
'boolean method'
,
:signup_disabled?
,
'SIGNUP_DISABLED'
,
false
it_behaves_like
'boolean method'
,
:signup_disabled?
,
'SIGNUP_DISABLED'
,
false
end
end
...
@@ -64,7 +68,54 @@ describe QA::Runtime::Env do
...
@@ -64,7 +68,54 @@ describe QA::Runtime::Env do
end
end
end
end
describe
'.personal_access_token'
do
around
do
|
example
|
described_class
.
instance_variable_set
(
:@personal_access_token
,
nil
)
example
.
run
described_class
.
instance_variable_set
(
:@personal_access_token
,
nil
)
end
context
'when PERSONAL_ACCESS_TOKEN is set'
do
before
do
stub_env
(
'PERSONAL_ACCESS_TOKEN'
,
'a_token'
)
end
it
'returns specified token from env'
do
expect
(
described_class
.
personal_access_token
).
to
eq
'a_token'
end
end
context
'when @personal_access_token is set'
do
before
do
described_class
.
personal_access_token
=
'another_token'
end
it
'returns the instance variable value'
do
expect
(
described_class
.
personal_access_token
).
to
eq
'another_token'
end
end
end
describe
'.personal_access_token='
do
around
do
|
example
|
described_class
.
instance_variable_set
(
:@personal_access_token
,
nil
)
example
.
run
described_class
.
instance_variable_set
(
:@personal_access_token
,
nil
)
end
it
'saves the token'
do
described_class
.
personal_access_token
=
'a_token'
expect
(
described_class
.
personal_access_token
).
to
eq
'a_token'
end
end
describe
'.forker?'
do
describe
'.forker?'
do
before
do
stub_env
(
'GITLAB_FORKER_USERNAME'
,
nil
)
stub_env
(
'GITLAB_FORKER_PASSWORD'
,
nil
)
end
it
'returns false if no forker credentials are defined'
do
it
'returns false if no forker credentials are defined'
do
expect
(
described_class
).
not_to
be_forker
expect
(
described_class
).
not_to
be_forker
end
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment