Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge/v0.8.6 #75

Open
wants to merge 12 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ COPY . .
RUN npm run build

# Setup process.env
ENV DRILL_ADMIN_IS_SECURE_CONNECTION=$DRILL_ADMIN_IS_SECURE_CONNECTION
ENV DRILL_ADMIN_HOST=$DRILL_ADMIN_HOST
ENV DRILL_ADMIN_USERNAME=$DRILL_ADMIN_USERNAME
ENV DRILL_ADMIN_PASSWORD=$DRILL_ADMIN_PASSWORD
ENV DRILL_ADMIN_ADDRESS=""
ENV DRILL_API_KEY=""
ENV DEBUG="drill:*"
ENV DEBUG_COLORS="true"
ENV FORCE_COLOR="3"
Expand Down
75 changes: 0 additions & 75 deletions admin.docker-compose.yml

This file was deleted.

30 changes: 0 additions & 30 deletions js-agent.docker-compose.yml

This file was deleted.

8 changes: 2 additions & 6 deletions nodemon.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,8 @@
"DEBUG_PROBES_ENABLED": "true",
"PERF_MEASUREMENT_ENABLED": "true",
"PERF_DIFFS_ENABLED": "true",
"DRILL_ADMIN_HOST": "localhost:8090",
"DRILL_ADMIN_IS_SECURE_CONNECTION": "false",
"DRILL_ADMIN_USERNAME": "user",
"DRILL_ADMIN_PASSWORD": "user",
"DEBUG_AGENT_SERVICE_CONNECTION": "true",
"DEBUG_AGENT_SERVICE_CONNECTION_MAX_ARGS_LENGTH": "400",
"DRILL_ADMIN_ADDRESS": "http://localhost:8090",
"DRILL_API_KEY": "",
"DEBUG": "drill:*",
"DEBUG_COLORS": "true",
"FORCE_COLOR": "3",
Expand Down
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions src/admin-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2020 EPAM Systems
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { AgentConfig, AstEntity, ExecClassData } from '@drill4j/test2code-types';
import axios from 'axios';

export default { sendInstance, sendClassMetadata, sendCoverage };

async function sendInstance(instanceId: string, data: AgentConfig) {
await axios.put(`/instances/${instanceId}`, JSON.stringify(data));
}

async function sendCoverage(instanceId: string, data: ExecClassData[]) {
await axios.post(
`/instances/${instanceId}/coverage`,
JSON.stringify({
execClassData: data,
}),
);
}

async function sendClassMetadata(instanceId: string, data: AstEntity[]) {
await axios.post(`/instances/${instanceId}/class-metadata`, JSON.stringify({ astEntities: data }));
}
135 changes: 81 additions & 54 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,30 @@ import cors from '@koa/cors';
import bodyParser from 'koa-bodyparser';

import responseHandler from './middleware/response.handler';

import loggerMiddleware from './middleware/logger';
import populateCtxWithPlugin from './middleware/populate.req.with.plugin';
import populateCtxWithAgent from './middleware/populate.req.with.agent';

import { Test2CodePlugin } from './services/plugin/test2code';
import { ILogger } from './util/logger';
import { AppConfig } from './app.types';

import { AgentHub } from './services/hub';
import { AgentData } from './services/agent/types';
import { AgentKey, AppConfig } from './app.types';
import AdminAPI from './admin-api';
import { AddSessionData, AgentConfig } from '@drill4j/test2code-types';
import { formatAst, formatForBackend } from 'services/plugin/test2code/processors/ast';

