From b8523430db1e5e23e326b80809d6360f3c601546 Mon Sep 17 00:00:00 2001 From: Ben West Date: Thu, 19 Mar 2026 17:31:31 -0700 Subject: [PATCH] test: add regression test proving #6923 legacy UUID data bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inserts a treatment directly into MongoDB with UUID as _id (no identifier field) — the shape of overrides created before normalizeTreatmentId(). All 3 tests fail as expected: - DELETE: responds 200 but deletedCount=0 (silent no-op) - PUT: creates duplicate document instead of updating in place - GET: returns 0 results (query rewrite misses legacy doc) These tests document the legacy data gap and will pass once updateIdQuery() is updated to use a $or fallback: {identifier: UUID} || {_id: UUID}. Relates to: #6923, #8450 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/issue-6923-legacy-uuid.test.js | 180 +++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 tests/issue-6923-legacy-uuid.test.js diff --git a/tests/issue-6923-legacy-uuid.test.js b/tests/issue-6923-legacy-uuid.test.js new file mode 100644 index 00000000..496a6b89 --- /dev/null +++ b/tests/issue-6923-legacy-uuid.test.js @@ -0,0 +1,180 @@ +'use strict'; + +/** + * Legacy UUID Data Test: Issue #6923 Reproduction + * + * ISSUE: https://github.com/nightscout/cgm-remote-monitor/issues/6923 + * + * This test verifies behavior when a Temporary Override with a UUID _id + * was created BEFORE the normalizeTreatmentId() fix. Such documents have + * the UUID directly in _id with no identifier field. + * + * The test inserts a legacy-shaped document directly into MongoDB + * (bypassing normalizeTreatmentId) and then exercises the API + * DELETE and PUT paths that a user would trigger from Reports > Treatments. + * + * EXPECTED RESULT: These tests FAIL, proving the legacy data bug. + * When all tests pass, the bug is fixed. + */ + +const request = require('supertest'); +const should = require('should'); +const language = require('../lib/language')(); + +describe('Issue #6923: Legacy UUID override edit/delete', function () { + this.timeout(30000); + const self = this; + + const api_secret_hash = 'b723e97aa97846eb92d5264f084b2823f57c4aa1'; + + const LEGACY_UUID = '69F15FD2-8075-4DEB-AEA3-4352F455840D'; + const LEGACY_OVERRIDE = { + _id: LEGACY_UUID, + eventType: 'Temporary Override', + created_at: '2026-02-17T02:00:16.000Z', + timestamp: '2026-02-17T02:00:16Z', + durationType: 'indefinite', + correctionRange: [90, 110], + insulinNeedsScaleFactor: 1.2, + reason: 'Legacy Override', + enteredBy: 'Loop', + utcOffset: 0 + }; + + before(function (done) { + process.env.API_SECRET = 'this is my long pass phrase'; + self.env = require('../lib/server/env')(); + self.env.settings.authDefaultRoles = 'readable'; + self.env.settings.enable = ['careportal', 'api']; + const wares = require('../lib/middleware/')(self.env); + self.app = require('express')(); + self.app.enable('api'); + require('../lib/server/bootevent')(self.env, language).boot(function booted (ctx) { + self.ctx = ctx; + self.ctx.wares = wares; + self.ctx.ddata = require('../lib/data/ddata')(); + self.app.use('/api', require('../lib/api/')(self.env, ctx)); + done(); + }); + }); + + function rawCollection () { + return self.ctx.store.collection(self.env.treatments_collection); + } + + beforeEach(function (done) { + rawCollection().deleteMany({}, function () { + done(); + }); + }); + + /** + * Insert a legacy-shaped document directly into MongoDB, + * bypassing normalizeTreatmentId(). UUID in _id, no identifier field. + */ + function insertLegacyDoc (callback) { + var doc = Object.assign({}, LEGACY_OVERRIDE); + rawCollection().insertOne(doc, function (err) { + should.not.exist(err); + rawCollection().findOne({ _id: LEGACY_UUID }, function (err, stored) { + should.not.exist(err); + should.exist(stored, 'Legacy doc should exist after direct insert'); + stored._id.should.equal(LEGACY_UUID); + should.not.exist(stored.identifier, 'Legacy doc must NOT have identifier field'); + callback(stored); + }); + }); + } + + describe('DELETE legacy UUID override via API', function () { + + it('DELETE /api/v1/treatments/:uuid should actually remove the legacy document', function (done) { + insertLegacyDoc(function () { + request(self.app) + .delete('/api/treatments/' + LEGACY_UUID) + .set('api-secret', api_secret_hash) + .end(function (err, res) { + should.not.exist(err); + should.exist(res.body); + var deletedCount = res.body.deletedCount || 0; + + deletedCount.should.be.above(0, + 'DELETE responded 200 but deletedCount is 0. ' + + 'The query layer rewrites {_id: UUID} to {identifier: UUID}, ' + + 'but the legacy document has no identifier field, so deleteMany matches nothing. ' + + 'The override silently persists in the database.' + ); + done(); + }); + }); + }); + }); + + describe('PUT (edit/save) legacy UUID override via API', function () { + + it('PUT /api/v1/treatments/ with UUID _id should update in place, not create a duplicate', function (done) { + insertLegacyDoc(function () { + var updated = Object.assign({}, LEGACY_OVERRIDE, { + reason: 'Edited Override', + insulinNeedsScaleFactor: 1.5 + }); + + // Fire PUT request — the HTTP response may hang due to data-received + // event processing, but the DB write completes immediately. + request(self.app) + .put('/api/treatments/') + .set('api-secret', api_secret_hash) + .send(updated) + .end(function () { /* response may never arrive; ignore */ }); + + // Check the database after the server has had time to process the upsert + setTimeout(function () { + rawCollection().find({ eventType: 'Temporary Override' }).toArray(function (err, docs) { + try { + should.not.exist(err); + + docs.length.should.equal(1, + 'PUT should update the existing legacy override, not create a duplicate. ' + + 'Found ' + docs.length + ' documents. ' + + 'normalizeTreatmentId promotes UUID to identifier, then upsertQueryFor ' + + 'matches by identifier -- which the legacy doc lacks -- so MongoDB ' + + 'inserts a NEW document instead of updating the original.' + ); + + done(); + } catch (e) { + done(e); + } + }); + }, 5000); + }); + }); + }); + + describe('GET legacy UUID override via API', function () { + + it('GET /api/v1/treatments/?find[_id]=UUID should find the legacy document', function (done) { + insertLegacyDoc(function () { + request(self.app) + .get('/api/treatments/') + .set('api-secret', api_secret_hash) + .query('find[_id]=' + LEGACY_UUID) + .end(function (err, res) { + res.status.should.equal(200, + 'GET with UUID _id should return 200, not ' + res.status + '. ' + + 'HTTP 500 means the query layer crashes on UUID _id (issue #6923).' + ); + + res.body.should.be.an.Array(); + res.body.length.should.equal(1, + 'GET should find the legacy override when querying by UUID _id. ' + + 'The query rewrite changes {_id: UUID} to {identifier: UUID}, ' + + 'but legacy docs have no identifier field, so 0 results returned.' + ); + + done(); + }); + }); + }); + }); +});