PageRenderTime 22ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/packages/backend-common/src/reading/BitbucketServerUrlReader.test.ts

https://github.com/backstage/backstage
TypeScript | 184 lines | 150 code | 19 blank | 15 comment | 4 complexity | 54622c87cc08f283b345d8fd3a5b534a MD5 | raw file
Possible License(s): Apache-2.0, MIT, BSD-3-Clause, MPL-2.0-no-copyleft-exception
  1. /*
  2. * Copyright 2020 The Backstage Authors
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import { ConfigReader } from '@backstage/config';
  17. import {
  18. BitbucketServerIntegration,
  19. readBitbucketServerIntegrationConfig,
  20. } from '@backstage/integration';
  21. import { setupRequestMockHandlers } from '@backstage/backend-test-utils';
  22. import fs from 'fs-extra';
  23. import mockFs from 'mock-fs';
  24. import { rest } from 'msw';
  25. import { setupServer } from 'msw/node';
  26. import os from 'os';
  27. import path from 'path';
  28. import { NotModifiedError } from '@backstage/errors';
  29. import { BitbucketServerUrlReader } from './BitbucketServerUrlReader';
  30. import { DefaultReadTreeResponseFactory } from './tree';
  31. const treeResponseFactory = DefaultReadTreeResponseFactory.create({
  32. config: new ConfigReader({}),
  33. });
  34. const reader = new BitbucketServerUrlReader(
  35. new BitbucketServerIntegration(
  36. readBitbucketServerIntegrationConfig(
  37. new ConfigReader({
  38. host: 'bitbucket.mycompany.net',
  39. apiBaseUrl: 'https://api.bitbucket.mycompany.net/rest/api/1.0',
  40. }),
  41. ),
  42. ),
  43. { treeResponseFactory },
  44. );
  45. const tmpDir = os.platform() === 'win32' ? 'C:\\tmp' : '/tmp';
  46. describe('BitbucketServerUrlReader', () => {
  47. beforeEach(() => {
  48. mockFs({
  49. [tmpDir]: mockFs.directory(),
  50. });
  51. });
  52. afterEach(() => {
  53. mockFs.restore();
  54. });
  55. const worker = setupServer();
  56. setupRequestMockHandlers(worker);
  57. describe('readTree', () => {
  58. const repoBuffer = fs.readFileSync(
  59. path.resolve(__dirname, '__fixtures__/bitbucket-server-repo.tar.gz'),
  60. );
  61. beforeEach(() => {
  62. worker.use(
  63. rest.get(
  64. 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/archive',
  65. (_, res, ctx) =>
  66. res(
  67. ctx.status(200),
  68. ctx.set('Content-Type', 'application/zip'),
  69. ctx.set(
  70. 'content-disposition',
  71. 'attachment; filename=backstage-mock.tgz',
  72. ),
  73. ctx.body(repoBuffer),
  74. ),
  75. ),
  76. rest.get(
  77. 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/commits',
  78. (_, res, ctx) =>
  79. res(
  80. ctx.status(200),
  81. ctx.json({
  82. values: [{ id: '12ab34cd56ef78gh90ij12kl34mn56op78qr90st' }],
  83. }),
  84. ),
  85. ),
  86. );
  87. });
  88. it('uses private bitbucket host', async () => {
  89. const response = await reader.readTree(
  90. 'https://bitbucket.mycompany.net/projects/backstage/repos/mock/browse/docs?at=some-branch',
  91. );
  92. expect(response.etag).toBe('12ab34cd56ef');
  93. const files = await response.files();
  94. expect(files.length).toBe(1);
  95. const indexMarkdownFile = await files[0].content();
  96. expect(indexMarkdownFile.toString()).toBe('# Test\n');
  97. });
  98. });
  99. describe('search private', () => {
  100. const repoBuffer = fs.readFileSync(
  101. path.resolve(__dirname, '__fixtures__/bitbucket-server-repo.tar.gz'),
  102. );
  103. beforeEach(() => {
  104. worker.use(
  105. rest.get(
  106. 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/archive',
  107. (_, res, ctx) =>
  108. res(
  109. ctx.status(200),
  110. ctx.set('Content-Type', 'application/zip'),
  111. ctx.set(
  112. 'content-disposition',
  113. 'attachment; filename=backstage-mock.tgz',
  114. ),
  115. ctx.body(repoBuffer),
  116. ),
  117. ),
  118. rest.get(
  119. 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/commits',
  120. (_, res, ctx) =>
  121. res(
  122. ctx.status(200),
  123. ctx.json({
  124. values: [{ id: '12ab34cd56ef78gh90ij12kl34mn56op78qr90st' }],
  125. }),
  126. ),
  127. ),
  128. );
  129. });
  130. it('works for the naive case', async () => {
  131. const result = await reader.search(
  132. 'https://bitbucket.mycompany.net/projects/backstage/repos/mock/browse/**/index.*?at=master',
  133. );
  134. expect(result.etag).toBe('12ab34cd56ef');
  135. expect(result.files.length).toBe(1);
  136. expect(result.files[0].url).toBe(
  137. 'https://bitbucket.mycompany.net/projects/backstage/repos/mock/browse/docs/index.md?at=master',
  138. );
  139. await expect(result.files[0].content()).resolves.toEqual(
  140. Buffer.from('# Test\n'),
  141. );
  142. });
  143. it('works in nested folders', async () => {
  144. const result = await reader.search(
  145. 'https://bitbucket.mycompany.net/projects/backstage/repos/mock/browse/docs/index.*?at=master',
  146. );
  147. expect(result.etag).toBe('12ab34cd56ef');
  148. expect(result.files.length).toBe(1);
  149. expect(result.files[0].url).toBe(
  150. 'https://bitbucket.mycompany.net/projects/backstage/repos/mock/browse/docs/index.md?at=master',
  151. );
  152. await expect(result.files[0].content()).resolves.toEqual(
  153. Buffer.from('# Test\n'),
  154. );
  155. });
  156. it('throws NotModifiedError when same etag', async () => {
  157. await expect(
  158. reader.search(
  159. 'https://bitbucket.mycompany.net/projects/backstage/repos/mock/browse/**/index.*?at=master',
  160. { etag: '12ab34cd56ef' },
  161. ),
  162. ).rejects.toThrow(NotModifiedError);
  163. });
  164. });
  165. });