Skip to content

Commit

Permalink
feat(rhelServices, redux): issues/17 rhsm api, and mock (#27)
Browse files Browse the repository at this point in the history
* build, dotenv rhsm api endpoint
* build, scripts and temporary rhsm swagger for local doc run
* rhelServices, implement rhsm endpoint, mock added
* redux, action, reducer, types
* unit tests, snapshots
  • Loading branch information
cdcabrera authored Jul 1, 2019
1 parent 4949cd0 commit 4641c5b
Show file tree
Hide file tree
Showing 12 changed files with 388 additions and 42 deletions.
3 changes: 2 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ REACT_APP_CONFIG_SERVICE_LOCALES=./locales/locales.json
REACT_APP_CONFIG_SERVICE_LOCALES_PATH=./locales/{{lng}}.json
REACT_APP_CONFIG_SERVICE_LOCALES_EXPIRE=604800000

REACT_APP_SERVICES_CLOUDMETER_REPORT=/api/cloudigrade/v2/concurrent/
REACT_APP_SERVICES_CLOUDMETER_REPORT_RHEL=/api/cloudigrade/v2/concurrent/
REACT_APP_SERVICES_RHSM_REPORT_RHEL=/api/rhsm-subscriptions/v1/tally/accounts/{0}/products/RHEL
3 changes: 2 additions & 1 deletion .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ PUBLIC_URL=/
REACT_APP_INCLUDE_CONTENT_HEADER=<!-- esi:include placeholder -->
REACT_APP_INCLUDE_CONTENT_BODY=<div id="root"></div>

REACT_APP_SERVICES_CLOUDMETER_REPORT=http://localhost:5000/api/cloudigrade/v2/concurrent/
REACT_APP_SERVICES_CLOUDMETER_REPORT_RHEL=http://localhost:5000/api/cloudigrade/v2/concurrent/
REACT_APP_SERVICES_RHSM_REPORT_RHEL=http://localhost:5000/api/rhsm-subscriptions/v1/tally/accounts/{0}/products/RHEL
201 changes: 201 additions & 0 deletions docs/rhsm-subscriptions-api-spec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
openapi: "3.0.2"
info:
title: "rhsm-subscriptions-api"
description: "REST interface for the rhsm-subscriptions service."
version: 1.0.0

servers:
- url: http://localhost:8080/api/rhsm-subscriptions/v1
- url: https://ci.cloud.paas.upshift.redhat.com/api/rhsm-subscriptions/v1
- url: https://qa.cloud.paas.upshift.redhat.com/api/rhsm-subscriptions/v1
- url: https://stage.cloud.paas.upshift.redhat.com/api/rhsm-subscriptions/v1
- url: https://cloud.redhat.com/api/rhsm-subscriptions/v1

paths:
/tally/accounts/{account_number}/products/{product_id}:
description: "Operations for a tally report of a specific account and product."
parameters:
- name: x-rh-identity
in: header
required: true
schema:
type: string
format: byte
description: "Identity header provided by 3Scale."
- name: account_number
in: path
required: true
schema:
type: string
description: "Account number to fetch data for. Must match the authenticated account number."
- name: product_id
in: path
required: true
schema:
type: string
description: "The ID for the product we wish to query"
get:
summary: "Fetch a tally report for an account and product."
operationId: getTallyReport
parameters:
- name: granularity
in: query
required: true
schema:
type: string
description: "The level of granularity to return."
- name: beginning
in: query
required: false
schema:
type: string
format: date-time
description: "Defines the start of the report period. Dates should be provided in ISO 8601
format but the only accepted offset is UTC. E.g. 2017-07-21T17:32:28Z"
- name: ending
in: query
required: false
schema:
type: string
format: date-time
description: "Defines the end of the report period. Defaults to the current time. Dates should
be provided in UTC."
responses:
'200':
description: 'The request for a tally report was successful.'
content:
application/vnd.api+json:
schema:
$ref: "#/components/schemas/TallyReport"
'400':
$ref: '#/components/responses/BadRequest'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/ResourceNotFound'
'500':
$ref: '#/components/responses/InternalServerError'
tags:
- tally
/openapi.json:
get:
description: "Get the OpenAPI spec in JSON format."
operationId: getOpenApiJson
tags:
- root
responses:
'200':
description: "The request to get the OpenAPI JSON was successful."
content:
application/json:
schema:
type: string
/openapi.yaml:
get:
description: "Get the OpenAPI spec in YAML format."
operationId: getOpenApiYaml
tags:
- root
responses:
'200':
description: "The request to get the OpenAPI YAML was successful."
content:
application/x-yaml:
schema:
type: string

components:
responses:
InternalServerError:
description: "An internal server error has occurred and is not recoverable."
content:
application/vnd.api+json:
schema:
$ref: "#/components/schemas/Errors"
BadRequest:
description: "The server could could not process the current request."
content:
application/vnd.api+json:
schema:
$ref: "#/components/schemas/Errors"
Forbidden:
description: "The request was valid, but the request was refused by the server."
content:
application/vnd.api+json:
schema:
$ref: "#/components/schemas/Errors"
ResourceNotFound:
description: "The requested resource was not found."
content:
application/vnd.api+json:
schema:
$ref: "#/components/schemas/Errors"
ServiceUnavailable:
description: "The server is currently unavailable."
content:
application/vnd.api+json:
schema:
$ref: "#/components/schemas/Errors"

schemas:
TallyReport:
properties:
product:
type: string
granularity:
description: "Describes the significance of each date in the TallySnapshot list. For example if the
granularity is set to 'weekly', the dates in the TallySnapshot list will represent the start of a
seven day period."
type: string
tally_snapshots:
type: array
items:
$ref: "#/components/schemas/TallySnapshot"

TallySnapshot:
# Container for fields we capture from the IT endpoint for upload to inventory service. The element
# being reported should be the only non-required element. E.g. snapshots containing memory will have
# date, instance count, and memory elements while snapshots containing cores will contain date,
# instance count, and cores.
required:
- date
- instance_count
properties:
date:
type: string
format: date-time
description: "The start date for this snapshot entry. Dates are returned in UTC. Clients must
consult the 'granularity' field in the TallyReport to determine the length of time each
TallySnapshot covers."
instance_count:
type: integer
format: int32
minimum: 0
cores:
type: integer
format: int32
minimum: 0

Errors:
required:
- errors
properties:
errors:
type: array
items:
$ref: "#/components/schemas/Error"

Error:
required:
- status
- code
- title
properties:
status:
type: string
code:
type: string
title:
type: string
detail:
type: string
28 changes: 18 additions & 10 deletions scripts/openapi.docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');
const openApiSpecs = [
{
file:
'https://raw.githubusercontent.com/RedHatInsights/rhsm-subscriptions/master/api/rhsm-subscriptions-api-spec.yaml',
outputDir: `${process.cwd()}/.openapi`,
outputFileName: 'rhsm.yaml',
file: `${process.cwd()}/docs/rhsm-subscriptions-api-spec.yaml`,
port: 5050
}
];
Expand All @@ -26,7 +23,9 @@ const serveDocs = (files = []) => {

app.listen(yamlFile.port, () => {
console.log(
`\nYou can now view API docs in the browser.\n Open: http://localhost:${yamlFile.port}/docs/api\n`
`\nYou can now view API docs for ${yamlFile.file
.split('/')
.pop()} in the browser.\n Open: http://localhost:${yamlFile.port}/docs/api\n`
);
});
} else if (cache.tryAgainCount < 10) {
Expand All @@ -45,21 +44,30 @@ const getLocalApiSpec = (inputPaths = []) => {
const outputPaths = [];

inputPaths.forEach(inputPath => {
const outputPath = path.join(inputPath.outputDir, inputPath.outputFileName);
if (/^http/i.test(inputPath.file)) {
const outputPath = path.join(inputPath.outputDir, inputPath.outputFileName);
const outputYaml = execSync(`curl ${inputPath.file}`);

if (fs.existsSync(outputPath)) {
outputPaths.push({ file: outputPath, port: inputPath.port });
} else {
if (!fs.existsSync(inputPath.outputDir)) {
fs.mkdirSync(inputPath.outputDir);
}

execSync(`curl ${inputPath.file} > ${outputPath}`);
if (/openapi/i.test(outputYaml.toString())) {
fs.writeFileSync(outputPath, outputYaml);
} else {
console.warn(
`Unable to load ${inputPath.file.split('/').pop()} -> ${inputPath.outputFileName}, checking cache...`
);
}

outputPaths.push({ file: outputPath, port: inputPath.port });
} else {
outputPaths.push({ file: inputPath.file, port: inputPath.port });
}
});

console.log(outputPaths);

return outputPaths;
};

Expand Down
2 changes: 1 addition & 1 deletion src/redux/actions/__tests__/rhelActions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('RhelActions', () => {
status: 200,
response: {
test: 'success',
[rhelApiTypes.CLOUDIGRADE_API_RESPONSE_CONCURRENT_DATA]: ['success']
[rhelApiTypes.RHSM_API_RESPONSE_ACCOUNTS_PRODUCTS_DATA]: ['success']
}
});
});
Expand Down
2 changes: 1 addition & 1 deletion src/redux/actions/rhelActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import rhelServices from '../../services/rhelServices';
const getGraphReports = () => dispatch =>
dispatch({
type: rhelTypes.GET_GRAPH_REPORT,
payload: rhelServices.getGraphReports()
payload: rhelServices.getGraphReportsRhsm()
});

export { getGraphReports as default, getGraphReports };
2 changes: 1 addition & 1 deletion src/redux/reducers/rhelGraphReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const rhelGraphReducer = (state = initialState, action) => {
null,
{
graphData: {
dailyUsage: action.payload.data[rhelApiTypes.CLOUDIGRADE_API_RESPONSE_CONCURRENT_DATA] || []
dailyUsage: action.payload.data[rhelApiTypes.RHSM_API_RESPONSE_ACCOUNTS_PRODUCTS_DATA] || []
},
fulfilled: true
},
Expand Down
7 changes: 4 additions & 3 deletions src/services/__tests__/rhelServices.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ describe('RhelServices', () => {
beforeEach(() => {
moxios.install();

moxios.stubRequest(/\/cloudigrade.*?/, {
moxios.stubRequest(/\/(cloudigrade|tally).*?/, {
status: 200,
responseText: 'success',
timeout: 1
Expand All @@ -17,11 +17,12 @@ describe('RhelServices', () => {
});

it('should export a specific number of methods and classes', () => {
expect(Object.keys(rhelServices)).toHaveLength(1);
expect(Object.keys(rhelServices)).toHaveLength(2);
});

it('should have specific methods', () => {
expect(rhelServices.getGraphReports).toBeDefined();
expect(rhelServices.getGraphReportsCm).toBeDefined();
expect(rhelServices.getGraphReportsRhsm).toBeDefined();
});

it('should return promises for every method', done => {
Expand Down
2 changes: 1 addition & 1 deletion src/services/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const authHeader = () => {
};
};

const serviceConfig = (passedConfig = {}, auth = true) =>
const serviceConfig = (passedConfig = {}, auth = false) =>
Object.assign(
{
headers: auth ? authHeader() : {},
Expand Down
Loading

0 comments on commit 4641c5b

Please sign in to comment.