Skip to content

Commit ddbdff5

Browse files
committed
分片上传的版本号使用枚举判断,并添加单元测试覆盖错误版本号
- 新增 `myclabs/php-enum` 包 - 新增枚举类 `SplitUploadVersion` - 新增错误版本号 `v`, `1`, `2` 的单元测试
1 parent dd4b3d3 commit ddbdff5

File tree

6 files changed

+140
-16
lines changed

6 files changed

+140
-16
lines changed

autoload.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
<?php
22

3+
if ( file_exists(dirname(__FILE__).'/vendor/autoload.php') ) {
4+
require_once dirname(__FILE__).'/vendor/autoload.php';
5+
}
6+
37
function classLoader($class)
48
{
59
$path = str_replace('\\', DIRECTORY_SEPARATOR, $class);

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
}
1919
],
2020
"require": {
21-
"php": ">=5.3.3"
21+
"php": ">=5.3.3",
22+
"myclabs/php-enum": "1.6.6"
2223
},
2324
"require-dev": {
2425
"paragonie/random_compat": ">=2",

src/Qiniu/Enum/QiniuEnum.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace Qiniu\Enum;
4+
5+
use MyCLabs\Enum\Enum;
6+
7+
/**
8+
* 扩展 MyCLabs\Enum\Enum 以使用其新版本的 from 方法
9+
*
10+
* @link https://github.com/myclabs/php-enum
11+
*/
12+
abstract class QiniuEnum extends Enum
13+
{
14+
/**
15+
* @param mixed $value
16+
* @return static
17+
*/
18+
public static function from($value)
19+
{
20+
$key = self::assertValidValueReturningKey($value);
21+
22+
return self::__callStatic($key, array());
23+
}
24+
25+
/**
26+
* Asserts valid enum value
27+
*
28+
* @psalm-pure
29+
* @psalm-assert T $value
30+
* @param mixed $value
31+
* @return string
32+
*/
33+
private static function assertValidValueReturningKey($value)
34+
{
35+
if (false === ($key = self::search($value))) {
36+
throw new \UnexpectedValueException("Value '$value' is not part of the enum " . __CLASS__);
37+
}
38+
39+
return $key;
40+
}
41+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Qiniu\Enum;
4+
5+
final class SplitUploadVersion extends QiniuEnum
6+
{
7+
const V1 = 'v1';
8+
const V2 = 'v2';
9+
}

src/Qiniu/Storage/ResumeUploader.php

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Qiniu\Config;
66
use Qiniu\Http\Client;
77
use Qiniu\Http\Error;
8+
use Qiniu\Enum\SplitUploadVersion;
89

910
/**
1011
* 断点续上传类, 该类主要实现了断点续上传中的分块上传,
@@ -70,9 +71,14 @@ public function __construct(
7071
$this->finishedEtags = array("etags"=>array(), "uploadId"=>"", "expiredAt"=>0, "uploaded"=>0);
7172
$this->config = $config;
7273
$this->resumeRecordFile = $resumeRecordFile ? $resumeRecordFile : null;
73-
$this->version = $version ? $version : 'v1';
7474
$this->partSize = $partSize ? $partSize : config::BLOCK_SIZE;
7575

76+
try {
77+
$this->version = SplitUploadVersion::from($version ? $version : 'v1');
78+
} catch (\Exception $e) {
79+
throw new \Exception("only support v1/v2 now!", 0, $e);
80+
}
81+
7682
list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken);
7783
$this->bucket = $bucket;
7884
if ($err != null) {
@@ -92,7 +98,7 @@ public function __construct(
9298
public function upload($fname)
9399
{
94100
$uploaded = 0;
95-
if ($this->version == 'v2') {
101+
if ($this->version == SplitUploadVersion::V2) {
96102
$partNumber = 1;
97103
$encodedObjectName = $this->key? \Qiniu\base64_urlSafeEncode($this->key) : '~';
98104
};
@@ -125,13 +131,13 @@ public function upload($fname)
125131
}
126132

127133
if ($blkputRets) {
128-
if ($this->version == 'v1') {
134+
if ($this->version == SplitUploadVersion::V1) {
129135
if (isset($blkputRets['contexts']) && isset($blkputRets['uploaded']) &&
130136
is_array($blkputRets['contexts']) && is_int($blkputRets['uploaded'])) {
131137
$this->contexts = $blkputRets['contexts'];
132138
$uploaded = $blkputRets['uploaded'];
133139
}
134-
} elseif ($this->version == 'v2') {
140+
} elseif ($this->version == SplitUploadVersion::V2) {
135141
if (isset($blkputRets["etags"]) && isset($blkputRets["uploadId"]) &&
136142
isset($blkputRets["expiredAt"]) && $blkputRets["expiredAt"] > time()
137143
&& $blkputRets["uploaded"] > 0 && is_array($blkputRets["etags"]) &&
@@ -149,13 +155,13 @@ public function upload($fname)
149155
throw new \Exception("only support v1/v2 now!");
150156
}
151157
} else {
152-
if ($this->version == 'v2') {
158+
if ($this->version == SplitUploadVersion::V2) {
153159
$this->makeInitReq($encodedObjectName);
154160
}
155161
}
156162
} else {
157163
// init a Multipart Upload task if choose v2
158-
if ($this->version == 'v2') {
164+
if ($this->version == SplitUploadVersion::V2) {
159165
$this->makeInitReq($encodedObjectName);
160166
}
161167
}
@@ -166,10 +172,10 @@ public function upload($fname)
166172
if ($data === false) {
167173
throw new \Exception("file read failed", 1);
168174
}
169-
if ($this->version == 'v1') {
175+
if ($this->version == SplitUploadVersion::V1) {
170176
$crc = \Qiniu\crc32_data($data);
171177
$response = $this->makeBlock($data, $blockSize);
172-
} else {
178+
} elseif ($this->version == SplitUploadVersion::V2) {
173179
$md5 = md5($data);
174180
$response = $this->uploadPart(
175181
$data,
@@ -178,6 +184,8 @@ public function upload($fname)
178184
$encodedObjectName,
179185
$md5
180186
);
187+
} else {
188+
throw new \Exception("only support v1/v2 now!");
181189
}
182190

183191
$ret = null;
@@ -193,7 +201,7 @@ public function upload($fname)
193201
$this->host = $upHostBackup;
194202
}
195203

196-
if ($this->version == 'v1') {
204+
if ($this->version == SplitUploadVersion::V1) {
197205
if ($response->needRetry() || !isset($ret['crc32']) || $crc != $ret['crc32']) {
198206
$response = $this->makeBlock($data, $blockSize);
199207
$ret = $response->json();
@@ -203,7 +211,7 @@ public function upload($fname)
203211
return array(null, new Error($this->currentUrl, $response));
204212
}
205213
array_push($this->contexts, $ret['ctx']);
206-
} else {
214+
} elseif ($this->version == SplitUploadVersion::V2) {
207215
if ($response->needRetry() || !isset($ret['md5']) || $md5 != $ret['md5']) {
208216
$response = $this->uploadPart(
209217
$data,
@@ -221,22 +229,26 @@ public function upload($fname)
221229
$blockStatus = array('etag' => $ret['etag'], 'partNumber' => $partNumber);
222230
array_push($this->finishedEtags['etags'], $blockStatus);
223231
$partNumber += 1;
232+
} else {
233+
throw new \Exception("only support v1/v2 now!");
224234
}
225235

226236
$uploaded += $blockSize;
227-
if ($this->version == 'v2') {
237+
if ($this->version == SplitUploadVersion::V2) {
228238
$this->finishedEtags['uploaded'] = $uploaded;
229239
}
230240

231241
if ($this->resumeRecordFile !== null) {
232-
if ($this->version == 'v1') {
242+
if ($this->version == SplitUploadVersion::V1) {
233243
$recordData = array(
234244
'contexts' => $this->contexts,
235245
'uploaded' => $uploaded
236246
);
237247
$recordData = json_encode($recordData);
238-
} else {
248+
} elseif ($this->version == SplitUploadVersion::V2) {
239249
$recordData = json_encode($this->finishedEtags);
250+
} else {
251+
throw new \Exception("only support v1/v2 now!");
240252
}
241253
if ($recordData) {
242254
$isWritten = file_put_contents($this->resumeRecordFile, $recordData);
@@ -248,10 +260,12 @@ public function upload($fname)
248260
}
249261
}
250262
}
251-
if ($this->version == 'v1') {
263+
if ($this->version == SplitUploadVersion::V1) {
252264
return $this->makeFile($fname);
253-
} else {
265+
} elseif ($this->version == SplitUploadVersion::V2) {
254266
return $this->completeParts($fname, $this->finishedEtags['uploadId'], $encodedObjectName);
267+
} else {
268+
throw new \Exception("only support v1/v2 now!");
255269
}
256270
}
257271

tests/Qiniu/Tests/ResumeUpTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,59 @@ public function testResumeUploadV2WithParams()
203203
$this->assertEquals("val_2", $response->headers()["X-Qn-Meta-M2"]);
204204
unlink($tempFile);
205205
}
206+
207+
// valid versions are tested above
208+
// Use PHPUnit's Data Provider to test multiple Exception is better,
209+
// but not match the test style of this project
210+
public function testResumeUploadWithInvalidVersion()
211+
{
212+
$zone = new Zone(array('up.qiniup.com'));
213+
$cfg = new Config($zone);
214+
$upManager = new UploadManager($cfg);
215+
$testFileSize = config::BLOCK_SIZE * 2;
216+
$partSize = 5 * 1024 * 1024;
217+
$testInvalidVersions = array(
218+
// High probability invalid versions
219+
'v',
220+
'1',
221+
'2'
222+
);
223+
224+
$expectExceptionCount = 0;
225+
foreach ($testInvalidVersions as $invalidVersion) {
226+
$key = 'resumePutFile4ML_'.rand()."_";
227+
$token = $this->auth->uploadToken($this->bucketName, $key);
228+
$tempFile = qiniuTempFile($testFileSize);
229+
$resumeFile = tempnam(sys_get_temp_dir(), 'resume_file');
230+
$this->assertNotFalse($resumeFile);
231+
try {
232+
$upManager->putFile(
233+
$token,
234+
$key,
235+
$tempFile,
236+
null,
237+
'application/octet-stream',
238+
false,
239+
$resumeFile,
240+
$invalidVersion,
241+
$partSize
242+
);
243+
} catch (\Exception $e) {
244+
$isRightException = false;
245+
$expectExceptionCount++;
246+
while ($e) {
247+
$isRightException = $e instanceof \UnexpectedValueException;
248+
if ($isRightException) {
249+
break;
250+
}
251+
$e = $e->getPrevious();
252+
}
253+
$this->assertTrue($isRightException);
254+
}
255+
256+
unlink($resumeFile);
257+
unlink($tempFile);
258+
}
259+
$this->assertEquals(count($testInvalidVersions), $expectExceptionCount);
260+
}
206261
}

0 commit comments

Comments
 (0)