1
1
import { HttpResponse } from "@smithy/protocol-http" ;
2
+ import { createChecksumStream } from "@smithy/util-stream" ;
2
3
import { afterEach , beforeEach , describe , expect , test as it , vi } from "vitest" ;
3
4
4
5
import { PreviouslyResolved } from "./configuration" ;
5
6
import { ChecksumAlgorithm } from "./constants" ;
6
7
import { getChecksum } from "./getChecksum" ;
7
8
import { getChecksumAlgorithmListForResponse } from "./getChecksumAlgorithmListForResponse" ;
8
9
import { getChecksumLocationName } from "./getChecksumLocationName" ;
10
+ import { isStreaming } from "./isStreaming" ;
9
11
import { selectChecksumAlgorithmFunction } from "./selectChecksumAlgorithmFunction" ;
10
12
import { validateChecksumFromResponse } from "./validateChecksumFromResponse" ;
11
13
14
+ vi . mock ( "@smithy/util-stream" ) ;
12
15
vi . mock ( "./getChecksum" ) ;
13
16
vi . mock ( "./getChecksumLocationName" ) ;
14
17
vi . mock ( "./getChecksumAlgorithmListForResponse" ) ;
18
+ vi . mock ( "./isStreaming" ) ;
15
19
vi . mock ( "./selectChecksumAlgorithmFunction" ) ;
16
20
17
21
describe ( validateChecksumFromResponse . name , ( ) => {
18
22
const mockConfig = {
19
- streamHasher : vi . fn ( ) ,
20
23
base64Encoder : vi . fn ( ) ,
21
24
} as unknown as PreviouslyResolved ;
22
25
23
26
const mockBody = { } ;
27
+ const mockBodyStream = { isStream : true } ;
24
28
const mockHeaders = { } ;
25
29
const mockResponse = {
26
30
body : mockBody ,
@@ -50,6 +54,7 @@ describe(validateChecksumFromResponse.name, () => {
50
54
vi . mocked ( getChecksumAlgorithmListForResponse ) . mockImplementation ( ( responseAlgorithms ) => responseAlgorithms ) ;
51
55
vi . mocked ( selectChecksumAlgorithmFunction ) . mockReturnValue ( mockChecksumAlgorithmFn ) ;
52
56
vi . mocked ( getChecksum ) . mockResolvedValue ( mockChecksum ) ;
57
+ vi . mocked ( createChecksumStream ) . mockReturnValue ( mockBodyStream ) ;
53
58
} ) ;
54
59
55
60
afterEach ( ( ) => {
@@ -85,31 +90,56 @@ describe(validateChecksumFromResponse.name, () => {
85
90
} ) ;
86
91
87
92
describe ( "successful validation" , ( ) => {
88
- afterEach ( ( ) => {
93
+ const validateCalls = ( isStream : boolean , checksumAlgoFn : ChecksumAlgorithm ) => {
89
94
expect ( getChecksumAlgorithmListForResponse ) . toHaveBeenCalledWith ( mockResponseAlgorithms ) ;
90
95
expect ( selectChecksumAlgorithmFunction ) . toHaveBeenCalledTimes ( 1 ) ;
91
- expect ( getChecksum ) . toHaveBeenCalledTimes ( 1 ) ;
92
- } ) ;
93
96
94
- it ( "when checksum is populated for first algorithm" , async ( ) => {
97
+ if ( isStream ) {
98
+ expect ( getChecksum ) . not . toHaveBeenCalled ( ) ;
99
+ expect ( createChecksumStream ) . toHaveBeenCalledTimes ( 1 ) ;
100
+ expect ( createChecksumStream ) . toHaveBeenCalledWith ( {
101
+ expectedChecksum : mockChecksum ,
102
+ checksumSourceLocation : checksumAlgoFn ,
103
+ checksum : new mockChecksumAlgorithmFn ( ) ,
104
+ source : mockBody ,
105
+ base64Encoder : mockConfig . base64Encoder ,
106
+ } ) ;
107
+ } else {
108
+ expect ( getChecksum ) . toHaveBeenCalledTimes ( 1 ) ;
109
+ expect ( getChecksum ) . toHaveBeenCalledWith ( mockBody , {
110
+ checksumAlgorithmFn : mockChecksumAlgorithmFn ,
111
+ base64Encoder : mockConfig . base64Encoder ,
112
+ } ) ;
113
+ expect ( createChecksumStream ) . not . toHaveBeenCalled ( ) ;
114
+ }
115
+ } ;
116
+
117
+ it . each ( [ false , true ] ) ( "when checksum is populated for first algorithm when streaming: %s" , async ( isStream ) => {
118
+ vi . mocked ( isStreaming ) . mockReturnValue ( isStream ) ;
95
119
const responseWithChecksum = getMockResponseWithHeader ( mockResponseAlgorithms [ 0 ] , mockChecksum ) ;
96
120
await validateChecksumFromResponse ( responseWithChecksum , mockOptions ) ;
97
121
expect ( getChecksumLocationName ) . toHaveBeenCalledTimes ( 1 ) ;
98
122
expect ( getChecksumLocationName ) . toHaveBeenCalledWith ( mockResponseAlgorithms [ 0 ] ) ;
123
+ validateCalls ( isStream , mockResponseAlgorithms [ 0 ] ) ;
99
124
} ) ;
100
125
101
- it ( "when checksum is populated for second algorithm" , async ( ) => {
126
+ it . each ( [ false , true ] ) ( "when checksum is populated for second algorithm when streaming: %s" , async ( isStream ) => {
127
+ vi . mocked ( isStreaming ) . mockReturnValue ( isStream ) ;
102
128
const responseWithChecksum = getMockResponseWithHeader ( mockResponseAlgorithms [ 1 ] , mockChecksum ) ;
103
129
await validateChecksumFromResponse ( responseWithChecksum , mockOptions ) ;
104
130
expect ( getChecksumLocationName ) . toHaveBeenCalledTimes ( 2 ) ;
105
131
expect ( getChecksumLocationName ) . toHaveBeenNthCalledWith ( 1 , mockResponseAlgorithms [ 0 ] ) ;
106
132
expect ( getChecksumLocationName ) . toHaveBeenNthCalledWith ( 2 , mockResponseAlgorithms [ 1 ] ) ;
133
+ validateCalls ( isStream , mockResponseAlgorithms [ 1 ] ) ;
107
134
} ) ;
108
135
} ) ;
109
136
110
- it ( "throw error if checksum value is not accurate" , async ( ) => {
137
+ it ( "throw error if checksum value is not accurate when not streaming" , async ( ) => {
138
+ vi . mocked ( isStreaming ) . mockReturnValue ( false ) ;
139
+
111
140
const incorrectChecksum = "incorrectChecksum" ;
112
141
const responseWithChecksum = getMockResponseWithHeader ( mockResponseAlgorithms [ 0 ] , incorrectChecksum ) ;
142
+
113
143
try {
114
144
await validateChecksumFromResponse ( responseWithChecksum , mockOptions ) ;
115
145
fail ( "should throw checksum mismatch error" ) ;
@@ -119,9 +149,28 @@ describe(validateChecksumFromResponse.name, () => {
119
149
` in response header "${ mockResponseAlgorithms [ 0 ] } ".`
120
150
) ;
121
151
}
152
+
122
153
expect ( getChecksumAlgorithmListForResponse ) . toHaveBeenCalledWith ( mockResponseAlgorithms ) ;
123
154
expect ( selectChecksumAlgorithmFunction ) . toHaveBeenCalledTimes ( 1 ) ;
124
155
expect ( getChecksumLocationName ) . toHaveBeenCalledTimes ( 1 ) ;
125
156
expect ( getChecksum ) . toHaveBeenCalledTimes ( 1 ) ;
157
+ expect ( createChecksumStream ) . not . toHaveBeenCalled ( ) ;
158
+ } ) ;
159
+
160
+ it ( "return if checksum value is not accurate when streaming, as error will be thrown when stream is consumed" , async ( ) => {
161
+ vi . mocked ( isStreaming ) . mockReturnValue ( true ) ;
162
+
163
+ // This override does not matter for the purpose of unit test, but is kept for completeness.
164
+ const incorrectChecksum = "incorrectChecksum" ;
165
+ const responseWithChecksum = getMockResponseWithHeader ( mockResponseAlgorithms [ 0 ] , incorrectChecksum ) ;
166
+
167
+ await validateChecksumFromResponse ( responseWithChecksum , mockOptions ) ;
168
+
169
+ expect ( getChecksumAlgorithmListForResponse ) . toHaveBeenCalledWith ( mockResponseAlgorithms ) ;
170
+ expect ( selectChecksumAlgorithmFunction ) . toHaveBeenCalledTimes ( 1 ) ;
171
+ expect ( getChecksumLocationName ) . toHaveBeenCalledTimes ( 1 ) ;
172
+ expect ( getChecksum ) . not . toHaveBeenCalled ( ) ;
173
+ expect ( createChecksumStream ) . toHaveBeenCalledTimes ( 1 ) ;
174
+ expect ( responseWithChecksum . body ) . toBe ( mockBodyStream ) ;
126
175
} ) ;
127
176
} ) ;
0 commit comments