• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pulibrary / tigerdata-app / 1f9ee909-20b2-467d-b493-b5be4964430d

22 Oct 2025 04:57PM UTC coverage: 91.212%. Remained the same
1f9ee909-20b2-467d-b493-b5be4964430d

push

circleci

web-flow
Fixing flaky tests (#2080)

10 times out of 10 one of these tests would fail for me locally.

Really we just have to look at the page for something new so that we are
sure the controller action has finished before we check for something
that is not waiting.

2740 of 3004 relevant lines covered (91.21%)

755.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.28
/app/models/project_metadata.rb
1
# frozen_string_literal: true
2

3
# rubocop:disable Metrics/ClassLength
4
class ProjectMetadata
6✔
5
  DOI_NOT_MINTED = "DOI-NOT-MINTED"
6✔
6

7
  # @return [String] The default directory protocol
8
  def self.default_directory_protocol
6✔
9
    "NFS"
92✔
10
  end
11

12
  # @return [String] The default project resource type
13
  def self.default_resource_type
6✔
14
    "TigerData Project"
914✔
15
  end
16

17
  # @return [String] The default HPC value
18
  def self.default_hpc
6✔
19
    "No"
908✔
20
  end
21

22
  # @return [String] The default project visibility
23
  def self.default_project_visibility
6✔
24
    "Restricted"
914✔
25
  end
26

27
  # @return [String] The default data use agreement
28
  def self.default_data_use_agreement
6✔
29
    "No"
914✔
30
  end
31

32
  # @return [Hash] The default globus request Hash entries
33
  def self.default_globus_request
6✔
34
    "No"
1,289✔
35
  end
36

37
  # @return [Hash] The default Samba/SMB request Hash entries
38
  def self.default_smb_request
6✔
39
    "No"
1,289✔
40
  end
41

42
  # @return [Boolean] The default value for whether a project is provisional
43
  def self.default_provisionality
6✔
44
    false
1,393✔
45
  end
46

47
  # Ensure that the project directory is a valid path
48
  def self.safe_directory(directory)
6✔
49
    return "" if directory.nil?
1,397✔
50

51
    # only alphanumeric characters and /
52
    directory.strip.gsub(/[^A-Za-z\d\/]/, "-")
1,395✔
53
  end
54

55
  attr_accessor(
6✔
56
    :title, :description, :status, :data_sponsor, :data_manager, :departments, :data_user_read_only, :data_user_read_write,
57
    :created_on, :created_by, :project_id, :project_directory, :project_purpose, :storage_capacity, :storage_performance_expectations,
58
    :updated_by, :updated_on, :approval_note, :schema_version, :submission,
59
    # NOTE: The following attributes are required by the XML schema
60
    :hpc,
61
    :data_use_agreement,
62
    :project_visibility,
63
    :resource_type,
64
    :project_directory_protocol,
65
    :globus_request,
66
    :smb_request,
67
    :number_of_files,
68
    :provisional
69
  )
70

71
  def initialize
6✔
72
    @departments = []
1,391✔
73
    @data_user_read_only = []
1,391✔
74
    @data_user_read_write = []
1,391✔
75
  end
76

77
  def self.new_from_hash(metadata_hash)
6✔
78
    pm = ProjectMetadata.new
1,373✔
79
    pm.initialize_from_hash(metadata_hash)
1,373✔
80
    pm
1,373✔
81
  end
82

83
  def self.new_from_params(metadata_params)
6✔
84
    pm = ProjectMetadata.new
×
85
    pm.initialize_from_params(metadata_params)
×
86
    pm
×
87
  end
88

89
  # rubocop:disable Metrics/AbcSize
90
  # rubocop:disable Metrics/CyclomaticComplexity
91
  # rubocop:disable Metrics/MethodLength
92
  # rubocop:disable Metrics/PerceivedComplexity
93
  def initialize_from_hash(metadata_hash)
6✔
94
    @title = metadata_hash[:title]
1,393✔
95
    @description = metadata_hash[:description]
1,393✔
96
    @status = metadata_hash[:status] if metadata_hash[:status]
1,393✔
97
    @data_sponsor = metadata_hash[:data_sponsor]
1,393✔
98
    @data_manager = metadata_hash[:data_manager]
1,393✔
99
    @departments = metadata_hash[:departments]
1,393✔
100
    @data_user_read_only = metadata_hash[:data_user_read_only] if metadata_hash[:data_user_read_only]
1,393✔
101
    @data_user_read_write = metadata_hash[:data_user_read_write] if metadata_hash[:data_user_read_write]
1,393✔
102

103
    @project_id = metadata_hash[:project_id] || ProjectMetadata::DOI_NOT_MINTED
1,393✔
104
    @project_purpose = metadata_hash[:project_purpose]
1,393✔
105
    @project_directory = ProjectMetadata.safe_directory(metadata_hash[:project_directory])
1,393✔
106

107
    @storage_capacity = metadata_hash[:storage_capacity]
1,393✔
108
    @storage_performance_expectations = metadata_hash[:storage_performance_expectations]
1,393✔
109

110
    @created_by = metadata_hash[:created_by] if metadata_hash[:created_by]
1,393✔
111
    @created_on = metadata_hash[:created_on] if metadata_hash[:created_on]
1,393✔
112
    @updated_by = metadata_hash[:updated_by] if metadata_hash[:updated_by]
1,393✔
113
    @updated_on = metadata_hash[:updated_on] if metadata_hash[:updated_on]
1,393✔
114

115
    # NOTE: The following attributes are required by the 0.8 XML schema
116
    @number_of_files = metadata_hash[:number_of_files] || "Less than 10,000"
1,393✔
117
    @hpc = metadata_hash[:hpc] || self.class.default_hpc
1,393✔
118
    @globus_request = metadata_hash[:globus] || self.class.default_globus_request
1,393✔
119
    @smb_request = metadata_hash[:smb] || self.class.default_smb_request
1,393✔
120

121
    @data_use_agreement = metadata_hash[:data_use_agreement] || self.class.default_data_use_agreement
1,393✔
122

123
    @project_visibility = metadata_hash[:project_visibility] || self.class.default_project_visibility
1,393✔
124
    @resource_type = metadata_hash[:resource_type] || self.class.default_resource_type
1,393✔
125

126
    @provisional = metadata_hash[:provisional] || self.class.default_provisionality
1,393✔
127

128
    set_defaults
1,393✔
129
  end
130
  # rubocop:enable Metrics/PerceivedComplexity
131
  # rubocop:enable Metrics/MethodLength
132
  # rubocop:enable Metrics/CyclomaticComplexity
133
  # rubocop:enable Metrics/AbcSize
134

135
  # Initializes the object with the values in the params (which is an ActionController::Parameters)
136
  def initialize_from_params(params)
6✔
137
    @data_user_read_only = ro_users_from_params(params)
14✔
138
    @data_user_read_write = rw_users_from_params(params)
14✔
139
    initialize_from_hash(params)
14✔
140
  end
141

142
  # Updates the object with the values in the params (which is an ActionController::Parameters)
143
  # Notice how we only update values that come in the params and don't change the values that
144
  # don't come as part of the params
145
  # rubocop:disable Metrics/MethodLength
146
  def update_with_params(params, current_user)
6✔
147
    set_value(params, "title")
14✔
148
    set_value(params, "description")
14✔
149
    set_value(params, "status")
14✔
150
    set_value(params, "data_sponsor")
14✔
151
    set_value(params, "data_manager")
14✔
152
    set_value(params, "departments")
14✔
153
    set_value(params, "project_id")
14✔
154
    set_value(params, "project_purpose")
14✔
155
    calculate_project_directory(params)
14✔
156

157
    if params["data_user_counter"].present?
14✔
158
      @data_user_read_only = ro_users_from_params(params)
×
159
      @data_user_read_write = rw_users_from_params(params)
×
160
    end
161

162
    update_storage_capacity(params)
14✔
163
    update_storage_performance_expectations
14✔
164
    update_approval_note(params, current_user)
14✔
165
    @submission = params[:submission] if params[:submission]
14✔
166

167
    # Fields that come from the edit form
168
    @updated_by = current_user.uid
14✔
169
    @updated_on = Time.current.in_time_zone("America/New_York").iso8601
14✔
170
  end
171
  # rubocop:enable Metrics/MethodLength
172

173
  # Alias for `data_user_read_only`
174
  def ro_users
6✔
175
    @data_user_read_only
284✔
176
  end
177

178
  # Alias for `data_user_read_write`
179
  def rw_users
6✔
180
    @data_user_read_write
284✔
181
  end
182

183
    private
6✔
184

185
      def data_users_from_params(params, access)
6✔
186
        return [] if params.nil?
28✔
187
        users = []
28✔
188
        counter = params[:data_user_counter].to_i
28✔
189
        (1..counter).each do |i|
28✔
190
          key = "data_user_#{i}"
8✔
191
          access_key = key + "_read_access"
8✔
192
          if params[access_key] == access
8✔
193
            users << params[key]
4✔
194
          end
195
        end
196
        users.compact.uniq
28✔
197
      end
198

199
      def ro_users_from_params(params)
6✔
200
        data_users_from_params(params, "read-only")
14✔
201
      end
202

203
      def rw_users_from_params(params)
6✔
204
        data_users_from_params(params, "read-write")
14✔
205
      end
206

207
      # Initializes values that we have defaults for.
208
      def set_defaults
6✔
209
        if @storage_capacity.nil?
1,393✔
210
          @storage_capacity = Rails.configuration.project_defaults[:storage_capacity]
120✔
211
        end
212

213
        if @storage_performance_expectations.nil?
1,393✔
214
          @storage_performance_expectations = Rails.configuration.project_defaults[:storage_performance_expectations]
120✔
215
        end
216

217
        if @project_purpose.nil?
1,393✔
218
          @project_purpose = Rails.configuration.project_defaults[:project_purpose]
380✔
219
        end
220

221
        @submission = { "requested_by" => @created_by, "request_date_time" => @created_on } if @submission.nil?
1,393✔
222
        @schema_version = TigerdataSchema::SCHEMA_VERSION
1,393✔
223
      end
224

225
      # Sets a value in the object if the value exists in the params
226
      def set_value(params, key)
6✔
227
        if params.include?(key)
112✔
228
          send("#{key}=", params[key])
30✔
229
        end
230
      end
231

232
      def update_storage_capacity(params)
6✔
233
        if params["storage_capacity"].present?
14✔
234
          @storage_capacity = {
235
            "size" => {
×
236
              "approved" => params["storage_capacity"].to_i,
237
              "requested" => storage_capacity[:size][:requested]
238
            },
239
            "unit" => {
240
              "approved" => params["storage_unit"],
241
              "requested" => storage_capacity[:unit][:requested]
242
            }
243
          }
244
        end
245
      end
246

247
      def update_storage_performance_expectations
6✔
248
        # we don't allow the user to specify an approve value so we use the requested
249
        @storage_performance_expectations = {
250
          "requested" => storage_performance_expectations[:requested],
14✔
251
          "approved" => storage_performance_expectations[:requested]
252
        }
253
      end
254

255
      def update_approval_note(params, current_user)
6✔
256
        if params[:event_note_message].present?
14✔
257
          @approval_note = {
258
            note_by: current_user.uid,
4✔
259
            note_date_time: Time.current.in_time_zone("America/New_York").iso8601,
260
            event_type: params[:event_note],
261
            message: params[:event_note_message]
262
          }
263
        end
264
      end
265

266
      def calculate_project_directory(params)
6✔
267
        if params.key?("project_directory_prefix") || params.key?("project_directory")
14✔
268
          full_path = [params["project_directory_prefix"], params["project_directory"]].compact.join("/")
4✔
269
          @project_directory = ProjectMetadata.safe_directory(full_path)
4✔
270
        end
271
      end
272
end
273
# rubocop:enable Metrics/ClassLength
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc