1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
# frozen_string_literal: true
FactoryBot.define do
factory :design, class: 'DesignManagement::Design' do
issue { create(:issue) }
project { issue&.project || create(:project) }
sequence(:filename) { |n| "homescreen-#{n}.jpg" }
transient do
author { issue.author }
end
trait :importing do
issue { nil }
importing { true }
imported { false }
end
trait :imported do
importing { false }
imported { true }
end
trait :with_relative_position do
sequence(:relative_position) { |n| n * 1000 }
end
create_versions = ->(design, evaluator, commit_version) do
unless evaluator.versions_count == 0
project = design.project
issue = design.issue
repository = project.design_repository
repository.create_if_not_exists
dv_table_name = DesignManagement::Action.table_name
updates = [0, evaluator.versions_count - (evaluator.deleted ? 2 : 1)].max
run_action = ->(action) do
sha = commit_version[action]
version = DesignManagement::Version.new(sha: sha, issue: issue, author: evaluator.author)
version.save!(validate: false) # We need it to have an ID, validate later
Gitlab::Database.bulk_insert(dv_table_name, [action.row_attrs(version)]) # rubocop:disable Gitlab/BulkInsert
end
# always a creation
run_action[DesignManagement::DesignAction.new(design, :create, evaluator.file)]
# 0 or more updates
updates.times do
run_action[DesignManagement::DesignAction.new(design, :update, evaluator.file)]
end
# and maybe a deletion
run_action[DesignManagement::DesignAction.new(design, :delete)] if evaluator.deleted
end
design.clear_version_cache
end
# Use this trait to build designs that are backed by Git LFS, committed
# to the repository, and with an LfsObject correctly created for it.
trait :with_lfs_file do
with_file
transient do
raw_file { fixture_file_upload('spec/fixtures/dk.png', 'image/png') }
lfs_pointer { Gitlab::Git::LfsPointerFile.new(SecureRandom.random_bytes) }
file { lfs_pointer.pointer }
end
after :create do |design, evaluator|
lfs_object = create(:lfs_object, file: evaluator.raw_file, oid: evaluator.lfs_pointer.sha256, size: evaluator.lfs_pointer.size)
create(:lfs_objects_project, project: design.project, lfs_object: lfs_object, repository_type: :design)
end
end
# Use this trait if you want versions in a particular history, but don't
# want to pay for gitaly calls.
trait :with_versions do
transient do
deleted { false }
versions_count { 1 }
sequence(:file) { |n| "some-file-content-#{n}" }
end
after :create do |design, evaluator|
counter = (1..).lazy
# Just produce a SHA by hashing the action and a monotonic counter
commit_version = ->(action) do
Digest::SHA1.hexdigest("#{action.gitaly_action}.#{counter.next}")
end
create_versions[design, evaluator, commit_version]
end
end
# Use this trait to build designs that have commits in the repository
# and files that can be retrieved.
trait :with_file do
transient do
deleted { false }
versions_count { 1 }
file { File.join(Rails.root, 'spec/fixtures/dk.png') }
end
after :create do |design, evaluator|
project = design.project
repository = project.design_repository
commit_version = ->(action) do
repository.multi_action(
evaluator.author,
branch_name: 'master',
message: "#{action.action} for #{design.filename}",
actions: [action.gitaly_action]
)
end
create_versions[design, evaluator, commit_version]
end
end
trait :with_smaller_image_versions do
with_lfs_file
after :create do |design|
design.versions.each { |v| DesignManagement::GenerateImageVersionsService.new(v).execute }
end
end
end
end
|