content_server 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/backup_server +8 -20
- data/bin/content_server +8 -20
- data/bin/testing_memory +60 -0
- data/bin/testing_server +57 -0
- data/ext/run_in_background/mkrf_conf.rb +34 -0
- data/lib/content_data/content_data.rb +613 -0
- data/lib/content_data/version.rb +3 -0
- data/lib/content_data.rb +6 -0
- data/lib/content_server/backup_server.rb +65 -86
- data/lib/content_server/content_server.rb +47 -77
- data/lib/content_server/file_streamer.rb +27 -33
- data/lib/content_server/queue_copy.rb +154 -49
- data/lib/content_server/queue_indexer.rb +19 -11
- data/lib/content_server/remote_content.rb +41 -23
- data/lib/content_server/server.rb +91 -0
- data/lib/content_server/version.rb +1 -1
- data/lib/content_server.rb +0 -15
- data/lib/email/email.rb +87 -0
- data/lib/email/version.rb +3 -0
- data/lib/email.rb +4 -0
- data/lib/file_copy/copy.rb +68 -0
- data/lib/file_copy/version.rb +4 -0
- data/lib/file_copy.rb +4 -0
- data/lib/file_indexing/index_agent.rb +170 -0
- data/lib/file_indexing/indexer_patterns.rb +72 -0
- data/lib/file_indexing/version.rb +3 -0
- data/lib/file_indexing.rb +9 -0
- data/lib/file_monitoring/file_monitoring.rb +105 -0
- data/lib/file_monitoring/monitor_path.rb +304 -0
- data/lib/file_monitoring/version.rb +3 -0
- data/lib/file_monitoring.rb +29 -0
- data/lib/file_utils/file_generator/README +97 -0
- data/lib/file_utils/file_generator/file_generator.rb +156 -0
- data/lib/file_utils/file_utils.rb +260 -0
- data/lib/file_utils/version.rb +3 -0
- data/lib/file_utils.rb +4 -0
- data/lib/log/version.rb +3 -0
- data/lib/log.rb +188 -0
- data/lib/networking/tcp.rb +213 -0
- data/lib/networking/version.rb +3 -0
- data/lib/networking.rb +4 -0
- data/lib/params/version.rb +3 -0
- data/lib/params.rb +419 -0
- data/lib/process_monitoring/monitoring.rb +85 -0
- data/lib/process_monitoring/monitoring_info.rb +79 -0
- data/lib/process_monitoring/send_email.rb +40 -0
- data/lib/process_monitoring/thread_safe_hash.rb +77 -0
- data/lib/process_monitoring/version.rb +3 -0
- data/lib/process_monitoring.rb +6 -0
- data/lib/run_in_background/version.rb +3 -0
- data/lib/run_in_background.rb +432 -0
- data/lib/testing_memory/testing_memory.rb +187 -0
- data/lib/testing_server/testing_server.rb +236 -0
- data/lib/testing_server/version.rb +3 -0
- data/lib/testing_server.rb +12 -0
- data/lib/validations/index_validations.rb +106 -0
- data/lib/validations/version.rb +3 -0
- data/lib/validations.rb +4 -0
- data/spec/content_data/validations_spec.rb +113 -0
- data/spec/file_copy/copy_spec.rb +54 -0
- data/spec/file_indexing/index_agent_spec.rb +53 -0
- data/spec/networking/tcp_spec.rb +95 -0
- data/spec/validations/index_validations_spec.rb +77 -0
- data/test/content_data/content_data_test.rb +290 -0
- data/test/file_generator/file_generator_spec.rb +84 -0
- data/test/file_indexing/index_agent_test/New.txt +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/libexslt.dll +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/libxslt.dll +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/xsltproc.exe +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exslt.h +102 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exsltconfig.h +73 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exsltexports.h +140 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/libexslt.h +29 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/attributes.h +38 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/documents.h +93 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/extensions.h +262 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/extra.h +80 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/functions.h +78 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/imports.h +75 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/keys.h +53 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/libxslt.h +30 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/namespaces.h +68 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/numbersInternals.h +69 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/pattern.h +81 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/preproc.h +43 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/security.h +104 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/templates.h +77 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/transform.h +207 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/trio.h +216 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/triodef.h +220 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/variables.h +91 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/win32config.h +101 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xslt.h +103 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltInternals.h +1967 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltconfig.h +172 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltexports.h +142 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltlocale.h +57 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltutils.h +309 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltwin32config.h +105 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libexslt.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libexslt_a.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libxslt.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libxslt_a.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/readme.txt +22 -0
- data/test/file_indexing/index_agent_test/patterns.input +3 -0
- data/test/file_indexing/index_agent_test.rb +51 -0
- data/test/file_monitoring/file_monitoring_test/conf.yml +4 -0
- data/test/file_monitoring/file_monitoring_test/conf_win32.yml +5 -0
- data/test/file_monitoring/file_monitoring_test/log +56 -0
- data/test/file_monitoring/file_monitoring_test.rb +0 -0
- data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000 +1000 -0
- data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000.0 +1000 -0
- data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000.1 +1000 -0
- data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500 +1500 -0
- data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500.0 +1500 -0
- data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500.1 +1500 -0
- data/test/file_monitoring/monitor_path_test/test_file.500 +500 -0
- data/test/file_monitoring/monitor_path_test/test_file.500.0 +500 -0
- data/test/file_monitoring/monitor_path_test/test_file.500.1 +500 -0
- data/test/file_monitoring/monitor_path_test.rb +153 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500 +1500 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500.0 +1500 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500.1 +1500 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000 +1000 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000.0 +1000 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000.1 +1000 -0
- data/test/file_utils/fileutil_mksymlink_test/test_file.500 +500 -0
- data/test/file_utils/fileutil_mksymlink_test/test_file.500.0 +500 -0
- data/test/file_utils/fileutil_mksymlink_test/test_file.500.1 +500 -0
- data/test/file_utils/fileutil_mksymlink_test.rb +125 -0
- data/test/file_utils/time_modification_test.rb +132 -0
- data/test/params/params_spec.rb +280 -0
- data/test/params/params_test.rb +43 -0
- data/test/run_in_background/run_in_background_test.rb +122 -0
- data/test/run_in_background/test_app +57 -0
- metadata +272 -132
- data/lib/content_server/globals.rb +0 -10
@@ -0,0 +1,236 @@
|
|
1
|
+
#require 'net/sftp'
|
2
|
+
#require 'net/ssh'
|
3
|
+
require 'log4r'
|
4
|
+
require 'log'
|
5
|
+
require 'params'
|
6
|
+
require 'content_server'
|
7
|
+
require 'content_server/content_server' # specific content server impl
|
8
|
+
require 'content_server/backup_server' # specific backup server impl
|
9
|
+
require 'content_data'
|
10
|
+
require 'email'
|
11
|
+
require 'file_utils/file_generator/file_generator'
|
12
|
+
require 'validations'
|
13
|
+
|
14
|
+
# Testing server. Assumes that content and backup servers are running.
|
15
|
+
# The server runs 24-7, generates/deletes files and validates content at backup periodically.
|
16
|
+
module TestingServer
|
17
|
+
# TODO get latest ContentData object directly from Content/BackupServer
|
18
|
+
# Then need changes in Content/BackupServers API
|
19
|
+
# TODO split to Backup/ContentTestingServers separate classes ?
|
20
|
+
# TODO split long methods
|
21
|
+
# TODO Tests
|
22
|
+
# TODO No default config taken by Params
|
23
|
+
# TODO Additional testing scenarios (remove/rename/change)
|
24
|
+
|
25
|
+
# Messages types
|
26
|
+
:GET_INDEX # get index from remote master
|
27
|
+
:PUT_INDEX # message contains requested index from master
|
28
|
+
# TODO in thus implementation validation called automatically on master side
|
29
|
+
# with receiving GET_INDEX message
|
30
|
+
# More flexible will be separating it to two separate operations:
|
31
|
+
# GET_INDEX and VALIDATE
|
32
|
+
#:VALIDATE # validate index on master
|
33
|
+
:PUT_VALIDATION # message contains validation result from master
|
34
|
+
|
35
|
+
Params.path('testing_log_path', nil, 'Testing server log path.')
|
36
|
+
|
37
|
+
# init process vars
|
38
|
+
$objects_counters = {}
|
39
|
+
$objects_counters["Time"] = Time.now.to_i
|
40
|
+
|
41
|
+
def init_log4r
|
42
|
+
#init log4r
|
43
|
+
log_path = Params['testing_log_path']
|
44
|
+
unless log_path
|
45
|
+
raise("pls specify testing log path through param:'testing_log_path'")
|
46
|
+
end
|
47
|
+
log_dir = File.dirname(log_path)
|
48
|
+
FileUtils.mkdir_p(log_dir) unless File.exists?(log_dir)
|
49
|
+
|
50
|
+
$log4r = Log4r::Logger.new 'BBFS testing server log'
|
51
|
+
$log4r.trace = true
|
52
|
+
formatter = Log4r::PatternFormatter.new(:pattern => "[%d] [%m]")
|
53
|
+
#file setup
|
54
|
+
file_config = {
|
55
|
+
"filename" => Params['testing_log_path'],
|
56
|
+
"maxsize" => Params['log_rotation_size'],
|
57
|
+
"trunc" => true
|
58
|
+
}
|
59
|
+
file_outputter = Log4r::RollingFileOutputter.new("testing_log", file_config)
|
60
|
+
file_outputter.level = Log4r::INFO
|
61
|
+
file_outputter.formatter = formatter
|
62
|
+
$log4r.outputters << file_outputter
|
63
|
+
end
|
64
|
+
|
65
|
+
def run_content_testing_server
|
66
|
+
Log.info('Testing server started')
|
67
|
+
init_log4r
|
68
|
+
$log4r.info 'Testing server started'
|
69
|
+
all_threads = [];
|
70
|
+
messages = Queue.new
|
71
|
+
|
72
|
+
all_threads << Thread.new do
|
73
|
+
ContentServer.run_content_server
|
74
|
+
end
|
75
|
+
|
76
|
+
all_threads << Thread.new do
|
77
|
+
fg = FileGenerator::FileGenerator.new
|
78
|
+
fg.run
|
79
|
+
end
|
80
|
+
|
81
|
+
receive_msg_proc = lambda do |addr_info, message|
|
82
|
+
$log4r.info("message received: #{message}")
|
83
|
+
messages.push(message)
|
84
|
+
end
|
85
|
+
tcp = Networking::TCPServer.new(Params['testing_server_port'], receive_msg_proc)
|
86
|
+
|
87
|
+
all_threads << tcp.tcp_thread
|
88
|
+
|
89
|
+
while(true) do
|
90
|
+
msg_type, validation_timestamp = messages.pop
|
91
|
+
if msg_type == :GET_INDEX
|
92
|
+
cur_index = ContentData::ContentData.new
|
93
|
+
cur_index.from_file(Params['local_content_data_path'])
|
94
|
+
tcp.send_obj([:PUT_INDEX, validation_timestamp, cur_index])
|
95
|
+
$log4r.info "PUT_INDEX sent with timestamp #{validation_timestamp}"
|
96
|
+
is_index_ok = cur_index.validate
|
97
|
+
tcp.send_obj([:PUT_VALIDATION, validation_timestamp, is_index_ok])
|
98
|
+
$log4r.info "PUT_VALIDATION sent with timestamp #{validation_timestamp}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
module_function :run_content_testing_server
|
103
|
+
|
104
|
+
def run_backup_testing_server
|
105
|
+
Log.info('Testing server started')
|
106
|
+
init_log4r
|
107
|
+
$log4r.info 'Testing server started'
|
108
|
+
all_threads = [];
|
109
|
+
messages = Queue.new
|
110
|
+
# used for synchronization between servers
|
111
|
+
validation_timestamp = Time.now.to_i
|
112
|
+
# holds boolean whether all contents according to this timestamp that should be backed are backed and OK
|
113
|
+
is_cur_synch_ok = nil
|
114
|
+
# holds boolean whether all already backuped files are OK
|
115
|
+
is_backup_ok = nil
|
116
|
+
# holds boolean whether master is valid. receive from master
|
117
|
+
is_master_ok = nil
|
118
|
+
# number of contents must be backuped this synch
|
119
|
+
# with current scenarios this number expected to grow
|
120
|
+
# used to check that file_generator is actually running
|
121
|
+
numb_backuped_contents = 0
|
122
|
+
|
123
|
+
all_threads << Thread.new do
|
124
|
+
ContentServer.run_backup_server
|
125
|
+
end
|
126
|
+
|
127
|
+
receive_msg_proc = lambda do |message|
|
128
|
+
$log4r.info("message received: #{message}")
|
129
|
+
messages.push(message)
|
130
|
+
end
|
131
|
+
tcp = Networking::TCPClient.new(Params['content_server_hostname'],
|
132
|
+
Params['testing_server_port'], receive_msg_proc)
|
133
|
+
all_threads << tcp.tcp_thread
|
134
|
+
|
135
|
+
# used to request index from master per validation interval of time
|
136
|
+
all_threads << Thread.new do
|
137
|
+
while(true) do
|
138
|
+
sleep Params['validation_interval']
|
139
|
+
validation_timestamp = Time.now.to_i
|
140
|
+
tcp.send_obj([:GET_INDEX, validation_timestamp])
|
141
|
+
$log4r.info "GET_INDEX sent with timestamp #{validation_timestamp}"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# gets messages from master via queue
|
146
|
+
# handles them according to type
|
147
|
+
while(true) do
|
148
|
+
msg_type, response_validation_timestamp, msg_body = messages.pop
|
149
|
+
$log4r.info "#{msg_type} : #{validation_timestamp} : #{msg_body.class}"
|
150
|
+
unless (validation_timestamp == response_validation_timestamp)
|
151
|
+
# TODO problem of servers synch. What should be done here?
|
152
|
+
$log4r.warning "Timestamps differs: requested #{validation_timestamp} : received #{response_validation_timestamp}"
|
153
|
+
end
|
154
|
+
|
155
|
+
case msg_type
|
156
|
+
when :PUT_INDEX
|
157
|
+
# index of already backuped contents
|
158
|
+
backuped_index = ContentData::ContentData.new
|
159
|
+
backuped_index.from_file Params['local_content_data_path']
|
160
|
+
# index contains only master current contents
|
161
|
+
# that must be backuped according to backup_time_requirement parameter
|
162
|
+
index_must_be_backuped = ContentData::ContentData.new(msg_body)
|
163
|
+
# we backup contents, so content mtime used to determine contents should be validated
|
164
|
+
index_must_be_backuped.each_content do |checksum, size, mtime|
|
165
|
+
if (validation_timestamp - mtime < Params['backup_time_requirement'])
|
166
|
+
index_must_be_backuped.remove_content checksum
|
167
|
+
end
|
168
|
+
end
|
169
|
+
is_cur_synch_ok =
|
170
|
+
Validations::IndexValidations.validate_remote_index index_must_be_backuped, backuped_index
|
171
|
+
is_backup_ok = backuped_index.validate
|
172
|
+
numb_backuped_contents = index_must_be_backuped.contents_size
|
173
|
+
when :PUT_VALIDATION
|
174
|
+
is_master_ok = msg_body
|
175
|
+
else
|
176
|
+
$log4r.error "Incorrect message received: #{msg_type}"
|
177
|
+
end
|
178
|
+
|
179
|
+
unless (is_master_ok.nil? || is_cur_synch_ok.nil? || is_backup_ok.nil?)
|
180
|
+
send_email is_master_ok, is_cur_synch_ok, is_backup_ok, numb_backuped_contents
|
181
|
+
is_master_ok = nil
|
182
|
+
is_cur_synch_ok = nil
|
183
|
+
is_backup_ok = nil
|
184
|
+
numb_backuped_contents = 0
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
def generate_mem_report
|
191
|
+
# Generate memory report
|
192
|
+
current_objects_counters = {}
|
193
|
+
time = Time.now
|
194
|
+
current_objects_counters['Time'] = time.to_i
|
195
|
+
count = ObjectSpace.each_object(String).count
|
196
|
+
current_objects_counters['String'] = count
|
197
|
+
count = ObjectSpace.each_object(ContentData::ContentData).count
|
198
|
+
current_objects_counters['ContentData'] = count
|
199
|
+
dir_count = ObjectSpace.each_object(FileMonitoring::DirStat).count
|
200
|
+
current_objects_counters['DirStat'] = dir_count
|
201
|
+
file_count = ObjectSpace.each_object(FileMonitoring::FileStat).count
|
202
|
+
current_objects_counters['FileStat'] = file_count-dir_count
|
203
|
+
|
204
|
+
# Generate report and update global counters
|
205
|
+
report = ""
|
206
|
+
current_objects_counters.each_key { |type|
|
207
|
+
$objects_counters[type] = 0 unless $objects_counters[type]
|
208
|
+
diff = current_objects_counters[type] - $objects_counters[type]
|
209
|
+
report += "Type:#{type} raised in:#{diff} \n"
|
210
|
+
$objects_counters[type] = current_objects_counters[type]
|
211
|
+
}
|
212
|
+
final_report = "Memory report at Time:#{time}:\n#{report}\n"
|
213
|
+
$log4r.info(final_report)
|
214
|
+
final_report
|
215
|
+
end
|
216
|
+
def send_email(is_master_ok, is_cur_synch_ok, is_backup_ok, numb_backuped_contents)
|
217
|
+
|
218
|
+
msg =<<EOF
|
219
|
+
Master index ok: #{is_master_ok}
|
220
|
+
Backup index ok: #{is_backup_ok}
|
221
|
+
Backup includes all master files upto -#{Params['backup_time_requirement']} sec: #{is_cur_synch_ok}
|
222
|
+
Number of contents must be back-up: #{numb_backuped_contents}
|
223
|
+
#{generate_mem_report}
|
224
|
+
EOF
|
225
|
+
Email.send_email(Params['from_email'],
|
226
|
+
Params['from_email_password'],
|
227
|
+
Params['to_email'],
|
228
|
+
'Testing server update',
|
229
|
+
msg)
|
230
|
+
end
|
231
|
+
|
232
|
+
module_function :send_email, :run_backup_testing_server, :init_log4r, :generate_mem_report
|
233
|
+
|
234
|
+
end # module TestingServer
|
235
|
+
|
236
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'testing_server/testing_server'
|
2
|
+
|
3
|
+
module TestingServer
|
4
|
+
Params.integer('testing_server_port', 4445, 'Remote port to synchronization between testing servers')
|
5
|
+
#Params.integer('email_delay_in_seconds', 60*60*6, 'Number of seconds before sending email again.')
|
6
|
+
Params.integer('validation_interval', 60*60*6, 'Number of seconds between validations')
|
7
|
+
Params.integer('backup_time_requirement', 60*60,
|
8
|
+
'Max diff in seconds between timestamps of file indexation on master ' +
|
9
|
+
'and its content indexation on backup.' +
|
10
|
+
' NOTE Machines must have time synchronization.' +
|
11
|
+
' NOTE This requirement must be set sufficient, i.e. enough to finish copy file process')
|
12
|
+
end # module TestingServer
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'params'
|
2
|
+
require 'log'
|
3
|
+
require 'content_data'
|
4
|
+
require 'file_indexing/index_agent'
|
5
|
+
|
6
|
+
# TODO additional params?
|
7
|
+
# TODO are params names good enough?
|
8
|
+
module Validations
|
9
|
+
class IndexValidations
|
10
|
+
|
11
|
+
# TODO should it be renamed cause it can validate any indexes, not specially remote, one against another.
|
12
|
+
|
13
|
+
# Validates remote index against local file system.
|
14
|
+
# Remote index defined valid when every remote content has at least one valid local instance.
|
15
|
+
#
|
16
|
+
# There are two levels of validation, controlled by instance_check_level system parameter:
|
17
|
+
# * shallow - quick, tests instance for file existence and attributes.
|
18
|
+
# * deep - can take more time, in addition to shallow recalculates hash sum.
|
19
|
+
# For more infoemation see <tt>ContentData</tt> documentation.
|
20
|
+
# @param [ContentData] remote_index it's contents should be validate against local index
|
21
|
+
# @param [ContentData] local_index contains local contents and instances used for validation
|
22
|
+
# @param [Hash] params hash of parameters of validation, can be used to return additional data
|
23
|
+
#
|
24
|
+
# Supported key/value combinations:
|
25
|
+
# * key is <tt>:failed</tt> value is <tt>ContentData</tt> used to return failed instances
|
26
|
+
# @return [Boolean] true when every remote content has at least one valid local instance, false otherwise
|
27
|
+
# @raise [ArgumentError] when instance_check_level is incorrect
|
28
|
+
def IndexValidations.validate_remote_index(remote_index, local_index, params = nil)
|
29
|
+
raise ArgumentError 'remote_index must be defined' if remote_index.nil?
|
30
|
+
raise ArgumentError 'local index must be defined' if local_index.nil?
|
31
|
+
|
32
|
+
# used to answer whether specific param was set
|
33
|
+
param_exists = Proc.new do |param|
|
34
|
+
!(params.nil? || params[param].nil?)
|
35
|
+
end
|
36
|
+
|
37
|
+
# used to process method parameters centrally
|
38
|
+
# TODO consider more convenient form of parameters
|
39
|
+
# TODO code duplication with ContentData::validate
|
40
|
+
process_params = Proc.new do |checksum, content_mtime, size, instance_mtime, server, path|
|
41
|
+
if param_exists.call(:failed)
|
42
|
+
params[:failed].add_instance(checksum, size, server, path, instance_mtime)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# result variable
|
47
|
+
is_valid = true
|
48
|
+
# contains contents absent or without valid instances on local system
|
49
|
+
# and corresponding local instances
|
50
|
+
failed = ContentData::ContentData.new
|
51
|
+
# contains checksums of contains absent in local
|
52
|
+
absent_checksums = Array.new
|
53
|
+
|
54
|
+
# contains local instances corresponding to given remote index contents
|
55
|
+
local_index_to_check = ContentData::ContentData.new
|
56
|
+
|
57
|
+
# check whether remote contents exist locally
|
58
|
+
remote_index.each_content do |checksum|
|
59
|
+
unless local_index.content_exists checksum
|
60
|
+
is_valid = false
|
61
|
+
absent_checksums << checksum
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# add instances of contents that should be check, i.e. exist in local
|
66
|
+
local_index.each_instance do |checksum, size, content_mtime, instance_mtime, server, path|
|
67
|
+
if remote_index.content_exists checksum
|
68
|
+
local_index_to_check.add_instance checksum, size, server, path, instance_mtime
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
# validate against local file system
|
74
|
+
is_valid = local_index_to_check.validate(:failed => failed) && is_valid
|
75
|
+
|
76
|
+
# contains contents that have at least one valid local instance,
|
77
|
+
# then also corresponding remote content defined valid
|
78
|
+
contents_with_succeeded_instances = ContentData.remove_instances failed, local_index
|
79
|
+
|
80
|
+
# write summary to log
|
81
|
+
# TODO should be controlled from params?
|
82
|
+
absent_checksums.each do |checksum|
|
83
|
+
Log.warning "Content #{checksum} is absent in the local file system"
|
84
|
+
end
|
85
|
+
failed.each_content do |checksum|
|
86
|
+
if !contents_with_succeeded_instances.content_exists checksum
|
87
|
+
# if checked content have no valid local instances
|
88
|
+
# then content defined invalid
|
89
|
+
Log.warning "Content #{checksum} is invalid in the local file system"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# if needed process output params
|
94
|
+
unless params.nil? || params.empty?
|
95
|
+
remote_index.each_instance do |checksum, size, content_mtime, instance_mtime, server, path|
|
96
|
+
unless contents_with_succeeded_instances.content_exists checksum
|
97
|
+
process_params.call checksum, content_mtime, size, instance_mtime, server, path
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
is_valid
|
103
|
+
end
|
104
|
+
|
105
|
+
end # class IndexValidations
|
106
|
+
end # module Validations
|
data/lib/validations.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'file_indexing/index_agent'
|
3
|
+
require 'params'
|
4
|
+
require_relative '../../lib/content_data.rb'
|
5
|
+
|
6
|
+
module ContentData
|
7
|
+
module Spec
|
8
|
+
describe 'Index validation' do
|
9
|
+
before :all do
|
10
|
+
@size = 100
|
11
|
+
@path = '/dir1/dir2/file'
|
12
|
+
@path2 = '/dir3/dir4/file'
|
13
|
+
@mod_time = 123456
|
14
|
+
@checksum = 'abcde987654321'
|
15
|
+
@checksum2 = '987654321abcde'
|
16
|
+
@server = 'server_1'
|
17
|
+
end
|
18
|
+
|
19
|
+
before :each do
|
20
|
+
@index = ContentData.new
|
21
|
+
@index.add_instance @checksum, @size, @server, @path, @mod_time
|
22
|
+
@index.add_instance @checksum2, @size, @server, @path2, @mod_time
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with shallow check' do
|
26
|
+
before :all do
|
27
|
+
Params['instance_check_level'] = 'shallow'
|
28
|
+
end
|
29
|
+
|
30
|
+
before :each do
|
31
|
+
File.stub(:exists?).and_return(true)
|
32
|
+
File.stub(:size).and_return(@size)
|
33
|
+
File.stub(:mtime).and_return(@mod_time)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'succeeds when files exist and their attributes the same as in the index' do
|
37
|
+
@index.validate().should be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'fails when there is a file that doesn\'t exist' do
|
41
|
+
File.stub(:exists?).with(@path).and_return(false)
|
42
|
+
@index.validate().should be_false
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'fails when there is a file with size different from indexed' do
|
46
|
+
File.stub(:size).with(@path).and_return(@size + 10)
|
47
|
+
@index.validate().should be_false
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'fails when there is a file with modification time different from indexed' do
|
51
|
+
modified_mtime = @mod_time + 10
|
52
|
+
File.stub(:mtime).with(@path).and_return(modified_mtime)
|
53
|
+
@index.validate().should be_false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'with deep check (shallow check assumed succeeded)' do
|
58
|
+
before :all do
|
59
|
+
Params['instance_check_level'] = 'deep'
|
60
|
+
end
|
61
|
+
|
62
|
+
before :each do
|
63
|
+
FileIndexing::IndexAgent.stub(:get_checksum).with(@path).and_return(@checksum)
|
64
|
+
FileIndexing::IndexAgent.stub(:get_checksum).with(@path2).and_return(@checksum2)
|
65
|
+
@index.stub(:shallow_check).and_return(true)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'succeeds when for all files checksums are the same as indexed' do
|
69
|
+
@index.validate().should be_true
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'fails when there is a file with checksum different from indexed' do
|
73
|
+
FileIndexing::IndexAgent.stub(:get_checksum).with(@path2).and_return(@checksum2 + 'a')
|
74
|
+
@index.validate().should be_false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'validation params' do
|
79
|
+
before :all do
|
80
|
+
Params['instance_check_level'] = 'shallow'
|
81
|
+
end
|
82
|
+
|
83
|
+
before :each do
|
84
|
+
File.stub(:exists?).and_return(true)
|
85
|
+
File.stub(:size).and_return(@size)
|
86
|
+
File.stub(:mtime).and_return(@mod_time)
|
87
|
+
end
|
88
|
+
|
89
|
+
it ':failed param returns index of absent or invalid instances' do
|
90
|
+
# one instance that absent,
|
91
|
+
absent_checksum = '123'
|
92
|
+
absent_path = @path2 + '1'
|
93
|
+
@index.add_instance absent_checksum, @size, @server, absent_path, @mod_time
|
94
|
+
File.stub(:exists?).with(absent_path).and_return(false)
|
95
|
+
|
96
|
+
# another instance with different content was changed
|
97
|
+
File.stub(:mtime).with(@path2).and_return(@mod_time + 10)
|
98
|
+
|
99
|
+
failed = ContentData.new
|
100
|
+
@index.validate(:failed => failed).should be_false
|
101
|
+
# should be two failed contents, with one instance per content
|
102
|
+
failed.contents_size.should eq(2)
|
103
|
+
failed.content_exists(absent_checksum).should be_true
|
104
|
+
failed.content_exists(@checksum2).should be_true
|
105
|
+
failed.checksum_instances_size(absent_checksum).should eq(1)
|
106
|
+
failed.checksum_instances_size(@checksum2).should eq(1)
|
107
|
+
failed.instance_exists(absent_path, @server, absent_checksum).should be_true
|
108
|
+
failed.instance_exists(@path2, @server, @checksum2).should be_true
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
|
3
|
+
require_relative '../../lib/file_copy/copy.rb'
|
4
|
+
|
5
|
+
module FileCopy
|
6
|
+
module Spec
|
7
|
+
|
8
|
+
describe 'FileCopy::ssh_connect' do
|
9
|
+
it 'should raise error when username not specified' do
|
10
|
+
ENV.stub(:[]).with(any_args()).and_return(nil)
|
11
|
+
expect { FileCopy::ssh_connect(nil, nil, 'a server') }.to raise_error "Undefined username"
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should raise error when server not specified' do
|
15
|
+
expect { FileCopy::ssh_connect('kuku', nil, nil) }.to raise_error "Undefined server"
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should try to connect if username is set explicitly' do
|
19
|
+
Net::SSH.should_receive(:start).with(any_args())
|
20
|
+
FileCopy::ssh_connect('kuku', nil, 'a server')
|
21
|
+
end
|
22
|
+
it 'should try to connect if username is set via ENV variable' do
|
23
|
+
Net::SSH.should_receive(:start).with(any_args())
|
24
|
+
ENV.stub(:[]).with("USER").and_return('kuku')
|
25
|
+
FileCopy::ssh_connect(nil, nil, 'a server')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# TODO(kolman): Bad test, should rewrite and understand how to write test correctly.
|
30
|
+
describe 'FileCopy::sftp_copy' do
|
31
|
+
it 'call upload with correct files' do
|
32
|
+
ssh_connection = double('Net::SSH::Connection')
|
33
|
+
sftp_session = double('Net::SFTP::Session')
|
34
|
+
uploader = double('Operations::Upload')
|
35
|
+
sftp_attributes = double('Attributes')
|
36
|
+
|
37
|
+
# Stubbing sftp.
|
38
|
+
FileCopy.stub(:ssh_connect).and_return(ssh_connection)
|
39
|
+
ssh_connection.stub(:sftp).and_return(sftp_session)
|
40
|
+
sftp_session.stub(:connect).and_yield(sftp_session)
|
41
|
+
sftp_session.stub(:stat!).and_return(sftp_attributes)
|
42
|
+
sftp_attributes.stub(:directory?).and_return(true)
|
43
|
+
uploader.stub(:wait).and_return(true, true)
|
44
|
+
|
45
|
+
# Test file uploaded
|
46
|
+
sftp_session.should_receive(:upload).with('a', 'b').and_return(uploader)
|
47
|
+
sftp_session.should_receive(:upload).with('c', 'd').and_return(uploader)
|
48
|
+
FileCopy::sftp_copy(nil, nil, nil, { 'a' => 'b', 'c' => 'd' })
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
require_relative '../../lib/file_indexing/index_agent.rb'
|
5
|
+
|
6
|
+
module FileCopy
|
7
|
+
module Spec
|
8
|
+
|
9
|
+
describe 'checksum' do
|
10
|
+
it 'should generate correct checksum' do
|
11
|
+
# The test does not checks the problem the problem is when reading from File
|
12
|
+
# class which handles read(num) different from read()
|
13
|
+
content = ''
|
14
|
+
100000.times { content << 'abagadavazahatikalamansapazkareshet' }
|
15
|
+
content_checksum = FileIndexing::IndexAgent.get_content_checksum(content)
|
16
|
+
|
17
|
+
stream = StringIO.new(content)
|
18
|
+
File.stub(:open).and_yield(stream)
|
19
|
+
file_checksum = FileIndexing::IndexAgent.get_checksum('kuku')
|
20
|
+
|
21
|
+
content_checksum.should == file_checksum
|
22
|
+
content_checksum.should == '381e99eb0e2dfcaf45c9a367a04a4197ef3039a6'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should generate correct checksum for temp file' do
|
26
|
+
# A hack to get tmp file name
|
27
|
+
tmp_file = Tempfile.new('foo')
|
28
|
+
path = tmp_file .path
|
29
|
+
tmp_file .close()
|
30
|
+
|
31
|
+
# Open file in binary mode.
|
32
|
+
file = File.open(path, 'wb')
|
33
|
+
100000.times { file.write('abagadavazahatikalamansapazkareshet') }
|
34
|
+
file.close()
|
35
|
+
|
36
|
+
file_checksum = FileIndexing::IndexAgent.get_checksum(path)
|
37
|
+
file_checksum.should == '381e99eb0e2dfcaf45c9a367a04a4197ef3039a6'
|
38
|
+
|
39
|
+
File.open(path, 'rb') { |f|
|
40
|
+
content = f.read()
|
41
|
+
content_checksum = FileIndexing::IndexAgent.get_content_checksum(content)
|
42
|
+
content_checksum.should == '381e99eb0e2dfcaf45c9a367a04a4197ef3039a6'
|
43
|
+
file_checksum.should == content_checksum
|
44
|
+
}
|
45
|
+
|
46
|
+
# Delete tmp file.
|
47
|
+
tmp_file.unlink
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'log'
|
2
|
+
require 'rspec'
|
3
|
+
require 'socket'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
require_relative '../../lib/networking/tcp'
|
7
|
+
|
8
|
+
# Uncomment to debug spec.
|
9
|
+
Params['log_write_to_console'] = true
|
10
|
+
Params['log_debug_level'] = 0
|
11
|
+
Log.init
|
12
|
+
|
13
|
+
module Networking
|
14
|
+
module Spec
|
15
|
+
|
16
|
+
describe 'TCPClient' do
|
17
|
+
it 'should warn when destination host+port are bad' do
|
18
|
+
data = 'kuku!!!'
|
19
|
+
stream = StringIO.new
|
20
|
+
stream.close()
|
21
|
+
::TCPSocket.stub(:new).and_return(stream)
|
22
|
+
Log.should_receive(:warning).with('Socket not opened for writing, skipping send.')
|
23
|
+
|
24
|
+
# Send data first.
|
25
|
+
tcp_client = TCPClient.new('kuku', 5555)
|
26
|
+
# Send has to fail.
|
27
|
+
tcp_client.send_obj(data).should be(false)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should send data and server should receive callback function' do
|
31
|
+
info = 'info'
|
32
|
+
data = 'kuku!!!'
|
33
|
+
stream = StringIO.new
|
34
|
+
::Socket.stub(:tcp_server_loop).and_yield(stream, info)
|
35
|
+
::TCPSocket.stub(:new).and_return(stream)
|
36
|
+
|
37
|
+
# Send data first.
|
38
|
+
tcp_client = TCPClient.new('kuku', 5555)
|
39
|
+
# Send has to be successful.
|
40
|
+
tcp_client.send_obj(data).should be(21)
|
41
|
+
|
42
|
+
# Note this is very important so that reading the stream from beginning.
|
43
|
+
stream.rewind
|
44
|
+
|
45
|
+
func = lambda { |info, data| Log.info("info, data: #{info}, #{data}") }
|
46
|
+
# Check data is received.
|
47
|
+
func.should_receive(:call).with(info, data)
|
48
|
+
|
49
|
+
tcp_server = TCPServer.new(5555, func)
|
50
|
+
# Wait on server thread.
|
51
|
+
tcp_server.tcp_thread.join
|
52
|
+
end
|
53
|
+
|
54
|
+
# TODO(kolman): Don't work, missing client send_obj/open_socket execution in
|
55
|
+
# the correct place.
|
56
|
+
it 'should connect and receive callback from server' do
|
57
|
+
info = 'info'
|
58
|
+
data = 'kuku!!!'
|
59
|
+
stream = StringIO.new
|
60
|
+
::Socket.stub(:tcp_server_loop).once.and_yield(stream, info)
|
61
|
+
::TCPSocket.stub(:new).and_return(stream)
|
62
|
+
|
63
|
+
tcp_server = nil
|
64
|
+
new_clb = lambda { |i|
|
65
|
+
Log.info("#2 - After after @sockets is filled. Send has to be successful.")
|
66
|
+
tcp_server.send_obj(data).should eq({info => 21})
|
67
|
+
|
68
|
+
stream.rewind
|
69
|
+
|
70
|
+
func = lambda { |d|
|
71
|
+
Log.info("#6, After client initialized, it should send object.")
|
72
|
+
Log.info("data: #{d}")
|
73
|
+
# Validate received data.
|
74
|
+
d.should eq(data)
|
75
|
+
# Exit tcp client reading loop thread.
|
76
|
+
Thread.exit
|
77
|
+
}
|
78
|
+
|
79
|
+
Log.info("#4 - Create client and wait for read data.")
|
80
|
+
tcp_client = TCPClient.new('kuku', 5555, func)
|
81
|
+
tcp_client.tcp_thread.abort_on_exception = true
|
82
|
+
tcp_client.tcp_thread.join()
|
83
|
+
# We can finish now. Exit tcp server listening loop.
|
84
|
+
Thread.exit
|
85
|
+
}
|
86
|
+
|
87
|
+
Log.info("#1 - Create server, send data and wait.")
|
88
|
+
tcp_server = TCPServer.new(5555, nil, new_clb)
|
89
|
+
tcp_server.tcp_thread.abort_on_exception = true
|
90
|
+
tcp_server.tcp_thread.join()
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|