export class App {
public app: Koa;

private config: AppConfig;

private agentHub: AgentHub;

private middlewares: { [key: string]: Middleware };

private logger: ILogger;

constructor(config: AppConfig, agentHub: AgentHub) {
private agentKeyToConverter: { [key: string]: Test2CodePlugin } = {};

constructor(config: AppConfig) {
this.middlewares = {
populateCtxWithAgent: populateCtxWithAgent.bind(this),
responseHandler: responseHandler.bind(this),
};

this.agentHub = agentHub;
this.config = config;
this.logger = this.config.loggerProvider.getLogger('webserver');
this.app = new Koa();
Expand Down Expand Up @@ -79,54 +74,86 @@ export class App {
const router = new Router();

router.use(this.middlewares.responseHandler);
router.get('/', () => ({ message: 'JS middleware API' }));

router.get('/', () => ({ message: 'js-agent API' }));

// Accept new build data sent by js-parser
router.post('/agents/:agentId/plugins/test2code/build', async (ctx: ExtendableContext & IRouterParamContext) => {
const agentId = String(ctx.params.agentId);
const { version, groupId, data } = ctx.request.body;
const { bundleFiles, config, data: rawAstEntites } = data;
const agentKey = getAgentBuildKey(groupId, agentId, version);

// STEP#1 Send instance metadata
const agentConfig: AgentConfig = {
id: agentId,
// send build version in place of instanceId to avoid mixing up classes from different versions
instanceId: version, // TODO implement actual instanceId (Idk how yet)
// or just make _build verfsion_ the ID of the "unique classes set" (risky due to runtime code changes / differences)
buildVersion: version,
serviceGroupId: groupId || '',
agentType: 'JAVASCRIPT',
agentVersion: '',
};

// HACK figure out instanceIds
const instanceId = version;

await AdminAPI.sendInstance(instanceId, agentConfig);

// HACK to allow admin save AgentConfig data before accepting classes
// TODO remove once test2code is removed from admin
await new Promise((res, _) => setTimeout(res, 1000));

// STEP#2 Send classes metadata
const astEntities = formatForBackend(formatAst(rawAstEntites));

await AdminAPI.sendClassMetadata(instanceId, astEntities);

// STEP#4 Create coverage mapper
if (this.agentKeyToConverter[agentKey] != undefined) return;

console.log('create converter...', agentKey);
this.agentKeyToConverter[agentKey] = new Test2CodePlugin(agentKey, this.config.loggerProvider);
console.log('converter created', agentKey);
console.log('save build metadata...', agentKey);
await this.agentKeyToConverter[agentKey].saveBuildMetadata(agentKey, data);
console.log('build metadata saved', agentKey);
});

// Accept raw v8 coverage; map it to original source; send mapped coverage to Admin Backend
router.post(
'/agents/:agentId/plugins/:pluginId/build',
async (ctx: ExtendableContext & IRouterParamContext, next: Next) => {
const agentId = String(ctx.params.agentId);

const agentExists = await this.agentHub.doesAgentExist(agentId);
const { version, groupId } = ctx.request.body;
const agentData: AgentData = {
id: agentId,
instanceId: '',
buildVersion: version,
serviceGroupId: groupId || '',
agentType: 'NODEJS',
};
if (agentExists) {
const agent = this.agentHub.getAgentById(agentData.id);
await agent.updateBuildVersion(agentData);
agent.checkPluginInstanceExistence('test2code');
ctx.state.drill = {
agent,
};
} else {
const newAgent = await this.agentHub.registerAgent(agentData);
ctx.state.drill = {
agent: newAgent,
};
'/groups/:groupId/agents/:agentId/builds/:buildVersion/v8-coverage',
async (ctx: ExtendableContext & IRouterParamContext) => {
const { groupId, agentId, buildVersion } = ctx.params;
const { data, sessionId } = ctx.request.body as AddSessionData;
const agentKey = getAgentBuildKey(groupId, agentId, buildVersion);

console.log('convert coverage for', agentKey);

const converter = this.agentKeyToConverter[agentKey];
if (!converter) {
console.log('no coverter for', agentKey);
}
return next();
},
populateCtxWithPlugin,
async (ctx: ExtendableContext) => {
const { test2Code } = ctx.state.drill;
const { data, version } = ctx.request.body;
await test2Code.updateBuildInfo(version, data);
},
);

router.get(
'/agents/:agentId/build/:buildVersion/plugins/:pluginId/ast',
this.middlewares.populateCtxWithAgent,
populateCtxWithPlugin,
async (ctx: ExtendableContext & IRouterParamContext, next: Next) => {
ctx.response.body = await ctx.state.drill.test2Code.getAst(ctx.params.buildVersion);
const coverage = await converter.convertV8Coverage(agentKey, data, sessionId);

// HACK figure out instanceIds
const instanceId = buildVersion;
await AdminAPI.sendCoverage(instanceId, coverage);
},
);

this.app.use(router.routes());
}
}

// TODO make groupId required; w/o default
export function getAgentBuildKey(groupId: string = '', agentId: string, buildVersion: string): AgentKey {
return `${groupId}_${agentId}_${buildVersion}` as AgentKey;
}

export function agentConfigToBuildKey(agentConfig: AgentConfig): AgentKey {
const { serviceGroupId: groupId, id: agentId, buildVersion } = agentConfig;
return getAgentBuildKey(groupId, agentId, buildVersion);
}
9 changes: 3 additions & 6 deletions src/app.types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,11 @@
* limitations under the License.
*/
import { ILoggerProvider } from './util/logger';
import { Agent } from './services/agent';
import { Test2CodePlugin } from './services/plugin/test2code';

declare module 'koa' {
interface ExtendableContext {
state: {
drill: {
agent: Agent;
test2Code?: Test2CodePlugin;
};
drill: {};
};
}
}
Expand All @@ -36,3 +31,5 @@ export interface AppConfig {
};
loggerProvider: ILoggerProvider;
}

export type AgentKey = Opaque<'AgentKey', string>;
Loading