mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 04:51:31 +08:00 
			
		
		
		
	test(etapi): port metrics
This commit is contained in:
		
							parent
							
								
									dddbb9d4d1
								
							
						
					
					
						commit
						bef121239c
					
				| @ -1,82 +0,0 @@ | ||||
| ### Test ETAPI metrics endpoint | ||||
| 
 | ||||
| # First login to get a token | ||||
| POST {{triliumHost}}/etapi/auth/login | ||||
| Content-Type: application/json | ||||
| 
 | ||||
| { | ||||
|   "password": "{{password}}" | ||||
| } | ||||
| 
 | ||||
| > {% | ||||
| client.test("Login successful", function() { | ||||
|     client.assert(response.status === 201, "Response status is not 201"); | ||||
|     client.assert(response.body.authToken, "Auth token not present"); | ||||
|     client.global.set("authToken", response.body.authToken); | ||||
| }); | ||||
| %} | ||||
| 
 | ||||
| ### Get metrics with authentication (default Prometheus format) | ||||
| GET {{triliumHost}}/etapi/metrics | ||||
| Authorization: {{authToken}} | ||||
| 
 | ||||
| > {% | ||||
| client.test("Metrics endpoint returns Prometheus format by default", function() { | ||||
|     client.assert(response.status === 200, "Response status is not 200"); | ||||
|     client.assert(response.headers["content-type"].includes("text/plain"), "Content-Type should be text/plain"); | ||||
|     client.assert(response.body.includes("trilium_info"), "Should contain trilium_info metric"); | ||||
|     client.assert(response.body.includes("trilium_notes_total"), "Should contain trilium_notes_total metric"); | ||||
|     client.assert(response.body.includes("# HELP"), "Should contain HELP comments"); | ||||
|     client.assert(response.body.includes("# TYPE"), "Should contain TYPE comments"); | ||||
| }); | ||||
| %} | ||||
| 
 | ||||
| ### Get metrics in JSON format | ||||
| GET {{triliumHost}}/etapi/metrics?format=json | ||||
| Authorization: {{authToken}} | ||||
| 
 | ||||
| > {% | ||||
| client.test("Metrics endpoint returns JSON when requested", function() { | ||||
|     client.assert(response.status === 200, "Response status is not 200"); | ||||
|     client.assert(response.headers["content-type"].includes("application/json"), "Content-Type should be application/json"); | ||||
|     client.assert(response.body.version, "Version info not present"); | ||||
|     client.assert(response.body.database, "Database info not present"); | ||||
|     client.assert(response.body.timestamp, "Timestamp not present"); | ||||
|     client.assert(typeof response.body.database.totalNotes === 'number', "Total notes should be a number"); | ||||
|     client.assert(typeof response.body.database.activeNotes === 'number', "Active notes should be a number"); | ||||
| }); | ||||
| %} | ||||
| 
 | ||||
| ### Get metrics in Prometheus format explicitly | ||||
| GET {{triliumHost}}/etapi/metrics?format=prometheus | ||||
| Authorization: {{authToken}} | ||||
| 
 | ||||
| > {% | ||||
| client.test("Metrics endpoint returns Prometheus format when requested", function() { | ||||
|     client.assert(response.status === 200, "Response status is not 200"); | ||||
|     client.assert(response.headers["content-type"].includes("text/plain"), "Content-Type should be text/plain"); | ||||
|     client.assert(response.body.includes("trilium_info"), "Should contain trilium_info metric"); | ||||
|     client.assert(response.body.includes("trilium_notes_total"), "Should contain trilium_notes_total metric"); | ||||
| }); | ||||
| %} | ||||
| 
 | ||||
| ### Test invalid format parameter | ||||
| GET {{triliumHost}}/etapi/metrics?format=xml | ||||
| Authorization: {{authToken}} | ||||
| 
 | ||||
| > {% | ||||
| client.test("Invalid format parameter returns error", function() { | ||||
|     client.assert(response.status === 400, "Response status should be 400"); | ||||
|     client.assert(response.body.code === "INVALID_FORMAT", "Error code should be INVALID_FORMAT"); | ||||
|     client.assert(response.body.message.includes("prometheus"), "Error message should mention supported formats"); | ||||
| }); | ||||
| %} | ||||
| 
 | ||||
