def delete_app(self): contract = jc.Contract() app_url_path = "/".join(["/v2/applications", self.TEST_APP]) f50_builder = st.http_observer.HttpContractBuilder(self.agent) # The application should be unlisted immediately (assuming 1 replica) # However given GCS rate limiting on updating the timestamp file, # there is a race condition in which the filesystem timestamp # was rate limited from updating AND a scheduled update is in progress # where the application was seen just before the delete so gets restored # back. Because the timestamp was not updated, this observer will read # from the cache thinking it is fresh. We need the extra second to allow # for the retry on the timestamp update to write out to GCS. (f50_builder.new_clause_builder( "Unlists Application", retryable_for_secs=8).get_url_path("/v2/applications").EXPECT( ov_factory.value_list_path_excludes( "name", jp.STR_SUBSTR(self.TEST_APP.upper())))) (f50_builder.new_clause_builder("Deletes Application").get_url_path( app_url_path).EXPECT( ov_factory.error_list_contains( st.HttpAgentErrorPredicate( st.HttpResponsePredicate(http_code=404))))) (f50_builder.new_clause_builder( "History Retains Application", retryable_for_secs=5).get_url_path( "/v2/applications/{app}/history".format( app=self.TEST_APP)).EXPECT( ov_factory.value_list_matches([ jp.DICT_MATCHES({ key: jp.EQUIVALENT(value) for key, value in self.app_history[0].items() }), jp.DICT_MATCHES({ key: jp.EQUIVALENT(value) for key, value in self.app_history[1].items() }), ]))) for clause in f50_builder.build().clauses: contract.add_clause(clause) gcs_builder = gcp.GcpStorageContractBuilder(self.gcs_observer) (gcs_builder.new_clause_builder( "Deleted File", retryable_for_secs=5).list_bucket( self.BUCKET, "/".join([self.BASE_PATH, "applications"])).EXPECT( ov_factory.value_list_path_excludes( "name", jp.STR_SUBSTR(self.TEST_APP)))) for clause in gcs_builder.build().clauses: contract.add_clause(clause) return st.OperationContract( self.new_delete_operation(title="delete_app", data=None, path=app_url_path), contract=contract, )
def test_k_expect_observe_error(self): """Example expects the observation itself to fail.""" key = self.make_key('InvalidKey') context = citest.base.ExecutionContext() builder = st.HttpContractBuilder(self.scenario.agent) (builder.new_clause_builder('Expect Not Found Error') .get_url_path('/lookup/' + key) .EXPECT(ov_factory.error_list_contains( st.HttpAgentErrorPredicate(st.HttpResponsePredicate(http_code=404))))) contract = builder.build() results = contract.verify(context) self.assertTrue(results)
def delete_app(self): contract = jc.Contract() app_url_path = '/'.join(['/v2/applications', self.TEST_APP]) f50_builder = st.http_observer.HttpContractBuilder(self.agent) (f50_builder.new_clause_builder('Unlists Application').get_url_path( '/v2/applications').EXPECT( ov_factory.value_list_path_excludes( 'name', jp.STR_SUBSTR(self.TEST_APP.upper())))) (f50_builder.new_clause_builder('Deletes Application').get_url_path( app_url_path).EXPECT( ov_factory.error_list_contains( st.HttpAgentErrorPredicate( st.HttpResponsePredicate(http_code=404))))) (f50_builder.new_clause_builder( 'History Retains Application', retryable_for_secs=5).get_url_path( '/v2/applications/{app}/history'.format( app=self.TEST_APP)).EXPECT( ov_factory.value_list_matches([ jp.DICT_MATCHES({ key: jp.EQUIVALENT(value) for key, value in self.app_history[0].items() }), jp.DICT_MATCHES({ key: jp.EQUIVALENT(value) for key, value in self.app_history[1].items() }) ]))) for clause in f50_builder.build().clauses: contract.add_clause(clause) gcs_builder = gcp.GcpStorageContractBuilder(self.gcs_observer) (gcs_builder.new_clause_builder( 'Deleted File', retryable_for_secs=5).list_bucket( self.BUCKET, '/'.join([self.BASE_PATH, 'applications'])).EXPECT( ov_factory.value_list_path_excludes( 'name', jp.STR_SUBSTR(self.TEST_APP)))) for clause in gcs_builder.build().clauses: contract.add_clause(clause) return st.OperationContract(self.new_delete_operation( title='delete_app', data=None, path=app_url_path), contract=contract)