Commit b9a9e69d authored by Shinya Maeda's avatar Shinya Maeda

Squashed commit of the following:

commit 1095f6636db1c9bcd200c9c59e4b14ae70c0884b
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Aug 2 14:25:45 2018 +0900

    Fix spec

commit dd3e46ee15712b046ca83600c9f2694fbdc3a5f8
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Aug 2 14:14:59 2018 +0900

    Fix static analysis

commit 32f46f402b53fc23770224f5c890bd4acfc39e60
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Aug 2 11:34:05 2018 +0900

    Add spec for preventing N+1 querires. Add spec for merge request controller.

commit 7e12ef867b3e20bf1d35421a3b82350e9c673962
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Aug 2 10:22:45 2018 +0900

    Add spec for test reports comparer serializer

commit 6d69bb297afc90386bb847cf0fd1e75fc377e9d7
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Aug 2 09:27:41 2018 +0900

    Remove unnecessary comments

commit aca76ded6abf65d1f54008f9865ec7055f51300c
Merge: f6cf7c1c98b 9812e5dd
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Aug 2 09:26:57 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2-with-parser

commit f6cf7c1c98b29c6a9a2e59d0a438bf77972e0aee
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Aug 2 09:23:08 2018 +0900

    Use iid for making unique key for reactive cache

commit 642a3d9215fc004ceaa431648a44d3a7671fb9e3
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Aug 1 23:39:14 2018 +0900

    Mkae reactive cache key unique per pipeline ids

commit 24ca34107837375364560e83b37fce8e4f7edfbd
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Aug 1 21:41:30 2018 +0900

    Add spec for entity

commit e761d9d3e9a56d878d6e71a636a29f0f13c9c78f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Aug 1 19:32:41 2018 +0900

    Add spec for merge request model

commit 3c740854b9ac348993c715f24eeb5e6487d57ad6
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Aug 1 16:19:01 2018 +0900

    Add spec for build and pipeline model

commit 027a553badc080195f3b3aceba931407939e1535
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Aug 1 15:17:00 2018 +0900

    Add specs for test reports comparer

commit f4a63066e5517605c40b526b3085097e885c6051
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Aug 1 14:00:46 2018 +0900

    Add test_reports_spec

commit 18a285a52b064dc894200925af15a2b1f02e7840
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Aug 1 11:16:57 2018 +0900

    Simpolify reactive cache usage. Improve code structure.

commit faaa41e5bcf4c6c76881957e96e4b3b278aee460
Merge: 9a6b3b7f0ab d799da4a18e
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Aug 1 09:19:26 2018 +0900

    Merge branch 'artifact-format-v2-with-parser' of gitlab.com:gitlab-org/gitlab-ce into artifact-format-v2-with-parser

commit 9a6b3b7f0ab32a70f63b1fe81d78616e6f88f4cc
Merge: 04cd0ed8812 b690c268
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Aug 1 09:18:48 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2-with-parser

commit d799da4a18ec9f0d91dd48ac1c9abc3283235b99
Merge: dc874468571 04cd0ed8812
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Tue Jul 31 17:49:53 2018 +0100

    Merge branch 'artifact-format-v2-with-parser' of https://gitlab.com/gitlab-org/gitlab-ce into artifact-format-v2-with-parser

    * 'artifact-format-v2-with-parser' of https://gitlab.com/gitlab-org/gitlab-ce:
      Remove debuggable fixtures

commit dc8744685713a8ab9d3eb7987c7fcf898e8dcd38
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Tue Jul 31 17:49:35 2018 +0100

    Removes frontend code

commit 04cd0ed8812f5fdd9cd00540155ec01edc0b42de
Merge: 8003540237e 0295e478b22
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Aug 1 00:13:58 2018 +0900

    Merge branch 'artifact-format-v2-with-parser' of gitlab.com:gitlab-org/gitlab-ce into artifact-format-v2-with-parser

commit 8003540237e9070a93ccd1b89a65b1f45ba8234d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Aug 1 00:13:39 2018 +0900

    Remove debuggable fixtures

commit 0295e478b2267c10186c7b9aa9e3bb1bfa8a1b43
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Tue Jul 31 16:12:25 2018 +0100

    Fixes broken tests

commit 4fa50ca7fc1e3ab5d0995dc85245fc8ba013d2ce
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Tue Jul 31 10:59:44 2018 +0100

    Ports EE css into CE code base
    Creates unit tests

    Creates code block component

commit 2dc45f714f449bd71b03f34585724e46be9bee4f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 31 18:20:22 2018 +0900

    Remove unnecessary parameters from build#each_test_report

commit 89d7398ae71bff15a397c2b10eb5134e2bc43a7b
Merge: 08d6ac5262c 02e35a0d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 31 18:09:49 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2-with-parser

commit 08d6ac5262c14f1d67d74238927bcaf62d8efab5
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 31 17:57:02 2018 +0900

    Add spec for test case and test suite

commit 9d6da7c97fea6ce2086225500a04663b10339b6b
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 31 16:35:31 2018 +0900

    Add spec for gzip parser and adapter

commit 4c29079c4aeda0bde7c3ce6d9f1d5d5da9ffd657
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 31 11:41:33 2018 +0900

    Include status at each level. Refactor back to success/failed

commit 3fa747db101f4d421e539b7c591a85db02011d2e
Merge: 4f7e9d54d52 69c87c3d1f0
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 31 10:18:51 2018 +0900

    Merge branch 'artifact-format-v2-with-parser' of gitlab.com:gitlab-org/gitlab-ce into artifact-format-v2-with-parser

commit 4f7e9d54d5298bfb1566028f59009cc2b665ae3b
Merge: 18ed332734a 7758fdf1
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 31 10:18:18 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2-with-parser

commit 69c87c3d1f0559ea21bb8b5f1005685db59aded5
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Mon Jul 30 15:58:11 2018 +0100

    Removes create issue handlers
    Hides grey block when no issues are present

commit 18ed332734a2c95a9f93bc7d173c8b76d22867fe
Merge: 05944862e9c 2c15e359c38
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 30 23:14:44 2018 +0900

    Merge branch 'artifact-format-v2-with-parser' of gitlab.com:gitlab-org/gitlab-ce into artifact-format-v2-with-parser

commit 05944862e9ce9983ed258b7795166faffb38522a
Merge: c1bef2ee559 3d2dad44
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 30 23:13:50 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2-with-parser

commit 2c15e359c38d208cab16852489d9317657bd805c
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Mon Jul 30 11:14:48 2018 +0100

     Patched a weird status issue

commit 5a76071b91aa40de9dc1b0e5537fa3f8f081fdcd
Merge: 6a2c69f8ab6 c1bef2ee559
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Mon Jul 30 11:14:06 2018 +0100

    Merge branch 'artifact-format-v2-with-parser' of gitlab.com:gitlab-org/gitlab-ce into artifact-format-v2-with-parser

commit c1bef2ee559c0f3c263daf2d3e92a4485cdd010e
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 30 17:23:58 2018 +0900

    Add fixtures to check the behavior with multi patterns

commit b2ccce593b578c434febdd2f945a665a6652fd4e
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 30 10:40:37 2018 +0900

    Fix a fixture in spec - merge request widget json

commit 29dfd45264427f6bd064aa62401c6be5ac4c4e14
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 30 10:35:34 2018 +0900

    Update old changes

commit c26dae72f28939e1ee2e884c260278035fa0549a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 30 10:26:39 2018 +0900

    Fix static analysis

commit e9ad9df37d09330c1a6d23ac46d0923cb24fe636
Merge: fda5e9bd986 1f999262
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 30 10:20:16 2018 +0900

    Merge branch 'artifact-format-v2' into artifact-format-v2-with-parser

commit 6a2c69f8ab643960e434af867e8b61399b1dafc2
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Fri Jul 27 15:54:02 2018 +0100

    Auto fixes with eslint

commit c7b9fa252b9726903ef808d1bf02441527f88c7b
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Fri Jul 27 15:53:30 2018 +0100

    Updates the textGenerator for reports

commit fda5e9bd9864be7fba8f576bd9af4e58a5929e98
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 27 16:20:15 2018 +0900

    Remove unnecessary schema change

commit 06e0967508e1fea5934bd68c490f505d8f7233d0
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 27 16:06:28 2018 +0900

    Fix schema version

commit e63cc95742eac125691f8d3aac2820bbcc6113ec
Merge: 8a734c3d933 8b3c7f57
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 27 16:03:31 2018 +0900

    Merge branch 'artifact-format-v2' into artifact-format-v2-with-parser

commit 0d613f03203a84f91efaec9b6e0244cfc6603457
Author: Sam Beckham <sbeckham@gitlab.com>
Date:   Thu Jul 26 16:24:48 2018 +0000

    Full list of vulnerabilities

commit 8a734c3d9333415707fe73a233278d2dbafabc38
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Thu Jul 26 17:20:07 2018 +0100

    Cherry picks an update to the report component and updates the codebase to use it

commit e16a2ddd47066521220c045daf3a55367d008edf
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Wed Jul 25 18:00:39 2018 +0100

    Adds the 'new' badge to the issues list

commit ac9bc3a293724c6729a2b58273344dc920fffa8b
Merge: f013f0219cf 44904f34593
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Wed Jul 25 16:44:25 2018 +0100

    Merge branch 'artifact-format-v2-with-parser' of gitlab.com:gitlab-org/gitlab-ce into artifact-format-v2-with-parser

commit f013f0219cf2ac52fc4a7c8937c1cadd750adeae
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Wed Jul 25 15:47:30 2018 +0100

    Fixes some missed conflicts

commit 44904f34593d62d3b68a57e54118b6c31b050a6f
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Wed Jul 25 15:47:30 2018 +0100

    Fixes a missed conflict

commit 735a49154075b4824421c4c1180ef6428b6fe64c
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Wed Jul 25 15:44:04 2018 +0100

    Fixes some merge conflicts

commit ef5c9a5853b3cff1f5a952e5a87593c187834019
Merge: 181f98f695e 8f3b9c0d313
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Wed Jul 25 15:31:48 2018 +0100

    Merge branch 'artifact-format-v2-with-parser' of gitlab.com:gitlab-org/gitlab-ce into artifact-format-v2-with-parser

commit 181f98f695eac05ffc6b5d57d665f4bd52d43f21
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Wed Jul 25 15:27:48 2018 +0100

    Adds a proper check for loading errors

commit 24b108d4b15c87c1dd530ccd9bf7ed1b1a44faa3
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Wed Jul 25 14:09:57 2018 +0100

    Adds a fake conditional for checking if we should render the modal footer or not

commit 5f4b682afae624feebeea101cae2517f673467f4
Author: samdbeckham <sbeckham@gitlab.com>
Date:   Wed Jul 25 13:43:24 2018 +0100

    Adds a patch to get this working again after the rebase

commit 0252d861556cf66098e7e589f5889887b7b0309b
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 16:25:05 2018 +0900

    Skip comparison if head and base pipelines are the same as before

commit b8207fae37cd035010e66c158211913f41790bf8
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 16:24:05 2018 +0900

    Fix N+1 problem at collect_test_reports

commit 297e51fed1ad30be6207f244e97a678c9275aa76
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 23 21:00:03 2018 +0900

    Implement reactive cache worker

commit b20da289fb6c45466bf47a09ac6c33625806936b
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 23 16:58:56 2018 +0900

    Refactoring test_results to test_reports

commit f1cef58465f5936a74c0cb23167b5d4a51ecc46c
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 23 14:12:58 2018 +0900

    Revert archive_metadata refactoring

commit c2387c534c11a29cc0db815cb3219dd80bb6ed03
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Fri Jul 20 22:57:01 2018 +0100

    Adds action to handle the create issue button
    Moves component to inside mr widget
    Fixes eslint errors

commit 761aec1dc095c30e1eee0bf2a3ea7eceb19a5e06
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Fri Jul 20 18:57:10 2018 +0100

    Removes mocked data

commit da01a9748c764e2d1ca4cc669417ef14ff11a195
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Fri Jul 20 18:54:06 2018 +0100

    Render grouped test report in MR widget

commit 8a8678f58e86f29a69d052978b3b76fcb9baeacc
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Fri Jul 20 13:15:35 2018 +0100

    Follow up after review: Clear Vuex actions and mutations

commit d84e1b0be459b314f4fb706e381f1c36235135e8
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Fri Jul 20 09:37:45 2018 +0100

    Moves payload to the correct action

commit 1a8490ffe81f1e8a9173a50a3c0a8b017e968697
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Thu Jul 19 16:10:25 2018 +0100

    Adds payload to the fetchReports success spec

commit b38389fa0e576d76f90075cb5a606260dd87cf95
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Thu Jul 19 14:48:54 2018 +0100

    Updates documentation and test mock endpoint

commit c6a1a39efefb7b8e938ec679c57ca6810a8f8919
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Thu Jul 19 12:49:44 2018 +0100

    Adds Vuex store for reports section in MR widget

commit f0077c4708c246eedb6f9259c3b3b23c29755b26
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Fri Jul 20 12:44:16 2018 +0100

    Initial structure for reports app

commit a76c54543e945b4f1644a4db151e639e2a000e0e
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 19:06:46 2018 +0900

    Check pipeline status at has_test_results?

commit 10475fab64d2fc13e52edf8bef83031e44232f15
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 18:19:46 2018 +0900

    Specify DOWNTIME=false

commit 6332df56993b28ce57713571df36ff03473993e7
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 18:14:44 2018 +0900

    Wrap long lines

commit f507f19e42941b2f01b4dda62b94e5b6ae546135
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 18:05:31 2018 +0900

    Checking filr_format and file_type paring

commit 364242eebe35946d2d2ff6face693af8da2a953f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 16:07:21 2018 +0900

    Fix build presenter spec

commit 5149115670f2afc57820cb564794d2452290763b
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 16:02:09 2018 +0900

    Erase test reports at the proper timing

commit cb70174fe7624a3dc128ab085e6ae529563b7f49
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 15:46:56 2018 +0900

    Make GENERAL_ARCHIVE_FILE_TYPE as a single entry

commit dceb8b58a13396d9181be0e8be49a0b35509c039
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 15:42:16 2018 +0900

    Implement config artifact presenter

