Skip to content
Snippets Groups Projects
Commit 7de5298f authored by Lin Jen-Shin's avatar Lin Jen-Shin
Browse files

Always use `attribute` to define the product

The idea is that we define the attributes on the factory,
and make them lazily loaded. The factory is free to use them,
and so is the product. The product will just load everything
from the factory.

This eliminate the difference between factory and product.
The product is now just a delegation to the factory, without
having `fabricate!` and other methods.
parent 79ba3892
No related branches found
No related tags found
No related merge requests found
Showing
with 137 additions and 152 deletions
# frozen_string_literal: true
require 'forwardable'
 
module QA
Loading
Loading
@@ -5,8 +7,7 @@ module QA
class Base
extend SingleForwardable
 
def_delegators :evaluator, :dependency, :dependencies
def_delegators :evaluator, :product, :attributes
def_delegators :evaluator, :attribute
 
def fabricate!(*_args)
raise NotImplementedError
Loading
Loading
@@ -16,10 +17,6 @@ module QA
new.tap do |factory|
yield factory if block_given?
 
dependencies.each do |name, signature|
Factory::Dependency.new(name, factory, signature).build!
end
factory.fabricate!(*args)
 
break Factory::Product.populate!(factory)
Loading
Loading
@@ -30,30 +27,35 @@ module QA
@evaluator ||= Factory::Base::DSL.new(self)
end
 
class DSL
attr_reader :dependencies, :attributes
def self.attributes_module
const_get(:Attributes)
rescue NameError
mod = const_set(:Attributes, Module.new)
include mod
mod
end
 
def self.attributes_names
attributes_module.instance_methods.grep_v(/=$/)
end
class DSL
def initialize(base)
@base = base
@dependencies = {}
@attributes = {}
end
 
def dependency(factory, as:, &block)
as.tap do |name|
@base.class_eval { attr_accessor name }
def attribute(name, &block)
@base.attributes_module.module_eval do
attr_writer(name)
 
Dependency::Signature.new(factory, block).tap do |signature|
@dependencies.store(name, signature)
define_method(name) do
instance_variable_get("@#{name}") ||
instance_variable_set("@#{name}", instance_exec(&block))
end
end
end
def product(attribute, &block)
Product::Attribute.new(attribute, block).tap do |signature|
@attributes.store(attribute, signature)
end
end
end
end
end
Loading
Loading
module QA
module Factory
class Dependency
Signature = Struct.new(:factory, :block)
def initialize(name, factory, signature)
@name = name
@factory = factory
@signature = signature
end
def overridden?
!!@factory.public_send(@name)
end
def build!
return if overridden?
Builder.new(@signature, @factory).fabricate!.tap do |product|
@factory.public_send("#{@name}=", product)
end
end
class Builder
def initialize(signature, caller_factory)
@factory = signature.factory
@block = signature.block
@caller_factory = caller_factory
end
def fabricate!
@factory.fabricate! do |factory|
@block&.call(factory, @caller_factory)
end
end
end
end
end
end
Loading
Loading
@@ -5,8 +5,6 @@ module QA
class Product
include Capybara::DSL
 
Attribute = Struct.new(:name, :block)
def initialize
@location = current_url
end
Loading
Loading
@@ -17,10 +15,9 @@ module QA
 
def self.populate!(factory)
new.tap do |product|
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 }
factory.class.attributes_names.each do |name|
product.define_singleton_method(name) do
factory.public_send(name)
end
end
end
Loading
Loading
Loading
Loading
@@ -2,18 +2,14 @@ module QA
module Factory
module Repository
class ProjectPush < Factory::Repository::Push
dependency Factory::Resource::Project, as: :project do |project|
project.name = 'project-with-code'
project.description = 'Project with repository'
end
product :output do |factory|
factory.output
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-with-code'
resource.description = 'Project with repository'
end
end
 
product :project do |factory|
factory.project
end
attribute :output
 
def initialize
@file_name = 'file.txt'
Loading
Loading
Loading
Loading
@@ -2,10 +2,12 @@ module QA
module Factory
module Repository
class WikiPush < Factory::Repository::Push
dependency Factory::Resource::Wiki, as: :wiki do |wiki|
wiki.title = 'Home'
wiki.content = '# My First Wiki Content'
wiki.message = 'Update home'
attribute :wiki do
Factory::Resource::Wiki.fabricate! do |resource|
resource.title = 'Home'
resource.content = '# My First Wiki Content'
resource.message = 'Update home'
end
end
 
def initialize
Loading
Loading
Loading
Loading
@@ -5,8 +5,10 @@ module QA
attr_accessor :project, :branch_name,
:allow_to_push, :allow_to_merge, :protected
 
dependency Factory::Resource::Project, as: :project do |project|
project.name = 'protected-branch-project'
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'protected-branch-project'
end
end
 
def initialize
Loading
Loading
Loading
Loading
@@ -4,11 +4,11 @@ module QA
class DeployKey < Factory::Base
attr_accessor :title, :key
 
product :fingerprint do |resource|
Page::Project::Settings::Repository.act do
expand_deploy_keys do |key|
key_offset = key.key_titles.index do |title|
title.text == resource.title
attribute :fingerprint do
Page::Project::Settings::Repository.perform do |setting|
setting.expand_deploy_keys do |key|
key_offset = key.key_titles.index do |key_title|
key_title.text == title
end
 
key.key_fingerprints[key_offset].text
Loading
Loading
@@ -16,9 +16,11 @@ module QA
end
end
 
dependency Factory::Resource::Project, as: :project do |project|
project.name = 'project-to-deploy'
project.description = 'project for adding deploy key test'
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-to-deploy'
resource.description = 'project for adding deploy key test'
end
end
 
def fabricate!
Loading
Loading
Loading
Loading
@@ -8,8 +8,10 @@ module QA
:content,
:commit_message
 
dependency Factory::Resource::Project, as: :project do |project|
project.name = 'project-with-new-file'
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-with-new-file'
end
end
 
def initialize
Loading
Loading
Loading
Loading
@@ -2,17 +2,19 @@ module QA
module Factory
module Resource
class Fork < Factory::Base
dependency Factory::Repository::ProjectPush, as: :push
attribute :push do
Factory::Repository::ProjectPush.fabricate!
end
 
dependency Factory::Resource::User, as: :user do |user|
if Runtime::Env.forker?
user.username = Runtime::Env.forker_username
user.password = Runtime::Env.forker_password
attribute :user do
Factory::Resource::User.fabricate! do |resource|
if Runtime::Env.forker?
resource.username = Runtime::Env.forker_username
resource.password = Runtime::Env.forker_password
end
end
end
 
product(:user) { |factory| factory.user }
def visit_project_with_retry
# The user intermittently fails to stay signed in after visiting the
# project page. The new user is registered and then signs in and a
Loading
Loading
@@ -48,6 +50,9 @@ module QA
end
 
def fabricate!
push
user
visit_project_with_retry
 
Page::Project::Show.act { fork_project }
Loading
Loading
Loading
Loading
@@ -4,7 +4,9 @@ module QA
class Group < Factory::Base
attr_accessor :path, :description
 
dependency Factory::Resource::Sandbox, as: :sandbox
attribute :sandbox do
Factory::Resource::Sandbox.fabricate!
end
 
def initialize
@path = Runtime::Namespace.name
Loading
Loading
Loading
Loading
@@ -2,14 +2,16 @@ module QA
module Factory
module Resource
class Issue < Factory::Base
attr_writer :title, :description, :project
attr_writer :description
 
dependency Factory::Resource::Project, as: :project do |project|
project.name = 'project-for-issues'
project.description = 'project for adding issues'
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-for-issues'
resource.description = 'project for adding issues'
end
end
 
product :title do
attribute :title do
Page::Project::Issue::Show.act { issue_title }
end
 
Loading
Loading
Loading
Loading
@@ -7,7 +7,7 @@ module QA
attr_writer :project, :cluster,
:install_helm_tiller, :install_ingress, :install_prometheus, :install_runner
 
product :ingress_ip do
attribute :ingress_ip do
Page::Project::Operations::Kubernetes::Show.perform do |page|
page.ingress_ip
end
Loading
Loading
Loading
Loading
@@ -12,31 +12,32 @@ module QA
:milestone,
:labels
 
product :project do |factory|
factory.project
end
attribute :source_branch
 
product :source_branch do |factory|
factory.source_branch
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-with-merge-request'
end
end
 
dependency Factory::Resource::Project, as: :project do |project|
project.name = 'project-with-merge-request'
end
attribute :target do
project.visit!
 
dependency Factory::Repository::ProjectPush, as: :target do |push, factory|
factory.project.visit!
push.project = factory.project
push.branch_name = 'master'
push.remote_branch = factory.target_branch
Factory::Repository::ProjectPush.fabricate! do |resource|
resource.project = project
resource.branch_name = 'master'
resource.remote_branch = target_branch
end
end
 
dependency Factory::Repository::ProjectPush, as: :source do |push, factory|
push.project = factory.project
push.branch_name = factory.target_branch
push.remote_branch = factory.source_branch
push.file_name = "added_file.txt"
push.file_content = "File Added"
attribute :source do
Factory::Repository::ProjectPush.fabricate! do |resource|
resource.project = project
resource.branch_name = target_branch
resource.remote_branch = source_branch
resource.file_name = "added_file.txt"
resource.file_content = "File Added"
end
end
 
def initialize
Loading
Loading
@@ -50,6 +51,8 @@ module QA
end
 
def fabricate!
target
source
project.visit!
Page::Project::Show.act { new_merge_request }
Page::MergeRequest::New.perform do |page|
Loading
Loading
Loading
Loading
@@ -4,16 +4,21 @@ module QA
class MergeRequestFromFork < MergeRequest
attr_accessor :fork_branch
 
dependency Factory::Resource::Fork, as: :fork
attribute :fork do
Factory::Resource::Fork.fabricate!
end
 
dependency Factory::Repository::ProjectPush, as: :push do |push, factory|
push.project = factory.fork
push.branch_name = factory.fork_branch
push.file_name = 'file2.txt'
push.user = factory.fork.user
attribute :push do
Factory::Repository::ProjectPush.fabricate! do |resource|
resource.project = fork
resource.branch_name = fork_branch
resource.file_name = 'file2.txt'
resource.user = fork.user
end
end
 
def fabricate!
push
fork.visit!
Page::Project::Show.act { new_merge_request }
Page::MergeRequest::New.act { create_merge_request }
Loading
Loading
Loading
Loading
@@ -7,7 +7,7 @@ module QA
class PersonalAccessToken < Factory::Base
attr_accessor :name
 
product :access_token do
attribute :access_token do
Page::Profile::PersonalAccessTokens.act { created_access_token }
end
 
Loading
Loading
Loading
Loading
@@ -5,22 +5,21 @@ module QA
module Resource
class Project < Factory::Base
attr_writer :description
attr_reader :name
 
dependency Factory::Resource::Group, as: :group
product :name do |factory|
factory.name
attribute :group do
Factory::Resource::Group.fabricate!
end
 
product :repository_ssh_location do
attribute :name
attribute :repository_ssh_location do
Page::Project::Show.act do
choose_repository_clone_ssh
repository_location
end
end
 
product :repository_http_location do
attribute :repository_http_location do
Page::Project::Show.act do
choose_repository_clone_http
repository_location
Loading
Loading
Loading
Loading
@@ -6,12 +6,12 @@ module QA
class ProjectImportedFromGithub < Resource::Project
attr_writer :personal_access_token, :github_repository_path
 
dependency Factory::Resource::Group, as: :group
product :name do |factory|
factory.name
attribute :group do
Factory::Resource::Group.fabricate!
end
 
attribute :name
def fabricate!
group.visit!
 
Loading
Loading
Loading
Loading
@@ -3,11 +3,12 @@ module QA
module Resource
class ProjectMilestone < Factory::Base
attr_accessor :description
attr_reader :title
 
dependency Factory::Resource::Project, as: :project
attribute :project do
Factory::Resource::Project.fabricate!
end
 
product(:title) { |factory| factory.title }
attribute :title
 
def title=(title)
@title = "#{title}-#{SecureRandom.hex(4)}"
Loading
Loading
Loading
Loading
@@ -6,9 +6,11 @@ module QA
class Runner < Factory::Base
attr_writer :name, :tags, :image
 
dependency Factory::Resource::Project, as: :project do |project|
project.name = 'project-with-ci-cd'
project.description = 'Project with CI/CD Pipelines'
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-with-ci-cd'
resource.description = 'Project with CI/CD Pipelines'
end
end
 
def name
Loading
Loading
Loading
Loading
@@ -4,9 +4,11 @@ module QA
class SecretVariable < Factory::Base
attr_accessor :key, :value
 
dependency Factory::Resource::Project, as: :project do |project|
project.name = 'project-with-secret-variables'
project.description = 'project for adding secret variable test'
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-with-secret-variables'
resource.description = 'project for adding secret variable test'
end
end
 
def fabricate!
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment