@@ -18,6 +18,7 @@ const {Spanner} = require('@google-cloud/spanner');
1818const { assert} = require ( 'chai' ) ;
1919const { describe, it, before, after} = require ( 'mocha' ) ;
2020const cp = require ( 'child_process' ) ;
21+ const pLimit = require ( 'p-limit' ) ;
2122
2223const execSync = cmd => cp . execSync ( cmd , { encoding : 'utf-8' } ) ;
2324
@@ -35,7 +36,8 @@ const backupsCmd = 'node backups.js';
3536
3637const date = Date . now ( ) ;
3738const PROJECT_ID = process . env . GCLOUD_PROJECT ;
38- const INSTANCE_ID = process . env . SPANNERTEST_INSTANCE || `test-instance-${ date } ` ;
39+ const PREFIX = 'test-instance' ;
40+ const INSTANCE_ID = process . env . SPANNERTEST_INSTANCE || `${ PREFIX } -${ date } ` ;
3941const INSTANCE_ALREADY_EXISTS = ! ! process . env . SPANNERTEST_INSTANCE ;
4042const DATABASE_ID = `test-database-${ date } ` ;
4143const RESTORE_DATABASE_ID = `test-database-${ date } -r` ;
@@ -45,137 +47,83 @@ const CANCELLED_BACKUP_ID = `test-backup-${date}-c`;
4547const spanner = new Spanner ( {
4648 projectId : PROJECT_ID ,
4749} ) ;
48-
49- function deleteInstance ( instance ) {
50- return new Promise ( ( resolve , reject ) => {
51- // Backups must be deleted before an instance can be deleted.
52- instance . request (
53- {
54- client : 'DatabaseAdminClient' ,
55- method : 'listBackups' ,
56- reqOpts : {
57- parent : instance . formattedName_ ,
58- } ,
59- } ,
60- async ( err , backups ) => {
61- if ( err ) {
62- reject ( err ) ;
63- return ;
64- }
65-
66- if ( backups . length > 0 ) {
67- try {
68- await deleteInstanceBackups ( instance , backups ) ;
69- } catch ( e ) {
70- reject ( err ) ;
71- return ;
72- }
73-
74- deleteInstance ( instance ) . then ( resolve , reject ) ;
75- return ;
76- }
77-
78- try {
79- await instance . delete ( ) ;
80- } catch ( e ) {
81- reject ( e ) ;
82- return ;
83- }
84-
85- resolve ( ) ;
86- }
87- ) ;
88- } ) ;
50+ const LABEL = 'node-sample-tests' ;
51+ const CURRENT_TIME = Math . round ( Date . now ( ) / 1000 ) . toString ( ) ;
52+
53+ async function deleteStaleInstances ( ) {
54+ const [ instances ] = await spanner . getInstances ( ) ;
55+ const yesterday = new Date ( ) ;
56+ yesterday . setHours ( - 24 ) ;
57+ const toDelete = instances . filter (
58+ instance =>
59+ instance . id . includes ( PREFIX ) &&
60+ instance . metadata . labels . created < yesterday . getTime ( )
61+ ) ;
62+
63+ return deleteInstanceArray ( toDelete ) ;
8964}
9065
91- function deleteInstanceBackups ( instance , instanceBackups ) {
92- const deleteInstanceBackupPromises = instanceBackups . map ( instanceBackup => {
93- return new Promise ( ( resolve , reject ) => {
94- instance . request (
95- {
96- client : 'DatabaseAdminClient' ,
97- method : 'deleteBackup' ,
98- reqOpts : { name : instanceBackup . name } ,
99- } ,
100- err => {
101- if ( err ) {
102- reject ( err ) ;
103- return ;
104- }
105- resolve ( ) ;
106- }
107- ) ;
108- } ) ;
109- } ) ;
66+ function deleteInstanceArray ( instanceArray ) {
67+ /**
68+ * Delay to allow instance and its databases to fully clear.
69+ * Refer to "Soon afterwards"
70+ * @see {@link https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.DeleteInstance }
71+ */
72+ const delay = 500 ;
73+ const limit = pLimit ( 5 ) ;
74+ return Promise . all (
75+ instanceArray . map ( instance =>
76+ limit ( ( ) => setTimeout ( deleteInstance , delay , instance ) )
77+ )
78+ ) ;
79+ }
11080
111- return Promise . all ( deleteInstanceBackupPromises ) ;
81+ async function deleteInstance ( instance ) {
82+ const [ backups ] = await instance . getBackups ( ) ;
83+ await Promise . all ( backups . map ( backup => backup . delete ( ) ) ) ;
84+ return instance . delete ( ) ;
11285}
11386
11487describe ( 'Spanner' , ( ) => {
115- before ( async ( ) => {
116- const instance = spanner . instance ( INSTANCE_ID ) ;
117- const database = instance . database ( DATABASE_ID ) ;
88+ const instance = spanner . instance ( INSTANCE_ID ) ;
11889
119- if ( ! INSTANCE_ALREADY_EXISTS ) {
120- try {
121- await instance . delete ( ) ;
122- } catch ( err ) {
123- // Ignore error
124- }
125- }
126- try {
127- await database . delete ( ) ;
128- } catch ( err ) {
129- // Ignore error
130- }
90+ before ( async ( ) => {
91+ await deleteStaleInstances ( ) ;
13192
13293 if ( ! INSTANCE_ALREADY_EXISTS ) {
133- const [ instances ] = await spanner . getInstances ( {
134- filter : 'labels.gcloud-sample-tests:true' ,
135- } ) ;
136-
137- await Promise . all (
138- instances . map ( async instance => {
139- const instanceName = instance . metadata . name ;
140- const res = await spanner . auth . request ( {
141- url : `https://spanner.googleapis.com/v1/${ instanceName } /operations` ,
142- } ) ;
143- const operations = res . data . operations ;
144- await Promise . all (
145- operations
146- . filter ( operation => {
147- return operation . metadata [ '@type' ] . includes ( 'CreateInstance' ) ;
148- } )
149- . filter ( operation => {
150- const yesterday = new Date ( ) ;
151- yesterday . setHours ( - 24 ) ;
152- const instanceCreated = new Date ( operation . metadata . startTime ) ;
153- return instanceCreated < yesterday ;
154- } )
155- . map ( ( ) => deleteInstance ( instance ) )
156- ) ;
157- } )
158- ) ;
159-
16094 const [ , operation ] = await instance . create ( {
16195 config : 'regional-us-central1' ,
16296 nodes : 1 ,
16397 labels : {
164- 'gcloud-sample-tests' : 'true' ,
98+ [ LABEL ] : 'true' ,
99+ created : CURRENT_TIME ,
165100 } ,
166101 } ) ;
167-
168102 await operation . promise ( ) ;
103+ } else {
104+ console . log (
105+ `Not creating temp instance, using + ${ instance . formattedName_ } ...`
106+ ) ;
169107 }
170108 } ) ;
171109
172110 after ( async ( ) => {
173111 const instance = spanner . instance ( INSTANCE_ID ) ;
174- const database = instance . database ( DATABASE_ID ) ;
175- await database . delete ( ) ;
176112
177113 if ( ! INSTANCE_ALREADY_EXISTS ) {
114+ // Make sure all backups are deleted before an instance can be deleted.
115+ await Promise . all ( [
116+ instance . backup ( BACKUP_ID ) . delete ( ) ,
117+ instance . backup ( CANCELLED_BACKUP_ID ) . delete ( ) ,
118+ ] ) ;
178119 await instance . delete ( ) ;
120+ } else {
121+ await Promise . all ( [
122+ instance . database ( DATABASE_ID ) . delete ( ) ,
123+ instance . database ( RESTORE_DATABASE_ID ) . delete ( ) ,
124+ instance . backup ( BACKUP_ID ) . delete ( ) ,
125+ instance . backup ( CANCELLED_BACKUP_ID ) . delete ( ) ,
126+ ] ) ;
179127 }
180128 } ) ;
181129
0 commit comments