1
1
require "common"
2
2
3
3
class DownloadTest < Net ::SFTP ::TestCase
4
+ FXP_DATA_CHUNK_SIZE = 1024
5
+
4
6
def setup
5
7
prepare_progress!
6
8
end
@@ -30,6 +32,19 @@ def test_download_large_file_should_transfer_remote_to_local
30
32
assert_equal text , file . string
31
33
end
32
34
35
+ def test_download_large_file_should_handle_too_large_read_size
36
+ local = "/path/to/local"
37
+ remote = "/path/to/remote"
38
+ text = "0123456789" * 1024
39
+
40
+ # some servers put upper bound on the max read_size value and send less data than requested
41
+ too_large_read_size = FXP_DATA_CHUNK_SIZE + 1
42
+ file = prepare_large_file_download ( local , remote , text , too_large_read_size )
43
+
44
+ assert_scripted_command { sftp . download ( remote , local , :read_size => too_large_read_size ) }
45
+ assert_equal text , file . string
46
+ end
47
+
33
48
def test_download_large_file_with_progress_should_report_progress
34
49
local = "/path/to/local"
35
50
remote = "/path/to/remote"
@@ -121,25 +136,29 @@ def expect_file_transfer(remote, text)
121
136
channel . gets_packet ( FXP_HANDLE , :long , 0 , :string , "handle" )
122
137
channel . sends_packet ( FXP_READ , :long , 1 , :string , "handle" , :int64 , 0 , :long , 32_000 )
123
138
channel . gets_packet ( FXP_DATA , :long , 1 , :string , text )
124
- channel . sends_packet ( FXP_READ , :long , 2 , :string , "handle" , :int64 , 32_000 , :long , 32_000 )
139
+ channel . sends_packet ( FXP_READ , :long , 2 , :string , "handle" , :int64 , text . bytesize , :long , 32_000 )
125
140
channel . gets_packet ( FXP_STATUS , :long , 2 , :long , 1 )
126
141
channel . sends_packet ( FXP_CLOSE , :long , 3 , :string , "handle" )
127
142
channel . gets_packet ( FXP_STATUS , :long , 3 , :long , 0 )
128
143
end
129
144
end
130
145
131
- def prepare_large_file_download ( local , remote , text )
146
+ def prepare_large_file_download ( local , remote , text , requested_chunk_size = FXP_DATA_CHUNK_SIZE )
132
147
expect_sftp_session :server_version => 3 do |channel |
133
148
channel . sends_packet ( FXP_OPEN , :long , 0 , :string , remote , :long , 0x01 , :long , 0 )
134
149
channel . gets_packet ( FXP_HANDLE , :long , 0 , :string , "handle" )
135
- 10 . times do |n |
136
- channel . sends_packet ( FXP_READ , :long , n +1 , :string , "handle" , :int64 , n *1024 , :long , 1024 )
137
- channel . gets_packet ( FXP_DATA , :long , n +1 , :string , text [ n *1024 , 1024 ] )
150
+ offset = 0
151
+ data_packet_count = ( text . bytesize / FXP_DATA_CHUNK_SIZE . to_f ) . ceil
152
+ data_packet_count . times do |n |
153
+ payload = text [ n *FXP_DATA_CHUNK_SIZE , FXP_DATA_CHUNK_SIZE ]
154
+ channel . sends_packet ( FXP_READ , :long , n +1 , :string , "handle" , :int64 , offset , :long , requested_chunk_size )
155
+ offset += payload . bytesize
156
+ channel . gets_packet ( FXP_DATA , :long , n +1 , :string , payload )
138
157
end
139
- channel . sends_packet ( FXP_READ , :long , 11 , :string , "handle" , :int64 , 10240 , :long , 1024 )
140
- channel . gets_packet ( FXP_STATUS , :long , 11 , :long , 1 )
141
- channel . sends_packet ( FXP_CLOSE , :long , 12 , :string , "handle" )
142
- channel . gets_packet ( FXP_STATUS , :long , 12 , :long , 0 )
158
+ channel . sends_packet ( FXP_READ , :long , data_packet_count + 1 , :string , "handle" , :int64 , offset , :long , requested_chunk_size )
159
+ channel . gets_packet ( FXP_STATUS , :long , data_packet_count + 1 , :long , 1 )
160
+ channel . sends_packet ( FXP_CLOSE , :long , data_packet_count + 2 , :string , "handle" )
161
+ channel . gets_packet ( FXP_STATUS , :long , data_packet_count + 2 , :long , 0 )
143
162
end
144
163
145
164
file = StringIO . new
@@ -182,6 +201,8 @@ def prepare_large_file_download(local, remote, text)
182
201
# <- 15:STATUS(0)
183
202
184
203
def prepare_directory_tree_download ( local , remote )
204
+ file1_contents = "contents of file1"
205
+ file2_contents = "contents of file2"
185
206
expect_sftp_session :server_version => 3 do |channel |
186
207
channel . sends_packet ( FXP_OPENDIR , :long , 0 , :string , remote )
187
208
channel . gets_packet ( FXP_HANDLE , :long , 0 , :string , "dir1" )
@@ -214,8 +235,8 @@ def prepare_directory_tree_download(local, remote)
214
235
channel . sends_packet ( FXP_OPEN , :long , 8 , :string , File . join ( remote , "subdir1" , "file2" ) , :long , 0x01 , :long , 0 )
215
236
channel . sends_packet ( FXP_READDIR , :long , 9 , :string , "dir2" )
216
237
217
- channel . gets_packet ( FXP_DATA , :long , 6 , :string , "contents of file1" )
218
- channel . sends_packet ( FXP_READ , :long , 10 , :string , "file1" , :int64 , 32_000 , :long , 32_000 )
238
+ channel . gets_packet ( FXP_DATA , :long , 6 , :string , file1_contents )
239
+ channel . sends_packet ( FXP_READ , :long , 10 , :string , "file1" , :int64 , file1_contents . bytesize , :long , 32_000 )
219
240
220
241
channel . gets_packet ( FXP_STATUS , :long , 7 , :long , 0 )
221
242
channel . gets_packet ( FXP_HANDLE , :long , 8 , :string , "file2" )
@@ -227,8 +248,8 @@ def prepare_directory_tree_download(local, remote)
227
248
channel . gets_packet ( FXP_STATUS , :long , 10 , :long , 1 )
228
249
channel . sends_packet ( FXP_CLOSE , :long , 13 , :string , "file1" )
229
250
230
- channel . gets_packet ( FXP_DATA , :long , 11 , :string , "contents of file2" )
231
- channel . sends_packet ( FXP_READ , :long , 14 , :string , "file2" , :int64 , 32_000 , :long , 32_000 )
251
+ channel . gets_packet ( FXP_DATA , :long , 11 , :string , file2_contents )
252
+ channel . sends_packet ( FXP_READ , :long , 14 , :string , "file2" , :int64 , file2_contents . bytesize , :long , 32_000 )
232
253
233
254
channel . gets_packet ( FXP_STATUS , :long , 12 , :long , 0 )
234
255
channel . gets_packet ( FXP_STATUS , :long , 13 , :long , 0 )
0 commit comments