commit d492832d30408d5f475910c8ccdd6f34108e7c61
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 14:27:54 2018 +0900

    Introduce ARCHIVE_LEGACY_TRACES_MIGRATION_VERSION check

commit f432fd975a0b2428c89dc0274be307bdf6b68438
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 21:00:40 2018 +0900

    Revert unnecessary change

commit f83de3fe4ba42a0e64dcdcb950aecdd632f94076
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 20:57:03 2018 +0900

    Remove scattering around erase_test_reports!

commit 575be347d8d29c8216b7ee5b449ac8adc5cbd349
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 20:53:00 2018 +0900

    Rever archive_metadata refactoring  (For simplifying)

commit f04fc5766ae45b3b7941c4447fd3d32a5e262245
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 20:45:19 2018 +0900

    Use array_of_strings_or_string in Command

commit 1511f7052aeb8f32b533fe56034f54ead3139f79
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 20:40:06 2018 +0900

    Fix spec

commit 78b3ba38298c6e7ca838e34bd0a3897a9ce78568
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 18:27:11 2018 +0900

    Fix presenter spec

commit ab583ce712314648900033de48b3a1e6a13f08d0
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 18:23:41 2018 +0900

    Fix artifact migratable

commit d432f1665b8146527721b667d4b6abe61d8c57f6
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 18:15:41 2018 +0900

    Increment migration version to use `file_format` when archiving traces

commit 7523168a1e9612e17c55d0b42d2d9c664d0d942d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 17:57:15 2018 +0900

    Impolement job_artifact.test_reports method

commit 55b9340539ac1ac69490d8c0e58a81c157964799
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 16:49:27 2018 +0900

    Fix erase method

commit b98c907a9cc5c165cf26b0297914ae57d202f715
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 16:28:00 2018 +0900

    Fix spec

commit 49d196a0d4964b23027bd429092c78ab05d28658
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 15:31:42 2018 +0900

    Add java ant Junit test report in fixtures

commit 292e10b98628abc554c53a8d7b0345edcb5dbd66
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 18 20:59:01 2018 +0900

    Add fixtures which can export all kind of reports (new/resolved/exisiting)

commit b59d68c9b9a39aeb4a25f19e27b2495c7e2b2f85
Author: Kamil Trzciński <ayufan@ayufan.eu>
Date:   Wed Jul 18 12:17:49 2018 +0200

    Add summary to test results json

commit 67137d6159e194290c2bb2fb2c25e6373453596d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 18 16:43:20 2018 +0900

    Fix fixtures for development

commit 2184358cfcc93394ed2bb5d6ace09101439596ea
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 18 15:43:28 2018 +0900

    Evaluate artifact_format

commit 618e023055f229d908c68213f456a7797156f7cf
Author: Kamil Trzciński <ayufan@ayufan.eu>
Date:   Tue Jul 17 18:00:59 2018 +0200

    Expose all data with API on Merge Request

commit 0b5f9ff76f87b5d3b9c2eebd4ab8c69de5d4c201
Author: Kamil Trzciński <ayufan@ayufan.eu>
Date:   Tue Jul 17 17:18:19 2018 +0200

    Improve code of JUnit reports

commit 5fa026db0baa32cd063fbff3ec2532144f089236
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 17 20:13:31 2018 +0900

    Refactoring suites. Adding gurad clause at collect_test_results

commit b4dcab7b7f89ed0bf3103a5b0022343620a0dec4
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 17 19:52:01 2018 +0900

    Implement comprare failed tests

commit 4f3c9f152e432c7d7fd18e21988a9c371cac4617
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 17 18:50:03 2018 +0900

    Objectize each test suit and summary

commit 1477d1a09bb3ba1fc6d82241f1414708a93a269d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 17 17:55:34 2018 +0900

    Pass build.group_name as testsuite name

commit 26d0d36671b3e6adb3d224a854f0eefe75cfc86c
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 17 16:35:06 2018 +0900

    Remove unnecessary files

commit 00487d2d0e29b7713a8e4d66d0b29c3fa98ed901
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 17 16:26:37 2018 +0900

    Add parser and testresults

commit 33c42f2185a1cc959ab4d2823be437cb81d4f144
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 22:27:46 2018 +0900

    Fix sending junit.xml

commit a53aa6539700a5719c87eb11be974384277d5d24
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 19:02:06 2018 +0900

    Add spec for Gitlab::Ci::Config::Entry::Artifacts

commit d4f837fe925171453c52b076b8a23231f72a9d4b
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:58:28 2018 +0900

    Revert refactoring

commit c4223e29138440f8debfe486d6a7bf8645930dbf
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:57:31 2018 +0900

    Revert refactoring

commit 3a50b86d147734ccf406991309d86ebb41a828c8
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:55:41 2018 +0900

    Add spec for file format. Add spec for config_artifacts

commit 0dd37009c4e202422746577cb95651b32def8c46
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:20:28 2018 +0900

    Add file_format to factory

commit 4db135e362ac05d71112d654334bd57271d23fd8
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:12:52 2018 +0900

    Rename migration file properly

commit 0f7a011aa7c2c996919653fd64cdc71f98d68bc4
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:09:57 2018 +0900

    Revert artifacts_archive_file refactoring

commit cd3d10e572f6036e46b96f760f1f8ab26099d2cc
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 16:03:26 2018 +0900

    Dry up the converion in Entry::Reports

commit cab90b2a5aac6f72ef5817ed568b002742039798
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 15:50:42 2018 +0900

    Set file_format at callers

commit 50780a664021ec5abe55d79541cc6b47a33c421b
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 15:47:51 2018 +0900

    Use presenter for presenting artifacts hash to runner

commit e6310b515c0a7d6bf02c58342f35dd327afbb3aa
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 14:59:09 2018 +0900

    Support deleting junit artifact. Make wording explicit

commit 0eb356b93d1834c6a32ee11b4bd488387406b257
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 14:35:12 2018 +0900

    Add changelog

commit 35f350d18de8df0bda6a27cf9cf5f88784108a5f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 17:33:07 2018 +0900

    Fix static analysis

commit 2db42fd6115ebc5710f89bd542a0cb724d480f25
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 16:43:02 2018 +0900

    Fix Config::Entry::Artifacts

commit fa73365d10ff56ceb9c19d2f0d17b8847059026f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 14:40:20 2018 +0900

    Generalized by DEFAULT_FILE_FORMAT

commit ac76ad67871225abf1830a87f05639296a4bf07d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 13:55:02 2018 +0900

    Cleanup API::Entities::JobRequest::Artifacts

commit 32d25b13914cb4e6e7d5293b181c2bbf2a083978
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 13:25:52 2018 +0900

    Simplified file_type relations

commit b62faddf033bcbf964e161b484b9b6ca8adbddd6
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 18:16:52 2018 +0900

    Remove unnecessary change

commit 314ac2baf2192a466a2873889798d4b90f27adc6
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 17:41:35 2018 +0900

    Add gzip XML parser

commit 37cbfbde7048bf5bc36c87d57bdf34399d7365c0
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 17:40:35 2018 +0900

    Fix errors typo

commit 2dc2d704366ca600e7fa064fb7db75a73a3b3149
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:32:35 2018 +0900

    Use the correct type name

commit 66edd04c62a6b33dfa12962b8e7ccc7132c49fa1
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:29:21 2018 +0900

    Refactor job_artifacts_metadata to job_artifacts_archive_metadata

commit d586f03067678457223c8ea4e6ed925e05a19c92
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:23:55 2018 +0900

    Add job_artifacts_junit relation

commit 58aef7a7a8944d0bbb0a87b86cad2bc250d759d8
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:14:03 2018 +0900

    Fix raw to raw?

commit f14e1b19af5e2657e5956815453525c2d1489e0f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 19:05:51 2018 +0900

    Temporaly use type Hash for reports

commit 05e4967af37ed8a211099a7a3623069a41c3d078
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:27:21 2018 +0900

    Revert unnecessary change

commit 8a7267c79ed0499a8352338170564d4a5f008cc5
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:21:46 2018 +0900

    Use file_format raw for trace

commit ca6820a76a00f56f851154ca4792e243b5df3ffd
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:20:10 2018 +0900

    Check the presence of the file_format

commit 9c78003f6d5d15da2074622007ca117b8b54226e
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:16:19 2018 +0900

    Add format_restriction validation

commit 9168513e33fa4b5bb40eb1a3af65535520ae4309
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 20:23:54 2018 +0900

    Artifacts presenter (Halfway)

commit d83cf2163a71c6606eafdbc79cc753cbd139ab77
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 20:22:52 2018 +0900

    Fix schema.rb

commit e64af496b4b147d221fd99ef6b2343c4fcbfef1d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 19:26:03 2018 +0900

    Allow reports type under artifacts. Allow junit keyword in it.

commit 20c333c9cb2cc66daaa000af5178c3d700a85e95
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 19:25:10 2018 +0900

    Change column name to artifact_format

commit 16b670f42daf3a3fc6ca1443b6a50e4473231c46
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 18:02:21 2018 +0900

    Rename metadata to archive_metadata, and compress to file_format

commit 808355fae0c9869a26c95a90b0efe17a7b6e26d2
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 17:47:18 2018 +0900

    Validate compression. Clean up schema

commit 8e2048603f94b29af55884edc3113b99af910dfa
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 5 19:06:54 2018 +0900

    Make compression params at the first level

commit 3331af0ab1761868a9daa1c8ab3dad7f2017f511
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 5 16:31:03 2018 +0900

    Reorganize components

commit 8f3b9c0d313f9eeef1b6e6b5eccf622156e960bd
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 16:25:05 2018 +0900

    Skip comparison if head and base pipelines are the same as before

commit 9cabd787fc392c7a442cd8b2de798da36c8b67bc
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 16:24:05 2018 +0900

    Fix N+1 problem at collect_test_reports

commit 21de18bf9fecdfadadb80c5a071ff5d7af6ff524
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 23 21:00:03 2018 +0900

    Implement reactive cache worker

commit 09c2fa31897bf8a42183a23bf98d5163c5e95860
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 23 16:58:56 2018 +0900

    Refactoring test_results to test_reports

commit 41a439c75983a8bd200e0728b231487ff6e1699c
Merge: bc959fffb1a 7105b37a558
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 23 14:23:29 2018 +0900

    Merge branch 'artifact-format-v2-with-parser' of gitlab.com:gitlab-org/gitlab-ce into artifact-format-v2-with-parser

commit bc959fffb1a1e8937078a1399dad2f698534ac84
Merge: 291a9236547 1ebaaaf2094
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 23 14:23:01 2018 +0900

    Merge branch 'artifact-format-v2' into artifact-format-v2-with-parser

commit 1ebaaaf2094c47c03e16745d2f8af736ec102b76
Merge: bfdf565800b dc7b4b7b
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 23 14:22:29 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2

commit 291a923654714b6c24fd654c41c5b0caa90daff2
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 23 14:12:58 2018 +0900

    Revert archive_metadata refactoring

commit 7105b37a558acf22a23125cddfefc517c040a0fb
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Fri Jul 20 22:57:01 2018 +0100

    Adds action to handle the create issue button
    Moves component to inside mr widget
    Fixes eslint errors

commit d82efd8fa8329758dd3a956d5d47956ccb3ce643
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Fri Jul 20 18:57:10 2018 +0100

    Removes mocked data

commit 5cfe99006ed539fbc9e0a184b09af4be63e6d91b
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Fri Jul 20 18:54:06 2018 +0100

    Render grouped test report in MR widget

commit 8e74f14c26b9df6a4fdc4fb79322b13b06c3c509
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Fri Jul 20 13:15:35 2018 +0100

    Follow up after review: Clear Vuex actions and mutations

commit 570e7713c76b247c6da886dc60edce10657558b1
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Fri Jul 20 09:37:45 2018 +0100

    Moves payload to the correct action

commit 04b473b68969a57d7c5fa33fe46c18bd9ee6bddf
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Thu Jul 19 16:10:25 2018 +0100

    Adds payload to the fetchReports success spec

commit a3eb4001181d6d0ae8f3a62d0452a06f67500cc6
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Thu Jul 19 14:48:54 2018 +0100

    Updates documentation and test mock endpoint

commit 920b74f519091000dc73a3be02c472ea226aa451
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Thu Jul 19 12:49:44 2018 +0100

    Adds Vuex store for reports section in MR widget

commit ebebf4042bbcdcc32d5aa65b0da470ddc52f0f8e
Author: Filipa Lacerda <filipa@gitlab.com>
Date:   Fri Jul 20 12:44:16 2018 +0100

    Initial structure for reports app

commit 746c260d5e4ae4604a3b072e9c58e6c2ee1e114e
Merge: 82a8d55742f bfdf565800b
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 19:15:32 2018 +0900

    Merge branch 'artifact-format-v2' into artifact-format-v2-with-parser

commit bfdf565800b58e838a760aa01d2fadb64e2d768f
Merge: 681bd6a878a 44dbeccb
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 19:10:47 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2

commit 82a8d55742f73a43c5281af8245f5e5873985344
Merge: b2183151e6a 44dbeccb
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 19:07:30 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2-with-parser

commit b2183151e6a7344a327883a2658030920e256e47
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 19:06:46 2018 +0900

    Check pipeline status at has_test_results?

commit 681bd6a878ad2a77c278f5619b51c542d7382aa2
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 18:19:46 2018 +0900

    Specify DOWNTIME=false

commit 59c4e31390e0d616d69babf8ac857e98f2dc774e
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 18:14:44 2018 +0900

    Wrap long lines

commit 3d85788edbe73fc74c72854508e47fe259d99236
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 18:05:31 2018 +0900

    Checking filr_format and file_type paring

commit 3c92a22faf6278e7a2d1ee13bd978bc659b72452
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 16:07:21 2018 +0900

    Fix build presenter spec

commit 36e69897b0524cdee6060c928c03af734afae664
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 16:02:09 2018 +0900

    Erase test reports at the proper timing

commit 402ae97ecf7f9e3fe541f2d6abef6e47ab740452
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 15:46:56 2018 +0900

    Make GENERAL_ARCHIVE_FILE_TYPE as a single entry

commit 75f75b3f5988398fff0660ca5f04aec756ab03bb
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 15:42:16 2018 +0900

    Implement config artifact presenter

commit 9ecaee914defba5f12a7a06375ea2876b4328d7f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 14:27:54 2018 +0900

    Introduce ARCHIVE_LEGACY_TRACES_MIGRATION_VERSION check

commit 34ea9610ab9a249a576ee435f365b9e1fcca7f00
Merge: d88523ca884 b60364c0
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 13:46:52 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2

commit d88523ca88420354f61bd36f533c62a6ca474423
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 21:00:40 2018 +0900

    Revert unnecessary change

commit d9beb10ede5e4e8abe388fadbd6412640293917a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 20:57:03 2018 +0900

    Remove scattering around erase_test_reports!

commit c79f361ca01f8dbc0d395edee5fab7f5a0697934
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 20:53:00 2018 +0900

    Rever archive_metadata refactoring  (For simplifying)

commit 55bc71a404d8cf5fa87e187f6e88da92ab95afa9
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 20:45:19 2018 +0900

    Use array_of_strings_or_string in Command

commit 8a576b18c8ab8ead2344e2885aaf2fde11af0328
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 20:40:06 2018 +0900

    Fix spec

commit a2cda62fb922184aaf0e78699e06846c96565e0d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 18:27:11 2018 +0900

    Fix presenter spec

commit 95502e605af9bcf1a61dbeb26f9be4d181f8a7ba
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 18:23:41 2018 +0900

    Fix artifact migratable

commit a3930853c93862007ba6814511bc32042c7f4986
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 18:15:41 2018 +0900

    Increment migration version to use `file_format` when archiving traces

commit e31121cb5e617b0f05e375c2150ece0e38e5e0d6
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 17:57:15 2018 +0900

    Impolement job_artifact.test_reports method

commit e54707fdf97392839cb2c4711160bd3bc89da196
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 16:49:27 2018 +0900

    Fix erase method

commit 20e95824341af1ebc5877d28dc5eba26f73eddf9
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 16:28:00 2018 +0900

    Fix spec

commit be2083ff9cceacd6bdd64a9521081278111400a7
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 15:31:42 2018 +0900

    Add java ant Junit test report in fixtures

commit d47efe84ff6dda79edd00c9b055d752872af1e11
Merge: e0dc7d97efd 7ade498101d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 12:37:57 2018 +0900

    Merge branch 'artifact-format-v2' into artifact-format-v2-with-parser

commit 7ade498101d02573b20a2405ebe0bdb8efd8aa3b
Merge: e7be6b2b362 98eccfc4
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 12:37:22 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2

commit e0dc7d97efdc0a3ddeb29f8b29f7d18e34607960
Merge: 26578902d09 1859a0f9e0c
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 18 20:59:20 2018 +0900

    Merge branch 'artifact-format-v2-with-parser' of gitlab.com:gitlab-org/gitlab-ce into artifact-format-v2-with-parser

commit 26578902d097979ca32a6453a33d699209077aa5
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 18 20:59:01 2018 +0900

    Add fixtures which can export all kind of reports (new/resolved/exisiting)

commit 1859a0f9e0c0f8f10ba640a8826b9ccade9fd15f
Author: Kamil Trzciński <ayufan@ayufan.eu>
Date:   Wed Jul 18 12:17:49 2018 +0200

    Add summary to test results json

commit 47dfdc732e850fd1390d25d50b1ef7a99491770a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 18 16:43:20 2018 +0900

    Fix fixtures for development

commit 8b761adfb85d0631d2a78169f8440aca3b40c86d
Merge: 84c64a792bf e7be6b2b362
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 18 15:44:10 2018 +0900

    Merge branch 'artifact-format-v2' into artifact-format-v2-with-parser

commit e7be6b2b3624ba44d56143084731cb9a6168f974
Merge: 5a8d4930e01 9bdc9b1a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 18 15:43:36 2018 +0900

    Merge branch 'master' into artifact-format-v2

commit 5a8d4930e0127aae311bfa3da70d9ab9637791e3
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 18 15:43:28 2018 +0900

    Evaluate artifact_format

commit 84c64a792bf5d3a42bd8000eaa9fc6f5aeacc604
Merge: e2670a3c642 9bdc9b1a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 18 13:28:42 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2-with-parser

commit e2670a3c642ba33e79202fc9adb044a78260c515
Author: Kamil Trzciński <ayufan@ayufan.eu>
Date:   Tue Jul 17 18:00:59 2018 +0200

    Expose all data with API on Merge Request

commit 5ea46ce5cd6d0f74802216d1c63d274a48d3cd08
Author: Kamil Trzciński <ayufan@ayufan.eu>
Date:   Tue Jul 17 17:18:19 2018 +0200

    Improve code of JUnit reports

commit 0553827fff5e1796bbfcdd7a5daf324a7dd16ea0
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 17 20:13:31 2018 +0900

    Refactoring suites. Adding gurad clause at collect_test_results

commit 55edde40b15b3499cfc7ecbbe08f15cae9f6661a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 17 19:52:01 2018 +0900

    Implement comprare failed tests

commit 612c44a39099edfb258cc3c1c8e650ab192d9a8b
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 17 18:50:03 2018 +0900

    Objectize each test suit and summary

commit 598b34072c2c7b417e47945389b88e5103fc4b17
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 17 17:55:34 2018 +0900

    Pass build.group_name as testsuite name

commit d0ad35fcc4b1d9c58d798775e13623026900ed27
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 17 16:35:06 2018 +0900

    Remove unnecessary files

commit 541292c37e5ad24f4d137454743808cfc1f3c216
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 17 16:26:37 2018 +0900

    Add parser and testresults

commit c61465b962dd2774cf08ef7db81ab358a2c08ba5
Merge: da6e141e7b9 c3ce06aa9bc
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 22:28:12 2018 +0900

    Merge branch 'artifact-format-v2' into artifact-format-v2-with-parser

commit c3ce06aa9bc6481b37a16d175adf0fd1c37a1bc0
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 22:27:46 2018 +0900

    Fix sending junit.xml

commit e5ce3668ee65217aba610d5311efd5e82bacddf3
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 19:02:06 2018 +0900

    Add spec for Gitlab::Ci::Config::Entry::Artifacts

commit ede107caf13fb215045576dcce18e20eec776df1
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:58:28 2018 +0900

    Revert refactoring

commit 15531ba9feff669b2ac05936e0feaee1856c1571
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:57:31 2018 +0900

    Revert refactoring

commit 14821f3babcc210bc52e4e825adc8333752fbc88
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:55:41 2018 +0900

    Add spec for file format. Add spec for config_artifacts

commit 882faeab57ab39d18f72abd9b65d286db92e1011
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:20:28 2018 +0900

    Add file_format to factory

commit 3cd0513e254db15141cd748f6209179f462974f2
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:12:52 2018 +0900

    Rename migration file properly

commit f511933b5f618fc47d1512554878913922dfba61
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:09:57 2018 +0900

    Revert artifacts_archive_file refactoring

commit e295e8cbdee065ee3af6dd82f512729554237cad
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 16:03:26 2018 +0900

    Dry up the converion in Entry::Reports

commit b0ffa42f6410be4718e7a36cb21f7b585421750e
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 15:50:42 2018 +0900

    Set file_format at callers

commit f3dc7a2e02901c79a9e572514a1b731c680e43cc
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 15:47:51 2018 +0900

    Use presenter for presenting artifacts hash to runner

commit e5299526138be90d65cf13368134e734b46f7597
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 14:59:09 2018 +0900

    Support deleting junit artifact. Make wording explicit

commit cc81c34acf23323257d190c23030d0a89265bccc
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 14:35:12 2018 +0900

    Add changelog

commit abde0f2ab5c5c1d99b2f94a049984877bb5a4d77
Merge: 4c87e5b388f fabf6a56
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 13:22:22 2018 +0900

    Merge branch 'master' into artifact-format-v2

commit 4c87e5b388fb098fb6da71e17a47fa204033e4ac
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 17:33:07 2018 +0900

    Fix static analysis

commit bc96346be6990b75da9a36055814b24b5b805707
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 16:43:02 2018 +0900

    Fix Config::Entry::Artifacts

commit aac284613b9db43e3021198dc5b43b81806f1bce
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 14:40:20 2018 +0900

    Generalized by DEFAULT_FILE_FORMAT

commit a79299fdbb0ed74000ca37cff8fef8268cd29b13
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 13:55:02 2018 +0900

    Cleanup API::Entities::JobRequest::Artifacts

commit 1650249214768c23f6f46ec62c0c54448017eeb5
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 13:25:52 2018 +0900

    Simplified file_type relations

commit 981da91bc4c255ff992870e4e4c4393696f5bece
Merge: e79808425eb 924146a8
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 13:18:20 2018 +0900

    Merge branch 'master' into artifact-format-v2

commit e79808425eb63c322a997e71d606d97b85e42048
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 18:16:52 2018 +0900

    Remove unnecessary change

commit da6e141e7b9ff28cc1fb25ab42c979b0dee46277
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 17:41:35 2018 +0900

    Add gzip XML parser

commit a531bd7487955143489d286a0fb2e5d0984acc52
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 17:40:35 2018 +0900

    Fix errors typo

commit 57d6f21821c8ad934874c1aac3f627335c64c80d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:32:35 2018 +0900

    Use the correct type name

commit da4ca63f25a27a1268317952061c81a28516653f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:29:21 2018 +0900

    Refactor job_artifacts_metadata to job_artifacts_archive_metadata

commit 4098a8f10f92a6efa48080f8925809e251066f9d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:23:55 2018 +0900

    Add job_artifacts_junit relation

commit 5342f07e100253713dbf50eb303da1977484077f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:14:03 2018 +0900

    Fix raw to raw?

commit 15e0abcb22d9db3d8ef955e647f0a5d0a49c26b6
Merge: 31252fe8d75 ba38931d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:12:38 2018 +0900

    Merge branch 'master' into artifact-format-v2

commit 31252fe8d751319c5390f898f66f0af4a8581013
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 19:05:51 2018 +0900

    Temporaly use type Hash for reports

commit 583165c0349f40e7be16a8039dbffb4139f94921
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:27:21 2018 +0900

    Revert unnecessary change

commit eb48369b8311b538f46f59a31f4a6d3f8c9e68e1
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:21:46 2018 +0900

    Use file_format raw for trace

commit fb69ae8349d58499ad21965c0d1cf95e2b79a8e3
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:20:10 2018 +0900

    Check the presence of the file_format

commit c0840224bc8789d35da032c2a0ee48aa9f2232aa
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:16:19 2018 +0900

    Add format_restriction validation

commit d64fbd388cb2294447df5185366d8b5016591949
Merge: 7ec81e7c7d1 c2a0a3ab
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:11:44 2018 +0900

    Merge branch 'master' into artifact-format-v2

commit 7ec81e7c7d115f77d712892dfc79db72b9f5bc7a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 20:23:54 2018 +0900

    Artifacts presenter (Halfway)

commit a3ccbe4c3a9b7d3095fe1929dee5fd9c57e168e0
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 20:22:52 2018 +0900

    Fix schema.rb

commit b630c670c707548799c6852e4465ef94fb4a0572
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 19:26:03 2018 +0900

    Allow reports type under artifacts. Allow junit keyword in it.

commit e7e37612487b556320d27f4fe0de32cd4ec20720
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 19:25:10 2018 +0900

    Change column name to artifact_format

commit f3f25d56a7c627f4bb9d91d19de175273a7a6a81
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 18:02:21 2018 +0900

    Rename metadata to archive_metadata, and compress to file_format

commit d7e0709319ab8fe35a2598a3d484eb89b1885934
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 17:47:18 2018 +0900

    Validate compression. Clean up schema

commit beb5990e7e3bfbb308245dc97284aaf9700bd982
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 5 19:06:54 2018 +0900

    Make compression params at the first level

commit 1e2e1c0db5412e1aed3bf47562350c20c69dc1a6
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 5 16:31:03 2018 +0900

    Reorganize components
