@@ -19,210 +19,161 @@ const proxyquire = require('proxyquire').noCallThru();
1919const assert = require ( 'assert' ) ;
2020
2121const getSample = ( ) => {
22- const requestPromise = sinon
23- . stub ( )
24- . returns ( new Promise ( resolve => resolve ( 'request sent' ) ) ) ;
22+ const getProjectIdStub = sinon . stub ( ) . resolves ( 'test-project' ) ;
23+ const listStub = sinon . stub ( ) . resolves ( [ { items : [ { name : 'test-instance' } ] } ] ) ;
24+ const patchStub = sinon . stub ( ) . resolves ( [ { name : 'test-operation' } ] ) ;
25+ const registeredFunctions = { } ;
26+
27+ proxyquire ( '../index' , {
28+ '@google-cloud/functions-framework' : {
29+ cloudEvent : ( name , handler ) => {
30+ registeredFunctions [ name ] = handler ;
31+ } ,
32+ } ,
33+ '@google-cloud/sql' : {
34+ SqlInstancesServiceClient : function ( ) {
35+ this . getProjectId = getProjectIdStub ;
36+ this . list = listStub ;
37+ this . patch = patchStub ;
38+ } ,
39+ } ,
40+ } ) ;
2541
2642 return {
27- program : proxyquire ( '../' , {
28- '@google-cloud/compute' : {
29- InstancesClient : function client ( ) {
30- this . list = ( ) => new Promise ( resolve => resolve ( [ [ ] ] ) ) ;
31- this . start = ( ) => new Promise ( resolve => resolve ( 'request sent' ) ) ;
32- this . getProjectId = ( ) => 'project' ;
33- } ,
34- ZoneOperationsClient : function client ( ) {
35- this . wait = ( ) => new Promise ( resolve => resolve ( 'request sent' ) ) ;
36- } ,
37- } ,
38- } ) ,
43+ registeredFunctions,
3944 mocks : {
40- requestPromise : requestPromise ,
45+ getProjectIdStub,
46+ listStub,
47+ patchStub,
4148 } ,
4249 } ;
4350} ;
4451
45- const getMocks = ( ) => {
46- const event = {
47- data : { } ,
48- } ;
49-
50- const callback = sinon . spy ( ) ;
51-
52- return {
53- event : event ,
54- context : { } ,
55- callback : callback ,
56- } ;
57- } ;
52+ const getCloudEvent = ( data ) => ( {
53+ data : {
54+ message : {
55+ data : Buffer . from ( JSON . stringify ( data ) ) . toString ( 'base64' ) ,
56+ } ,
57+ } ,
58+ } ) ;
5859
5960const stubConsole = function ( ) {
6061 sinon . stub ( console , 'error' ) ;
6162 sinon . stub ( console , 'log' ) ;
6263} ;
6364
64- //Restore console
6565const restoreConsole = function ( ) {
6666 console . log . restore ( ) ;
6767 console . error . restore ( ) ;
6868} ;
69+
6970beforeEach ( stubConsole ) ;
7071afterEach ( restoreConsole ) ;
7172
72- /** Tests for startInstancePubSub */
73- describe ( 'functions_start_instance_pubsub' , ( ) => {
74- it ( 'startInstancePubSub: should accept JSON-formatted event payload with label' , async ( ) => {
75- const mocks = getMocks ( ) ;
73+ describe ( 'functions_start_instance_event' , ( ) => {
74+ it ( 'startInstanceEvent: should accept CloudEvent payload with label' , async ( ) => {
7675 const sample = getSample ( ) ;
77- const pubsubData = { zone : 'test-zone' , label : 'testkey=value' } ;
78- mocks . event . data = Buffer . from ( JSON . stringify ( pubsubData ) ) . toString (
79- 'base64'
80- ) ;
81- await sample . program . startInstancePubSub (
82- mocks . event ,
83- mocks . context ,
84- mocks . callback
85- ) ;
86-
87- assert . deepStrictEqual (
88- mocks . callback . firstCall . args [ 1 ] ,
89- 'Successfully started instance(s)'
90- ) ;
76+ const cloudEvent = getCloudEvent ( { label : 'env=dev' } ) ;
77+
78+ await sample . registeredFunctions . startInstanceEvent ( cloudEvent ) ;
79+
80+ assert . strictEqual ( sample . mocks . getProjectIdStub . calledOnce , true ) ;
81+ assert . strictEqual ( sample . mocks . listStub . calledOnce , true ) ;
82+ assert . deepStrictEqual ( sample . mocks . listStub . firstCall . args [ 0 ] , {
83+ project : 'test-project' ,
84+ filter : 'settings.userLabels.env:dev' ,
85+ } ) ;
86+ assert . strictEqual ( sample . mocks . patchStub . calledOnce , true ) ;
87+ assert . deepStrictEqual ( sample . mocks . patchStub . firstCall . args [ 0 ] , {
88+ project : 'test-project' ,
89+ instance : 'test-instance' ,
90+ body : {
91+ settings : {
92+ activationPolicy : 'ALWAYS' ,
93+ } ,
94+ } ,
95+ } ) ;
9196 } ) ;
9297
93- it ( "startInstancePubSub: should fail with missing 'zone' attribute" , async ( ) => {
94- const mocks = getMocks ( ) ;
98+ it ( "startInstanceEvent: should fail with missing 'label' attribute" , async ( ) => {
9599 const sample = getSample ( ) ;
96- const pubsubData = { label : 'testkey=value' } ;
97- mocks . event . data = Buffer . from ( JSON . stringify ( pubsubData ) ) . toString (
98- 'base64'
99- ) ;
100- await sample . program . startInstancePubSub (
101- mocks . event ,
102- mocks . context ,
103- mocks . callback
104- ) ;
100+ const cloudEvent = getCloudEvent ( { other : 'value' } ) ;
105101
106- assert . deepStrictEqual (
107- mocks . callback . firstCall . args [ 0 ] ,
108- new Error ( " Attribute 'zone ' missing from payload" )
102+ await assert . rejects (
103+ sample . registeredFunctions . startInstanceEvent ( cloudEvent ) ,
104+ / A t t r i b u t e ' l a b e l ' m i s s i n g f r o m p a y l o a d /
109105 ) ;
110106 } ) ;
111107
112- it ( "startInstancePubSub: should fail with missing 'label' attribute" , async ( ) => {
113- const mocks = getMocks ( ) ;
108+ it ( 'startInstanceEvent: should handle zero instances gracefully' , async ( ) => {
114109 const sample = getSample ( ) ;
115- const pubsubData = { zone : 'test-zone' } ;
116- mocks . event . data = Buffer . from ( JSON . stringify ( pubsubData ) ) . toString (
117- 'base64'
118- ) ;
119- await sample . program . startInstancePubSub (
120- mocks . event ,
121- mocks . context ,
122- mocks . callback
123- ) ;
110+ sample . mocks . listStub . resolves ( [ { } ] ) ; // Empty object missing 'items' property
111+ const cloudEvent = getCloudEvent ( { label : 'env=dev' } ) ;
124112
125- assert . deepStrictEqual (
126- mocks . callback . firstCall . args [ 0 ] ,
127- new Error ( "Attribute 'label' missing from payload" )
128- ) ;
113+ await sample . registeredFunctions . startInstanceEvent ( cloudEvent ) ;
114+
115+ assert . strictEqual ( sample . mocks . patchStub . called , false ) ;
129116 } ) ;
130117
131- it ( 'startInstancePubSub: should fail with empty event payload' , async ( ) => {
132- const mocks = getMocks ( ) ;
118+ it ( 'startInstanceEvent: should fail with invalid CloudEvent payload' , async ( ) => {
133119 const sample = getSample ( ) ;
134- const pubsubData = { } ;
135- mocks . event . data = Buffer . from ( JSON . stringify ( pubsubData ) ) . toString (
136- 'base64'
137- ) ;
138- await sample . program . startInstancePubSub (
139- mocks . event ,
140- mocks . context ,
141- mocks . callback
142- ) ;
120+ const cloudEvent = {
121+ data : {
122+ message : {
123+ data : 'invalid-base64-payload' ,
124+ } ,
125+ } ,
126+ } ;
143127
144- assert . deepStrictEqual (
145- mocks . callback . firstCall . args [ 0 ] ,
146- new Error ( "Attribute 'zone' missing from payload" )
128+ await assert . rejects (
129+ sample . registeredFunctions . startInstanceEvent ( cloudEvent ) ,
130+ / I n v a l i d C l o u d E v e n t \/ P u b \/ S u b m e s s a g e /
147131 ) ;
148132 } ) ;
149133} ) ;
150134
151- /** Tests for stopInstancePubSub */
152- describe ( 'functions_stop_instance_pubsub' , ( ) => {
153- it ( 'stopInstancePubSub: should accept JSON-formatted event payload with label' , async ( ) => {
154- const mocks = getMocks ( ) ;
135+ describe ( 'functions_stop_instance_event' , ( ) => {
136+ it ( 'stopInstanceEvent: should accept CloudEvent payload with label' , async ( ) => {
155137 const sample = getSample ( ) ;
156- const pubsubData = { zone : 'test-zone' , label : 'testkey=value' } ;
157- mocks . event . data = Buffer . from ( JSON . stringify ( pubsubData ) ) . toString (
158- 'base64'
159- ) ;
160- await sample . program . stopInstancePubSub (
161- mocks . event ,
162- mocks . context ,
163- mocks . callback
164- ) ;
165-
166- assert . deepStrictEqual (
167- mocks . callback . firstCall . args [ 1 ] ,
168- 'Successfully stopped instance(s)'
169- ) ;
138+ const cloudEvent = getCloudEvent ( { label : 'env=dev' } ) ;
139+
140+ await sample . registeredFunctions . stopInstanceEvent ( cloudEvent ) ;
141+
142+ assert . strictEqual ( sample . mocks . getProjectIdStub . calledOnce , true ) ;
143+ assert . strictEqual ( sample . mocks . listStub . calledOnce , true ) ;
144+ assert . deepStrictEqual ( sample . mocks . listStub . firstCall . args [ 0 ] , {
145+ project : 'test-project' ,
146+ filter : 'settings.userLabels.env:dev' ,
147+ } ) ;
148+ assert . strictEqual ( sample . mocks . patchStub . calledOnce , true ) ;
149+ assert . deepStrictEqual ( sample . mocks . patchStub . firstCall . args [ 0 ] , {
150+ project : 'test-project' ,
151+ instance : 'test-instance' ,
152+ body : {
153+ settings : {
154+ activationPolicy : 'NEVER' ,
155+ } ,
156+ } ,
157+ } ) ;
170158 } ) ;
171159
172- it ( "stopInstancePubSub: should fail with missing 'zone' attribute" , async ( ) => {
173- const mocks = getMocks ( ) ;
160+ it ( "stopInstanceEvent: should fail with missing 'label' attribute" , async ( ) => {
174161 const sample = getSample ( ) ;
175- const pubsubData = { label : 'testkey=value' } ;
176- mocks . event . data = Buffer . from ( JSON . stringify ( pubsubData ) ) . toString (
177- 'base64'
178- ) ;
179- await sample . program . stopInstancePubSub (
180- mocks . event ,
181- mocks . context ,
182- mocks . callback
183- ) ;
162+ const cloudEvent = getCloudEvent ( { other : 'value' } ) ;
184163
185- assert . deepStrictEqual (
186- mocks . callback . firstCall . args [ 0 ] ,
187- new Error ( " Attribute 'zone ' missing from payload" )
164+ await assert . rejects (
165+ sample . registeredFunctions . stopInstanceEvent ( cloudEvent ) ,
166+ / A t t r i b u t e ' l a b e l ' m i s s i n g f r o m p a y l o a d /
188167 ) ;
189168 } ) ;
190169
191- it ( "stopInstancePubSub: should fail with missing 'label' attribute" , async ( ) => {
192- const mocks = getMocks ( ) ;
170+ it ( 'stopInstanceEvent: should handle zero instances gracefully' , async ( ) => {
193171 const sample = getSample ( ) ;
194- const pubsubData = { zone : 'test-zone' } ;
195- mocks . event . data = Buffer . from ( JSON . stringify ( pubsubData ) ) . toString (
196- 'base64'
197- ) ;
198- await sample . program . stopInstancePubSub (
199- mocks . event ,
200- mocks . context ,
201- mocks . callback
202- ) ;
203-
204- assert . deepStrictEqual (
205- mocks . callback . firstCall . args [ 0 ] ,
206- new Error ( "Attribute 'label' missing from payload" )
207- ) ;
208- } ) ;
172+ sample . mocks . listStub . resolves ( [ { items : [ ] } ] ) ; // Empty items array
173+ const cloudEvent = getCloudEvent ( { label : 'env=dev' } ) ;
209174
210- it ( 'stopInstancePubSub: should fail with empty event payload' , async ( ) => {
211- const mocks = getMocks ( ) ;
212- const sample = getSample ( ) ;
213- const pubsubData = { } ;
214- mocks . event . data = Buffer . from ( JSON . stringify ( pubsubData ) ) . toString (
215- 'base64'
216- ) ;
217- await sample . program . stopInstancePubSub (
218- mocks . event ,
219- mocks . context ,
220- mocks . callback
221- ) ;
175+ await sample . registeredFunctions . stopInstanceEvent ( cloudEvent ) ;
222176
223- assert . deepStrictEqual (
224- mocks . callback . firstCall . args [ 0 ] ,
225- new Error ( "Attribute 'zone' missing from payload" )
226- ) ;
177+ assert . strictEqual ( sample . mocks . patchStub . called , false ) ;
227178 } ) ;
228179} ) ;
0 commit comments