├── .gitignore
├── Features.md
├── Readme.md
├── UpcomingFeatures.md
├── sql
└── Coreservice.sql
└── src
├── .vs
└── config
│ └── applicationhost.config
├── Core.Services.Tests.Automation
├── .vscode
│ └── launch.json
├── Core.Services.Tests.Automation.njsproj
├── README.md
├── package.json
└── tests
│ ├── features
│ ├── service.feature
│ ├── step_definitions
│ │ ├── config.js
│ │ ├── hooks.js
│ │ └── stepDefinition.js
│ └── support
│ │ └── world.js
│ └── report
├── Core.Services.Tests.Unit
├── Core.Services.Tests.Unit.csproj
└── ServiceControllerTests.cs
├── Core.Services.sln
├── Core.Services
├── .dockerignore
├── Areas
│ └── V1
│ │ ├── Controlllers
│ │ ├── AddEmployee.cs
│ │ ├── GetEmployeeById.cs
│ │ ├── GetEmployeeList.cs
│ │ ├── RemoveEmployee.cs
│ │ └── _ServiceController.cs
│ │ └── Models
│ │ ├── Requests
│ │ └── AddEmployeeRequest.cs
│ │ └── Responses
│ │ ├── AddEmployeeResponse.cs
│ │ ├── GetEmployeeResponse.cs
│ │ ├── GetEmployeesListResponse.cs
│ │ └── RemoveEmployeeResponse.cs
├── Configurations
│ └── AppSettings.cs
├── Controllers
│ └── VersionController.cs
├── Core.Services.csproj
├── Dockerfile
├── Entities
│ ├── Constants.cs
│ ├── Employee.cs
│ ├── ResponseMessage.cs
│ ├── VersionDocument.cs
│ ├── VersionModel.cs
│ └── VersionStatus.cs
├── Filters
│ ├── CustomAuthorize.cs
│ └── CustomExceptionFilter.cs
├── Helpers
│ └── Helper.cs
├── Logger
│ └── LogResponseMiddleware.cs
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Repositories
│ ├── Database
│ │ ├── DatabaseRepository.cs
│ │ └── IDatabaseRepository.cs
│ └── Models
│ │ └── DBErrorResponse.cs
├── Startup.cs
├── appsettings.Development.json
├── appsettings.Production.json
├── appsettings.QA.json
├── appsettings.Staging.json
└── appsettings.json
├── docker-compose.ci.build.yml
├── docker-compose.dcproj
├── docker-compose.override.yml
└── docker-compose.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | Core.Services/.vs/
2 | Core.Services/Core.Services/bin/
3 | Core.Services/Core.Services/newrelic/
4 | Core.Services/Core.Services/obj/
5 | Core.Services/obj/
6 | Core.Services/Core.Services.Tests.Automation/.vscode/
7 | Core.Services/Core.Services.Tests.Automation/node_modules/
8 | Core.Services/Core.Services.Tests.Automation/obj/
9 | src/Core.Services/obj/
10 | src/obj/
11 | src/Core.Services/newrelic/
12 | src/Core.Services/bin/
13 | src/Core.Services.Tests.Automation/node_modules/
14 | src/Core.Services.Tests.Automation/obj/
15 | src/.vs/Core.Services/v15/
16 | src/Core.Services.Tests.Unit/bin/
17 | src/Core.Services.Tests.Unit/obj/
18 | src/.vs/
19 |
--------------------------------------------------------------------------------
/Features.md:
--------------------------------------------------------------------------------
1 | # This .NetCore Microservice Application contains below features:
2 | * Authentication (Basic Key)
3 | * Exception handling
4 | * Database connectivity
5 | * Database script
6 | * Docker
7 | * Logging:
8 | 1. Docker logging (Kitematic)
9 | * Monitoring:
10 | 1. NewRelic
11 | * Tests:
12 | 1. Cucumber Automation Tests
13 | 2. Unit Tests with Mock
14 |
15 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | ## Prerequisite:
2 |
3 | * Windows 10
4 | * Visual Studio 2017
5 | * .Net Core SDK : Download and install from
6 | 1. https://www.microsoft.com/net/learn/get-started/windows#windowscmd
7 | * Docker : https://docs.docker.com/docker-for-windows/install/#download-docker-for-windows
8 | * Docker Toolbox :https://docs.docker.com/toolbox/toolbox_install_windows/
9 | 1. It will provide Kitematic .It's a Docker UI for docker containers and logs.
10 |
11 | ## Database
12 | If you want to use your local database then Execute Database script "/sql/Coreservice.sql" :
13 | * It will create coreservices databse with required tables and sps
14 | * Update connection string with your database connections.
15 |
16 | ## NewRelic
17 | * Case1: If you donot want to use NewRelic then comment below three lines in DockerFile : ../src/Core.Services/Dockerfile :
18 | 1. ARG NewRelic=./newrelic
19 | 2. COPY $NewRelic ./newrelic
20 | 3. RUN dpkg -i ./newrelic/newrelic-netcore20-agent*.deb
21 |
22 | * Case2: In you want to use NewRelic monitoring:
23 | * Download below from http://download.newrelic.com/dot_net_agent/core_20/current
24 | 1. newrelic-netcore20-agent_8.0.0.0_amd64.deb
25 | * Create a folder named "newrelic" inside ../src/Core.Services
26 | * Add below line in .dockerignore file :
27 | !newrelic
28 | * Register into Newrelic and get NEW_RELIC_LICENSE_KEY
29 | * Replace this NEW_RELIC_LICENSE_KEY value in dockerfile
30 |
31 |
32 | ## Run application using below steps:
33 | * Open command promt and go to ../src/Core.Services
34 | * dotnet restore
35 | * dotnet build
36 | * dotnet publish -o obj/Docker/publish
37 | * docker build -t coreimage .
38 | * See images using command "docker images",it will list your image "coreimage" also
39 | * docker run -d -p 28601:8601 --name core1 --env ASPNETCORE_ENVIRONMENT=QA coreimage
40 | 1. d => detached mode
41 | 2. p => host protocol and here you will acees api by localhost:28601
42 | 3. name => container name
43 | 4. env => Environmentname like QA/Development/Staging/PROD for running transformation
44 | * See conatainers running using command "docker ps",it will lsit your container "core1" also
45 |
46 | ## Access Apis
47 |
48 | * http://localhost:28601/service/version
49 | * To access below apis ,you need to pass authentication key in header
50 | apikey:67cd910a-6a6d-4cb3-b57b-92f7a4dee9c2
51 | 1. To GetList of Employees:
52 | http://localhost:28601/service/v1/
53 | 2. To GetList of Employees:
54 | http://localhost:28601/service/v1/{id}
55 |
56 | ## Check Kitematic for logs
57 |
58 | ## To see NewRelic logs
59 | * Run docker image with NewRelic app name
60 | docker run -d -p 28601:8601 --name core1 --env ASPNETCORE_ENVIRONMENT=QA coreimage --env NEW_RELIC_APP_NAME=CoreServiceApp
61 | * Go to newrelic and click on Application and select your app "CoreServiceApp"
62 |
63 | ## Run Unit Tests
64 | 1. Open command prompt and go to unit test project : ../src/Core.Services.Tests.Unit
65 | 2. run tests using command : dotnet test
66 |
--------------------------------------------------------------------------------
/UpcomingFeatures.md:
--------------------------------------------------------------------------------
1 | # Upcoming Features:
2 |
3 | ## Phase 2:
4 | * Rename repo and servicename to core-microservices-template
5 | * Tables and seed data creation as part of the migration in the source (rather than the separate SQL file)
6 | * Unit test case coverage - target for 100%
7 | * Swagger and OpenAPI Documentation
8 | * transfer this repo to 3Pillar Global Open Source (handle 3pillarlabs)
9 |
10 | ## Phase 3:
11 | * Visual Studio Template
12 | * Create Idserver Application and Setup
13 | * Idserver integration in CustomServiceTemplate
14 |
--------------------------------------------------------------------------------
/sql/Coreservice.sql:
--------------------------------------------------------------------------------
1 | IF NOT EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE name = N'CoreServices')
2 | Create Database CoreServices
3 | GO
4 |
5 | use CoreServices
6 | GO
7 |
8 | Create table Department(DepartmentId int primary key identity(1000,1) ,Name varchar(15))
9 | GO
10 |
11 | CREATE table Employee(EmployeeId int primary key identity(100,1),Name varchar(20),Address varchar(30),Salary int,IsActive bit,deptId int references Department)
12 | GO
13 |
14 |
15 | CREATE PROC usp_GetEmployeesList
16 | AS
17 | BEGIN
18 | SELECT EMP.EMPLOYEEID,EMP.NAME,EMP.ADDRESS,DEPT.NAME as DeptName FROM Employee EMP
19 | INNER JOIN Department DEPT ON EMP.deptId=DEPT.DepartmentId
20 | Where EMP.IsActive=1
21 | END
22 |
23 | GO
24 | CREATE PROC usp_GetEmployeeDetail
25 | @empId int
26 | AS
27 | BEGIN
28 | SELECT EMP.EMPLOYEEID,EMP.NAME,EMP.ADDRESS,EMP.SALARY,EMP.IsActive,DEPT.NAME as DeptName FROM Employee EMP
29 | INNER JOIN Department DEPT ON EMP.deptId=DEPT.DepartmentId
30 | WHERE EMP.EMPLOYEEID=@empId
31 | END
32 |
33 | GO
34 | CREATE PROC usp_AddEmployee
35 | @name varchar(20),
36 | @address varchar(30),
37 | @salary int,
38 | @deptId int
39 | AS
40 | BEGIN
41 | INSERT INTO Employee (Name,Address,Salary,isActive,deptId)
42 | VALUES(@name,@address,@salary,1,@deptId)
43 | END
44 |
45 | GO
46 | CREATE PROC usp_DeleteEmployee
47 | @empId int
48 | AS
49 | BEGIN
50 | DELETE FROM Employee WHERE EMPLOYEEID=@empId
51 | END
52 |
53 | GO
54 |
55 | INSERT INTO Department (Name)
56 | VALUES('DEVELOPMENT'),('HR'),('QA'),('SALES')
57 |
58 | INSERT INTO Employee (Name,Address,Salary,IsActive,deptId)
59 | VALUES('Ram','Noida',3743,1,1003),
60 | ('Seeta','Gurgaon',5033,1,1000),
61 | ('Reeta','Delhi',2300,1,1001),
62 | ('Mohan','Noida',6522,1,1000)
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/.vs/config/applicationhost.config:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 |
806 |
807 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
819 |
820 |
821 |
822 |
823 |
824 |
825 |
826 |
827 |
828 |
829 |
830 |
831 |
832 |
833 |
834 |
835 |
836 |
837 |
838 |
841 |
842 |
843 |
844 |
845 |
846 |
847 |
848 |
849 |
850 |
851 |
852 |
853 |
856 |
857 |
858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 |
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
878 |
879 |
880 |
881 |
882 |
883 |
884 |
885 |
886 |
887 |
888 |
889 |
890 |
891 |
892 |
893 |
894 |
895 |
896 |
897 |
898 |
899 |
900 |
901 |
902 |
903 |
904 |
905 |
906 |
907 |
908 |
909 |
910 |
911 |
912 |
913 |
914 |
915 |
916 |
917 |
918 |
919 |
920 |
921 |
922 |
923 |
924 |
925 |
926 |
927 |
928 |
929 |
930 |
931 |
932 |
933 |
934 |
935 |
936 |
937 |
938 |
939 |
940 |
941 |
942 |
943 |
944 |
945 |
946 |
947 |
948 |
949 |
950 |
951 |
952 |
953 |
954 |
955 |
956 |
957 |
958 |
959 |
960 |
961 |
962 |
963 |
964 |
965 |
966 |
967 |
968 |
969 |
970 |
971 |
972 |
973 |
974 |
975 |
976 |
977 |
978 |
979 |
980 |
981 |
982 |
983 |
984 |
985 |
986 |
987 |
988 |
989 |
990 |
991 |
992 |
993 |
994 |
995 |
996 |
997 |
--------------------------------------------------------------------------------
/src/Core.Services.Tests.Automation/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "request": "launch",
10 | "name": "Launch Program",
11 | "program": "${workspaceFolder}\\index.js"
12 | }
13 | ]
14 | }
--------------------------------------------------------------------------------
/src/Core.Services.Tests.Automation/Core.Services.Tests.Automation.njsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | 14.0
4 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
5 | Core.Services.Tests.Automation
6 | Hypergate.DigitalPlatform.User.Tests.Automation
7 |
8 |
9 |
10 | Debug
11 | 2.0
12 | f37735b1-251a-4ce6-a238-68ce76a1a149
13 |
14 |
15 |
16 |
17 | False
18 |
19 |
20 | .
21 | .
22 | v4.0
23 | {3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}
24 | ShowAllFiles
25 | false
26 |
27 |
28 | true
29 |
30 |
31 | true
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/Core.Services.Tests.Automation/README.md:
--------------------------------------------------------------------------------
1 | cucumber-html-reporter
2 | ======================
3 |
4 | Generate Cucumber HTML reports with pie charts
5 | > Available HTML themes: `['bootstrap', 'foundation', 'simple']`
6 |
7 |
8 | ## Preview of HTML Reports
9 |
10 | 1. [Bootstrap Theme Reports with Pie Chart][3]
11 | 2. [Foundation Theme Reports][4]
12 | 3. [Simple Theme Reports][5]
13 |
14 |
15 | ## Install
16 |
17 | ``` bash
18 | npm install
19 | ```
20 |
21 | ## Usage
22 |
23 | ```
24 | $ cucumberjs tests/features/ -f json:tests/report/cucumber_report.json
25 | ```
26 |
27 | > Multiple formatter are also supported,
28 |
29 | ```
30 | $ cucumberjs tests/features/ -f pretty -f json:tests/report/cucumber_report.json
31 | ```
32 |
33 | > Are you using cucumber with other frameworks or running [cucumber-parallel][6]? Pass relative path of JSON file to the `options` as shown [here][7]
34 |
35 |
36 | ## Options
37 |
38 | #### `theme`
39 | Available: `['bootstrap', 'foundation', 'simple']`
40 | Type: `String`
41 |
42 | Select the Theme for HTML report.
43 |
44 |
45 | #### `jsonFile`
46 | Type: `String`
47 |
48 | Provide path of the Cucumber JSON format file
49 |
50 | #### `jsonDir`
51 | Type: `String`
52 |
53 | If you have more than one cucumber JSON files, provide the path of JSON directory. This module will create consolidated report of all Cucumber JSON files.
54 |
55 | e.g. `jsonDir: 'tests/reports'` //where _reports_ directory contains valid `*.json` files
56 |
57 |
58 | N.B.: `jsonFile` takes precedence over `jsonDir`. We recommend to use either `jsonFile` or `jsonDir` option.
59 |
60 |
61 | #### `output`
62 | Type: `String`
63 |
64 | Provide HTML output file path and name
65 |
66 |
67 | #### `reportSuiteAsScenarios`
68 | Type: `Boolean`
69 | Supported in the Bootstrap theme.
70 |
71 | `true`: Reports total number of passed/failed scenarios as HEADER.
72 |
73 | `false`: Reports total number of passed/failed features as HEADER.
74 |
75 | #### `launchReport`
76 | Type: `Boolean`
77 |
78 | Automatically launch HTML report at the end of test suite
79 |
80 | `true`: Launch HTML report in the default browser
81 |
82 | `false`: Do not launch HTML report at the end of test suite
83 |
84 | #### `ignoreBadJsonFile`
85 | Type: `Boolean`
86 |
87 | Report any bad json files found during merging json files from directory option.
88 |
89 | `true`: ignore any bad json files found and continue with remaining files to merge.
90 |
91 | `false`: Default option. Fail report generation if any bad files found during merge.
92 |
93 | #### `name`
94 | Type: `String` (optional)
95 |
96 | Custom project name. If not passed, module reads the name from projects package.json which is preferable.
97 |
98 | #### `storeScreenShots`
99 | Type: `Boolean`
100 | Default: `undefined`
101 |
102 | `true`: Stores the screenShots to the default directory. It creates a directory 'screehshot' if does not exists.
103 |
104 | `false` or `undefined` : Does not store screenShots but attaches screenShots as a step-inline images to HTML report
105 |
106 |
107 | #### `metadata`
108 | Type: `JSON` (optional)
109 | Default: `undefined`
110 |
111 | Print more data to your report, such as _browser info, platform, app info, environments_ etc. Data can be passed as JSON `key-value` pair. Reporter will parse the JSON and will show the _Key-Value_ under `Metadata` section on HTML report. Checkout the below preview HTML Report with Metadata.
112 |
113 | Pass the _Key-Value_ pair as per your need, as shown in below example,
114 |
115 | ```json
116 |
117 | metadata: {
118 | "App Version":"0.3.2",
119 | "Test Environment": "STAGING",
120 | "Browser": "Chrome 54.0.2840.98",
121 | "Platform": "Windows 10",
122 | "Parallel": "Scenarios",
123 | "Executed": "Remote"
124 | }
125 |
126 | ```
--------------------------------------------------------------------------------
/src/Core.Services.Tests.Automation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CoreService_Report",
3 | "version": "0.3.8",
4 | "description": "Generates Cucumber HTML reports in three different themes",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "npm run features && npm run clean",
8 | "clean": "rm -rf tests/report/*.html tests/report/*.json tests/report/screenshot",
9 | "features": "node node_modules/cucumber/bin/cucumber tests/features/invoices.feature -f json:tests/report/cucumber_report.json",
10 | "debug": "node --debug-brk=5858 ./node_modules/.bin/cucumber-js tests/features"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/gkushang/cucumber-html-reporter.git"
15 | },
16 | "keywords": [
17 | "cucumber",
18 | "html",
19 | "cucumber-html-reporter",
20 | "html report",
21 | "json to html"
22 | ],
23 | "license": "MIT",
24 | "homepage": "https://github.com/gkushang/cucumber-html-reporter#readme",
25 | "dependencies": {
26 | "JSONPath": "^0.11.2",
27 | "cucumber": "^2.3.1",
28 | "dataobject-parser": "^1.1.3",
29 | "request": "^2.81.0",
30 | "stackframe": "^1.0.4"
31 | },
32 | "devDependencies": {
33 | "cucumber-html-reporter": "^0.3.2"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Core.Services.Tests.Automation/tests/features/service.feature:
--------------------------------------------------------------------------------
1 | Feature: CoreService's automation tests
2 |
3 | Scenario: Get the version
4 | When I GET the version
5 | Then the http status should be 200
6 |
7 | Scenario: Get the employees detail
8 | Given I have an authorized key
9 | And path parameter id = "100"
10 | When I send a "GET" request on "v1/{id}"
11 | Then the http status should be 200
12 | And the result should not equal to null
13 |
14 | Scenario: Get the employees list
15 | Given I have an authorized key
16 | When I send a "GET" request on "v1/"
17 | Then the http status should be 200
18 | And the result should equal to null
19 |
20 | Scenario: Submit delete employee
21 | Given I have an authorized key
22 | And path parameter id = "105"
23 | When I send a "DELETE" request on "v1/{id}"
24 | Then the http status should be 200
25 |
26 | Scenario: Submit Add new employee
27 | Given I have an authorized key
28 | And body parameter Name = "Automation User1"
29 | And body parameter Address = "Delhi"
30 | And body parameter DepartmentId = "1002"
31 | And body parameter Salary = "3500"
32 | When I send a "POST" request on "v1/"
33 | Then the http status should be 200
34 | And the success should equal "true"
--------------------------------------------------------------------------------
/src/Core.Services.Tests.Automation/tests/features/step_definitions/config.js:
--------------------------------------------------------------------------------
1 | exports.BASE_URL = "http://localhost:28601/service/"
2 | exports.API_KEY = "67cd910a-6a6d-4cb3-b57b-92f7a4dee9c2"
--------------------------------------------------------------------------------
/src/Core.Services.Tests.Automation/tests/features/step_definitions/hooks.js:
--------------------------------------------------------------------------------
1 | var reporter = require('cucumber-html-reporter');
2 |
3 | var cucumber_html_option = {
4 | theme: 'bootstrap',
5 | jsonFile: 'tests/report/cucumber_report.json',
6 | output: 'tests/report/cucumber_report.html',
7 | reportSuiteAsScenarios: true,
8 | launchReport: true,
9 | name:"CoreService Automation Tests Results",
10 | metadata: {
11 | "App Version":"0.3.2",
12 | "Test Environment": "STAGING",
13 | "Browser": "Chrome 54.0.2840.98",
14 | "Platform": "Windows 10",
15 | "Parallel": "Scenarios",
16 | "Executed": "Remote"
17 | }
18 | };
19 |
20 |
21 | var {defineSupportCode} = require('cucumber');
22 |
23 | defineSupportCode(function({After, Before, registerHandler}) {
24 | Before(function (scenario, callback) {
25 | this.scenario = scenario;
26 | callback();
27 | });
28 |
29 | Before({tags: '@testPassing'}, function (scenario, callback)
30 | {
31 | callback();
32 | });
33 |
34 | registerHandler('AfterFeatures', function (features,callback) {
35 | reporter.generate(cucumber_html_option);
36 | setTimeout(function(){callback(); },1000);
37 | });
38 |
39 |
40 | });
--------------------------------------------------------------------------------
/src/Core.Services.Tests.Automation/tests/features/step_definitions/stepDefinition.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var jsonPath = require('JSONPath').eval,
4 | url = require('url'),
5 | request = require('request'),
6 | config = require('./config'),
7 | DataObjectParser = require('dataobject-parser'),
8 | {defineSupportCode} = require('cucumber');
9 |
10 | defineSupportCode(function({Given,When,Then,Before,setWorldConstructor,registerHandler, After}){
11 | var parameters = {},
12 | headers={},
13 | befores =0,
14 | dParser = null;
15 |
16 | setWorldConstructor(require('../support/world.js').World);
17 | Before(function(scenario, callback) {
18 | //console.log('Test number: (' + befores + ')');
19 | befores++;
20 | parameters = {};
21 | headers = {};
22 | callback();
23 | dParser = new DataObjectParser()
24 | });
25 |
26 | Given(/^(body|query|path|header) parameter ([^"]*) = "([^"]*)"(?:.*)$/,function(parameterType, name, data, callback) {
27 | parameters[name] = {
28 | data : data?data.replace(/"/g,""):""
29 | ,type : parameterType
30 | };
31 | callback()
32 | })
33 |
34 | When(/^I send a "([^"]*)" request on "([^"]*)"(?:.*)$/,
35 | function(method,uri,callback){
36 | send.call(this, method,uri,callback);
37 | //console.log(requestBody)
38 | })
39 |
40 | var send = function(method, uri, callback) {
41 | var requestBody={};
42 | for(var name in parameters) {
43 | var parameter = parameters[name];
44 | var data = parameter.data;
45 | switch(parameter.type) {
46 | case "path":
47 | uri = uri.replace("{"+ name +"}", data);
48 | break;
49 | case "body":
50 | dParser.set(name, data);
51 | //requestBody[name] = data;
52 | break;
53 | case "query":
54 | var separator = uri.indexOf('?') !== -1 ? "&" : "?";
55 | uri = uri + separator + name + "=" + data;
56 | break;
57 | case "header":
58 | headers[name] = parameter.data;
59 | break;
60 | }
61 | }
62 | switch(method.toLowerCase()){
63 | case "post":
64 | //console.log(uri);
65 | this.post(uri, JSON.stringify(dParser.data()),headers, callback)
66 | break;
67 | case "delete":
68 | this.delete(uri, headers, callback)
69 | break;
70 | case "put":
71 | this.put(uri,JSON.stringify(dParser.data()), headers, callback)
72 | break;
73 | case "get":
74 | this.get(uri,headers, callback);
75 | break;
76 | }
77 | }
78 |
79 |
80 | Given(/^I have an authorized key$/,function(callback){
81 | headers["apikey"] = config.API_KEY
82 | callback();
83 | })
84 |
85 |
86 | When(/^I GET the service root$/,
87 | function (callback) {
88 | this.get('/v1', headers, callback)
89 | })
90 |
91 | When(/^I GET the version$/,
92 | function (callback) {
93 | this.get("version/", headers, callback)
94 | })
95 |
96 | When(/^I GET the employees list "([^"]*)"$/,
97 | function (invoiceId, callback) {
98 | var url = "v1/" ;
99 | this.get(url,headers, callback)
100 | })
101 |
102 | When(/^I GET the employees detail "([^"]*)"$/,
103 | function (id, callback) {
104 | var url = "v1/" + id;
105 | this.get(url, headers, callback)
106 | })
107 |
108 |
109 | //=== end user =====
110 | When(/^I GET a non-existing resource$/, function (callback) {
111 | this.get('/does/not/exist',headers, callback)
112 | })
113 |
114 |
115 | Then(/^the http status should be (\d+)$/, function (status, callback) {
116 | if (!assertResponse(this.lastResponse, callback)) { return }
117 | // deliberately using != here (no need to cast integer/string)
118 | /* jshint -W116 */
119 | if (this.lastResponse.statusCode != status) {
120 | /* jshint +W116 */
121 | callback('The last http response did not have the expected ' +
122 | 'status, expected ' + status + ' but got ' +
123 | this.lastResponse.statusCode)
124 | } else {
125 | callback()
126 | }
127 | })
128 | Then(/^(?:the )?([\w_.$\[\]]+) should equal to null$/, function (key, callback) {
129 | if (!assertPropertyIsNotNull(this.lastResponse, key, callback)) {
130 | //callback()
131 | //return
132 | }
133 | callback()
134 | });
135 | // Check if a certain property of the response is equal to something
136 | Then(/^(?:the )?([\w_.$\[\]]+) should equal "([^"]+)"$/,
137 | function (key, expectedValue, callback) {
138 | if (!assertPropertyIs(this.lastResponse, key, expectedValue, callback)) {
139 | //return
140 | }
141 | callback()
142 | })
143 | Then(/^(?:the )?([\w_.$\[\]]+) should not equal to null$/, function (key,callback) {
144 | if (!assertPropertyIsNotNull(this.lastResponse, key, callback)) {
145 | //callback()
146 | //return
147 | }
148 | callback()
149 | });
150 | // Check if a substring is contained in a certain property of the response
151 | Then(/^I should see "([^"]+)" in the (\w+)$/, function (callback)
152 | {
153 | callback()
154 | })
155 |
156 | function assertResponse(lastResponse, callback) {
157 | if (!lastResponse) {
158 | callback('No request has been made until now.')
159 | return false
160 | }
161 | return true
162 | }
163 |
164 | function assertBody(lastResponse, callback) {
165 | if (!assertResponse(lastResponse, callback)) { return false }
166 | if (!lastResponse.body) {
167 | callback('The response to the last request had no body.')
168 | return null
169 | }
170 | return lastResponse.body
171 | }
172 |
173 | function assertValidJson(lastResponse, callback) {
174 | var body = assertBody(lastResponse, callback)
175 | if (!body) {
176 | return null
177 | }
178 | try {
179 | return JSON.parse(body)
180 | } catch (e) {
181 | callback(
182 | 'The body of the last response was not valid JSON.')
183 | return null
184 | }
185 | }
186 |
187 | function assertPropertyExists(lastResponse, key, expectedValue,
188 | callback) {
189 | var object = assertValidJson(lastResponse, callback)
190 | if (!object) { return null }
191 | var property
192 | if (key.indexOf('$.') !== 0 && key.indexOf('$[') !== 0) {
193 | // normal property
194 | property = object[key]
195 | } else {
196 | // JSONPath expression
197 | var matches = jsonPath(object, key)
198 | if (matches.length === 0) {
199 | // no match
200 | callback('The last response did not have the property: ' +
201 | key + '\nExpected it to be\n' + expectedValue)
202 | return null
203 | } else if (matches.length > 1) {
204 | // ambigious match
205 | callback('JSONPath expression ' + key + ' returned more than ' +
206 | 'one match in object:\n' + JSON.stringify(object))
207 | return null
208 | } else {
209 | // exactly one match, good
210 | property = matches[0]
211 | }
212 | }
213 | if (property == null) {
214 | callback('The last response did not have the property ' +
215 | key + '\nExpected it to be\n' + expectedValue)
216 | return null
217 | }
218 | return property
219 | }
220 |
221 | function assertPropertyIs(lastResponse, key, expectedValue, callback) {
222 |
223 | var value = assertPropertyExists(lastResponse, key, expectedValue, callback)
224 | if (value == null) { return false; } // success false
225 | if (value.toString() !== expectedValue) {
226 |
227 | callback('The last response did not have the expected content in ' +
228 | 'property ' + key + '. ' + 'Got:\n\n' + value + '\n\nExpected:\n\n' +
229 | expectedValue)
230 |
231 | return false
232 | }
233 | return true
234 | }
235 | function assertPropertyIsNotNull(lastResponse, key, callback) {
236 |
237 | var value = assertPropertyExists(lastResponse, key, null, callback)
238 | if (value && value.length) {
239 | return true
240 | }
241 | return false
242 | }
243 |
244 | function assertPropertyContains(lastResponse, key, expectedValue, callback) {
245 | var value = assertPropertyExists(lastResponse, key, expectedValue, callback)
246 | if (!value) { return false }
247 | if (value.indexOf(expectedValue) === -1) {
248 | callback('The last response did not have the expected content in ' +
249 | 'property ' + key + '. ' +
250 | 'Got:\n\n' + value + '\n\nExpected it to contain:\n\n' + expectedValue)
251 | return false
252 | }
253 | return true
254 | }
255 | });
--------------------------------------------------------------------------------
/src/Core.Services.Tests.Automation/tests/features/support/world.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var request = require('request')
4 |
5 | var config = require('../step_definitions/config')
6 |
7 | var World = function World(callback) {
8 | var self = this
9 | this.defaultHeaders = {'User-Agent': 'request','Content-Type': 'application/json; charset=utf-8'};
10 | this.lastResponse = null
11 |
12 | this.get = function(path, headers, callback) {
13 | var uri = this.uri(path)
14 | console.log(uri);
15 | request.get({url: uri, headers: this.addDefaultHeaders(headers)},
16 | function (error, response) {
17 | console.log("response "+ response);
18 | if (error || !('' + response.statusCode).match(/^2\d\d$/)) {
19 | callback('Error on GET request to ' + uri +
20 | ': ' + (error!=null?error.message: response.body))
21 | return
22 | }
23 |
24 | self.lastResponse = response
25 | callback()
26 | })
27 | }
28 |
29 | this.post = function(path, requestBody, headers, callback) {
30 | var uri = this.uri(path)
31 | //console.log(uri);
32 | request({url: uri, body: requestBody, method: 'POST',headers: this.addDefaultHeaders(headers)}
33 | ,function(error, response) {
34 | //console.log("response "+ response.body);
35 | if (error || !('' + response.statusCode).match(/^2\d\d$/)) {
36 | return callback('Error on POST request to ' + uri + ': ' +
37 | (error!=null?error.message: response.body))
38 | }
39 | self.lastResponse = response
40 | callback(null, self.lastResponse.headers.location)
41 | })
42 | }
43 |
44 | this.put = function(path, requestBody, headers, callback) {
45 | var uri = this.uri(path)
46 | request({url: uri, body: requestBody, method: 'PUT',
47 | headers: this.addDefaultHeaders(headers)},
48 | function(error, response) {
49 | if (error) {
50 | return callback('Error on PUT request to ' + uri + ': ' +
51 | error.message)
52 | }
53 | self.lastResponse = response
54 | callback(null, self.lastResponse.headers.locations)
55 | })
56 | }
57 |
58 | this.delete = function(path, headers, callback) {
59 | var uri = this.uri(path)
60 | request({ url: uri, method: 'DELETE',
61 | headers: this.addDefaultHeaders(headers)},
62 | function(error, response) {
63 | if (error) {
64 | return callback('Error on DELETE request to ' + uri + ': ' +
65 | error.message)
66 | }
67 | self.lastResponse = response
68 | callback()
69 | })
70 | }
71 |
72 | this.options = function(path, headers, callback) {
73 | var uri = this.uri(path)
74 | request({'uri': uri, method: 'OPTIONS',
75 | headers: this.addDefaultHeaders(headers)
76 | },
77 | function(error, response) {
78 | if (error) {
79 | return callback('Error on OPTIONS request to ' + uri +
80 | ': ' + error.message)
81 | }
82 | self.lastResponse = response
83 | callback()
84 | })
85 | }
86 |
87 | this.rootPath = function() {
88 | return '/'
89 | }
90 |
91 | this.uri = function(path) {
92 | return config.BASE_URL + path
93 | }
94 |
95 | this.addDefaultHeaders = function(reqHeaders){
96 | reqHeaders= reqHeaders || [];
97 | for(var h in this.defaultHeaders){
98 | reqHeaders[h] = this.defaultHeaders[h]
99 | }
100 | return reqHeaders;
101 | }
102 | }
103 |
104 | exports.World = World
105 |
--------------------------------------------------------------------------------
/src/Core.Services.Tests.Automation/tests/report:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "keyword": "Feature",
4 | "line": 1,
5 | "name": "Invoice's automation tests",
6 | "tags": [],
7 | "uri": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\service.feature",
8 | "elements": [
9 | {
10 | "keyword": "Scenario",
11 | "line": 3,
12 | "name": "Get the version",
13 | "tags": [],
14 | "id": "invoice's-automation-tests;get-the-version",
15 | "steps": [
16 | {
17 | "arguments": [],
18 | "keyword": "Before",
19 | "result": {
20 | "status": "passed",
21 | "duration": 1
22 | },
23 | "hidden": true,
24 | "match": {
25 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\hooks.js:24"
26 | }
27 | },
28 | {
29 | "arguments": [],
30 | "keyword": "Before",
31 | "result": {
32 | "status": "passed",
33 | "duration": 1
34 | },
35 | "hidden": true,
36 | "match": {
37 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:17"
38 | }
39 | },
40 | {
41 | "arguments": [],
42 | "keyword": "When ",
43 | "name": "I GET the version",
44 | "result": {
45 | "status": "failed",
46 | "duration": 1021,
47 | "error_message": "Error: Error on GET request to http://localhost:52973/serviceversion/: connect ECONNREFUSED 127.0.0.1:52973\n at Function. (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\cucumber\\lib\\user_code_runner.js:105:21)\n at throw (native)\n at tryCatcher (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\util.js:16:23)\n at PromiseSpawn._promiseRejected (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\generators.js:107:10)\n at Promise._settlePromise (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:576:26)\n at Promise._settlePromise0 (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:614:10)\n at Promise._settlePromises (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:689:18)\n at Async._drainQueue (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:133:16)\n at Async._drainQueues (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:143:10)\n at Immediate.Async.drainQueues (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:17:14)\n at runCallback (timers.js:672:20)\n at tryOnImmediate (timers.js:645:5)\n at processImmediate [as _immediateCallback] (timers.js:617:5)"
48 | },
49 | "line": 4,
50 | "match": {
51 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:91"
52 | }
53 | },
54 | {
55 | "arguments": [],
56 | "keyword": "Then ",
57 | "name": "the http status should be 200",
58 | "result": {
59 | "status": "skipped"
60 | },
61 | "line": 5,
62 | "match": {
63 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:115"
64 | }
65 | }
66 | ]
67 | },
68 | {
69 | "keyword": "Scenario",
70 | "line": 7,
71 | "name": "Get the employees detail",
72 | "tags": [],
73 | "id": "invoice's-automation-tests;get-the-employees-detail",
74 | "steps": [
75 | {
76 | "arguments": [],
77 | "keyword": "Before",
78 | "result": {
79 | "status": "passed",
80 | "duration": 0
81 | },
82 | "hidden": true,
83 | "match": {
84 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\hooks.js:24"
85 | }
86 | },
87 | {
88 | "arguments": [],
89 | "keyword": "Before",
90 | "result": {
91 | "status": "passed",
92 | "duration": 0
93 | },
94 | "hidden": true,
95 | "match": {
96 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:17"
97 | }
98 | },
99 | {
100 | "arguments": [],
101 | "keyword": "Given ",
102 | "name": "I have an authorized key",
103 | "result": {
104 | "status": "passed",
105 | "duration": 1
106 | },
107 | "line": 8,
108 | "match": {
109 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:80"
110 | }
111 | },
112 | {
113 | "arguments": [],
114 | "keyword": "And ",
115 | "name": "path parameter id = \"102\"",
116 | "result": {
117 | "status": "passed",
118 | "duration": 1
119 | },
120 | "line": 9,
121 | "match": {
122 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:26"
123 | }
124 | },
125 | {
126 | "arguments": [],
127 | "keyword": "When ",
128 | "name": "I send a \"GET\" request on \"v1/{id}\"",
129 | "result": {
130 | "status": "failed",
131 | "duration": 1008,
132 | "error_message": "Error: Error on GET request to http://localhost:52973/servicev1/102: connect ECONNREFUSED 127.0.0.1:52973\n at Function. (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\cucumber\\lib\\user_code_runner.js:105:21)\n at throw (native)\n at tryCatcher (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\util.js:16:23)\n at PromiseSpawn._promiseRejected (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\generators.js:107:10)\n at Promise._settlePromise (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:576:26)\n at Promise._settlePromise0 (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:614:10)\n at Promise._settlePromises (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:689:18)\n at Async._drainQueue (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:133:16)\n at Async._drainQueues (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:143:10)\n at Immediate.Async.drainQueues (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:17:14)\n at runCallback (timers.js:672:20)\n at tryOnImmediate (timers.js:645:5)\n at processImmediate [as _immediateCallback] (timers.js:617:5)"
133 | },
134 | "line": 10,
135 | "match": {
136 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:34"
137 | }
138 | },
139 | {
140 | "arguments": [],
141 | "keyword": "Then ",
142 | "name": "the http status should be 200",
143 | "result": {
144 | "status": "skipped"
145 | },
146 | "line": 11,
147 | "match": {
148 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:115"
149 | }
150 | },
151 | {
152 | "arguments": [],
153 | "keyword": "And ",
154 | "name": "the result should not equal to null",
155 | "result": {
156 | "status": "skipped"
157 | },
158 | "line": 12,
159 | "match": {
160 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:143"
161 | }
162 | }
163 | ]
164 | },
165 | {
166 | "keyword": "Scenario",
167 | "line": 14,
168 | "name": "Get the employees list",
169 | "tags": [],
170 | "id": "invoice's-automation-tests;get-the-employees-list",
171 | "steps": [
172 | {
173 | "arguments": [],
174 | "keyword": "Before",
175 | "result": {
176 | "status": "passed",
177 | "duration": 0
178 | },
179 | "hidden": true,
180 | "match": {
181 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\hooks.js:24"
182 | }
183 | },
184 | {
185 | "arguments": [],
186 | "keyword": "Before",
187 | "result": {
188 | "status": "passed",
189 | "duration": 1
190 | },
191 | "hidden": true,
192 | "match": {
193 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:17"
194 | }
195 | },
196 | {
197 | "arguments": [],
198 | "keyword": "Given ",
199 | "name": "I have an authorized key",
200 | "result": {
201 | "status": "passed",
202 | "duration": 1
203 | },
204 | "line": 15,
205 | "match": {
206 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:80"
207 | }
208 | },
209 | {
210 | "arguments": [],
211 | "keyword": "When ",
212 | "name": "I send a \"GET\" request on \"v1/\"",
213 | "result": {
214 | "status": "failed",
215 | "duration": 1006,
216 | "error_message": "Error: Error on GET request to http://localhost:52973/servicev1/: connect ECONNREFUSED 127.0.0.1:52973\n at Function. (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\cucumber\\lib\\user_code_runner.js:105:21)\n at throw (native)\n at tryCatcher (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\util.js:16:23)\n at PromiseSpawn._promiseRejected (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\generators.js:107:10)\n at Promise._settlePromise (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:576:26)\n at Promise._settlePromise0 (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:614:10)\n at Promise._settlePromises (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:689:18)\n at Async._drainQueue (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:133:16)\n at Async._drainQueues (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:143:10)\n at Immediate.Async.drainQueues (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:17:14)\n at runCallback (timers.js:672:20)\n at tryOnImmediate (timers.js:645:5)\n at processImmediate [as _immediateCallback] (timers.js:617:5)"
217 | },
218 | "line": 16,
219 | "match": {
220 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:34"
221 | }
222 | },
223 | {
224 | "arguments": [],
225 | "keyword": "Then ",
226 | "name": "the http status should be 200",
227 | "result": {
228 | "status": "skipped"
229 | },
230 | "line": 17,
231 | "match": {
232 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:115"
233 | }
234 | },
235 | {
236 | "arguments": [],
237 | "keyword": "And ",
238 | "name": "the result should equal to null",
239 | "result": {
240 | "status": "skipped"
241 | },
242 | "line": 18,
243 | "match": {
244 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:128"
245 | }
246 | }
247 | ]
248 | },
249 | {
250 | "keyword": "Scenario",
251 | "line": 20,
252 | "name": "Submit Add new employee",
253 | "tags": [],
254 | "id": "invoice's-automation-tests;submit-add-new-employee",
255 | "steps": [
256 | {
257 | "arguments": [],
258 | "keyword": "Before",
259 | "result": {
260 | "status": "passed",
261 | "duration": 1
262 | },
263 | "hidden": true,
264 | "match": {
265 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\hooks.js:24"
266 | }
267 | },
268 | {
269 | "arguments": [],
270 | "keyword": "Before",
271 | "result": {
272 | "status": "passed",
273 | "duration": 0
274 | },
275 | "hidden": true,
276 | "match": {
277 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:17"
278 | }
279 | },
280 | {
281 | "arguments": [],
282 | "keyword": "Given ",
283 | "name": "I have an authorized key",
284 | "result": {
285 | "status": "passed",
286 | "duration": 0
287 | },
288 | "line": 21,
289 | "match": {
290 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:80"
291 | }
292 | },
293 | {
294 | "arguments": [],
295 | "keyword": "And ",
296 | "name": "path parameter Name = \"AutomationUser\"",
297 | "result": {
298 | "status": "passed",
299 | "duration": 0
300 | },
301 | "line": 22,
302 | "match": {
303 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:26"
304 | }
305 | },
306 | {
307 | "arguments": [],
308 | "keyword": "And ",
309 | "name": "body parameter Address = \"Delhi\"",
310 | "result": {
311 | "status": "passed",
312 | "duration": 0
313 | },
314 | "line": 23,
315 | "match": {
316 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:26"
317 | }
318 | },
319 | {
320 | "arguments": [],
321 | "keyword": "And ",
322 | "name": "body parameter DepartmentId = \"1002\"",
323 | "result": {
324 | "status": "passed",
325 | "duration": 0
326 | },
327 | "line": 24,
328 | "match": {
329 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:26"
330 | }
331 | },
332 | {
333 | "arguments": [],
334 | "keyword": "And ",
335 | "name": "body parameter Salary = \"3500\"",
336 | "result": {
337 | "status": "passed",
338 | "duration": 0
339 | },
340 | "line": 25,
341 | "match": {
342 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:26"
343 | }
344 | },
345 | {
346 | "arguments": [],
347 | "keyword": "When ",
348 | "name": "I send a \"POST\" request on \"v1/\"",
349 | "result": {
350 | "status": "failed",
351 | "duration": 1007,
352 | "error_message": "Error: Error on POST request to http://localhost:52973/servicev1/: connect ECONNREFUSED 127.0.0.1:52973\n at Function. (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\cucumber\\lib\\user_code_runner.js:105:21)\n at throw (native)\n at tryCatcher (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\util.js:16:23)\n at PromiseSpawn._promiseRejected (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\generators.js:107:10)\n at Promise._settlePromise (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:576:26)\n at Promise._settlePromise0 (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:614:10)\n at Promise._settlePromises (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:689:18)\n at Async._drainQueue (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:133:16)\n at Async._drainQueues (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:143:10)\n at Immediate.Async.drainQueues (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:17:14)\n at runCallback (timers.js:672:20)\n at tryOnImmediate (timers.js:645:5)\n at processImmediate [as _immediateCallback] (timers.js:617:5)"
353 | },
354 | "line": 26,
355 | "match": {
356 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:34"
357 | }
358 | },
359 | {
360 | "arguments": [],
361 | "keyword": "Then ",
362 | "name": "the http status should be 200",
363 | "result": {
364 | "status": "skipped"
365 | },
366 | "line": 27,
367 | "match": {
368 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:115"
369 | }
370 | },
371 | {
372 | "arguments": [],
373 | "keyword": "And ",
374 | "name": "the success should equal \"true\"",
375 | "result": {
376 | "status": "skipped"
377 | },
378 | "line": 28,
379 | "match": {
380 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:136"
381 | }
382 | }
383 | ]
384 | },
385 | {
386 | "keyword": "Scenario",
387 | "line": 30,
388 | "name": "Submit delete new employee",
389 | "tags": [],
390 | "id": "invoice's-automation-tests;submit-delete-new-employee",
391 | "steps": [
392 | {
393 | "arguments": [],
394 | "keyword": "Before",
395 | "result": {
396 | "status": "passed",
397 | "duration": 0
398 | },
399 | "hidden": true,
400 | "match": {
401 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\hooks.js:24"
402 | }
403 | },
404 | {
405 | "arguments": [],
406 | "keyword": "Before",
407 | "result": {
408 | "status": "passed",
409 | "duration": 1
410 | },
411 | "hidden": true,
412 | "match": {
413 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:17"
414 | }
415 | },
416 | {
417 | "arguments": [],
418 | "keyword": "Given ",
419 | "name": "I have an authorized key",
420 | "result": {
421 | "status": "passed",
422 | "duration": 1
423 | },
424 | "line": 31,
425 | "match": {
426 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:80"
427 | }
428 | },
429 | {
430 | "arguments": [],
431 | "keyword": "And ",
432 | "name": "path parameter id = \"101\"",
433 | "result": {
434 | "status": "passed",
435 | "duration": 1
436 | },
437 | "line": 32,
438 | "match": {
439 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:26"
440 | }
441 | },
442 | {
443 | "arguments": [],
444 | "keyword": "When ",
445 | "name": "I send a \"DELETE\" request on \"v1/{id}\"",
446 | "result": {
447 | "status": "failed",
448 | "duration": 1009,
449 | "error_message": "Error: Error on DELETE request to http://localhost:52973/servicev1/101: connect ECONNREFUSED 127.0.0.1:52973\n at Function. (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\cucumber\\lib\\user_code_runner.js:105:21)\n at throw (native)\n at tryCatcher (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\util.js:16:23)\n at PromiseSpawn._promiseRejected (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\generators.js:107:10)\n at Promise._settlePromise (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:576:26)\n at Promise._settlePromise0 (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:614:10)\n at Promise._settlePromises (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\promise.js:689:18)\n at Async._drainQueue (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:133:16)\n at Async._drainQueues (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:143:10)\n at Immediate.Async.drainQueues (D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\node_modules\\bluebird\\js\\release\\async.js:17:14)\n at runCallback (timers.js:672:20)\n at tryOnImmediate (timers.js:645:5)\n at processImmediate [as _immediateCallback] (timers.js:617:5)"
450 | },
451 | "line": 33,
452 | "match": {
453 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:34"
454 | }
455 | },
456 | {
457 | "arguments": [],
458 | "keyword": "Then ",
459 | "name": "the http status should be 200",
460 | "result": {
461 | "status": "skipped"
462 | },
463 | "line": 34,
464 | "match": {
465 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:115"
466 | }
467 | },
468 | {
469 | "arguments": [],
470 | "keyword": "And ",
471 | "name": "the success should equal \"true\"",
472 | "result": {
473 | "status": "skipped"
474 | },
475 | "line": 35,
476 | "match": {
477 | "location": "D:\\Rakhi\\TPG\\CoreServiceTemplate\\Core.Services\\Core.Services.Tests.Automation\\tests\\features\\step_definitions\\stepDefinition.js:136"
478 | }
479 | }
480 | ]
481 | }
482 | ],
483 | "id": "invoice's-automation-tests"
484 | }
485 | ]
--------------------------------------------------------------------------------
/src/Core.Services.Tests.Unit/Core.Services.Tests.Unit.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Core.Services.Tests.Unit/ServiceControllerTests.cs:
--------------------------------------------------------------------------------
1 | using Castle.Core.Logging;
2 | using Core.Services.Areas.V1.Controlllers;
3 | using Core.Services.Areas.V1.Models.Requests;
4 | using Core.Services.Areas.V1.Models.Responses;
5 | using Core.Services.Configurations;
6 | using Core.Services.Entities;
7 | using Core.Services.Repositories.Database;
8 | using Microsoft.AspNetCore.Mvc;
9 | using Microsoft.VisualStudio.TestTools.UnitTesting;
10 | using Moq;
11 | using System.Collections.Generic;
12 | using System.ComponentModel.DataAnnotations;
13 | using System.Linq;
14 |
15 | namespace Core.Services.Tests.Unit
16 | {
17 | [TestClass]
18 | public class ServiceControllerTests
19 | {
20 | #region Initialize
21 | Mock mockAppSettings = null;
22 | Mock mockDatabaseRepository = null;
23 |
24 |
25 | [TestInitialize]
26 | public void Initialize()
27 | {
28 | mockAppSettings = new Mock();
29 | mockDatabaseRepository = new Mock();
30 | mockDatabaseRepository.Setup(ee=>ee.AddEmployee(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())).Returns(1);
31 | mockDatabaseRepository.Setup(ee => ee.RemoveEmployee(Moq.It.IsAny())).Returns(1);
32 | mockDatabaseRepository.Setup(ee => ee.GetEmployeeDetailById(Moq.It.IsAny())).Returns(new Entities.EmployeeDetail() { Name="test",Address="gg",Salary=333,DeptName="HR"});
33 | mockDatabaseRepository.Setup(ee => ee.GetEmployeesList()).Returns(new List() { new Employee() {EmployeeId=101, Name = "test", DeptName = "HR" } });
34 | }
35 | #endregion
36 |
37 | #region Validation Failed StatusCode: 400
38 | [TestMethod]
39 | public void AddEmployee_400_Name_Missing()
40 | {
41 | var controller = new ServiceController(mockAppSettings.Object, mockDatabaseRepository.Object);
42 | var request = new AddEmployeeRequest() { };
43 | var validationResults = ValidateRequest(request);
44 | foreach (var validationResult in validationResults)
45 | {
46 | controller.ModelState.AddModelError(validationResult.MemberNames.First(), validationResult.ErrorMessage);
47 | }
48 | var response = controller.AddEmployee(request) as ObjectResult;
49 | var result = response.Value as AddEmployeeResponse;
50 | Assert.AreEqual(result.Success, false);
51 | Assert.IsTrue(result.ErrorResponse.Message.Contains("Name"));
52 | Assert.AreEqual(response.StatusCode, 400);
53 | }
54 | [TestMethod]
55 | public void AddEmployee_400_Address_Missing()
56 | {
57 | var controller = new ServiceController(mockAppSettings.Object, mockDatabaseRepository.Object);
58 | var request = new AddEmployeeRequest() {Name="Unit Testing",DepartmentId=1002,Salary=3200 };
59 | var validationResults = ValidateRequest(request);
60 | foreach (var validationResult in validationResults)
61 | {
62 | controller.ModelState.AddModelError(validationResult.MemberNames.First(), validationResult.ErrorMessage);
63 | }
64 | var response = controller.AddEmployee(request) as ObjectResult;
65 | var result = response.Value as AddEmployeeResponse;
66 | Assert.AreEqual(result.Success, false);
67 | Assert.IsTrue(result.ErrorResponse.Message.Contains("Address"));
68 | Assert.AreEqual(response.StatusCode, 400);
69 | }
70 | [TestMethod]
71 | public void AddEmployee_400_Salary_Missing()
72 | {
73 | var controller = new ServiceController(mockAppSettings.Object, mockDatabaseRepository.Object);
74 | var request = new AddEmployeeRequest() { Name = "Unit Testing", Address = "TestAddress", DepartmentId = 1002 };
75 | var validationResults = ValidateRequest(request);
76 | foreach (var validationResult in validationResults)
77 | {
78 | controller.ModelState.AddModelError(validationResult.MemberNames.First(), validationResult.ErrorMessage);
79 | }
80 | var response = controller.AddEmployee(request) as ObjectResult;
81 | var result = response.Value as AddEmployeeResponse;
82 | Assert.AreEqual(result.Success, false);
83 | Assert.IsTrue(result.ErrorResponse.Message.Contains("Salary"));
84 | Assert.AreEqual(response.StatusCode, 400);
85 | }
86 | [TestMethod]
87 | public void AddEmployee_200_OK()
88 | {
89 | var controller = new ServiceController(mockAppSettings.Object, mockDatabaseRepository.Object);
90 | var request = new AddEmployeeRequest() { Name = "Unit Testing", Address = "TestAddress", DepartmentId = 1002, Salary = 3200 };
91 | var validationResults = ValidateRequest(request);
92 | foreach (var validationResult in validationResults)
93 | {
94 | controller.ModelState.AddModelError(validationResult.MemberNames.First(), validationResult.ErrorMessage);
95 | }
96 | var response = controller.AddEmployee(request) as ObjectResult;
97 | var result = response.Value as AddEmployeeResponse;
98 | Assert.AreEqual(result.Success, true);
99 | Assert.AreEqual(response.StatusCode, 200);
100 | }
101 | [TestMethod]
102 | public void GetEmployeeById_200_OK()
103 | {
104 | var controller = new ServiceController(mockAppSettings.Object, mockDatabaseRepository.Object);
105 | var response = controller.GetEmployeeById(101) as ObjectResult;
106 | var result = response.Value as GetEmployeeResponse;
107 | Assert.AreEqual(result.Success, true);
108 | Assert.AreEqual(response.StatusCode, 200);
109 | }
110 | [TestMethod]
111 | public void GetEmployeeList_200_OK()
112 | {
113 | var controller = new ServiceController(mockAppSettings.Object, mockDatabaseRepository.Object);
114 | var response = controller.GetEmployeeList() as ObjectResult;
115 | var result = response.Value as GetEmployeesListResponse;
116 | Assert.AreEqual(result.Success, true);
117 | Assert.AreEqual(response.StatusCode, 200);
118 | }
119 | [TestMethod]
120 | public void RemoveEmployee_200_OK()
121 | {
122 | var controller = new ServiceController(mockAppSettings.Object, mockDatabaseRepository.Object);
123 | var response = controller.RemoveEmployee(102) as ObjectResult;
124 | var result = response.Value as RemoveEmployeeResponse;
125 | Assert.AreEqual(result.Success, true);
126 | Assert.AreEqual(response.StatusCode, 200);
127 | }
128 | #endregion
129 | #region private methods
130 | private List ValidateRequest(AddEmployeeRequest request)
131 | {
132 | var validationContext = new ValidationContext(request, null, null);
133 | var validationResults = new List();
134 | Validator.TryValidateObject(request, validationContext, validationResults, true);
135 | return validationResults;
136 | }
137 | #endregion
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/Core.Services.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27004.2005
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.Services", "Core.Services\Core.Services.csproj", "{8A93C7F9-BCDA-4C30-8D3B-D5AED9F281EF}"
7 | EndProject
8 | Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FD57D91B-39F1-41D1-BB1B-34BF6BD90075}"
9 | EndProject
10 | Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "Core.Services.Tests.Automation", "Core.Services.Tests.Automation\Core.Services.Tests.Automation.njsproj", "{F37735B1-251A-4CE6-A238-68CE76A1A149}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Services.Tests.Unit", "Core.Services.Tests.Unit\Core.Services.Tests.Unit.csproj", "{6AC225C7-9743-4B04-80D4-58BE9150ACD0}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {8A93C7F9-BCDA-4C30-8D3B-D5AED9F281EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {8A93C7F9-BCDA-4C30-8D3B-D5AED9F281EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {8A93C7F9-BCDA-4C30-8D3B-D5AED9F281EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {8A93C7F9-BCDA-4C30-8D3B-D5AED9F281EF}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {FD57D91B-39F1-41D1-BB1B-34BF6BD90075}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {FD57D91B-39F1-41D1-BB1B-34BF6BD90075}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {FD57D91B-39F1-41D1-BB1B-34BF6BD90075}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {FD57D91B-39F1-41D1-BB1B-34BF6BD90075}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {F37735B1-251A-4CE6-A238-68CE76A1A149}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {F37735B1-251A-4CE6-A238-68CE76A1A149}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {F37735B1-251A-4CE6-A238-68CE76A1A149}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {F37735B1-251A-4CE6-A238-68CE76A1A149}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {6AC225C7-9743-4B04-80D4-58BE9150ACD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {6AC225C7-9743-4B04-80D4-58BE9150ACD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {6AC225C7-9743-4B04-80D4-58BE9150ACD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {6AC225C7-9743-4B04-80D4-58BE9150ACD0}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {EF05920F-E2A8-4F0A-8F58-3E1DEEE0140E}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/src/Core.Services/.dockerignore:
--------------------------------------------------------------------------------
1 | *
2 | !obj/Docker/publish/*
3 | !obj/Docker/empty/
4 | !newrelic
5 |
--------------------------------------------------------------------------------
/src/Core.Services/Areas/V1/Controlllers/AddEmployee.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Areas.V1.Models.Requests;
2 | using Core.Services.Areas.V1.Models.Responses;
3 | using Core.Services.Entities;
4 | using Microsoft.AspNetCore.Mvc;
5 | using System.Linq;
6 |
7 | namespace Core.Services.Areas.V1.Controlllers
8 | {
9 | public partial class ServiceController : Controller
10 | {
11 | [Route("")]
12 | [HttpPost]
13 | public IActionResult AddEmployee([FromBody]AddEmployeeRequest request)
14 | {
15 | var response =new AddEmployeeResponse();
16 |
17 | if (!ModelState.IsValid)
18 | {
19 | var errors = ModelState.Where(e => e.Value.Errors.Count > 0).Select(ee => ee.Value.Errors.First().ErrorMessage);
20 | response.ErrorResponse = Helpers.Helper.ConvertToErrorResponse(errors.FirstOrDefault(), ErrorsType.ValidationError.ToString(), ErrorMessageType.Validation.ToString());
21 | return BadRequest(response);
22 | }
23 |
24 | var result = _dbRepository.AddEmployee(request.Name,request.Address,request.Salary,request.DepartmentId);
25 | if (result > 0)
26 | {
27 | response.Result = true;
28 | response.Success = true;
29 | }
30 | else
31 | {
32 | response.ErrorResponse = Helpers.Helper.ConvertToErrorResponse("Some error occured in adding employee..", ErrorsType.DatabaseError.ToString(), ErrorMessageType.Error.ToString());
33 | }
34 | return Ok(response);
35 |
36 | }
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/Core.Services/Areas/V1/Controlllers/GetEmployeeById.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Areas.V1.Models.Responses;
2 | using Core.Services.Entities;
3 | using Microsoft.AspNetCore.Mvc;
4 | using System.Linq;
5 | using System.Net;
6 |
7 | namespace Core.Services.Areas.V1.Controlllers
8 | {
9 | public partial class ServiceController : Controller
10 | {
11 | [Route("{id:int}")]
12 | [HttpGet]
13 | public IActionResult GetEmployeeById(int id)
14 | {
15 | var response =new GetEmployeeResponse();
16 |
17 | if(id<=0)
18 | {
19 | response.ErrorResponse = Helpers.Helper.ConvertToErrorResponse("Invalid Id..", ErrorsType.ValidationError.ToString(), ErrorMessageType.Validation.ToString());
20 | return BadRequest(response);
21 | }
22 |
23 | var result = _dbRepository.GetEmployeeDetailById(id);
24 | if (result != null)
25 | {
26 | response.Result = result;
27 | response.Success = true;
28 | return Ok(response);
29 | }
30 | else
31 | {
32 | response.ErrorResponse = Helpers.Helper.ConvertToErrorResponse("No Resource found..", ErrorsType.ResourceNotFoundError.ToString(), ErrorMessageType.Error.ToString());
33 | return NotFound(response);
34 | }
35 | }
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/Core.Services/Areas/V1/Controlllers/GetEmployeeList.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Areas.V1.Models.Responses;
2 | using Core.Services.Entities;
3 | using Microsoft.AspNetCore.Mvc;
4 | using System.Linq;
5 |
6 | namespace Core.Services.Areas.V1.Controlllers
7 | {
8 | public partial class ServiceController : Controller
9 | {
10 | [Route("")]
11 | [HttpGet]
12 | public IActionResult GetEmployeeList()
13 | {
14 | var response =new GetEmployeesListResponse();
15 |
16 | var result= _dbRepository.GetEmployeesList();
17 | if (result != null && result.Any())
18 | {
19 | response.Result = result;
20 | response.Success = true;
21 | }
22 | else
23 | {
24 | response.ErrorResponse = Helpers.Helper.ConvertToErrorResponse("No employee record found..",ErrorsType.NoRecordFound.ToString() , ErrorMessageType.Validation.ToString());
25 | }
26 |
27 | return Ok(response);
28 |
29 | }
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/Core.Services/Areas/V1/Controlllers/RemoveEmployee.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Areas.V1.Models.Responses;
2 | using Core.Services.Entities;
3 | using Microsoft.AspNetCore.Mvc;
4 | using System.Linq;
5 |
6 | namespace Core.Services.Areas.V1.Controlllers
7 | {
8 | public partial class ServiceController : Controller
9 | {
10 | [Route("{id:int}")]
11 | [HttpDelete]
12 | public IActionResult RemoveEmployee(int id)
13 | {
14 | var response =new RemoveEmployeeResponse();
15 |
16 | if(id<=0)
17 | {
18 | response.ErrorResponse = Helpers.Helper.ConvertToErrorResponse("Invalid Id..", ErrorsType.ValidationError.ToString(), ErrorMessageType.Validation.ToString());
19 | return BadRequest(response);
20 | }
21 | if (!ModelState.IsValid)
22 | {
23 | var errors = ModelState.Where(e => e.Value.Errors.Count > 0).Select(ee => ee.Value.Errors.First().ErrorMessage);
24 |
25 | return BadRequest(errors);
26 | }
27 |
28 | var result = _dbRepository.RemoveEmployee(id);
29 | if (result > 0)
30 | {
31 | response.Result = true;
32 | response.Success = true;
33 | }
34 | else
35 | {
36 | response.ErrorResponse = Helpers.Helper.ConvertToErrorResponse("Some error occured in removing employee info..", ErrorsType.DatabaseError.ToString(), ErrorMessageType.Error.ToString());
37 | }
38 | return Ok(response);
39 |
40 | }
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/Core.Services/Areas/V1/Controlllers/_ServiceController.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Configurations;
2 | using Core.Services.Filters;
3 | using Core.Services.Repositories.Database;
4 | using Microsoft.AspNetCore.Mvc;
5 |
6 | namespace Core.Services.Areas.V1.Controlllers
7 | {
8 | [Route("/service/v1")]
9 | [ServiceFilter(typeof(CustomAuthorize))]
10 | public partial class ServiceController : Controller
11 | {
12 | public const int REFUND_NOTE_TYPE_ID = 24;
13 | public const int TAX_EXEMPT_ID = 2;
14 | private readonly IAppSettings _apiSettings;
15 | private readonly IDatabaseRepository _dbRepository;
16 |
17 | public ServiceController(IAppSettings apiSettings, IDatabaseRepository dbRepository)
18 | {
19 | _apiSettings = apiSettings;
20 | _dbRepository = dbRepository;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Core.Services/Areas/V1/Models/Requests/AddEmployeeRequest.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace Core.Services.Areas.V1.Models.Requests
5 | {
6 | public class AddEmployeeRequest
7 | {
8 | [Required(AllowEmptyStrings = false,ErrorMessage ="Name is required..")]
9 | public string Name { get; set; }
10 | [Required(AllowEmptyStrings = false, ErrorMessage = "Address is required..")]
11 | public string Address { get; set; }
12 | [Range(1000,1100, ErrorMessage = "DepartmentId is required..")]
13 | public int DepartmentId { get; set; }
14 | [Range(1000,200000, ErrorMessage = "Salary is required..")]
15 | public int Salary { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Core.Services/Areas/V1/Models/Responses/AddEmployeeResponse.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Entities;
2 |
3 | namespace Core.Services.Areas.V1.Models.Responses
4 | {
5 | public class AddEmployeeResponse
6 | {
7 | public bool Success { get; set; }
8 | public bool Result { get; set; }
9 | public ResponseMessage ErrorResponse { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Core.Services/Areas/V1/Models/Responses/GetEmployeeResponse.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Entities;
2 |
3 | namespace Core.Services.Areas.V1.Models.Responses
4 | {
5 | public class GetEmployeeResponse
6 | {
7 | public bool Success { get; set; }
8 | public EmployeeDetail Result { get; set; }
9 | public ResponseMessage ErrorResponse { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Core.Services/Areas/V1/Models/Responses/GetEmployeesListResponse.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Entities;
2 | using System.Collections.Generic;
3 |
4 | namespace Core.Services.Areas.V1.Models.Responses
5 | {
6 | public class GetEmployeesListResponse
7 | {
8 | public bool Success { get; set; }
9 | public List Result { get; set; }
10 | public ResponseMessage ErrorResponse { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Core.Services/Areas/V1/Models/Responses/RemoveEmployeeResponse.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Entities;
2 |
3 | namespace Core.Services.Areas.V1.Models.Responses
4 | {
5 | public class RemoveEmployeeResponse
6 | {
7 | public bool Success { get; set; }
8 | public bool Result { get; set; }
9 | public ResponseMessage ErrorResponse { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Core.Services/Configurations/AppSettings.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Core.Services.Configurations
3 | {
4 | public interface IAppSettings
5 | {
6 | string ApplicationName { get; set; }
7 | string ConnectionString { get; set; }
8 | bool IsProd { get; set; }
9 | string AuthKeyName { get; set; }
10 | string ApiKey { get; set; }
11 | }
12 |
13 | public class AppSettings : IAppSettings
14 | {
15 | public string ApplicationName { get; set; }
16 | public string ConnectionString { get; set; }
17 | public bool IsProd { get; set; }
18 | public string AuthKeyName { get; set; }
19 | public string ApiKey { get; set; }
20 |
21 | public AppSettings()
22 | {
23 |
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Core.Services/Controllers/VersionController.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Entities;
2 | using Microsoft.AspNetCore.Mvc;
3 | using System.Reflection;
4 |
5 | namespace Core.Services.Controllers
6 | {
7 | [Route("service")]
8 | public class VersionController : Controller
9 | {
10 | [Route("version")]
11 | [HttpGet]
12 | public IActionResult GetVersion()
13 | {
14 | var projectionsAssembly = Assembly.GetEntryAssembly();
15 | var version = new VersionModel
16 | {
17 | Version = projectionsAssembly.GetCustomAttribute().InformationalVersion,
18 | Documents = new System.Collections.Generic.List
19 | {
20 | new VersionDocument
21 | {
22 | Status = VersionStatus.Live.ToString()
23 | }
24 | }
25 | };
26 | return Ok(version);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Core.Services/Core.Services.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 | ..\docker-compose.dcproj
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/Core.Services/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM microsoft/aspnetcore:2.0
2 | FROM microsoft/dotnet:2.0.0-sdk-2.0.2-stretch
3 |
4 | ENV CORECLR_ENABLE_PROFILING="1" \
5 | CORECLR_PROFILER="{36032161-FFC0-4B61-B559-F6C5D41BAE5A}" \
6 | CORECLR_NEWRELIC_HOME="/usr/local/newrelic-netcore20-agent" \
7 | CORECLR_PROFILER_PATH="/usr/local/newrelic-netcore20-agent/libNewRelicProfiler.so" \
8 | NEW_RELIC_LICENSE_KEY="3746113fec7f21e85135087aa6d47225369db05e"
9 |
10 |
11 | ARG source
12 | WORKDIR /app
13 |
14 |
15 | ARG NewRelic=./newrelic
16 | COPY $NewRelic ./newrelic
17 |
18 | RUN dpkg -i ./newrelic/newrelic-netcore20-agent*.deb
19 |
20 | ENV ASPNETCORE_URLS http://+:8601
21 | EXPOSE 8601
22 | COPY ${source:-obj/Docker/publish} .
23 | ENTRYPOINT ["dotnet", "Core.Services.dll"]
24 |
--------------------------------------------------------------------------------
/src/Core.Services/Entities/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace Core.Services.Entities
2 | {
3 | public enum ErrorMessageType
4 | {
5 | Validation,
6 | Error
7 | }
8 | public enum ErrorsType
9 | {
10 | ValidationError=100,
11 | ResourceNotFoundError = 102,
12 | NoRecordFound =101,
13 | DatabaseError=103,
14 | UnhandledError=104
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Core.Services/Entities/Employee.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Core.Services.Entities
3 | {
4 | public class Employee
5 | {
6 | public int EmployeeId { get; set; }
7 | public string Name { get; set; }
8 | public string DeptName { get; set; }
9 | }
10 | public class EmployeeDetail : Employee
11 | {
12 | public string Address { get; set; }
13 | public int Salary { get; set; }
14 | public bool IsActive { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Core.Services/Entities/ResponseMessage.cs:
--------------------------------------------------------------------------------
1 | namespace Core.Services.Entities
2 | {
3 | public class ResponseMessage
4 | {
5 | public string MessageId { get; set; }
6 | public string Message { get; set; }
7 | public string FriendlyMessage { get; set; }
8 | public string MessageType { get; set; }
9 | public string StackTrace { get; set; }
10 | }
11 | }
--------------------------------------------------------------------------------
/src/Core.Services/Entities/VersionDocument.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Core.Services.Entities
3 | {
4 | public class VersionDocument
5 | {
6 | public string Url { get; set; }
7 | public string Status { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Core.Services/Entities/VersionModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections.Generic;
3 |
4 | namespace Core.Services.Entities
5 | {
6 | public class VersionModel
7 | {
8 | public string Version { get; set; }
9 | [JsonProperty("Docs")]
10 | public List Documents { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Core.Services/Entities/VersionStatus.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Core.Services.Entities
3 | {
4 | public enum VersionStatus
5 | {
6 | Deprecated,
7 | Live,
8 | Preview
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Core.Services/Filters/CustomAuthorize.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc.Filters;
2 | using System;
3 | using System.Linq;
4 | using Microsoft.AspNetCore.Mvc;
5 | using Core.Services.Configurations;
6 |
7 | namespace Core.Services.Filters
8 | {
9 | [AttributeUsage(validOn: AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
10 | public class CustomAuthorize : ActionFilterAttribute
11 | {
12 | private readonly IAppSettings _apiSettings;
13 |
14 | public CustomAuthorize(IAppSettings apiSettings) : base()
15 | {
16 | _apiSettings = apiSettings;
17 | }
18 |
19 | public CustomAuthorize() { }
20 |
21 |
22 | public override void OnActionExecuting(ActionExecutingContext context)
23 | {
24 | var headers = context.HttpContext.Request.Headers;
25 | bool isAuthorized = false;
26 | var authKeyName = _apiSettings.AuthKeyName;
27 | var allowedAuthKeys = _apiSettings.ApiKey;
28 |
29 | var allowedKeysList = allowedAuthKeys.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
30 | if (headers.Keys.Contains(authKeyName) && allowedKeysList.Any())
31 | {
32 | var header = headers.FirstOrDefault(x => x.Key == authKeyName).Value.FirstOrDefault();
33 | if (header != null)
34 | isAuthorized = Array.Exists(allowedKeysList, key => key.Equals(header));
35 | }
36 |
37 | if (!isAuthorized)
38 | {
39 | context.Result = new ContentResult()
40 | {
41 | Content = "Authorization has been denied !!",
42 | ContentType = "text/plain",
43 | StatusCode = 401
44 | };
45 | }
46 | }
47 | }
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/Core.Services/Filters/CustomExceptionFilter.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Configurations;
2 | using Core.Services.Entities;
3 | using Microsoft.AspNetCore.Http;
4 | using Microsoft.AspNetCore.Mvc;
5 | using Microsoft.AspNetCore.Mvc.Filters;
6 | using Microsoft.Extensions.Logging;
7 | using System;
8 | using System.IO;
9 | using System.Net;
10 | using System.Text;
11 | using System.Threading;
12 |
13 | namespace Core.Services.Filters
14 | {
15 | public class CustomExceptionFilter : IExceptionFilter
16 | {
17 | private readonly IAppSettings _apiSettings;
18 | private readonly ILogger _logger;
19 | public CustomExceptionFilter(IAppSettings apiSettings, ILoggerFactory loggerFactory) : base()
20 | {
21 | _apiSettings = apiSettings;
22 | _logger = loggerFactory.CreateLogger("ServiceLogFilter");
23 | }
24 |
25 | public void OnException(ExceptionContext context)
26 | {
27 | var transactionName = "Core_Service";
28 | if (context.ActionDescriptor!=null && context.ActionDescriptor.AttributeRouteInfo!=null)
29 | transactionName = context.ActionDescriptor.AttributeRouteInfo.Template;
30 | HttpResponse response = context.HttpContext.Response;
31 | response.StatusCode = (int)HttpStatusCode.InternalServerError;
32 | response.ContentType = "application/json";
33 | var request = context.HttpContext.Request;
34 | var requestMethod = (request != null) ? request.Method : string.Empty;
35 | var message = context.Exception.Message + " StackTrace : " + context.Exception.StackTrace;
36 | Helpers.Helper.NewRelicLogging(transactionName, request.Path, requestMethod, string.Empty, response.StatusCode.ToString(), context.Exception, "Some Error has occured");
37 |
38 |
39 | byte[] byteArray = Encoding.UTF8.GetBytes(message);
40 |
41 | using (var messageStream = new MemoryStream(byteArray))
42 | {
43 |
44 | using (var stream = new StreamReader(messageStream))
45 | {
46 | var responseBody = stream.ReadToEnd();
47 | responseBody = responseBody.Replace(Environment.NewLine, "");
48 | _logger.LogError($"@timestamp: {DateTime.Now},@site: {"core-service"}, @level: error, @threadid: {Thread.CurrentThread.ManagedThreadId}, @message: response -{responseBody}, requestUrl: {request.Path},requestMethod: {requestMethod}, responseCode: { response.StatusCode}");
49 | }
50 | }
51 |
52 | var errorResponse = Helpers.Helper.ConvertToErrorResponse(context.Exception.Message, ErrorsType.UnhandledError.ToString(), ErrorMessageType.Error.ToString());
53 | if (!_apiSettings.IsProd)
54 | {
55 | errorResponse.StackTrace = context.Exception.StackTrace;
56 | }
57 |
58 | context.Result = new ObjectResult(errorResponse);
59 | }
60 | }
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/src/Core.Services/Helpers/Helper.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Entities;
2 | using Microsoft.Extensions.Logging;
3 | using System;
4 | using System.IO;
5 | using System.Text;
6 | using System.Threading;
7 |
8 | namespace Core.Services.Helpers
9 | {
10 | public static class Helper
11 | {
12 | public static void LogInfo(ILogger logger,string transactionName,string request,string url,string requestMethodType,string statusCode,string response)
13 | {
14 | byte[] byteArray = Encoding.UTF8.GetBytes(request);
15 | using (var messageStream = new MemoryStream(byteArray))
16 | {
17 | using (var stream = new StreamReader(messageStream))
18 | {
19 | var requestInfo = stream.ReadToEnd();
20 | requestInfo = requestInfo.Replace(Environment.NewLine, "");
21 | NewRelicLogging(transactionName, url, requestMethodType, request, statusCode, null, response);
22 | logger.LogInformation($"@timestamp: {DateTime.Now},@site: {"core-service"}, @level: error, @threadid: {Thread.CurrentThread.ManagedThreadId}, @message: request -{requestInfo}, requestUrl: {url},requestMethod: {requestMethodType}, responseCode: { statusCode},response:{response}");
23 | }
24 | }
25 | }
26 |
27 | public static void NewRelicLogging(string transactionName, string url,string requestMethod,string requestMessage,string statusCode, Exception exception,string responseMessage)
28 | {
29 | NewRelic.Api.Agent.NewRelic.SetTransactionName("Other", "/" + transactionName);
30 | NewRelic.Api.Agent.NewRelic.AddCustomParameter("URL: ", url);
31 | NewRelic.Api.Agent.NewRelic.AddCustomParameter("RequestType: ", requestMethod);
32 | NewRelic.Api.Agent.NewRelic.AddCustomParameter("Request: ", requestMessage);
33 | NewRelic.Api.Agent.NewRelic.AddCustomParameter("ResponseStatus: ", statusCode);
34 |
35 | if (exception!=null)
36 | {
37 | NewRelic.Api.Agent.NewRelic.AddCustomParameter("Error: ", exception.Message);
38 | if(!string.IsNullOrEmpty(exception.StackTrace) )
39 | {
40 | NewRelic.Api.Agent.NewRelic.AddCustomParameter("StackTrace: ", exception.StackTrace);
41 | if ( exception.StackTrace.Length > 250)
42 | NewRelic.Api.Agent.NewRelic.AddCustomParameter("StackTrace1: ", exception.StackTrace.Substring(250));
43 | }
44 | }
45 | NewRelic.Api.Agent.NewRelic.AddCustomParameter("Response: ", responseMessage);
46 | }
47 | public static ResponseMessage ConvertToErrorResponse(string errorMessage, string messageId, string messageType)
48 | {
49 | ResponseMessage response = new ResponseMessage()
50 | {
51 | Message = errorMessage,
52 | FriendlyMessage = "Some error has occured....",
53 | MessageId = messageId,
54 | MessageType = messageType
55 | };
56 | return response;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Core.Services/Logger/LogResponseMiddleware.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using Microsoft.AspNetCore.Http.Internal;
3 | using Microsoft.Extensions.Logging;
4 | using System;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Text.RegularExpressions;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 |
12 | namespace Core.Services.Logger
13 | {
14 | public class LogResponseMiddleware
15 | {
16 | private readonly RequestDelegate _next;
17 | private readonly ILogger _logger;
18 | private Func _defaultFormatter = (state, exception) => state;
19 |
20 | public LogResponseMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
21 | {
22 | _next = next;
23 | _logger = loggerFactory.CreateLogger("HyperLogFilter");
24 | }
25 |
26 | public async Task Invoke(HttpContext context)
27 | {
28 |
29 | context.Request.EnableRewind();
30 | var body = context.Request.Body;
31 | var buffer = new byte[Convert.ToInt32(context.Request.ContentLength)];
32 | await context.Request.Body.ReadAsync(buffer, 0, buffer.Length);
33 | var requestBody = Encoding.UTF8.GetString(buffer);
34 | body.Seek(0, SeekOrigin.Begin);
35 | context.Request.Body = body;
36 |
37 |
38 | var bodyStream = context.Response.Body;
39 | var responseBodyStream = new MemoryStream();
40 | context.Response.Body = responseBodyStream;
41 |
42 | await _next(context);
43 |
44 | responseBodyStream.Seek(0, SeekOrigin.Begin);
45 | var responseBody = new StreamReader(responseBodyStream).ReadToEnd();
46 |
47 | var responseCode = context.Response.StatusCode;
48 | var requestpath = context.Request.Path;
49 | var requestMethod = context.Request.Method;
50 | if (responseCode == 200 || responseCode == 404 || responseCode == 400 || responseCode == 401)
51 | {
52 | var transactionName = "invoices/v1";
53 | _logger.LogInformation($"@timestamp: {DateTime.Now},@site: {"hyper-invoices"}, @level: info, @threadid: {Thread.CurrentThread.ManagedThreadId}, @message: Logger Middleware response -{responseBody},requestBody:{requestBody}, requestUrl: {requestpath},requestMethod: {requestMethod}, responseCode: {responseCode}");
54 |
55 | if (!string.IsNullOrEmpty(requestpath.Value) && requestpath.Value.Contains("/"))
56 | {
57 | var requestPaths = requestpath.Value.Split("/").Where(ee => !string.IsNullOrEmpty(ee)).Select(ee => Regex.Replace(ee, @"^\d+$", "{invoiceId}"));
58 | if(requestPaths.Any())
59 | transactionName = String.Join("/", requestPaths.ToArray());
60 | }
61 | Helpers.Helper.NewRelicLogging(transactionName, requestpath, requestMethod, requestBody, responseCode.ToString(), null, responseBody);
62 | }
63 |
64 | responseBodyStream.Seek(0, SeekOrigin.Begin);
65 | await responseBodyStream.CopyToAsync(bodyStream);
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Core.Services/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore;
2 | using Microsoft.AspNetCore.Hosting;
3 |
4 | namespace Core.Services
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | BuildWebHost(args).Run();
11 | }
12 |
13 | public static IWebHost BuildWebHost(string[] args) =>
14 | WebHost.CreateDefaultBuilder(args)
15 | .UseStartup()
16 | .Build();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Core.Services/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:52972/",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "launchUrl": "service/version",
15 | "environmentVariables": {
16 | "ASPNETCORE_ENVIRONMENT": "Development"
17 | }
18 | },
19 | "MicroserviceTemplate": {
20 | "commandName": "Project",
21 | "launchBrowser": true,
22 | "launchUrl": "service/version",
23 | "environmentVariables": {
24 | "ASPNETCORE_ENVIRONMENT": "Development"
25 | },
26 | "applicationUrl": "http://localhost:52973/"
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Core.Services/Repositories/Database/DatabaseRepository.cs:
--------------------------------------------------------------------------------
1 | using Core.Services.Configurations;
2 | using Core.Services.Entities;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Data;
6 | using System.Data.SqlClient;
7 | using System.Linq;
8 |
9 | namespace Core.Services.Repositories.Database
10 | {
11 | public class DatabaseRepository : IDatabaseRepository
12 | {
13 | private readonly IAppSettings _appSettings;
14 |
15 | public DatabaseRepository(IAppSettings appSettings)
16 | {
17 | _appSettings = appSettings;
18 | }
19 |
20 | #region Private Methods
21 | private string ConnectionString
22 | {
23 | get
24 | {
25 | return _appSettings.ConnectionString;
26 | }
27 | }
28 | private void CreateProcedureCommand(SqlCommand command, string procedureName, SqlConnection connection, SqlParameter[] dbParameters = null)
29 | {
30 |
31 | command.CommandText = procedureName;
32 | command.Connection = connection;
33 | command.CommandType = CommandType.StoredProcedure;
34 | if (dbParameters != null && dbParameters.Any())
35 | command.Parameters.AddRange(dbParameters);
36 | }
37 |
38 | #endregion
39 |
40 | #region Public Methods
41 | public EmployeeDetail GetEmployeeDetailById(int employeeId)
42 | {
43 | EmployeeDetail employee = null;
44 | using (var connection = new SqlConnection(ConnectionString))
45 | {
46 | if (connection.State == ConnectionState.Closed)
47 | connection.Open();
48 |
49 | var sqlParameters = new List() { new SqlParameter("@empId", employeeId) };
50 | using (var command = new SqlCommand())
51 | {
52 | CreateProcedureCommand(command, "usp_GetEmployeeDetail", connection, sqlParameters.ToArray());
53 | using (var rdr = command.ExecuteReader())
54 | {
55 | while (rdr.Read())
56 | {
57 | employee = new EmployeeDetail();
58 | employee.EmployeeId = Convert.ToInt32(rdr["EmployeeId"]);
59 | employee.Name = Convert.ToString(rdr["Name"]);
60 | employee.Address = Convert.ToString(rdr["Address"]);
61 | employee.Salary = (!string.IsNullOrEmpty(Convert.ToString(rdr["Salary"]))) ? Convert.ToInt32(rdr["Salary"]) : 0;
62 | employee.DeptName = Convert.ToString(rdr["DeptName"]);
63 | employee.IsActive = Convert.ToBoolean(rdr["IsActive"]);
64 | }
65 | }
66 | }
67 | return employee;
68 | }
69 | }
70 |
71 | public List GetEmployeesList()
72 | {
73 | var employeeList = new List();
74 | using (var connection = new SqlConnection(ConnectionString))
75 | {
76 | if (connection.State == ConnectionState.Closed)
77 | connection.Open();
78 | using (var command = new SqlCommand())
79 | {
80 | CreateProcedureCommand(command, "usp_GetEmployeesList", connection, null);
81 | using (var rdr = command.ExecuteReader())
82 | {
83 | while (rdr.Read())
84 | {
85 | var employee = new Employee();
86 | employee.EmployeeId = Convert.ToInt32(rdr["EMPLOYEEID"]);
87 | employee.Name = Convert.ToString(rdr["NAME"]);
88 | employee.DeptName = Convert.ToString(rdr["DeptName"]);
89 | employeeList.Add(employee);
90 | }
91 | }
92 | }
93 | return employeeList;
94 | }
95 | #endregion
96 | }
97 | public int AddEmployee(string name, string address, int salary, int departmentId)
98 | {
99 | int result=0;
100 | using (var connection = new SqlConnection(ConnectionString))
101 | {
102 | if (connection.State == ConnectionState.Closed)
103 | connection.Open();
104 |
105 | var sqlParameters = new List() {
106 | new SqlParameter("@name", name),
107 | new SqlParameter("@address", address),
108 | new SqlParameter("@salary", salary),
109 | new SqlParameter("@deptId", departmentId)
110 | };
111 | using (var command = new SqlCommand())
112 | {
113 | CreateProcedureCommand(command, "usp_AddEmployee", connection, sqlParameters.ToArray());
114 | result = command.ExecuteNonQuery();
115 | }
116 | return result;
117 | }
118 | }
119 | public int RemoveEmployee(int employeeId)
120 | {
121 | int result = 0;
122 | using (var connection = new SqlConnection(ConnectionString))
123 | {
124 | if (connection.State == ConnectionState.Closed)
125 | connection.Open();
126 | var sqlParameters = new List() { new SqlParameter("@empId", employeeId) };
127 |
128 | using (var command = new SqlCommand())
129 | {
130 | CreateProcedureCommand(command, "usp_DeleteEmployee", connection, sqlParameters.ToArray());
131 | result = command.ExecuteNonQuery();
132 | }
133 | return result;
134 | }
135 | }
136 |
137 | }
138 | }
--------------------------------------------------------------------------------
/src/Core.Services/Repositories/Database/IDatabaseRepository.cs:
--------------------------------------------------------------------------------
1 |
2 | using Core.Services.Entities;
3 | using System.Collections.Generic;
4 |
5 | namespace Core.Services.Repositories.Database
6 | {
7 | public interface IDatabaseRepository
8 | {
9 | List GetEmployeesList();
10 | EmployeeDetail GetEmployeeDetailById(int employeeId);
11 | int AddEmployee(string name, string address, int salary, int departmentId);
12 | int RemoveEmployee(int employeeId);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Core.Services/Repositories/Models/DBErrorResponse.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Hypergate.Invoices.Repositories.Models
3 | {
4 | public class DBErrorResponse
5 | {
6 | public string ErrorMessage { get; set; }
7 | public string MessageId { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Core.Services/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.Extensions.Configuration;
8 | using Microsoft.Extensions.DependencyInjection;
9 | using Microsoft.Extensions.Logging;
10 | using Core.Services.Logger;
11 | using Core.Services.Filters;
12 | using Core.Services.Configurations;
13 | using Core.Services.Repositories.Database;
14 |
15 | namespace Core.Services
16 | {
17 | public class Startup
18 | {
19 | public Startup(IConfiguration configuration)
20 | {
21 | Configuration = configuration;
22 | }
23 |
24 | public IConfiguration Configuration { get; }
25 |
26 | // This method gets called by the runtime. Use this method to add services to the container.
27 | public void ConfigureServices(IServiceCollection services)
28 | {
29 | var appSettings = new AppSettings();
30 | ConfigurationBinder.Bind(Configuration.GetSection("AppSettings"), appSettings);
31 | services.AddSingleton(appSettings);
32 | services.AddSingleton();
33 | services.AddSingleton();
34 | var loggerFactory = new LoggerFactory();
35 | loggerFactory
36 | .WithFilter(new FilterLoggerSettings
37 | {
38 | { "Microsoft", Microsoft.Extensions.Logging.LogLevel.None },
39 | { "System", Microsoft.Extensions.Logging.LogLevel.Warning },
40 | { "HyperLogFilter", Microsoft.Extensions.Logging.LogLevel.Trace }
41 | })
42 | .AddConsole();
43 | loggerFactory.AddDebug();
44 | services.AddMvc(_ =>
45 | {
46 | _.Filters.Add(new CustomExceptionFilter(appSettings, loggerFactory));
47 | });
48 | }
49 |
50 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
51 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
52 | {
53 | loggerFactory
54 | .WithFilter(new FilterLoggerSettings
55 | {
56 | { "Microsoft",LogLevel.None },
57 | { "System", LogLevel.Warning },
58 | { "HyperLogFilter", LogLevel.Trace }
59 | })
60 | .AddConsole();
61 | loggerFactory.AddDebug();
62 | app.UseMiddleware();
63 | if (env.IsDevelopment())
64 | {
65 | app.UseDeveloperExceptionPage();
66 | }
67 |
68 | app.UseMvc();
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Core.Services/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "AppSettings": {
3 | "ApiKey": "67cd910a-6a6d-4cb3-b57b-92f7a4dee9c2"
4 | }
5 | }
--------------------------------------------------------------------------------
/src/Core.Services/appsettings.Production.json:
--------------------------------------------------------------------------------
1 | {
2 | "AppSettings": {
3 | "ApiKey": "be1367bc-bf77-49a6-8099-e8322ba9a52b",
4 | "IsProd": "true"
5 | }
6 | }
--------------------------------------------------------------------------------
/src/Core.Services/appsettings.QA.json:
--------------------------------------------------------------------------------
1 | {
2 | "AppSettings": {
3 | "ApiKey": "67cd910a-6a6d-4cb3-b57b-92f7a4dee9c2"
4 | }
5 | }
--------------------------------------------------------------------------------
/src/Core.Services/appsettings.Staging.json:
--------------------------------------------------------------------------------
1 | {
2 | "AppSettings": {
3 | "ApiKey": "67cd910a-6a6d-4cb3-b57b-92f7a4dee9c2"
4 | }
5 | }
--------------------------------------------------------------------------------
/src/Core.Services/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "AppSettings": {
3 | "ConnectionString": "data source=118.185.136.36;initial catalog=CoreServices;user id=sa;password=Tpg@1234;MultipleActiveResultSets=True;Connection Lifetime=0;Min Pool Size=0;Max Pool Size=100;Pooling=true;",
4 | "IsProd": "false",
5 | "AuthKeyName": "apikey",
6 | "ApiKey": "67cd910a-6a6d-4cb3-b57b-92f7a4dee9c2"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/docker-compose.ci.build.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | ci-build:
5 | image: microsoft/aspnetcore-build:1.0-2.0
6 | volumes:
7 | - .:/src
8 | working_dir: /src
9 | command: /bin/bash -c "dotnet restore ./Core.Services.sln && dotnet publish ./Core.Services.sln -c Release -o ./obj/Docker/publish"
10 |
--------------------------------------------------------------------------------
/src/docker-compose.dcproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 2.0
5 | Linux
6 | fd57d91b-39f1-41d1-bb1b-34bf6bd90075
7 | True
8 | http://localhost:{ServicePort}/api/values
9 | microservicetemplate
10 |
11 |
12 |
13 |
14 | docker-compose.yml
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/docker-compose.override.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | microservicetemplate:
5 | environment:
6 | - ASPNETCORE_ENVIRONMENT=Development
7 | ports:
8 | - "18601:8601"
9 |
--------------------------------------------------------------------------------
/src/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | microservicetemplate:
5 | image: core.services
6 | build:
7 | context: ./Core.Services
8 | dockerfile: Dockerfile
9 |
--------------------------------------------------------------------------------