| ### Test without authentication (should fail) | ||||
| GET {{triliumHost}}/etapi/metrics | ||||
| 
 | ||||
| > {% | ||||
| client.test("Metrics endpoint requires authentication", function() { | ||||
|     client.assert(response.status === 401, "Response status should be 401"); | ||||
| }); | ||||
| %}  | ||||
							
								
								
									
										71
									
								
								apps/server/spec/etapi/etapi-metrics.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								apps/server/spec/etapi/etapi-metrics.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | ||||
| import { Application } from "express"; | ||||
| import { beforeAll, describe, expect, it } from "vitest"; | ||||
| import supertest from "supertest"; | ||||
| import { login } from "./utils.js"; | ||||
| import config from "../../src/services/config.js"; | ||||
| 
 | ||||
| let app: Application; | ||||
| let token: string; | ||||
| 
 | ||||
| const USER = "etapi"; | ||||
| 
 | ||||
| describe("etapi/metrics", () => { | ||||
|     beforeAll(async () => { | ||||
|         config.General.noAuthentication = false; | ||||
|         const buildApp = (await (import("../../src/app.js"))).default; | ||||
|         app = await buildApp(); | ||||
|         token = await login(app); | ||||
|     }); | ||||
| 
 | ||||
|     it("returns Prometheus format by default", async () => { | ||||
|         const response = await supertest(app) | ||||
|             .get("/etapi/metrics") | ||||
|             .auth(USER, token, { "type": "basic"}) | ||||
|             .expect(200); | ||||
|         expect(response.headers["content-type"]).toContain("text/plain"); | ||||
|         expect(response.text).toContain("trilium_info"); | ||||
|         expect(response.text).toContain("trilium_notes_total"); | ||||
|         expect(response.text).toContain("# HELP"); | ||||
|         expect(response.text).toContain("# TYPE"); | ||||
|     }); | ||||
| 
 | ||||
|     it("returns JSON when requested", async() => { | ||||
|         const response = await supertest(app) | ||||
|             .get("/etapi/metrics?format=json") | ||||
|             .auth(USER, token, { "type": "basic"}) | ||||
|             .expect(200); | ||||
|         expect(response.headers["content-type"]).toContain("application/json"); | ||||
|         expect(response.body.version).toBeTruthy(); | ||||
|         expect(response.body.database).toBeTruthy(); | ||||
|         expect(response.body.timestamp).toBeTruthy(); | ||||
|         expect(response.body.database.totalNotes).toBeTypeOf("number"); | ||||
|         expect(response.body.database.activeNotes).toBeTypeOf("number"); | ||||
|         expect(response.body.noteTypes).toBeTruthy(); | ||||
|         expect(response.body.attachmentTypes).toBeTruthy(); | ||||
|         expect(response.body.statistics).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("returns Prometheus format explicitly", async () => { | ||||
|         const response = await supertest(app) | ||||
|             .get("/etapi/metrics?format=prometheus") | ||||
|             .auth(USER, token, { "type": "basic"}) | ||||
|             .expect(200); | ||||
|         expect(response.headers["content-type"]).toContain("text/plain"); | ||||
|         expect(response.text).toContain("trilium_info"); | ||||
|         expect(response.text).toContain("trilium_notes_total"); | ||||
|     }); | ||||
| 
 | ||||
|     it("returns error on invalid format", async() => { | ||||
|         const response = await supertest(app) | ||||
|             .get("/etapi/metrics?format=xml") | ||||
|             .auth(USER, token, { "type": "basic"}) | ||||
|             .expect(500); | ||||
|         expect(response.body.message).toContain("prometheus"); | ||||
|     }); | ||||
| 
 | ||||
|     it("should fail without authentication", async() => { | ||||
|         await supertest(app) | ||||
|             .get("/etapi/metrics") | ||||
|             .expect(401); | ||||
|     }); | ||||
| }); | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran