From 37d4f60488249a2001e30e8826557f820ffb5fb6 Mon Sep 17 00:00:00 2001 From: Robert Carcasses Quevedo Date: Wed, 20 Mar 2019 13:05:18 +0000 Subject: [PATCH] trigger test topic/subscription creation implemented --- plugins/gcp-pub-subs/main.js | 52 +++++++- .../gcp-pub-subs/stylesheets/gcp-pub-subs.css | 4 + plugins/gcp-pub-subs/stylesheets/prism.css | 126 ++++++++++++++++++ plugins/gcp-pub-subs/view/form.jsx | 115 +++++++++++++--- 4 files changed, 280 insertions(+), 17 deletions(-) create mode 100644 plugins/gcp-pub-subs/stylesheets/prism.css diff --git a/plugins/gcp-pub-subs/main.js b/plugins/gcp-pub-subs/main.js index dcfd731..6c0aee5 100644 --- a/plugins/gcp-pub-subs/main.js +++ b/plugins/gcp-pub-subs/main.js @@ -4,7 +4,6 @@ let consume = require("pluginbot/effects/consume") let bcrypt = require("bcryptjs") let fetch = require("node-fetch") let fs = require("fs") -const crypto = require("crypto") function* run(config, provide, channels) { let db = yield consume(channels.database) @@ -97,7 +96,9 @@ function* run(config, provide, channels) { try { const messageIds = await Promise.all( pubsubs[eventName].map(({ client, topic }) => - client.topic(topic).publish(Buffer.from(JSON.stringify(event))) + client + .topic(topic, { autoCreate: true }) + .publish(Buffer.from(JSON.stringify(event))) ) ) console.log(`message with id ${messageIds} sent`) @@ -168,6 +169,45 @@ function* run(config, provide, channels) { res.json({ reload: "success" }) } + const testTrigger = async (req, res, next) => { + const { id, event } = req.params + console.log("[GCP-PUB-SUB] testing trigger id:", id, " event:", event) + try { + const messages = [] + // get the correspondent client + const { client: pubsub, topic: topicName } = pubsubs[event].filter( + c => `${c.id}` === id + )[0] + messages.push("const pubsub = new PubSub({...})") + // Creates the new topic + const topic = await pubsub.topic(topicName, { autoCreate: true }) + + messages.push(`const topicName = "${topicName}"`) + messages.push( + "const topic = await pubsub.topic(topicName, { autoCreate: true })" + ) + messages.push(`=> Topic ${topic.name} created.`) + const subscriptionName = "servicebot-test-subscription" + const subscription = await topic + .subscription(subscriptionName) + .get({ autoCreate: true }) + + messages.push(`const subscriptionName = "servicebot-test-subscription"`) + messages.push( + `const subscription = await topic.createSubscription(subscriptionName)` + ) + messages.push(`=> Subscription ${subscriptionName} created.`) + + await pubsub.subscription(subscriptionName).delete() + messages.push(`await pubsub.subscription(subscriptionName).delete();`) + messages.push(`=> Subscription ${subscriptionName} deleted.`) + + res.json({ test: "success", messages }) + } catch (e) { + next(e) + } + } + const routeDefinition = [ { endpoint: "/gcp-pub-sub/reload", @@ -175,6 +215,14 @@ function* run(config, provide, channels) { middleware: [reloadTriggers], permissions: [], description: "Reload and set all the triggers" + }, + { + endpoint: "/gcp-pub-sub/test/:id/:event", + method: "get", + middleware: [testTrigger], + permissions: [], + description: + "Check if the trigger can create a topic, push a message to it and read it" } ] diff --git a/plugins/gcp-pub-subs/stylesheets/gcp-pub-subs.css b/plugins/gcp-pub-subs/stylesheets/gcp-pub-subs.css index 80340ad..fe22d31 100644 --- a/plugins/gcp-pub-subs/stylesheets/gcp-pub-subs.css +++ b/plugins/gcp-pub-subs/stylesheets/gcp-pub-subs.css @@ -2,6 +2,10 @@ textarea[name="service_account_key"] { min-height: 300px; } +.test-results { + font-size: 14px; +} + .page-servicebot-gcp-pub-subs { padding: 40px 45px; min-height: 705px; diff --git a/plugins/gcp-pub-subs/stylesheets/prism.css b/plugins/gcp-pub-subs/stylesheets/prism.css new file mode 100644 index 0000000..80d0ec9 --- /dev/null +++ b/plugins/gcp-pub-subs/stylesheets/prism.css @@ -0,0 +1,126 @@ +/* PrismJS 1.15.0 +https://prismjs.com/download.html#themes=prism-okaidia&languages=markup+css+clike+javascript */ +/** + * okaidia theme for JavaScript, CSS and HTML + * Loosely based on Monokai textmate theme by http://www.monokai.nl/ + * @author ocodia + */ + +code[class*="language-"], +pre[class*="language-"] { + color: #f8f8f2; + background: none; + text-shadow: 0 1px rgba(0, 0, 0, 0.3); + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; + border-radius: 0.3em; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #272822; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #f8f8f2; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.constant, +.token.symbol, +.token.deleted { + color: #f92672; +} + +.token.boolean, +.token.number { + color: #ae81ff; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #a6e22e; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string, +.token.variable { + color: #f8f8f2; +} + +.token.atrule, +.token.attr-value, +.token.function, +.token.class-name { + color: #e6db74; +} + +.token.keyword { + color: #66d9ef; +} + +.token.regex, +.token.important { + color: #fd971f; +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + diff --git a/plugins/gcp-pub-subs/view/form.jsx b/plugins/gcp-pub-subs/view/form.jsx index 06a6631..82edcb1 100644 --- a/plugins/gcp-pub-subs/view/form.jsx +++ b/plugins/gcp-pub-subs/view/form.jsx @@ -9,6 +9,7 @@ import { Field } from "redux-form" import Buttons from "../../../views/components/elements/buttons.jsx" import Modal from "../../../views/components/utilities/modal.jsx" import "../stylesheets/gcp-pub-subs.css" +import "../stylesheets/prism.css" import Content from "../../../views/components/layouts/content.jsx" const isJsonString = str => { @@ -48,7 +49,7 @@ const validJSON = value => { return undefined } -function GCPConfigForm(props) { +const GCPConfigForm = props => { return (
{ let { show, hide, @@ -137,7 +138,7 @@ const lifecycleEvents = [ { value: "post_cancellation_pending", name: "Post cancellation pending" } ] -function GCPTriggerForm(props) { +const GCPTriggerForm = props => { console.log("[GCPTriggerForm] props: ", props) return ( @@ -183,7 +184,7 @@ function GCPTriggerForm(props) { ) } -function GCPTriggerModal(props) { +const GCPTriggerModal = props => { let { show, hide, @@ -224,7 +225,56 @@ function GCPTriggerModal(props) { ) } -function timeFormater(cell) { +class GCPTestTriggerModal extends React.Component { + constructor(props) { + super() + this.state = { + testSteps: [] + } + } + + async componentWillMount() { + const { id, event } = this.props.trigger + const response = await Fetcher(`/api/v1/gcp-pub-sub/test/${id}/${event}`) + console.log("test steps received", response) + this.setState({ testSteps: response.messages }) + } + + render() { + const { show, hide, trigger } = this.props + const { testSteps } = this.state + let content =

Please wait ...

+ if (testSteps.length > 0) + content = ( +
+

Results:

+
+
+              
+                {testSteps.map(msg => (
+                  
{msg}
+ ))} +
+
+
+
+ ) + return ( + +
{content}
+
+ ) + } +} + +const timeFormater = cell => { return (
{ if (!response.error) { self.setState({ configs: response }) } @@ -302,7 +355,7 @@ class GCPPubSubs extends React.Component { fetchTriggersData() { let self = this - return Fetcher("/api/v1/gcp-pub-subs").then(function(response) { + return Fetcher("/api/v1/gcp-pub-subs").then(response => { if (!response.error) { self.setState({ triggers: response }) } @@ -315,9 +368,7 @@ class GCPPubSubs extends React.Component { */ deleteConfig(config) { let self = this - Fetcher("/api/v1/gcp-configs/" + config.id, "DELETE").then(function( - response - ) { + Fetcher("/api/v1/gcp-configs/" + config.id, "DELETE").then(response => { if (!response.error) { self.fetchConfigsData() } @@ -326,9 +377,7 @@ class GCPPubSubs extends React.Component { deleteTrigger(trigger) { let self = this - Fetcher("/api/v1/gcp-pub-subs/" + trigger.id, "DELETE").then(function( - response - ) { + Fetcher("/api/v1/gcp-pub-subs/" + trigger.id, "DELETE").then(response => { if (!response.error) { self.fetchTriggersData() } @@ -353,10 +402,23 @@ class GCPPubSubs extends React.Component { this.setState({ openTrigger: false, trigger: {}, lastFetch: Date.now() }) } + openTestTriggerModal(trigger) { + this.setState({ openTestTrigger: true, trigger }) + } + + closeTestTriggerModal() { + this.setState({ + openTestTrigger: false, + trigger: {}, + lastFetch: Date.now() + }) + } + handleSuccessResponse() { this.setState({ openConfig: false, openTrigger: false, + openTestTrigger: false, config: {}, trigger: {}, lastFetch: Date.now(), @@ -431,6 +493,13 @@ class GCPPubSubs extends React.Component { action: () => { return this.deleteTrigger(row) } + }, + { + type: "button", + label: "Test", + action: () => { + return this.openTestTriggerModal(row) + } } ] @@ -438,8 +507,16 @@ class GCPPubSubs extends React.Component { } render() { + // TODO: is *self* usage really neccesary? let self = this - let { openConfig, config, openTrigger, trigger, configs } = this.state + let { + openConfig, + config, + openTrigger, + openTestTrigger, + trigger, + configs + } = this.state const endpointModals = () => { if (openConfig) { return ( @@ -462,6 +539,14 @@ class GCPPubSubs extends React.Component { hide={this.closeTriggerForm} /> ) + } else if (openTestTrigger) { + return ( + + ) } else { return null } @@ -656,7 +741,7 @@ const RouteDefinition = { navType: "settings", name: "GCP Pub/Sub Settings", path: "/gcp-pub-sub", - isVisible: function(user) { + isVisible: user => { //todo: this is dirty, need to do permission based... return user.role_id === 1 }