diff --git a/README.md b/README.md index 40696ce0..3c0955fd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ # Allure notifications **Allure notifications** - это библиотека, позволяющая выполнять автоматическое оповещение о результатах прохождения автотестов, которое направляется в нужный вам мессенджер (Telegram, Slack, Skype, Email, Mattermost). +| Telegram | Slack | +:-------------------------:|:-------------------------: +![shakal_screenshot](readme_images/telegram-en.png) | ![shakal_screenshot](readme_images/slack-en.png) +| **Mattermost** | **Email** | +![shakal_screenshot](readme_images/mattermost-ru.png) | ![shakal_screenshot](readme_images/email_en.png) +| **RocketChat** | +![shakal_screenshot](readme_images/allure_testops_en.png) | +| **Skype** | **Icq** | +| Done | Wat? lol | + Languages: 🇬🇧 🇫🇷 🇷🇺 🇺🇦 🇧🇾 🇨🇳 ## Содержание @@ -11,6 +21,22 @@ Languages: 🇬🇧 🇫🇷 🇷🇺 🇺🇦 🇧🇾 🇨🇳 + [для запуска из Jenkins](#Jenkins) + [Особенности заполнения файла config.json в зависимости от выбранного мессенджера](#config) +
How to:
+ +- [x] [Telegram config](https://github.com/qa-guru/allure-notifications/wiki/Telegram-configuration) +- [x] [Slack config](https://github.com/qa-guru/allure-notifications/wiki/Slack-configuration) +- [x] [Email config](https://github.com/qa-guru/allure-notifications/wiki/Email-configuration) +- [x] [Skype config](https://github.com/qa-guru/allure-notifications/wiki/Skype-configuration) +- [x] [Mattermost config](https://github.com/qa-guru/allure-notifications/wiki/Mattermost-configuration) +- [x] [Rocket config] + + +
CommandLine options
+All keys should be used with `-D`:
+ +| key | description | +|:---:| :---------: | +| configFile | Path to JSON-config file | @@ -92,6 +118,12 @@ Languages: 🇬🇧 🇫🇷 🇷🇺 🇺🇦 🇧🇾 🇨🇳 "token": "", "chat": "" }, + "rocket" : { + "url": "", + "auth_token": "", + "user_id": "", + "channel": "" + }, "skype": { "appId": "", "appSecret": "", @@ -109,6 +141,12 @@ Languages: 🇬🇧 🇫🇷 🇷🇺 🇺🇦 🇧🇾 🇨🇳 "from": "", "recipient": "" }, + "testOps": { + "url": "", + "auth_token": "", + "xsrf_token": "", + "project_id": "" + }, "proxy": { "host": "", "port": 0, @@ -117,6 +155,11 @@ Languages: 🇬🇧 🇫🇷 🇷🇺 🇺🇦 🇧🇾 🇨🇳 } } ``` +You only need: + - to fill needed options in `base` block (please, be careful, `language` field is required!); + - to configure desired destinations for notifications (`telegram`, `slack`, `mattermost`, `skype`, `mail`), keep in mind it's possible to set multiple destinations at once, if no destination is set, then no notification will be sent and no error will occur; + - to specify optional proxy configuration in `proxy` block. + - if you need Allure TestOps integration, you must fill field `enableTestOpsIntegration` in `base` block and fill `testOps` block Блок `proxy` используется если нужно указать дополнительную конфигурацию proxy. diff --git a/build.gradle b/build.gradle index 37093d74..bb265a70 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,8 @@ dependencies { implementation('com.jayway.jsonpath:json-path:2.7.0') implementation('commons-io:commons-io:2.11.0') implementation('org.apache.commons:commons-lang3:3.12.0') + implementation('io.rest-assured:rest-assured:4.4.0') + implementation('org.jboss.resteasy:resteasy-jackson2-provider:3.0.6.Final') testImplementation('org.junit.jupiter:junit-jupiter:5.9.0') testImplementation('org.springframework:spring-test:5.3.22') { diff --git a/readme_images/allure_testops_en.png b/readme_images/allure_testops_en.png new file mode 100644 index 00000000..ab3538fc Binary files /dev/null and b/readme_images/allure_testops_en.png differ diff --git a/src/main/java/guru/qa/allure/notifications/Application.java b/src/main/java/guru/qa/allure/notifications/Application.java index c8093cbe..24d024e9 100644 --- a/src/main/java/guru/qa/allure/notifications/Application.java +++ b/src/main/java/guru/qa/allure/notifications/Application.java @@ -3,7 +3,6 @@ import guru.qa.allure.notifications.clients.Notification; import guru.qa.allure.notifications.config.ApplicationConfig; import guru.qa.allure.notifications.config.Config; -import guru.qa.allure.notifications.exceptions.MessagingException; import guru.qa.allure.notifications.util.LogInterceptor; import guru.qa.allure.notifications.util.ProxyManager; import kong.unirest.Unirest; diff --git a/src/main/java/guru/qa/allure/notifications/chart/Chart.java b/src/main/java/guru/qa/allure/notifications/chart/Chart.java index 7e213e0a..42e2916d 100644 --- a/src/main/java/guru/qa/allure/notifications/chart/Chart.java +++ b/src/main/java/guru/qa/allure/notifications/chart/Chart.java @@ -1,5 +1,6 @@ package guru.qa.allure.notifications.chart; +import guru.qa.allure.notifications.config.testops.TestOps; import guru.qa.allure.notifications.exceptions.MessageBuildException; import lombok.extern.slf4j.Slf4j; import org.knowm.xchart.BitmapEncoder; @@ -9,6 +10,7 @@ import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; import java.io.File; @@ -19,6 +21,9 @@ public class Chart { public static byte[] createChart(Base base) throws MessageBuildException { + return createChart(base, null); + } + public static byte[] createChart(Base base, TestOps testOps) throws MessageBuildException { log.info("Creating chart..."); PieChart chart = ChartBuilder.createBaseChart(base); log.info("Adding legend to chart..."); @@ -26,7 +31,13 @@ public static byte[] createChart(Base base) throws MessageBuildException { log.info("Adding view to chart..."); ChartView.addViewTo(chart); log.info("Adding series to chart..."); - List colors = new ChartSeries(base).addSeriesTo(chart); + List colors; + if (base.getEnableTestOpsIntegration()) { + colors = new ChartSeries(base, testOps).addSeriesTo(chart); + } + else { + colors = new ChartSeries(base).addSeriesTo(chart); + } log.info("Adding colors to series..."); chart.getStyler().setSeriesColors(colors.toArray(new Color[0])); BufferedImage chartImage = BitmapEncoder.getBufferedImage(chart); diff --git a/src/main/java/guru/qa/allure/notifications/chart/ChartSeries.java b/src/main/java/guru/qa/allure/notifications/chart/ChartSeries.java index a07afb06..61e5dcbd 100644 --- a/src/main/java/guru/qa/allure/notifications/chart/ChartSeries.java +++ b/src/main/java/guru/qa/allure/notifications/chart/ChartSeries.java @@ -1,28 +1,47 @@ package guru.qa.allure.notifications.chart; import guru.qa.allure.notifications.config.base.Base; +import guru.qa.allure.notifications.config.testops.TestOps; import guru.qa.allure.notifications.mapper.LegendMapper; import guru.qa.allure.notifications.mapper.SummaryMapper; import guru.qa.allure.notifications.model.legend.Legend; import guru.qa.allure.notifications.model.summary.Summary; +import guru.qa.allure.notifications.util.TestOpsClient; import org.knowm.xchart.PieChart; import java.awt.*; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public class ChartSeries { private final LegendMapper legendMapper; private final SummaryMapper summaryMapper; + private final TestOps testOps; public ChartSeries(Base base) { this.legendMapper = new LegendMapper(base); this.summaryMapper = new SummaryMapper(base); + testOps = null; + } + + public ChartSeries(Base base, TestOps testOps) { + this.legendMapper = new LegendMapper(base); + this.summaryMapper = new SummaryMapper(base); + this.testOps = testOps; } public List addSeriesTo(PieChart chart) { List colors = new ArrayList<>(); - final Summary summary = summaryMapper.map(); + Summary summary; + if (testOps != null) { + TestOpsClient testOpsClient = new TestOpsClient(testOps); + HashMap statistics = testOpsClient.getLaunchStatistic(); + summary = Summary.getInstance(statistics); + } + else { + summary = summaryMapper.map(); + } final Legend legend = legendMapper.map(); addSeries(chart, colors, summary.getStatistic().getPassed(), legend.getPassed(), new Color(148, 202, 102)); diff --git a/src/main/java/guru/qa/allure/notifications/clients/ClientFactory.java b/src/main/java/guru/qa/allure/notifications/clients/ClientFactory.java index ef79da8e..31d6e6e0 100644 --- a/src/main/java/guru/qa/allure/notifications/clients/ClientFactory.java +++ b/src/main/java/guru/qa/allure/notifications/clients/ClientFactory.java @@ -5,6 +5,7 @@ import guru.qa.allure.notifications.clients.mail.Email; import guru.qa.allure.notifications.clients.mattermost.MattermostClient; +import guru.qa.allure.notifications.clients.rocket.RocketClient; import guru.qa.allure.notifications.clients.skype.SkypeClient; import guru.qa.allure.notifications.clients.slack.SlackClient; import guru.qa.allure.notifications.clients.telegram.TelegramClient; @@ -15,6 +16,9 @@ public class ClientFactory { public static List from(Config config) { MessageData messageData = new MessageData(config.getBase()); + if (config.getTestops() != null) { + messageData = new MessageData(config.getBase(), config.getTestops()); + } List notifiers = new ArrayList<>(); if (config.getTelegram() != null) { @@ -32,6 +36,9 @@ public static List from(Config config) { if (config.getSkype() != null) { notifiers.add(new SkypeClient(messageData, config.getSkype())); } + if (config.getRocket() != null) { + notifiers.add(new RocketClient(messageData, config.getRocket())); + } return notifiers; } } diff --git a/src/main/java/guru/qa/allure/notifications/clients/Notification.java b/src/main/java/guru/qa/allure/notifications/clients/Notification.java index 41e51c98..1511e5f4 100644 --- a/src/main/java/guru/qa/allure/notifications/clients/Notification.java +++ b/src/main/java/guru/qa/allure/notifications/clients/Notification.java @@ -1,5 +1,6 @@ package guru.qa.allure.notifications.clients; +import com.sun.mail.iap.ByteArray; import guru.qa.allure.notifications.chart.Chart; import java.util.List; @@ -19,7 +20,13 @@ public static boolean send(Config config) { try { log.info("Sending message..."); if (config.getBase().getEnableChart()) { - byte[] chartImage = Chart.createChart(config.getBase()); + byte[] chartImage = null; + if (config.getTestops() != null) { + chartImage = Chart.createChart(config.getBase(), config.getTestops()); + } + else { + chartImage = Chart.createChart(config.getBase()); + } notifier.sendPhoto(chartImage); } else { diff --git a/src/main/java/guru/qa/allure/notifications/clients/rocket/RocketClient.java b/src/main/java/guru/qa/allure/notifications/clients/rocket/RocketClient.java new file mode 100644 index 00000000..5458c1db --- /dev/null +++ b/src/main/java/guru/qa/allure/notifications/clients/rocket/RocketClient.java @@ -0,0 +1,50 @@ +package guru.qa.allure.notifications.clients.rocket; + +import guru.qa.allure.notifications.clients.Notifier; +import guru.qa.allure.notifications.config.rocket.Rocket; +import guru.qa.allure.notifications.exceptions.MessagingException; +import guru.qa.allure.notifications.json.JSON; +import guru.qa.allure.notifications.template.MarkdownTemplate; +import guru.qa.allure.notifications.template.RocketTemplate; +import guru.qa.allure.notifications.template.data.MessageData; +import kong.unirest.ContentType; +import kong.unirest.Unirest; + +import java.io.ByteArrayInputStream; +public class RocketClient implements Notifier { + private final JSON json = new JSON(); + private final Rocket rocket; + private final RocketTemplate template; + + public RocketClient(MessageData messageData, Rocket rocket) { + this.rocket = rocket; + this.template = new RocketTemplate(messageData); + } + + @Override + public void sendText() throws MessagingException { + String body = String.format("{\"channel\": \"%s\", \"text\": \"%s\" }", + rocket.getChannel(), template.create().replace("\r\n", "\\\n")); + String url = String.format("%s/api/v1/chat.postMessage", rocket.getUrl()); + Unirest.post(url) + .header("X-Auth-Token", rocket.getToken()) + .header("X-User-Id", rocket.getUserId()) + .header("Content-Type", "application/json") + .body(json.prettyPrint(body)) + .asString() + .getBody(); + } + + @Override + public void sendPhoto(byte[] chartImage) throws MessagingException { + sendText(); + String url = String.format("%s/api/v1/rooms.upload/%s", rocket.getUrl(), rocket.getChannel()); + + Unirest.post(url) + .header("X-Auth-Token", rocket.getToken()) + .header("X-User-Id", rocket.getUserId()) + .field("file", new ByteArrayInputStream(chartImage), ContentType.IMAGE_PNG, "chart.png") + .asString() + .getBody(); + } +} diff --git a/src/main/java/guru/qa/allure/notifications/config/Config.java b/src/main/java/guru/qa/allure/notifications/config/Config.java index 2116e8bd..e00b1da7 100644 --- a/src/main/java/guru/qa/allure/notifications/config/Config.java +++ b/src/main/java/guru/qa/allure/notifications/config/Config.java @@ -5,9 +5,11 @@ import guru.qa.allure.notifications.config.mail.Mail; import guru.qa.allure.notifications.config.mattermost.Mattermost; import guru.qa.allure.notifications.config.proxy.Proxy; +import guru.qa.allure.notifications.config.rocket.Rocket; import guru.qa.allure.notifications.config.skype.Skype; import guru.qa.allure.notifications.config.slack.Slack; import guru.qa.allure.notifications.config.telegram.Telegram; +import guru.qa.allure.notifications.config.testops.TestOps; import lombok.Data; /** @@ -29,6 +31,10 @@ public class Config { private Skype skype; @SerializedName("mail") private Mail mail; + @SerializedName("rocket") + private Rocket rocket; + @SerializedName("testOps") + private TestOps testops; @SerializedName("proxy") private Proxy proxy; } diff --git a/src/main/java/guru/qa/allure/notifications/config/base/Base.java b/src/main/java/guru/qa/allure/notifications/config/base/Base.java index a6ee2ca9..e6de33da 100644 --- a/src/main/java/guru/qa/allure/notifications/config/base/Base.java +++ b/src/main/java/guru/qa/allure/notifications/config/base/Base.java @@ -27,4 +27,6 @@ public class Base { private String allureFolder; @SerializedName("enableChart") private Boolean enableChart; + @SerializedName("enableTestOpsIntegration") + private Boolean enableTestOpsIntegration; } diff --git a/src/main/java/guru/qa/allure/notifications/config/rocket/Rocket.java b/src/main/java/guru/qa/allure/notifications/config/rocket/Rocket.java new file mode 100644 index 00000000..77f9cbc0 --- /dev/null +++ b/src/main/java/guru/qa/allure/notifications/config/rocket/Rocket.java @@ -0,0 +1,22 @@ +package guru.qa.allure.notifications.config.rocket; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +/** + * @author GerasimchukDV + * @since 4.2.2 + * Model class representing Rocket client settings. + */ +@Data +public class Rocket { + @SerializedName("url") + private String url; + @SerializedName("auth_token") + private String token; + + @SerializedName("user_id") + private String userId; + @SerializedName("channel") + private String channel; +} diff --git a/src/main/java/guru/qa/allure/notifications/config/testops/TestOps.java b/src/main/java/guru/qa/allure/notifications/config/testops/TestOps.java new file mode 100644 index 00000000..f9b1b0c9 --- /dev/null +++ b/src/main/java/guru/qa/allure/notifications/config/testops/TestOps.java @@ -0,0 +1,23 @@ +package guru.qa.allure.notifications.config.testops; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +/** + * @author GerasimchukDV + * @since 4.2.2 + * Model class representing Allure TestOps client settings. + */ + +@Data +public class TestOps { + @SerializedName("url") + private String url; + @SerializedName("auth_token") + private String auth_token; + + @SerializedName("xsrf_token") + private String xsrf_token; + @SerializedName("project_id") + private String projectId; +} diff --git a/src/main/java/guru/qa/allure/notifications/json/JSON.java b/src/main/java/guru/qa/allure/notifications/json/JSON.java index 2b404f3e..60a38c85 100644 --- a/src/main/java/guru/qa/allure/notifications/json/JSON.java +++ b/src/main/java/guru/qa/allure/notifications/json/JSON.java @@ -3,11 +3,14 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; +import com.google.gson.stream.JsonReader; import guru.qa.allure.notifications.exceptions.ConfigNotFoundException; import lombok.extern.slf4j.Slf4j; import java.io.FileNotFoundException; import java.io.FileReader; +import java.io.StringReader; /** * @author kadehar @@ -28,6 +31,15 @@ public T parse(String file, Class clazz) { } public String prettyPrint(String json) { - return GSON.toJson(JsonParser.parseString(json)); + String result = ""; + try { + result = GSON.toJson(JsonParser.parseString(json)); + } + catch (JsonSyntaxException e) { + JsonReader reader = new JsonReader(new StringReader(json)); + reader.setLenient(true); + result = GSON.toJson(JsonParser.parseReader(reader)); + } + return result; } } diff --git a/src/main/java/guru/qa/allure/notifications/model/summary/Statistic.java b/src/main/java/guru/qa/allure/notifications/model/summary/Statistic.java index 03731d00..39b1f3e9 100644 --- a/src/main/java/guru/qa/allure/notifications/model/summary/Statistic.java +++ b/src/main/java/guru/qa/allure/notifications/model/summary/Statistic.java @@ -1,14 +1,19 @@ package guru.qa.allure.notifications.model.summary; import com.google.gson.annotations.SerializedName; -import lombok.Getter; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; /** * @author kadehar * @since 1.0 * Model class, representing test statistic from Allure Report. */ -@Getter +@Data +@NoArgsConstructor(access = AccessLevel.PUBLIC) +@AllArgsConstructor(access = AccessLevel.PUBLIC) public class Statistic { @SerializedName("passed") private Integer passed; diff --git a/src/main/java/guru/qa/allure/notifications/model/summary/Summary.java b/src/main/java/guru/qa/allure/notifications/model/summary/Summary.java index 08dcb960..4ac8721c 100644 --- a/src/main/java/guru/qa/allure/notifications/model/summary/Summary.java +++ b/src/main/java/guru/qa/allure/notifications/model/summary/Summary.java @@ -1,17 +1,32 @@ package guru.qa.allure.notifications.model.summary; import com.google.gson.annotations.SerializedName; -import lombok.Getter; +import lombok.Data; + +import java.util.HashMap; /** * @author kadehar * @since 1.0 * Model class, representing test summary from Allure Report. */ -@Getter +@Data public class Summary { @SerializedName("statistic") private Statistic statistic; @SerializedName("time") private Time time; + + public static Summary getInstance(HashMap statistic) { + Summary summary = new Summary(); + Statistic stat = new Statistic(); + stat.setTotal(statistic.get("total")); + stat.setFailed(statistic.get("failed")); + stat.setBroken(statistic.get("broken")); + stat.setPassed(statistic.get("passed")); + stat.setSkipped(statistic.get("skipped")); + stat.setUnknown(statistic.containsKey("unknown")?statistic.get("unknown"):0); + summary.setStatistic(stat); + return summary; + } } diff --git a/src/main/java/guru/qa/allure/notifications/model/summary/Time.java b/src/main/java/guru/qa/allure/notifications/model/summary/Time.java index c0960b3b..4bc702b3 100644 --- a/src/main/java/guru/qa/allure/notifications/model/summary/Time.java +++ b/src/main/java/guru/qa/allure/notifications/model/summary/Time.java @@ -1,14 +1,14 @@ package guru.qa.allure.notifications.model.summary; import com.google.gson.annotations.SerializedName; -import lombok.Getter; +import lombok.Data; /** * @author kadehar * @since 1.0 * Model class, representing test duration from Allure Report. */ -@Getter +@Data public class Time { @SerializedName("duration") private Long duration; diff --git a/src/main/java/guru/qa/allure/notifications/template/RocketTemplate.java b/src/main/java/guru/qa/allure/notifications/template/RocketTemplate.java new file mode 100644 index 00000000..6cb9963e --- /dev/null +++ b/src/main/java/guru/qa/allure/notifications/template/RocketTemplate.java @@ -0,0 +1,21 @@ +package guru.qa.allure.notifications.template; + +import guru.qa.allure.notifications.exceptions.MessageBuildException; +import guru.qa.allure.notifications.template.data.MessageData; + +/** + * @author GerasimchukDV + * @since 4.2.2 + * Utility class for KaTeX template creation. + */ +public class RocketTemplate { + private final MessageData messageData; + + public RocketTemplate(MessageData messageData) { + this.messageData = messageData; + } + + public String create() throws MessageBuildException { + return new MessageTemplate(messageData).of("rocket.ftl"); + } +} diff --git a/src/main/java/guru/qa/allure/notifications/template/data/BuildData.java b/src/main/java/guru/qa/allure/notifications/template/data/BuildData.java index 253d9c06..45362118 100644 --- a/src/main/java/guru/qa/allure/notifications/template/data/BuildData.java +++ b/src/main/java/guru/qa/allure/notifications/template/data/BuildData.java @@ -1,7 +1,9 @@ package guru.qa.allure.notifications.template.data; import guru.qa.allure.notifications.config.base.Base; +import guru.qa.allure.notifications.config.testops.TestOps; import guru.qa.allure.notifications.formatters.Formatters; +import guru.qa.allure.notifications.util.TestOpsClient; import lombok.extern.slf4j.Slf4j; import java.util.HashMap; @@ -14,11 +16,17 @@ */ @Slf4j public class BuildData implements TemplateData { - private final Base base; + private final TestOps testOps; public BuildData(Base base) { this.base = base; + this.testOps = null; + } + + public BuildData(Base base, TestOps testOps) { + this.base = base; + this.testOps = testOps; } @Override @@ -27,8 +35,16 @@ public Map map() { Map info = new HashMap<>(); info.put("env", base.getEnvironment()); info.put("comm", base.getComment()); - info.put("reportLink", - new Formatters().formatReportLink(base.getReportLink())); + if (base.getEnableTestOpsIntegration()) { + TestOpsClient testOpsClient = new TestOpsClient(testOps); + String launchId = testOpsClient.getLastLaunchId(); + String testOpsLink = String.format("%s/launch/%s", testOps.getUrl(), launchId); + info.put("reportLink", testOpsLink); + } + else { + info.put("reportLink", + new Formatters().formatReportLink(base.getReportLink())); + } log.info("Build data: {}", info); return info; } diff --git a/src/main/java/guru/qa/allure/notifications/template/data/MessageData.java b/src/main/java/guru/qa/allure/notifications/template/data/MessageData.java index 032772f0..c2db5938 100644 --- a/src/main/java/guru/qa/allure/notifications/template/data/MessageData.java +++ b/src/main/java/guru/qa/allure/notifications/template/data/MessageData.java @@ -4,6 +4,7 @@ import java.util.Map; import guru.qa.allure.notifications.config.base.Base; +import guru.qa.allure.notifications.config.testops.TestOps; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -28,6 +29,13 @@ public MessageData(Base base) { this.phrasesData = new PhrasesData(base); } + public MessageData(Base base, TestOps testOps) { + this.project = base.getProject(); + this.buildData = new BuildData(base, testOps); + this.summaryData = new SummaryData(base, testOps); + this.phrasesData = new PhrasesData(base); + } + public Map getValues() { if (data == null) { this.data = new HashMap<>(); diff --git a/src/main/java/guru/qa/allure/notifications/template/data/SummaryData.java b/src/main/java/guru/qa/allure/notifications/template/data/SummaryData.java index 97127c17..0d84fb48 100644 --- a/src/main/java/guru/qa/allure/notifications/template/data/SummaryData.java +++ b/src/main/java/guru/qa/allure/notifications/template/data/SummaryData.java @@ -1,10 +1,13 @@ package guru.qa.allure.notifications.template.data; import guru.qa.allure.notifications.config.base.Base; +import guru.qa.allure.notifications.config.testops.TestOps; import guru.qa.allure.notifications.formatters.Formatters; import guru.qa.allure.notifications.mapper.SummaryMapper; +import guru.qa.allure.notifications.model.summary.Statistic; import guru.qa.allure.notifications.model.summary.Summary; import guru.qa.allure.notifications.util.Percentage; +import guru.qa.allure.notifications.util.TestOpsClient; import lombok.extern.slf4j.Slf4j; import java.util.HashMap; @@ -19,30 +22,47 @@ public class SummaryData implements TemplateData { private final SummaryMapper summaryMapper; + private final TestOps testOps; public SummaryData(Base base) { this.summaryMapper = new SummaryMapper(base); + this.testOps = null; + } + + public SummaryData(Base base, TestOps testOps) { + this.summaryMapper = new SummaryMapper(base); + this.testOps = testOps; } @Override public Map map() { log.info("Collecting summary data for template"); - Summary summary = summaryMapper.map(); + Summary summary; + if (testOps != null) { + TestOpsClient testOpsClient = new TestOpsClient(testOps); + HashMap statistics = testOpsClient.getLaunchStatistic(); + summary = Summary.getInstance(statistics); + } + else { + summary = summaryMapper.map(); + } Map info = new HashMap<>(); - info.put("time", new Formatters().formatTime(summary.getTime() - .getDuration())); + if (testOps == null) { + info.put("time", new Formatters().formatTime(summary.getTime() + .getDuration())); + info.put("passedPercentage", + new Percentage().eval(summary.getStatistic().getPassed(), + summary.getStatistic().getTotal())); + info.put("failedPercentage", + new Percentage().eval(summary.getStatistic().getFailed(), + summary.getStatistic().getTotal())); + } info.put("total", summary.getStatistic().getTotal()); info.put("passed", summary.getStatistic().getPassed()); info.put("failed", summary.getStatistic().getFailed()); info.put("broken", summary.getStatistic().getBroken()); info.put("unknown", summary.getStatistic().getUnknown()); info.put("skipped", summary.getStatistic().getSkipped()); - info.put("passedPercentage", - new Percentage().eval(summary.getStatistic().getPassed(), - summary.getStatistic().getTotal())); - info.put("failedPercentage", - new Percentage().eval(summary.getStatistic().getFailed(), - summary.getStatistic().getTotal())); log.info("Summary data: {}", info); return info; } diff --git a/src/main/java/guru/qa/allure/notifications/util/TestOpsClient.java b/src/main/java/guru/qa/allure/notifications/util/TestOpsClient.java new file mode 100644 index 00000000..28afa732 --- /dev/null +++ b/src/main/java/guru/qa/allure/notifications/util/TestOpsClient.java @@ -0,0 +1,61 @@ +package guru.qa.allure.notifications.util; + +import guru.qa.allure.notifications.config.testops.TestOps; +import kong.unirest.Unirest; +import kong.unirest.json.JSONArray; +import kong.unirest.json.JSONObject; + +import java.util.HashMap; + +public class TestOpsClient { + + public static TestOps testops; + + public TestOpsClient(TestOps testOps) { + this.testops = testOps; + } + + public static String getLastLaunchId() { + String url = String.format("%s/api/rs/launch?projectId=%s&page=0&size=10&sort=created_date,DESC", + testops.getUrl(), + testops.getProjectId()); + + String jsonString = Unirest.get(url) + .header("Authorization", testops.getAuth_token()) + .header("XSRF-TOKEN", testops.getXsrf_token()) + .header("accept", "*/*") + .asString() + .getBody(); + JSONObject jsonObject = new JSONObject(jsonString); + JSONArray jsonArray = jsonObject.getJSONArray("content"); + String launchId = jsonArray.getJSONObject(0).getString("id"); + return launchId; + } + + public static HashMap getLaunchStatistic() { + String launchId = getLastLaunchId(); + return getLaunchStatistic(launchId); + } + public static HashMap getLaunchStatistic(String launchId) { + String url = String.format("%s/api/rs/launch/%s/statistic", testops.getUrl(), launchId); + + String jsonString = Unirest.get(url) + .header("Authorization", testops.getAuth_token()) + .header("XSRF-TOKEN", testops.getXsrf_token()) + .header("accept", "*/*") + .asString() + .getBody(); + JSONArray jsonArray = new JSONArray(jsonString); + HashMap statistics = new HashMap<>(); + Integer total = 0; + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject element = jsonArray.getJSONObject(i); + String status = element.getString("status"); + Integer count = element.getInt("count"); + statistics.put(status, count); + total = total + count; + } + statistics.put("total", total); + return statistics; + } +} diff --git a/src/main/resources/templates/rocket.ftl b/src/main/resources/templates/rocket.ftl new file mode 100644 index 00000000..d1209581 --- /dev/null +++ b/src/main/resources/templates/rocket.ftl @@ -0,0 +1,12 @@ +<#compress> +**${results}:** + **-${environment}:** ${env} + **-${comment}:** ${comm} + **-${totalScenarios}:** ${total} + <#if passed != 0 > **-${totalPassed}:** ${passed} + <#if failed != 0 > **-${totalFailed}:** ${failed} + <#if broken != 0 > **-${totalBroken}:** ${broken} + <#if unknown != 0 > **-${totalUnknown}:** ${unknown} + <#if skipped != 0 > **-${totalSkipped}:** ${skipped} + <#if reportLink??>**${reportAvailableAtLink}:** ${reportLink} + \ No newline at end of file