parent 9812e5dd
import Visibility from 'visibilityjs'; import Visibility from 'visibilityjs';
import $ from 'jquery';
import axios from '../../lib/utils/axios_utils'; import axios from '../../lib/utils/axios_utils';
import Poll from '../../lib/utils/poll'; import Poll from '../../lib/utils/poll';
import * as types from './mutation_types'; import * as types from './mutation_types';
...@@ -63,5 +64,13 @@ export const receiveReportsSuccess = ({ commit }, response) => ...@@ -63,5 +64,13 @@ export const receiveReportsSuccess = ({ commit }, response) =>
export const receiveReportsError = ({ commit }) => commit(types.RECEIVE_REPORTS_ERROR); export const receiveReportsError = ({ commit }) => commit(types.RECEIVE_REPORTS_ERROR);
export const openModal = ({ dispatch }, payload) => {
dispatch('setModalData', payload);
$('#modal-mrwidget-reports').modal('show');
};
export const setModalData = ({ commit }, payload) => commit(types.SET_ISSUE_MODAL_DATA, payload);
// prevent babel-plugin-rewire from generating an invalid default during karma tests // prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {}; export default () => {};
...@@ -99,6 +99,21 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -99,6 +99,21 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
} }
end end
def test_reports
result = @merge_request.compare_test_reports
case result[:status]
when :parsing
render json: '', status: :no_content
when :parsed
render json: result[:data], status: :ok
when :error
render json: { status_reason: result[:status_reason] }, status: :bad_request
else
render json: { status_reason: 'Unknown error' }, status: :internal_server_error
end
end
def edit def edit
define_edit_vars define_edit_vars
end end
......
...@@ -69,6 +69,11 @@ module Ci ...@@ -69,6 +69,11 @@ module Ci
where('NOT EXISTS (?)', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').trace) where('NOT EXISTS (?)', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').trace)
end end
scope :with_test_reports, ->() do
includes(:job_artifacts_junit) # Prevent N+1 problem when iterating each ci_job_artifact row
.where('EXISTS (?)', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').test_reports)
end
scope :with_artifacts_stored_locally, -> { with_artifacts_archive.where(artifacts_file_store: [nil, LegacyArtifactUploader::Store::LOCAL]) } scope :with_artifacts_stored_locally, -> { with_artifacts_archive.where(artifacts_file_store: [nil, LegacyArtifactUploader::Store::LOCAL]) }
scope :with_artifacts_not_expired, ->() { with_artifacts_archive.where('artifacts_expire_at IS NULL OR artifacts_expire_at > ?', Time.now) } scope :with_artifacts_not_expired, ->() { with_artifacts_archive.where('artifacts_expire_at IS NULL OR artifacts_expire_at > ?', Time.now) }
scope :with_expired_artifacts, ->() { with_artifacts_archive.where('artifacts_expire_at < ?', Time.now) } scope :with_expired_artifacts, ->() { with_artifacts_archive.where('artifacts_expire_at < ?', Time.now) }
...@@ -627,8 +632,31 @@ module Ci ...@@ -627,8 +632,31 @@ module Ci
running? && runner_session_url.present? running? && runner_session_url.present?
end end
def collect_test_reports!(test_reports)
raise ArgumentError, 'build does not have test reports' unless has_test_reports?
test_reports.get_suite(group_name).tap do |test_suite|
each_test_report do |file_type, blob|
parse_test_report!(test_suite, file_type, blob)
end
end
end
private private
def each_test_report
Ci::JobArtifact::TEST_REPORT_FILE_TYPES.each do |file_type|
public_send("job_artifacts_#{file_type}").each_blob do |blob| # rubocop:disable GitlabSecurity/PublicSend
yield file_type, blob
end
end
end
def parse_test_report!(test_suite, file_type, blob)
"Gitlab::Ci::Parsers::#{file_type.capitalize}Parser".constantize
.new(blob).parse!(test_suite)
end
def update_artifacts_size def update_artifacts_size
self.artifacts_size = legacy_artifacts_file&.size self.artifacts_size = legacy_artifacts_file&.size
end end
......
...@@ -4,6 +4,8 @@ module Ci ...@@ -4,6 +4,8 @@ module Ci
include ObjectStorage::BackgroundMove include ObjectStorage::BackgroundMove
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
NotSupportedAdapterError = Class.new(StandardError)
TEST_REPORT_FILE_TYPES = %w[junit].freeze TEST_REPORT_FILE_TYPES = %w[junit].freeze
DEFAULT_FILE_NAMES = { junit: 'junit.xml' }.freeze DEFAULT_FILE_NAMES = { junit: 'junit.xml' }.freeze
TYPE_AND_FORMAT_PAIRS = { archive: :zip, metadata: :gzip, trace: :raw, junit: :gzip }.freeze TYPE_AND_FORMAT_PAIRS = { archive: :zip, metadata: :gzip, trace: :raw, junit: :gzip }.freeze
...@@ -44,6 +46,10 @@ module Ci ...@@ -44,6 +46,10 @@ module Ci
gzip: 3 gzip: 3
} }
FILE_FORMAT_ADAPTERS = {
gzip: Gitlab::Ci::Build::Artifacts::GzipFileAdapter
}.freeze
def valid_file_format? def valid_file_format?
unless TYPE_AND_FORMAT_PAIRS[self.file_type&.to_sym] == self.file_format&.to_sym unless TYPE_AND_FORMAT_PAIRS[self.file_type&.to_sym] == self.file_format&.to_sym
errors.add(:file_format, 'Invalid file format with specified file type') errors.add(:file_format, 'Invalid file format with specified file type')
...@@ -75,8 +81,22 @@ module Ci ...@@ -75,8 +81,22 @@ module Ci
end end
end end
def each_blob(&blk)
unless file_format_adapter_class
raise NotSupportedAdapterError, 'This file format requires a dedicated adapter'
end
file.open do |stream|
file_format_adapter_class.new(stream).each_blob(&blk)
end
end
private private
def file_format_adapter_class
FILE_FORMAT_ADAPTERS[file_format.to_sym]
end
def set_size def set_size
self.size = file.size self.size = file.size
end end
......
...@@ -603,6 +603,18 @@ module Ci ...@@ -603,6 +603,18 @@ module Ci
@latest_builds_with_artifacts ||= builds.latest.with_artifacts_archive.to_a @latest_builds_with_artifacts ||= builds.latest.with_artifacts_archive.to_a
end end
def has_test_reports?
complete? && builds.with_test_reports.any?
end
def test_reports
Gitlab::Ci::Reports::TestReports.new.tap do |test_reports|
builds.with_test_reports.each do |build|
build.collect_test_reports!(test_reports)
end
end
end
private private
def ci_yaml_from_repo def ci_yaml_from_repo
......
...@@ -11,6 +11,11 @@ class MergeRequest < ActiveRecord::Base ...@@ -11,6 +11,11 @@ class MergeRequest < ActiveRecord::Base
include ThrottledTouch include ThrottledTouch
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
include LabelEventable include LabelEventable
include ReactiveCaching
self.reactive_cache_key = ->(model) { [model.project.id, model.iid] }
self.reactive_cache_refresh_interval = 1.hour
self.reactive_cache_lifetime = 1.hour
ignore_column :locked_at, ignore_column :locked_at,
:ref_fetched, :ref_fetched,
...@@ -1010,6 +1015,40 @@ class MergeRequest < ActiveRecord::Base ...@@ -1010,6 +1015,40 @@ class MergeRequest < ActiveRecord::Base
.order(id: :desc) .order(id: :desc)
end end
def has_test_reports?
actual_head_pipeline&.has_test_reports?
end
def compare_test_reports
unless actual_head_pipeline && actual_head_pipeline.has_test_reports?
return { status: :error, status_reason: 'head pipeline does not have test reports' }
end
with_reactive_cache(base_pipeline&.iid, actual_head_pipeline.iid) { |data| data } || { status: :parsing }
end
def calculate_reactive_cache(base_pipeline_iid, head_pipeline_iid)
begin
if base_pipeline_iid
base_pipeline, head_pipeline = project.pipelines.where(iid: [base_pipeline_iid, head_pipeline_iid]).all
else
head_pipeline = project.pipelines.find(iid: head_pipeline_iid)
end
comparer = Gitlab::Ci::Reports::TestReportsComparer
.new(base_pipeline&.test_reports, head_pipeline.test_reports)
{
status: :parsed,
data: TestReportsComparerSerializer
.new(project: project)
.represent(comparer).to_json
}
rescue => e
{ status: :error, status_reason: e.message }
end
end
def all_commits def all_commits
# MySQL doesn't support LIMIT in a subquery. # MySQL doesn't support LIMIT in a subquery.
diffs_relation = if Gitlab::Database.postgresql? diffs_relation = if Gitlab::Database.postgresql?
...@@ -1122,6 +1161,12 @@ class MergeRequest < ActiveRecord::Base ...@@ -1122,6 +1161,12 @@ class MergeRequest < ActiveRecord::Base
true true
end end
def base_pipeline
@base_pipeline ||= project.pipelines
.order(id: :desc)
.find_by(sha: diff_base_sha)
end
def discussions_rendered_on_frontend? def discussions_rendered_on_frontend?
true true
end end
......
...@@ -231,6 +231,12 @@ class MergeRequestWidgetEntity < IssuableEntity ...@@ -231,6 +231,12 @@ class MergeRequestWidgetEntity < IssuableEntity
end end
end end
expose :test_reports_path do |merge_request|
if merge_request.has_test_reports?
test_reports_project_merge_request_path(merge_request.project, merge_request, format: :json)
end
end
private private
delegate :current_user, to: :request delegate :current_user, to: :request
......
class TestCaseEntity < Grape::Entity
expose :status
expose :name
expose :execution_time
expose :system_output
expose :stack_trace
end
class TestReportsComparerEntity < Grape::Entity
expose :total_status, as: :status
expose :summary do
expose :total_count, as: :total
expose :resolved_count, as: :resolved
expose :failed_count, as: :failed
end
expose :suite_comparers, as: :suites, using: TestSuiteComparerEntity
end
class TestReportsComparerSerializer < BaseSerializer
entity TestReportsComparerEntity
end
class TestSuiteComparerEntity < Grape::Entity
expose :name
expose :total_status, as: :status
expose :summary do
expose :total_count, as: :total
expose :resolved_count, as: :resolved
expose :failed_count, as: :failed
end
expose :new_failures, using: TestCaseEntity
expose :resolved_failures, using: TestCaseEntity
expose :existing_failures, using: TestCaseEntity
end
...@@ -109,6 +109,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -109,6 +109,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
post :assign_related_issues post :assign_related_issues
get :discussions, format: :json get :discussions, format: :json
post :rebase post :rebase
get :test_reports
scope constraints: { format: nil }, action: :show do scope constraints: { format: nil }, action: :show do
get :commits, defaults: { tab: 'commits' } get :commits, defaults: { tab: 'commits' }
......
...@@ -30,6 +30,8 @@ class Gitlab::Seeder::Pipelines ...@@ -30,6 +30,8 @@ class Gitlab::Seeder::Pipelines
queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago }, queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'spinach:osx', stage: 'test', status: :failed, allow_failure: true, { name: 'spinach:osx', stage: 'test', status: :failed, allow_failure: true,
queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago }, queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'java ant', stage: 'test', status: :failed, allow_failure: true,
queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
# deploy stage # deploy stage
{ name: 'staging', stage: 'deploy', environment: 'staging', status_event: :success, { name: 'staging', stage: 'deploy', environment: 'staging', status_event: :success,
...@@ -41,7 +43,7 @@ class Gitlab::Seeder::Pipelines ...@@ -41,7 +43,7 @@ class Gitlab::Seeder::Pipelines
when: 'manual', status: :skipped }, when: 'manual', status: :skipped },
# notify stage # notify stage
{ name: 'slack', stage: 'notify', when: 'manual', status: :created }, { name: 'slack', stage: 'notify', when: 'manual', status: :success },
] ]
EXTERNAL_JOBS = [ EXTERNAL_JOBS = [
{ name: 'jenkins', stage: 'test', status: :success, { name: 'jenkins', stage: 'test', status: :success,
...@@ -54,18 +56,12 @@ class Gitlab::Seeder::Pipelines ...@@ -54,18 +56,12 @@ class Gitlab::Seeder::Pipelines
def seed! def seed!
pipelines.each do |pipeline| pipelines.each do |pipeline|
begin
BUILDS.each { |opts| build_create!(pipeline, opts) } BUILDS.each { |opts| build_create!(pipeline, opts) }
EXTERNAL_JOBS.each { |opts| commit_status_create!(pipeline, opts) } EXTERNAL_JOBS.each { |opts| commit_status_create!(pipeline, opts) }
print '.'
rescue ActiveRecord::RecordInvalid
print 'F'
ensure
pipeline.update_duration pipeline.update_duration
pipeline.update_status pipeline.update_status
end end
end end
end
private private
...@@ -87,7 +83,9 @@ class Gitlab::Seeder::Pipelines ...@@ -87,7 +83,9 @@ class Gitlab::Seeder::Pipelines
branch = merge_request.source_branch branch = merge_request.source_branch
merge_request.commits.last(4).map do |commit| merge_request.commits.last(4).map do |commit|
create_pipeline!(project, branch, commit) create_pipeline!(project, branch, commit).tap do |pipeline|
merge_request.update!(head_pipeline_id: pipeline.id)
end
end end
end end
...@@ -98,7 +96,7 @@ class Gitlab::Seeder::Pipelines ...@@ -98,7 +96,7 @@ class Gitlab::Seeder::Pipelines
def create_pipeline!(project, ref, commit) def create_pipeline!(project, ref, commit)
project.pipelines.create(sha: commit.id, ref: ref, source: :push) project.pipelines.create!(sha: commit.id, ref: ref, source: :push)
end end
def build_create!(pipeline, opts = {}) def build_create!(pipeline, opts = {})
...@@ -110,25 +108,50 @@ class Gitlab::Seeder::Pipelines ...@@ -110,25 +108,50 @@ class Gitlab::Seeder::Pipelines
# (id required), that is why we need `#tap` method instead of passing # (id required), that is why we need `#tap` method instead of passing
# block directly to `Ci::Build#create!`. # block directly to `Ci::Build#create!`.
setup_artifacts(build) setup_artifacts(build) if %w[build test].include?(build.stage)
setup_test_reports(build) if %w[test].include?(build.stage)
setup_build_log(build) setup_build_log(build)
build.project.environments. build.project.environments.
find_or_create_by(name: build.expanded_environment_name) find_or_create_by(name: build.expanded_environment_name)
build.save build.save!
end end
end end
def setup_artifacts(build) def setup_artifacts(build)
return unless %w[build test].include?(build.stage)
artifacts_cache_file(artifacts_archive_path) do |file| artifacts_cache_file(artifacts_archive_path) do |file|
build.job_artifacts.build(project: build.project, file_type: :archive, file: file) build.job_artifacts.build(project: build.project, file_type: :archive, file_format: :zip, file: file)
end end
artifacts_cache_file(artifacts_metadata_path) do |file| artifacts_cache_file(artifacts_metadata_path) do |file|
build.job_artifacts.build(project: build.project, file_type: :metadata, file: file) build.job_artifacts.build(project: build.project, file_type: :metadata, file_format: :gzip, file: file)
end
end
def setup_test_reports(build)
if build.ref == build.project.default_branch
if build.name.include?('rspec:linux')
artifacts_cache_file(artifacts_rspec_junit_master_path(build.name)) do |file|
build.job_artifacts.build(project: build.project, file_type: :junit, file_format: :gzip, file: file)
end
elsif build.name.include?('java ant')
artifacts_cache_file(artifacts_ant_junit_master_path) do |file|
build.job_artifacts.build(project: build.project, file_type: :junit, file_format: :gzip, file: file)
end
end
else
if build.name.include?('rspec:linux')
artifacts_rspec_junit_feature_path(build.name).try do |path|
artifacts_cache_file(path) do |file|
build.job_artifacts.build(project: build.project, file_type: :junit, file_format: :gzip, file: file)
end
end
elsif build.name.include?('java ant')
artifacts_cache_file(artifacts_ant_junit_feature_path) do |file|
build.job_artifacts.build(project: build.project, file_type: :junit, file_format: :gzip, file: file)
end
end
end end
end end
...@@ -171,13 +194,31 @@ class Gitlab::Seeder::Pipelines ...@@ -171,13 +194,31 @@ class Gitlab::Seeder::Pipelines
Rails.root + 'spec/fixtures/ci_build_artifacts_metadata.gz' Rails.root + 'spec/fixtures/ci_build_artifacts_metadata.gz'
end end
def artifacts_cache_file(file_path) def artifacts_rspec_junit_master_path(build_name)
cache_path = file_path.to_s.gsub('ci_', "p#{@project.id}_") index, total = build_name.scan(/ (\d) (\d)/).first
Rails.root + "spec/fixtures/junit/junit_master_rspec_#{index}_#{total}.xml.gz"
end
def artifacts_rspec_junit_feature_path(build_name)
index, total = build_name.scan(/ (\d) (\d)/).first
Rails.root + "spec/fixtures/junit/junit_feature_rspec_#{index}_#{total}.xml.gz"
end
FileUtils.copy(file_path, cache_path) def artifacts_ant_junit_master_path
File.open(cache_path) do |file| Rails.root + "spec/fixtures/junit/junit_master_ant.xml.gz"
yield file
end end
def artifacts_ant_junit_feature_path
Rails.root + "spec/fixtures/junit/junit_feature_ant.xml.gz"
end
def artifacts_cache_file(file_path)
file = Tempfile.new("artifacts")
file.close
FileUtils.copy(file_path, file.path)
yield(UploadedFile.new(file.path, filename: File.basename(file_path)))
end end
end end
......
module Gitlab
module Ci
module Build
module Artifacts
class GzipFileAdapter
attr_reader :stream
InvalidStreamError = Class.new(StandardError)
def initialize(stream)
raise InvalidStreamError, "Stream is required" unless stream
@stream = stream
end
def each_blob
stream.seek(0)
until stream.eof?
gzip(stream) do |gz|
yield gz.read, gz.orig_name
unused = gz.unused&.length.to_i
# pos has already reached to EOF at the moment
# We rewind the pos to the top of unused files
# to read next gzip stream, to support multistream archives
# https://golang.org/src/compress/gzip/gunzip.go#L117
stream.seek(-unused, IO::SEEK_CUR)
end
end
end
private
def gzip(stream, &block)
gz = Zlib::GzipReader.new(stream)
yield(gz)
rescue Zlib::Error => e
raise InvalidStreamError, e.message
ensure
gz&.finish
end
end
end
end
end
end
module Gitlab
module Ci
module Parsers
class JunitParser
attr_reader :data
JunitParserError = Class.new(StandardError)
def initialize(xml_data)
@data = Hash.from_xml(xml_data)
rescue
raise JunitParserError, 'Invalid XML data'
end
def parse!(test_suite)
each_suite do |testcases|
testcases.each do |testcase|
test_case = create_test_case(testcase)
test_suite.add_test_case(test_case)
end
end
rescue
raise JunitParserError, 'Invalid JUnit xml structure'
end
private
def each_suite
testsuites.each do |testsuite|
yield testcases(testsuite)
end
end
def testsuites
if data['testsuites']
data['testsuites']['testsuite']
else
[data['testsuite']]
end
end
def testcases(testsuite)
if testsuite['testcase'].is_a?(Array)
testsuite['testcase']
else
[testsuite['testcase']]
end
end
def create_test_case(data)
if data['failure']
status = ::Gitlab::Ci::Reports::TestCase::STATUS_FAILED
system_output = data['failure']
else
status = ::Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS
system_output = nil
end
::Gitlab::Ci::Reports::TestCase.new(
classname: data['classname'],
name: data['name'],
file: data['file'],
execution_time: data['time'],
status: status,
system_output: system_output
)
end
end
end
end
end
module Gitlab
module Ci
module Reports
class TestCase
STATUS_SUCCESS = 'success'.freeze
STATUS_FAILED = 'failed'.freeze
STATUS_SKIPPED = 'skipped'.freeze
STATUS_ERROR = 'error'.freeze
STATUS_TYPES = [STATUS_SUCCESS, STATUS_FAILED, STATUS_SKIPPED, STATUS_ERROR].freeze
attr_reader :name, :classname, :execution_time, :status, :file, :system_output, :stack_trace, :key
def initialize(name:, classname:, execution_time:, status:, file: nil, system_output: nil, stack_trace: nil)
@name = name
@classname = classname
@file = file
@execution_time = execution_time.to_f
@status = status
@system_output = system_output
@stack_trace = stack_trace
@key = sanitize_key_name("#{classname}_#{name}")
end
private
def sanitize_key_name(key)
key.gsub(/[^0-9A-Za-z]/, '-')
end
end
end
end
end
module Gitlab
module Ci
module Reports
class TestReports
attr_reader :test_suites
def initialize
@test_suites = {}
end
def get_suite(suite_name)
test_suites[suite_name] ||= TestSuite.new(suite_name)
end
def total_time
test_suites.values.sum(&:total_time)
end
def total_count
test_suites.values.sum(&:total_count)
end
def total_status
if failed_count > 0 || error_count > 0
TestCase::STATUS_FAILED
else
TestCase::STATUS_SUCCESS
end
end
TestCase::STATUS_TYPES.each do |status_type|
define_method("#{status_type}_count") do
test_suites.values.sum { |suite| suite.public_send("#{status_type}_count") } # rubocop:disable GitlabSecurity/PublicSend
end
end
end
end
end
end
module Gitlab
module Ci
module Reports
class TestReportsComparer
include Gitlab::Utils::StrongMemoize
attr_reader :base_reports, :head_reports
def initialize(base_reports, head_reports)
@base_reports = base_reports || TestReports.new
@head_reports = head_reports
end
def suite_comparers
strong_memoize(:suite_comparers) do
head_reports.test_suites.map do |name, test_suite|
TestSuiteComparer.new(name, base_reports.get_suite(name), test_suite)
end
end
end
def total_status
if suite_comparers.any? { |suite| suite.total_status == TestCase::STATUS_FAILED }
TestCase::STATUS_FAILED
else
TestCase::STATUS_SUCCESS
end
end
%w(total_count resolved_count failed_count).each do |method|
define_method(method) do
suite_comparers.sum { |suite| suite.public_send(method) } # rubocop:disable GitlabSecurity/PublicSend
end
end
end
end
end
end
module Gitlab
module Ci
module Reports
class TestSuite
attr_reader :name
attr_reader :test_cases
attr_reader :total_time
def initialize(name = nil)
@name = name
@test_cases = {}
@total_time = 0.0
@duplicate_cases = []
end
def add_test_case(test_case)
@duplicate_cases << test_case unless unique_key?(test_case)
@test_cases[test_case.status] ||= {}
@test_cases[test_case.status][test_case.key] = test_case
@total_time += test_case.execution_time
end
def total_count
test_cases.values.sum(&:count)
end
def total_status
if failed_count > 0 || error_count > 0
TestCase::STATUS_FAILED
else
TestCase::STATUS_SUCCESS
end
end
TestCase::STATUS_TYPES.each do |status_type|
define_method("#{status_type}") do
test_cases[status_type] || {}
end
define_method("#{status_type}_count") do
test_cases[status_type]&.length.to_i
end
end
private
def unique_key?(test_case)
@test_cases[test_case.status]&.key?(test_case.key)
end
end
end
end
end
module Gitlab
module Ci
module Reports
class TestSuiteComparer
include Gitlab::Utils::StrongMemoize
attr_reader :name, :base_suite, :head_suite
def initialize(name, base_suite, head_suite)
@name = name
@base_suite = base_suite || TestSuite.new
@head_suite = head_suite
end
def new_failures
strong_memoize(:new_failures) do
head_suite.failed.reject do |key, _|
base_suite.failed.include?(key)
end.values
end
end
def existing_failures
strong_memoize(:existing_failures) do
head_suite.failed.select do |key, _|
base_suite.failed.include?(key)
end.values
end
end
def resolved_failures
strong_memoize(:resolved_failures) do
head_suite.success.select do |key, _|
base_suite.failed.include?(key)
end.values
end
end
def total_count
head_suite.total_count
end
def total_status
head_suite.total_status
end
def resolved_count
resolved_failures.count
end
def failed_count
new_failures.count + existing_failures.count
end
end
end
end
end
...@@ -580,6 +580,64 @@ describe Projects::MergeRequestsController do ...@@ -580,6 +580,64 @@ describe Projects::MergeRequestsController do
end end
end end
describe 'GET test_reports' do
subject do
get :test_reports,
namespace_id: project.namespace.to_param,
project_id: project,
id: merge_request.iid,
format: :json
end
before do
allow_any_instance_of(MergeRequest)
.to receive(:compare_test_reports).and_return(comparison_status)
end
context 'when comparison is being processed' do
let(:comparison_status) { { status: :parsing } }
it 'returns 204 HTTP status' do
subject
expect(response).to have_gitlab_http_status(:no_content)
end
end
context 'when comparison is done' do
let(:comparison_status) { { status: :parsed, data: { summary: 1 }.to_json } }
it 'returns 200 HTTP status' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq({ 'summary' => 1 })
end
end
context 'when user created corrupted test reports' do
let(:comparison_status) { { status: :error, status_reason: 'Failed to parse test reports' } }
it 'returns 400 HTTP status' do
subject
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response).to eq({ 'status_reason' => 'Failed to parse test reports' })
end
end
context 'when something went wrong on our system' do
let(:comparison_status) { {} }
it 'returns 500 HTTP status' do
subject
expect(response).to have_gitlab_http_status(:internal_server_error)
expect(json_response).to eq({ 'status_reason' => 'Unknown error' })
end
end
end
describe 'POST remove_wip' do describe 'POST remove_wip' do
before do before do
merge_request.title = merge_request.wip_title merge_request.title = merge_request.wip_title
......
...@@ -54,6 +54,36 @@ FactoryBot.define do ...@@ -54,6 +54,36 @@ FactoryBot.define do
end end
end end
trait :junit_with_ant do
file_type :junit
file_format :gzip
after(:build) do |artifact, evaluator|
artifact.file = fixture_file_upload(
Rails.root.join('spec/fixtures/junit/junit_master_ant.xml.gz'), 'application/x-gzip')
end
end
trait :junit_with_three_testsuites do
file_type :junit
file_format :gzip
after(:build) do |artifact, evaluator|
artifact.file = fixture_file_upload(
Rails.root.join('spec/fixtures/junit/junit_with_three_testsuites.xml.gz'), 'application/x-gzip')
end
end
trait :junit_with_corrupted_data do
file_type :junit
file_format :gzip
after(:build) do |artifact, evaluator|
artifact.file = fixture_file_upload(
Rails.root.join('spec/fixtures/junit/junit_with_corrupted_data.xml.gz'), 'application/x-gzip')
end
end
trait :correct_checksum do trait :correct_checksum do
after(:build) do |artifact, evaluator| after(:build) do |artifact, evaluator|
artifact.file_sha256 = Digest::SHA256.file(artifact.file.path).hexdigest artifact.file_sha256 = Digest::SHA256.file(artifact.file.path).hexdigest
......
...@@ -58,6 +58,10 @@ FactoryBot.define do ...@@ -58,6 +58,10 @@ FactoryBot.define do
status :success status :success
end end
trait :running do
status :running
end
trait :failed do trait :failed do
status :failed status :failed
end end
...@@ -65,6 +69,14 @@ FactoryBot.define do ...@@ -65,6 +69,14 @@ FactoryBot.define do
trait :protected do trait :protected do
protected true protected true
end end
trait :test_reports do
status :success
after(:build) do |pipeline, evaluator|
create(:ci_build, :test_reports, pipeline: pipeline, project: pipeline.project)
end
end
end end
end end
end end
...@@ -89,6 +89,19 @@ FactoryBot.define do ...@@ -89,6 +89,19 @@ FactoryBot.define do
end end
end end
trait :with_test_reports do
after(:create) do |merge_request|
create(:ci_pipeline,
:success,
:test_reports,
project: merge_request.source_project,
ref: merge_request.source_branch,
sha: merge_request.diff_head_sha).tap do |pipeline|
merge_request.update!(head_pipeline_id: pipeline.id)
end
end
end
after(:build) do |merge_request| after(:build) do |merge_request|
target_project = merge_request.target_project target_project = merge_request.target_project
source_project = merge_request.source_project source_project = merge_request.source_project
......
...@@ -117,7 +117,8 @@ ...@@ -117,7 +117,8 @@
"rebase_in_progress": { "type": "boolean" }, "rebase_in_progress": { "type": "boolean" },
"can_push_to_source_branch": { "type": "boolean" }, "can_push_to_source_branch": { "type": "boolean" },
"rebase_path": { "type": ["string", "null"] }, "rebase_path": { "type": ["string", "null"] },
"squash": { "type": "boolean" } "squash": { "type": "boolean" },
"test_reports_path": { "type": ["string", "null"] }
}, },
"additionalProperties": false "additionalProperties": false
} }
{
"type": "object",
"properties": {
"status": { "type": "string" },
"name": { "type": "string" },
"execution_time": { "type": "float" },
"system_output": { "type": ["string", "null"] },
"stack_trace": { "type": ["string", "null"] }
},
"additionalProperties": false
}
{
"type": "object",
"properties": {
"status": { "type": "string" },
"summary": {
"total": { "type": "integer" },
"resolved": { "type": "integer" },
"failed": { "type": "integer" }
},
"suites": { "type": "array", "items": { "$ref": "test_suite_comparer.json" } }
},
"additionalProperties": false
}
{
"type": "object",
"properties": {
"name": { "type": "string" },
"status": { "type": "string" },
"summary": {
"total": { "type": "integer" },
"resolved": { "type": "integer" },
"failed": { "type": "integer" }
},
"new_failures": { "type": "array", "items": { "$ref": "test_case.json" } },
"resolved_failures": { "type": "array", "items": { "$ref": "test_case.json" } },
"existing_failures": { "type": "array", "items": { "$ref": "test_case.json" } }
},
"additionalProperties": false
}
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="rspec" tests="4" skipped="0" failures="2" errors="0" time="0.011289" timestamp="2018-07-17T10:48:13+00:00" hostname="runner-400e3f62-project-15-concurrent-0">
<properties>
<property name="seed" value="404"/>
</properties>
<testcase classname="spec.test_spec" name="Test#sum when a is 1 and b is 2 returns summary" file="./spec/test_spec.rb" time="0.009292"><failure message="
expected: 3
got: -1
(compared using ==)
" type="RSpec::Expectations::ExpectationNotMetError">Failure/Error: is_expected.to eq(3)
expected: 3
got: -1
(compared using ==)
./spec/test_spec.rb:12:in `block (4 levels) in &lt;top (required)&gt;&apos;</failure></testcase>
<testcase classname="spec.test_spec" name="Test#sum when a is 100 and b is 200 returns summary" file="./spec/test_spec.rb" time="0.000180"><failure message="
expected: 300
got: -100
(compared using ==)
" type="RSpec::Expectations::ExpectationNotMetError">Failure/Error: is_expected.to eq(300)
expected: 300
got: -100
(compared using ==)
./spec/test_spec.rb:21:in `block (4 levels) in &lt;top (required)&gt;&apos;</failure></testcase>
<testcase classname="spec.test_spec" name="Test#subtract when a is 1 and b is 2 raises an error" file="./spec/test_spec.rb" time="0.000748"></testcase>
<testcase classname="spec.test_spec" name="Test#subtract when a is 2 and b is 1 returns correct result" file="./spec/test_spec.rb" time="0.000064"></testcase>
</testsuite>
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="rspec" tests="2" skipped="0" failures="0" errors="0" time="0.001670" timestamp="2018-07-30T10:02:37+00:00" hostname="runner-7661726c-project-14-concurrent-0">
<properties>
<property name="seed" value="52549"/>
</properties>
<testcase classname="spec.hash_scan_spec" name="HashScan#scan when argument is hash returns the value" file="./spec/hash_scan_spec.rb" time="0.000287"></testcase>
<testcase classname="spec.hash_scan_spec" name="HashScan#scan when argument is not hash raises and error" file="./spec/hash_scan_spec.rb" time="0.000686"></testcase>
</testsuite>
This source diff could not be displayed because it is too large. You can view the blob instead.
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="rspec" tests="2" skipped="0" failures="0" errors="0" time="0.001691" timestamp="2018-07-30T10:02:37+00:00" hostname="runner-7661726c-project-14-concurrent-0">
<properties>
<property name="seed" value="8528"/>
</properties>
<testcase classname="spec.string_helper_spec" name="StringHelper#concatenate when a is git and b is lab returns summary" file="./spec/string_helper_spec.rb" time="0.000287"></testcase>
<testcase classname="spec.string_helper_spec" name="StringHelper#concatenate when a is git and b is 200 raises an error" file="./spec/string_helper_spec.rb" time="0.000706"></testcase>
</testsuite>
...@@ -56,7 +56,9 @@ describe('Reports Store Actions', () => { ...@@ -56,7 +56,9 @@ describe('Reports Store Actions', () => {
describe('success', () => { describe('success', () => {
it('dispatches requestReports and receiveReportsSuccess ', done => { it('dispatches requestReports and receiveReportsSuccess ', done => {
mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(200, { summary: {}, suites: [{ name: 'rspec' }] }); mock
.onGet(`${TEST_HOST}/endpoint.json`)
.replyOnce(200, { summary: {}, suites: [{ name: 'rspec' }] });
testAction( testAction(
fetchReports, fetchReports,
......
...@@ -96,6 +96,5 @@ describe('Reports Store Mutations', () => { ...@@ -96,6 +96,5 @@ describe('Reports Store Mutations', () => {
it('should set hasError to true', () => { it('should set hasError to true', () => {
expect(stateCopy.hasError).toEqual(true); expect(stateCopy.hasError).toEqual(true);
}); });
}); });
}); });
require 'spec_helper'
describe Gitlab::Ci::Build::Artifacts::GzipFileAdapter do
describe '#initialize' do
context 'when stream is passed' do
let(:stream) { File.open(expand_fixture_path('junit/junit.xml.gz'), 'rb') }
it 'initialized' do
expect { described_class.new(stream) }.not_to raise_error
end
end
context 'when stream is not passed' do
let(:stream) { nil }
it 'raises an error' do
expect { described_class.new(stream) }.to raise_error(described_class::InvalidStreamError)
end
end
end
describe '#each_blob' do
let(:adapter) { described_class.new(stream) }
context 'when stream is gzip file' do
context 'when gzip file contains one file' do
let(:stream) { File.open(expand_fixture_path('junit/junit.xml.gz'), 'rb') }
it 'iterates content and file_name' do
expect { |b| adapter.each_blob(&b) }
.to yield_with_args(fixture_file('junit/junit.xml'), 'rspec.xml')
end
end
context 'when gzip file contains three files' do
let(:stream) { File.open(expand_fixture_path('junit/junit_with_three_testsuites.xml.gz'), 'rb') }
it 'iterates content and file_name' do
expect { |b| adapter.each_blob(&b) }
.to yield_successive_args(
[fixture_file('junit/junit_with_three_testsuites_1.xml'), 'rspec-3.xml'],
[fixture_file('junit/junit_with_three_testsuites_2.xml'), 'rspec-1.xml'],
[fixture_file('junit/junit_with_three_testsuites_3.xml'), 'rspec-2.xml'])
end
end
end
context 'when stream is zip file' do
let(:stream) { File.open(expand_fixture_path('ci_build_artifacts.zip'), 'rb') }
it 'raises an error' do
expect { |b| adapter.each_blob(&b) }.to raise_error(described_class::InvalidStreamError)
end
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Parsers::JunitParser do
describe '#initialize' do
context 'when xml data is given' do
let(:data) do
<<-EOF.strip_heredoc
<testsuite></testsuite>
EOF
end
let(:parser) { described_class.new(data) }
it 'initialize Hash from the given data' do
expect { parser }.not_to raise_error
expect(parser.data).to be_a(Hash)
end
end
context 'when json data is given' do
let(:data) { { testsuite: 'abc' }.to_json }
it 'raises an error' do
expect { described_class.new(data) }.to raise_error(described_class::JunitParserError)
end
end
end
describe '#parse!' do
subject { described_class.new(junit).parse!(test_suite) }
let(:test_suite) { Gitlab::Ci::Reports::TestSuite.new('rspec') }
let(:test_cases) { flattened_test_cases(test_suite) }
context 'when XML is formated as JUnit' do
context 'when there are no test cases' do
let(:junit) do
<<-EOF.strip_heredoc
<testsuite></testsuite>
EOF
end
it 'raises an error and does not add any test cases' do
expect { subject }.to raise_error(described_class::JunitParserError)
expect(test_cases.count).to eq(0)
end
end
context 'when there is a test case' do
let(:junit) do
<<-EOF.strip_heredoc
<testsuite>
<testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
</testsuite>
EOF
end
it 'parses XML and adds a test case to a suite' do
expect { subject }.not_to raise_error
expect(test_cases[0].classname).to eq('Calculator')
expect(test_cases[0].name).to eq('sumTest1')
expect(test_cases[0].execution_time).to eq(0.01)
end
end
context 'when there are two test cases' do
let(:junit) do
<<-EOF.strip_heredoc
<testsuite>
<testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
<testcase classname='Calculator' name='sumTest2' time='0.02'></testcase>
</testsuite>
EOF
end
it 'parses XML and adds test cases to a suite' do
expect { subject }.not_to raise_error
expect(test_cases[0].classname).to eq('Calculator')
expect(test_cases[0].name).to eq('sumTest1')
expect(test_cases[0].execution_time).to eq(0.01)
expect(test_cases[1].classname).to eq('Calculator')
expect(test_cases[1].name).to eq('sumTest2')
expect(test_cases[1].execution_time).to eq(0.02)
end
end
context 'when there are two test suites' do
let(:junit) do
<<-EOF.strip_heredoc
<testsuites>
<testsuite>
<testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
<testcase classname='Calculator' name='sumTest2' time='0.02'></testcase>
</testsuite>
<testsuite>
<testcase classname='Statemachine' name='happy path' time='100'></testcase>
<testcase classname='Statemachine' name='unhappy path' time='200'></testcase>
</testsuite>
</testsuites>
EOF
end
it 'parses XML and adds test cases to a suite' do
expect { subject }.not_to raise_error
expect(test_cases[0].classname).to eq('Calculator')
expect(test_cases[0].name).to eq('sumTest1')
expect(test_cases[0].execution_time).to eq(0.01)
expect(test_cases[1].classname).to eq('Calculator')
expect(test_cases[1].name).to eq('sumTest2')
expect(test_cases[1].execution_time).to eq(0.02)
expect(test_cases[2].classname).to eq('Statemachine')
expect(test_cases[2].name).to eq('happy path')
expect(test_cases[2].execution_time).to eq(100)
expect(test_cases[3].classname).to eq('Statemachine')
expect(test_cases[3].name).to eq('unhappy path')
expect(test_cases[3].execution_time).to eq(200)
end
end
end
def flattened_test_cases(test_suite)
test_suite.test_cases.map do |status, value|
value.map do |key, test_case|
test_case
end
end.flatten
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Reports::TestCase do
describe '#initialize' do
let(:test_case) { described_class.new(**params)}
context 'when both classname and name are given' do
context 'when test case is passed' do
let(:params) do
{
name: 'test-1',
classname: 'trace',
file: 'spec/trace_spec.rb',
execution_time: 1.23,
status: described_class::STATUS_SUCCESS,
system_output: nil
}
end
it 'initializes an instance' do
expect { test_case }.not_to raise_error
expect(test_case.name).to eq('test-1')
expect(test_case.classname).to eq('trace')
expect(test_case.file).to eq('spec/trace_spec.rb')
expect(test_case.execution_time).to eq(1.23)
expect(test_case.status).to eq(described_class::STATUS_SUCCESS)
expect(test_case.system_output).to be_nil
end
end
context 'when test case is failed' do
let(:params) do
{
name: 'test-1',
classname: 'trace',
file: 'spec/trace_spec.rb',
execution_time: 1.23,
status: described_class::STATUS_FAILED,
system_output: "Failure/Error: is_expected.to eq(300) expected: 300 got: -100"
}
end
it 'initializes an instance' do
expect { test_case }.not_to raise_error
expect(test_case.name).to eq('test-1')
expect(test_case.classname).to eq('trace')
expect(test_case.file).to eq('spec/trace_spec.rb')
expect(test_case.execution_time).to eq(1.23)
expect(test_case.status).to eq(described_class::STATUS_FAILED)
expect(test_case.system_output)
.to eq('Failure/Error: is_expected.to eq(300) expected: 300 got: -100')
end
end
end
context 'when classname is missing' do
let(:params) do
{
name: 'test-1',
file: 'spec/trace_spec.rb',
execution_time: 1.23,
status: described_class::STATUS_SUCCESS,
system_output: nil
}
end
it 'raises an error' do
expect { test_case }.to raise_error(ArgumentError)
end
end
context 'when name is missing' do
let(:params) do
{
classname: 'trace',
file: 'spec/trace_spec.rb',
execution_time: 1.23,
status: described_class::STATUS_SUCCESS,
system_output: nil
}
end
it 'raises an error' do
expect { test_case }.to raise_error(ArgumentError)
end
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Reports::TestReportsComparer do
include TestReportsHelper
let(:comparer) { described_class.new(base_reports, head_reports) }
let(:base_reports) { Gitlab::Ci::Reports::TestReports.new }
let(:head_reports) { Gitlab::Ci::Reports::TestReports.new }
describe '#suite_comparers' do
subject { comparer.suite_comparers }
context 'when head and base reports include two test suites' do
before do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_success)
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_success)
end
it 'returns test suite comparers with specified values' do
expect(subject[0]).to be_a(Gitlab::Ci::Reports::TestSuiteComparer)
expect(subject[0].name).to eq('rspec')
expect(subject[0].head_suite).to eq(head_reports.get_suite('rspec'))
expect(subject[0].base_suite).to eq(base_reports.get_suite('rspec'))
expect(subject[1]).to be_a(Gitlab::Ci::Reports::TestSuiteComparer)
expect(subject[1].name).to eq('junit')
expect(subject[1].head_suite).to eq(head_reports.get_suite('junit'))
expect(subject[1].base_suite).to eq(base_reports.get_suite('junit'))
end
end
end
describe '#total_status' do
subject { comparer.total_status }
context 'when all tests cases are success in head suites' do
before do
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_success)
end
it 'returns the total status' do
is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
end
context 'when there is a failed test case in head suites' do
before do
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
end
it 'returns the total status in head suite' do
is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
end
end
end
describe '#total_count' do
subject { comparer.total_count }
before do
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
end
it 'returns the total test counts in head suites' do
is_expected.to eq(2)
end
end
describe '#resolved_count' do
subject { comparer.resolved_count }
context 'when there is a resolved test case in head suites' do
let(:create_test_case_java_resolved) do
create_test_case_java_failed.tap do |test_case|
test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
end
before do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_resolved)
end
it 'returns the correct count' do
is_expected.to eq(1)
end
end
context 'when there are no resolved test cases in head suites' do
before do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
end
it 'returns the correct count' do
is_expected.to eq(0)
end
end
end
describe '#failed_count' do
subject { comparer.failed_count }
context 'when there is a failed test case in head suites' do
before do
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
end
it 'returns the correct count' do
is_expected.to eq(1)
end
end
context 'when there are no failed test cases in head suites' do
before do
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_rspec_success)
end
it 'returns the correct count' do
is_expected.to eq(0)
end
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Reports::TestReports do
include TestReportsHelper
let(:test_reports) { described_class.new }
describe '#get_suite' do
subject { test_reports.get_suite(suite_name) }
context 'when suite name is rspec' do
let(:suite_name) { 'rspec' }
it { expect(subject.name).to eq('rspec') }
it 'initializes a new test suite and returns it' do
expect(Gitlab::Ci::Reports::TestSuite).to receive(:new).and_call_original
is_expected.to be_a(Gitlab::Ci::Reports::TestSuite)
end
context 'when suite name is already allocated' do
before do
subject
end
it 'does not initialize a new test suite' do
expect(Gitlab::Ci::Reports::TestSuite).not_to receive(:new)
is_expected.to be_a(Gitlab::Ci::Reports::TestSuite)
end
end
end
end
describe '#total_time' do
subject { test_reports.total_time }
before do
test_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
test_reports.get_suite('junit').add_test_case(create_test_case_java_success)
end
it 'returns the total time' do
is_expected.to eq(6.66)
end
end
describe '#total_count' do
subject { test_reports.total_count }
before do
test_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
test_reports.get_suite('junit').add_test_case(create_test_case_java_success)
end
it 'returns the total count' do
is_expected.to eq(2)
end
end
describe '#total_status' do
subject { test_reports.total_status }
context 'when all test cases succeeded' do
before do
test_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
test_reports.get_suite('junit').add_test_case(create_test_case_java_success)
end
it 'returns correct total status' do
is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
end
context 'when there is a failed test case' do
before do
test_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
test_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
end
it 'returns correct total status' do
is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
end
end
context 'when there is a skipped test case' do
before do
test_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
test_reports.get_suite('junit').add_test_case(create_test_case_java_skipped)
end
it 'returns correct total status' do
is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
end
context 'when there is an error test case' do
before do
test_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
test_reports.get_suite('junit').add_test_case(create_test_case_java_error)
end
it 'returns correct total status' do
is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
end
end
end
Gitlab::Ci::Reports::TestCase::STATUS_TYPES.each do |status_type|
describe "##{status_type}_count" do
subject { test_reports.public_send("#{status_type}_count") }
context "when #{status_type} test case exists" do
before do
test_reports.get_suite('rspec').add_test_case(public_send("create_test_case_rspec_#{status_type}"))
test_reports.get_suite('junit').add_test_case(public_send("create_test_case_java_#{status_type}"))
end
it 'returns the count' do
is_expected.to eq(2)
end
end
context "when #{status_type} test case do not exist" do
it 'returns nothing' do
is_expected.to be(0)
end
end
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Reports::TestSuiteComparer do
include TestReportsHelper
let(:comparer) { described_class.new(name, base_suite, head_suite) }
let(:name) { 'rpsec' }
let(:base_suite) { Gitlab::Ci::Reports::TestSuite.new(name) }
let(:head_suite) { Gitlab::Ci::Reports::TestSuite.new(name) }
let(:test_case_success) { create_test_case_rspec_success }
let(:test_case_failed) { create_test_case_rspec_failed }
let(:test_case_resolved) do
create_test_case_rspec_failed.tap do |test_case|
test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
end
describe '#new_failures' do
subject { comparer.new_failures }
context 'when head sutie has a newly failed test case which does not exist in base' do
before do
base_suite.add_test_case(test_case_success)
head_suite.add_test_case(test_case_failed)
end
it 'returns the failed test case' do
is_expected.to eq([test_case_failed])
end
end
context 'when head sutie still has a failed test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_failed)
end
it 'does not return the failed test case' do
is_expected.to be_empty
end
end
context 'when head sutie has a success test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_resolved)
end
it 'does not return the failed test case' do
is_expected.to be_empty
end
end
end
describe '#existing_failures' do
subject { comparer.existing_failures }
context 'when head sutie has a newly failed test case which does not exist in base' do
before do
base_suite.add_test_case(test_case_success)
head_suite.add_test_case(test_case_failed)
end
it 'returns the failed test case' do
is_expected.to be_empty
end
end
context 'when head sutie still has a failed test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_failed)
end
it 'does not return the failed test case' do
is_expected.to eq([test_case_failed])
end
end
context 'when head sutie has a success test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_resolved)
end
it 'does not return the failed test case' do
is_expected.to be_empty
end
end
end
describe '#resolved_failures' do
subject { comparer.resolved_failures }
context 'when head sutie has a newly failed test case which does not exist in base' do
before do
base_suite.add_test_case(test_case_success)
head_suite.add_test_case(test_case_failed)
end
it 'returns the failed test case' do
is_expected.to be_empty
end
it 'returns the correct resolved count' do
expect(comparer.resolved_count).to eq(0)
end
end
context 'when head sutie still has a failed test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_failed)
end
it 'does not return the failed test case' do
is_expected.to be_empty
end
it 'returns the correct resolved count' do
expect(comparer.resolved_count).to eq(0)
end
end
context 'when head sutie has a success test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_resolved)
end
it 'does not return the resolved test case' do
is_expected.to eq([test_case_resolved])
end
it 'returns the correct resolved count' do
expect(comparer.resolved_count).to eq(1)
end
end
end
describe '#total_count' do
subject { comparer.total_count }
before do
head_suite.add_test_case(test_case_success)
end
it 'returns the total test counts in head suite' do
is_expected.to eq(1)
end
end
describe '#failed_count' do
subject { comparer.failed_count }
context 'when there are a new failure and an existing failure' do
let(:test_case_1_success) { create_test_case_rspec_success }
let(:test_case_2_failed) { create_test_case_rspec_failed }
let(:test_case_1_failed) do
create_test_case_rspec_success.tap do |test_case|
test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
end
end
before do
base_suite.add_test_case(test_case_1_success)
base_suite.add_test_case(test_case_2_failed)
head_suite.add_test_case(test_case_1_failed)
head_suite.add_test_case(test_case_2_failed)
end
it 'returns the correct count' do
is_expected.to eq(2)
end
end
context 'when there is a new failure' do
before do
base_suite.add_test_case(test_case_success)
head_suite.add_test_case(test_case_failed)
end
it 'returns the correct count' do
is_expected.to eq(1)
end
end
context 'when there is an existing failure' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_failed)
end
it 'returns the correct count' do
is_expected.to eq(1)
end
end
end
describe '#total_status' do
subject { comparer.total_status }
context 'when all test cases in head suite are success' do
before do
head_suite.add_test_case(test_case_success)
end
it 'returns the total status in head suite' do
is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
end
context 'when there is a failed test case in head suite' do
before do
head_suite.add_test_case(test_case_failed)
end
it 'returns the total status in head suite' do
is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
end
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Reports::TestSuite do
include TestReportsHelper
let(:test_suite) { described_class.new('Rspec') }
let(:test_case_success) { create_test_case_rspec_success }
let(:test_case_failed) { create_test_case_rspec_failed }
let(:test_case_skipped) { create_test_case_rspec_skipped }
let(:test_case_error) { create_test_case_rspec_error }
it { expect(test_suite.name).to eq('Rspec') }
describe '#add_test_case' do
context 'when status of the test case is success' do
it 'stores data correctly' do
test_suite.add_test_case(test_case_success)
expect(test_suite.test_cases[test_case_success.status][test_case_success.key])
.to eq(test_case_success)
expect(test_suite.total_time).to eq(1.11)
end
end
context 'when status of the test case is failed' do
it 'stores data correctly' do
test_suite.add_test_case(test_case_failed)
expect(test_suite.test_cases[test_case_failed.status][test_case_failed.key])
.to eq(test_case_failed)
expect(test_suite.total_time).to eq(2.22)
end
end
context 'when two test cases are added' do
it 'sums up total time' do
test_suite.add_test_case(test_case_success)
test_suite.add_test_case(test_case_failed)
expect(test_suite.total_time).to eq(3.33)
end
end
end
describe '#total_count' do
subject { test_suite.total_count }
before do
test_suite.add_test_case(test_case_success)
test_suite.add_test_case(test_case_failed)
end
it { is_expected.to eq(2) }
end
describe '#total_status' do
subject { test_suite.total_status }
context 'when all test cases succeeded' do
before do
test_suite.add_test_case(test_case_success)
end
it { is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS) }
end
context 'when a test case failed' do
before do
test_suite.add_test_case(test_case_success)
test_suite.add_test_case(test_case_failed)
end
it { is_expected.to eq(Gitlab::Ci::Reports::TestCase::STATUS_FAILED) }
end
end
Gitlab::Ci::Reports::TestCase::STATUS_TYPES.each do |status_type|
describe "##{status_type}" do
subject { test_suite.public_send("#{status_type}") }
context "when #{status_type} test case exists" do
before do
test_suite.add_test_case(public_send("test_case_#{status_type}"))
end
it 'returns all success test cases' do
is_expected.to eq( { public_send("test_case_#{status_type}").key => public_send("test_case_#{status_type}") })
end
end
context "when #{status_type} test case do not exist" do
it 'returns nothing' do
is_expected.to be_empty
end
end
end
end
Gitlab::Ci::Reports::TestCase::STATUS_TYPES.each do |status_type|
describe "##{status_type}_count" do
subject { test_suite.public_send("#{status_type}_count") }
context "when #{status_type} test case exists" do
before do
test_suite.add_test_case(public_send("test_case_#{status_type}"))
end
it 'returns the count' do
is_expected.to eq(1)
end
end
context "when #{status_type} test case do not exist" do
it 'returns nothing' do
is_expected.to be(0)
end
end
end
end
end
...@@ -151,6 +151,42 @@ describe Ci::Build do ...@@ -151,6 +151,42 @@ describe Ci::Build do
end end
end end
describe '.with_test_reports' do
subject { described_class.with_test_reports }
context 'when build has a test report' do
let!(:build) { create(:ci_build, :success, :test_reports) }
it 'selects the build' do
is_expected.to eq([build])
end
end
context 'when build does not have test reports' do
let!(:build) { create(:ci_build, :success, :trace_artifact) }
it 'does not select the build' do
is_expected.to be_empty
end
end
context 'when there are multiple builds with test reports' do
let!(:builds) { create_list(:ci_build, 5, :success, :test_reports) }
it 'does not execute a query for selecting job artifact one by one' do
recorded = ActiveRecord::QueryRecorder.new do
subject.each do |build|
Ci::JobArtifact::TEST_REPORT_FILE_TYPES.each do |file_type|
build.public_send("job_artifacts_#{file_type}").file.exists?
end
end
end
expect(recorded.count).to eq(2)
end
end
end
describe '#actionize' do describe '#actionize' do
context 'when build is a created' do context 'when build is a created' do
before do before do
...@@ -2760,6 +2796,60 @@ describe Ci::Build do ...@@ -2760,6 +2796,60 @@ describe Ci::Build do
end end
end end
describe '#collect_test_reports!' do
subject { build.collect_test_reports!(test_reports) }
let(:test_reports) { Gitlab::Ci::Reports::TestReports.new }
it { expect(test_reports.get_suite(build.name).total_count).to eq(0) }
context 'when build has a test report' do
context 'when there is a JUnit test report from rspec test suite' do
before do
create(:ci_job_artifact, :junit, job: build, project: build.project)
end
it 'parses blobs and add the results to the test suite' do
expect { subject }.not_to raise_error
expect(test_reports.get_suite(build.name).total_count).to eq(4)
expect(test_reports.get_suite(build.name).success_count).to be(2)
expect(test_reports.get_suite(build.name).failed_count).to be(2)
end
end
context 'when there is a JUnit test report from java ant test suite' do
before do
create(:ci_job_artifact, :junit_with_ant, job: build, project: build.project)
end
it 'parses blobs and add the results to the test suite' do
expect { subject }.not_to raise_error
expect(test_reports.get_suite(build.name).total_count).to eq(3)
expect(test_reports.get_suite(build.name).success_count).to be(3)
expect(test_reports.get_suite(build.name).failed_count).to be(0)
end
end
context 'when there is a corrupted JUnit test report' do
before do
create(:ci_job_artifact, :junit_with_corrupted_data, job: build, project: build.project)
end
it 'raises an error' do
expect { subject }.to raise_error(Gitlab::Ci::Parsers::JunitParser::JunitParserError)
end
end
end
context 'when build does not have test reports' do
it 'raises an error' do
expect { subject }.to raise_error(ArgumentError)
end
end
end
describe '#artifacts_metadata_entry' do describe '#artifacts_metadata_entry' do
set(:build) { create(:ci_build, project: project) } set(:build) { create(:ci_build, project: project) }
let(:path) { 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif' } let(:path) { 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif' }
......
...@@ -147,6 +147,34 @@ describe Ci::JobArtifact do ...@@ -147,6 +147,34 @@ describe Ci::JobArtifact do
end end
end end
describe '#each_blob' do
context 'when file format is gzip' do
context 'when gzip file contains one file' do
let(:artifact) { build(:ci_job_artifact, :junit) }
it 'iterates blob once' do
expect { |b| artifact.each_blob(&b) }.to yield_control.once
end
end
context 'when gzip file contains three files' do
let(:artifact) { build(:ci_job_artifact, :junit_with_three_testsuites) }
it 'iterates blob three times' do
expect { |b| artifact.each_blob(&b) }.to yield_control.exactly(3).times
end
end
end
context 'when there are no adapters for the file format' do
let(:artifact) { build(:ci_job_artifact, :junit, file_format: :zip) }
it 'raises an error' do
expect { |b| artifact.each_blob(&b) }.to raise_error(described_class::NotSupportedAdapterError)
end
end
end
describe '#expire_in' do describe '#expire_in' do
subject { artifact.expire_in } subject { artifact.expire_in }
......
...@@ -1851,6 +1851,62 @@ describe Ci::Pipeline, :mailer do ...@@ -1851,6 +1851,62 @@ describe Ci::Pipeline, :mailer do
end end
end end
describe '#has_test_reports?' do
subject { pipeline.has_test_reports? }
context 'when pipeline has builds with test reports' do
before do
create(:ci_build, pipeline: pipeline, project: project).tap do |build|
create(:ci_job_artifact, :junit, job: build, project: build.project)
end
end
context 'when pipeline status is running' do
let(:pipeline) { create(:ci_pipeline, :running, project: project) }
it { is_expected.to be_falsey }
end
context 'when pipeline status is success' do
let(:pipeline) { create(:ci_pipeline, :success, project: project) }
it { is_expected.to be_truthy }
end
end
context 'when pipeline does not have builds with test reports' do
it { is_expected.to be_falsey }
end
end
describe '#test_reports' do
subject { pipeline.test_reports }
context 'when pipeline has multiple builds with test reports' do
before do
create(:ci_build, :success, name: 'rspec', pipeline: pipeline, project: project).tap do |build|
create(:ci_job_artifact, :junit, job: build, project: build.project)
end
create(:ci_build, :success, name: 'java', pipeline: pipeline, project: project).tap do |build|
create(:ci_job_artifact, :junit_with_ant, job: build, project: build.project)
end
end
it 'returns test reports with collected data' do
expect(subject.total_count).to be(7)
expect(subject.success_count).to be(5)
expect(subject.failed_count).to be(2)
end
end
context 'when pipeline does not have any builds with test reports' do
it 'returns empty test reports' do
expect(subject.total_count).to be(0)
end
end
end
describe '#total_size' do describe '#total_size' do
let!(:build_job1) { create(:ci_build, pipeline: pipeline, stage_idx: 0) } let!(:build_job1) { create(:ci_build, pipeline: pipeline, stage_idx: 0) }
let!(:build_job2) { create(:ci_build, pipeline: pipeline, stage_idx: 0) } let!(:build_job2) { create(:ci_build, pipeline: pipeline, stage_idx: 0) }
......
...@@ -3,6 +3,7 @@ require 'spec_helper' ...@@ -3,6 +3,7 @@ require 'spec_helper'
describe MergeRequest do describe MergeRequest do
include RepoHelpers include RepoHelpers
include ProjectForksHelper include ProjectForksHelper
include ReactiveCachingHelpers
subject { create(:merge_request) } subject { create(:merge_request) }
...@@ -1079,6 +1080,90 @@ describe MergeRequest do ...@@ -1079,6 +1080,90 @@ describe MergeRequest do
end end
end end
describe '#has_test_reports?' do
subject { merge_request.has_test_reports? }
let(:project) { create(:project, :repository) }
context 'when head pipeline has test reports' do
let(:merge_request) { create(:merge_request, :with_test_reports, source_project: project) }
it { is_expected.to be_truthy }
end
context 'when head pipeline does not have test reports' do
let(:merge_request) { create(:merge_request, source_project: project) }
it { is_expected.to be_falsey }
end
end
describe '#compare_test_reports' do
subject { merge_request.compare_test_reports }
let(:project) { create(:project, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:base_pipeline) do
create(:ci_pipeline,
:success,
project: merge_request.source_project,
ref: merge_request.source_branch,
sha: merge_request.diff_base_sha).tap do |pipeline|
merge_request.update!(head_pipeline_id: pipeline.id)
create(:ci_build, name: 'rspec', pipeline: pipeline, project: project)
end
end
let!(:head_pipeline) do
create(:ci_pipeline,
:success,
project: merge_request.source_project,
ref: merge_request.source_branch,
sha: merge_request.diff_head_sha).tap do |pipeline|
merge_request.update!(head_pipeline_id: pipeline.id)
create(:ci_build, name: 'rspec', pipeline: pipeline, project: project)
end
end
context 'when head pipeline has test reports' do
let!(:job_artifact) { create(:ci_job_artifact, :junit, job: head_pipeline.builds.first, project: project) }
context 'when reactive cache worker is parsing asynchronously' do
it 'returns status' do
expect(subject[:status]).to eq(:parsing)
end
end
context 'when reactive cache worker is inline' do
before do
synchronous_reactive_cache(merge_request)
end
it 'returns status and data' do
expect(subject[:status]).to eq(:parsed)
expect(subject[:data]).to be_a(String)
end
context 'when test reports contains invalid data' do
let!(:job_artifact) { create(:ci_job_artifact, :junit_with_corrupted_data, job: head_pipeline.builds.first, project: project) }
it 'returns status and error message' do
expect(subject[:status]).to eq(:error)
expect(subject[:status_reason]).to eq('Invalid XML data')
end
end
end
end
context 'when head pipeline does not have test reports' do
it 'returns status and error message' do
expect(subject[:status]).to eq(:error)
expect(subject[:status_reason]).to eq('head pipeline does not have test reports')
end
end
end
describe '#all_commit_shas' do describe '#all_commit_shas' do
context 'when merge request is persisted' do context 'when merge request is persisted' do
let(:all_commit_shas) do let(:all_commit_shas) do
...@@ -2010,6 +2095,26 @@ describe MergeRequest do ...@@ -2010,6 +2095,26 @@ describe MergeRequest do
end end
end end
describe '#base_pipeline' do
let(:pipeline_arguments) do
{
project: project,
ref: merge_request.target_branch,
sha: merge_request.diff_base_sha
}
end
let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:first_pipeline) { create(:ci_pipeline_without_jobs, pipeline_arguments) }
let!(:last_pipeline) { create(:ci_pipeline_without_jobs, pipeline_arguments) }
it 'returns latest pipeline' do
expect(merge_request.base_pipeline).to eq(last_pipeline)
end
end
describe '#has_commits?' do describe '#has_commits?' do
before do before do
allow(subject.merge_request_diff).to receive(:commits_count) allow(subject.merge_request_diff).to receive(:commits_count)
......
require 'spec_helper'
describe TestCaseEntity do
include TestReportsHelper
let(:entity) { described_class.new(test_case) }
describe '#as_json' do
subject { entity.as_json }
context 'when test case is success' do
let(:test_case) { create_test_case_rspec_success }
it 'contains correct test case details' do
expect(subject[:status]).to eq('success')
expect(subject[:name]).to eq('Test#sum when a is 1 and b is 3 returns summary')
expect(subject[:execution_time]).to eq(1.11)
end
end
context 'when test case is failed' do
let(:test_case) { create_test_case_rspec_failed }
it 'contains correct test case details' do
expect(subject[:status]).to eq('failed')
expect(subject[:name]).to eq('Test#sum when a is 2 and b is 2 returns summary')
expect(subject[:execution_time]).to eq(2.22)
end
end
end
end
require 'spec_helper'
describe TestReportsComparerEntity do
include TestReportsHelper
let(:entity) { described_class.new(comparer) }
let(:comparer) { Gitlab::Ci::Reports::TestReportsComparer.new(base_reports, head_reports) }
let(:base_reports) { Gitlab::Ci::Reports::TestReports.new }
let(:head_reports) { Gitlab::Ci::Reports::TestReports.new }
describe '#as_json' do
subject { entity.as_json }
context 'when head and base reports include two test suites' do
context 'when the status of head report is success' do
before do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_success)
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_success)
end
it 'contains correct compared test reports details' do
expect(subject[:status]).to eq('success')
expect(subject[:summary]).to include(total: 2, resolved: 0, failed: 0)
expect(subject[:suites].first[:name]).to eq('rspec')
expect(subject[:suites].first[:status]).to eq('success')
expect(subject[:suites].second[:name]).to eq('junit')
expect(subject[:suites].second[:status]).to eq('success')
end
end
context 'when the status of head report is failed' do
before do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_success)
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
end
it 'contains correct compared test reports details' do
expect(subject[:status]).to eq('failed')
expect(subject[:summary]).to include(total: 2, resolved: 0, failed: 1)
expect(subject[:suites].first[:name]).to eq('rspec')
expect(subject[:suites].first[:status]).to eq('success')
expect(subject[:suites].second[:name]).to eq('junit')
expect(subject[:suites].second[:status]).to eq('failed')
end
end
context 'when the status of head report is resolved' do
before do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_resolved)
end
let(:create_test_case_java_resolved) do
create_test_case_java_failed.tap do |test_case|
test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
end
it 'contains correct compared test reports details' do
expect(subject[:status]).to eq('success')
expect(subject[:summary]).to include(total: 2, resolved: 1, failed: 0)
expect(subject[:suites].first[:name]).to eq('rspec')
expect(subject[:suites].first[:status]).to eq('success')
expect(subject[:suites].second[:name]).to eq('junit')
expect(subject[:suites].second[:status]).to eq('success')
end
end
end
end
end
require 'spec_helper'
describe TestReportsComparerSerializer do
include TestReportsHelper
let(:project) { double(:project) }
let(:serializer) { described_class.new(project: project).represent(comparer) }
let(:comparer) { Gitlab::Ci::Reports::TestReportsComparer.new(base_reports, head_reports) }
let(:base_reports) { Gitlab::Ci::Reports::TestReports.new }
let(:head_reports) { Gitlab::Ci::Reports::TestReports.new }
describe '#to_json' do
subject { serializer.to_json }
context 'when head and base reports include two test suites' do
context 'when the status of head report is success' do
before do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_success)
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_success)
end
it 'matches the schema' do
expect(subject).to match_schema('entities/test_reports_comparer')
end
end
context 'when the status of head report is failed' do
before do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_success)
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
end
it 'matches the schema' do
expect(subject).to match_schema('entities/test_reports_comparer')
end
end
context 'when the status of head report is resolved' do
before do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
head_reports.get_suite('junit').add_test_case(create_test_case_java_resolved)
end
let(:create_test_case_java_resolved) do
create_test_case_java_failed.tap do |test_case|
test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
end
it 'matches the schema' do
expect(subject).to match_schema('entities/test_reports_comparer')
end
end
end
end
end
require 'spec_helper'
describe TestSuiteComparerEntity do
include TestReportsHelper
let(:entity) { described_class.new(comparer) }
let(:comparer) { Gitlab::Ci::Reports::TestSuiteComparer.new(name, base_suite, head_suite) }
let(:name) { 'rpsec' }
let(:base_suite) { Gitlab::Ci::Reports::TestSuite.new(name) }
let(:head_suite) { Gitlab::Ci::Reports::TestSuite.new(name) }
let(:test_case_success) { create_test_case_rspec_success }
let(:test_case_failed) { create_test_case_rspec_failed }
let(:test_case_resolved) do
create_test_case_rspec_failed.tap do |test_case|
test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
end
describe '#as_json' do
subject { entity.as_json }
context 'when head sutie has a newly failed test case which does not exist in base' do
before do
base_suite.add_test_case(test_case_success)
head_suite.add_test_case(test_case_failed)
end
it 'contains correct compared test suite details' do
expect(subject[:name]).to eq(name)
expect(subject[:status]).to eq('failed')
expect(subject[:summary]).to include(total: 1, resolved: 0, failed: 1)
subject[:new_failures].first.tap do |new_failure|
expect(new_failure[:status]).to eq(test_case_failed.status)
expect(new_failure[:name]).to eq(test_case_failed.name)
expect(new_failure[:execution_time]).to eq(test_case_failed.execution_time)
expect(new_failure[:system_output]).to eq(test_case_failed.system_output)
end
expect(subject[:resolved_failures]).to be_empty
expect(subject[:existing_failures]).to be_empty
end
end
context 'when head sutie still has a failed test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_failed)
end
it 'contains correct compared test suite details' do
expect(subject[:name]).to eq(name)
expect(subject[:status]).to eq('failed')
expect(subject[:summary]).to include(total: 1, resolved: 0, failed: 1)
expect(subject[:new_failures]).to be_empty
expect(subject[:resolved_failures]).to be_empty
subject[:existing_failures].first.tap do |existing_failure|
expect(existing_failure[:status]).to eq(test_case_failed.status)
expect(existing_failure[:name]).to eq(test_case_failed.name)
expect(existing_failure[:execution_time]).to eq(test_case_failed.execution_time)
expect(existing_failure[:system_output]).to eq(test_case_failed.system_output)
end
end
end
context 'when head sutie has a success test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_resolved)
end
it 'contains correct compared test suite details' do
expect(subject[:name]).to eq(name)
expect(subject[:status]).to eq('success')
expect(subject[:summary]).to include(total: 1, resolved: 1, failed: 0)
expect(subject[:new_failures]).to be_empty
subject[:resolved_failures].first.tap do |resolved_failure|
expect(resolved_failure[:status]).to eq(test_case_resolved.status)
expect(resolved_failure[:name]).to eq(test_case_resolved.name)
expect(resolved_failure[:execution_time]).to eq(test_case_resolved.execution_time)
expect(resolved_failure[:system_output]).to eq(test_case_resolved.system_output)
end
expect(subject[:existing_failures]).to be_empty
end
end
end
end
...@@ -14,8 +14,8 @@ module ReactiveCachingHelpers ...@@ -14,8 +14,8 @@ module ReactiveCachingHelpers
end end
def synchronous_reactive_cache(subject) def synchronous_reactive_cache(subject)
allow(service).to receive(:with_reactive_cache) do |*args, &block| allow(subject).to receive(:with_reactive_cache) do |*args, &block|
block.call(service.calculate_reactive_cache(*args)) block.call(subject.calculate_reactive_cache(*args))
end end
end end
......
module TestReportsHelper
def create_test_case_rspec_success
Gitlab::Ci::Reports::TestCase.new(
name: 'Test#sum when a is 1 and b is 3 returns summary',
classname: 'spec.test_spec',
file: './spec/test_spec.rb',
execution_time: 1.11,
status: Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
def create_test_case_rspec_failed
Gitlab::Ci::Reports::TestCase.new(
name: 'Test#sum when a is 2 and b is 2 returns summary',
classname: 'spec.test_spec',
file: './spec/test_spec.rb',
execution_time: 2.22,
system_output: sample_rspec_failed_message,
status: Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
end
def create_test_case_rspec_skipped
Gitlab::Ci::Reports::TestCase.new(
name: 'Test#sum when a is 3 and b is 3 returns summary',
classname: 'spec.test_spec',
file: './spec/test_spec.rb',
execution_time: 3.33,
status: Gitlab::Ci::Reports::TestCase::STATUS_SKIPPED)
end
def create_test_case_rspec_error
Gitlab::Ci::Reports::TestCase.new(
name: 'Test#sum when a is 4 and b is 4 returns summary',
classname: 'spec.test_spec',
file: './spec/test_spec.rb',
execution_time: 4.44,
status: Gitlab::Ci::Reports::TestCase::STATUS_ERROR)
end
def sample_rspec_failed_message
<<-EOF.strip_heredoc
Failure/Error: is_expected.to eq(3)
expected: 3
got: -1
(compared using ==)
./spec/test_spec.rb:12:in `block (4 levels) in &lt;top (required)&gt;&apos;
EOF
end
def create_test_case_java_success
Gitlab::Ci::Reports::TestCase.new(
name: 'addTest',
classname: 'CalculatorTest',
execution_time: 5.55,
status: Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
def create_test_case_java_failed
Gitlab::Ci::Reports::TestCase.new(
name: 'subtractTest',
classname: 'CalculatorTest',
execution_time: 6.66,
system_output: sample_java_failed_message,
status: Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
end
def create_test_case_java_skipped
Gitlab::Ci::Reports::TestCase.new(
name: 'multiplyTest',
classname: 'CalculatorTest',
execution_time: 7.77,
status: Gitlab::Ci::Reports::TestCase::STATUS_SKIPPED)
end
def create_test_case_java_error
Gitlab::Ci::Reports::TestCase.new(
name: 'divideTest',
classname: 'CalculatorTest',
execution_time: 8.88,
status: Gitlab::Ci::Reports::TestCase::STATUS_ERROR)
end
def sample_java_failed_message
<<-EOF.strip_heredoc
junit.framework.AssertionFailedError: expected:&lt;1&gt; but was:&lt;3&gt;
at CalculatorTest.subtractExpression(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
EOF
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment