Skip to content

Commit

Permalink
fix(commands): fix regression due to changes to test|task result output
Browse files Browse the repository at this point in the history
  • Loading branch information
eysi09 authored and thsig committed Oct 2, 2019
1 parent b730377 commit 71e204d
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 143 deletions.
36 changes: 23 additions & 13 deletions dashboard/src/api/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import { groupBy } from "lodash"

import { ServiceLogEntry } from "garden-service/build/src/types/plugin/service/getServiceLogs"
import { StatusCommandResult } from "garden-service/build/src/commands/get/get-status"
import { TaskResultOutput } from "garden-service/build/src/commands/get/get-task-result"
import { GetTaskResultCommandResult } from "garden-service/build/src/commands/get/get-task-result"
import { ConfigDump } from "garden-service/build/src/garden"
import { TestResultOutput } from "garden-service/build/src/commands/get/get-test-result"
import { GetTestResultCommandResult } from "garden-service/build/src/commands/get/get-test-result"
import { GraphOutput } from "garden-service/build/src/commands/get/get-graph"
import {
Entities,
Expand All @@ -33,6 +33,7 @@ import {
FetchTaskResultParams,
FetchTestResultParams,
} from "./api"
import { getTestKey } from "../util/helpers"

/**
* This file contains the API action functions.
Expand Down Expand Up @@ -86,7 +87,8 @@ function processConfig(entities: Entities, config: ConfigDump) {
}
}
for (const testConfig of cfg.testConfigs) {
const testKey = `${cfg.name}.${testConfig.name}`
// Test names are not unique so we store the data under a unique test key
const testKey = getTestKey({ testName: testConfig.name, moduleName: cfg.name })
tests[testKey] = {
...tests[testKey],
config: testConfig,
Expand Down Expand Up @@ -184,7 +186,7 @@ export async function loadTaskResult({ dispatch, ...fetchParams }: LoadTaskResul

dispatch({ requestKey, type: "fetchStart" })

let res: TaskResultOutput
let res: GetTaskResultCommandResult
try {
res = await fetchTaskResult(fetchParams)
} catch (error) {
Expand All @@ -197,11 +199,14 @@ export async function loadTaskResult({ dispatch, ...fetchParams }: LoadTaskResul
dispatch({ type: "fetchSuccess", requestKey, processResults })
}

function processTaskResult(entities: Entities, result: TaskResultOutput) {
function processTaskResult(entities: Entities, result: GetTaskResultCommandResult) {
return produce(entities, draft => {
draft.tasks = draft.tasks || {}
draft.tasks[result.name] = draft.tasks[result.name] || {}
draft.tasks[result.name].result = result
if (result) {
draft.tasks[result.taskName] = {
...draft.tasks[result.taskName],
result,
}
}
})
}

Expand All @@ -214,7 +219,7 @@ export async function loadTestResult({ dispatch, ...fetchParams }: LoadTestResul

dispatch({ requestKey, type: "fetchStart" })

let res: TestResultOutput
let res: GetTestResultCommandResult
try {
res = await fetchTestResult(fetchParams)
} catch (error) {
Expand All @@ -227,11 +232,16 @@ export async function loadTestResult({ dispatch, ...fetchParams }: LoadTestResul
dispatch({ type: "fetchSuccess", requestKey, processResults })
}

function processTestResult(entities: Entities, result: TestResultOutput) {
function processTestResult(entities: Entities, result: GetTestResultCommandResult) {
return produce(entities, draft => {
draft.tests = draft.tests || {}
draft.tests[result.name] = draft.tests[result.name] || {}
draft.tests[result.name].result = result
if (result) {
// Test names are not unique so we store the data under a unique test key
const testKey = getTestKey({ testName: result.testName, moduleName: result.moduleName })
draft.tests[testKey] = {
...draft.tests[testKey],
result,
}
}
})
}

Expand Down
10 changes: 5 additions & 5 deletions dashboard/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import axios from "axios"

import { GraphOutput } from "garden-service/build/src/commands/get/get-graph"
import { TaskResultOutput } from "garden-service/build/src/commands/get/get-task-result"
import { TestResultOutput } from "garden-service/build/src/commands/get/get-test-result"
import { GetTaskResultCommandResult } from "garden-service/build/src/commands/get/get-task-result"
import { GetTestResultCommandResult } from "garden-service/build/src/commands/get/get-test-result"
import { ServiceLogEntry } from "garden-service/build/src/types/plugin/service/getServiceLogs"
import { CommandResult } from "garden-service/build/src/commands/base"
import { ConfigDump } from "garden-service/build/src/garden"
Expand Down Expand Up @@ -49,7 +49,7 @@ export interface FetchTaskResultParams {
}

export async function fetchTaskResult(params: FetchTaskResultParams) {
return apiPost<TaskResultOutput>("get.task-result", params)
return apiPost<GetTaskResultCommandResult>("get.task-result", params)
}

export interface FetchTestResultParams {
Expand All @@ -58,7 +58,7 @@ export interface FetchTestResultParams {
}

export async function fetchTestResult({ name, moduleName }: FetchTestResultParams) {
return apiPost<TestResultOutput>("get.test-result", { name, module: moduleName })
return apiPost<GetTestResultCommandResult>("get.test-result", { name, module: moduleName })
}

async function apiPost<T>(command: string, parameters: {} = {}): Promise<T> {
Expand All @@ -73,7 +73,7 @@ async function apiPost<T>(command: string, parameters: {} = {}): Promise<T> {
throw res.data.errors
}

if (!res.data.result) {
if (res.data.result === undefined) {
throw new Error("Empty response from server")
}

Expand Down
39 changes: 29 additions & 10 deletions dashboard/src/api/ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
Action,
SupportedEventName,
supportedEventNames,
TaskState,
taskStates,
} from "../contexts/api"
import getApiUrl from "./get-api-url"
import produce from "immer"
Expand All @@ -24,11 +26,25 @@ export type WsEventMessage = ServerWebsocketMessage & {
payload: Events[SupportedEventName],
}

interface TaskStateChangeEventMessage {
type: "event"
name: TaskState
payload: Events[TaskState]
}

/**
* Type guard to check whether websocket message is a type supported by the Dashboard
*/
export function isSupportedEvent(data: ServerWebsocketMessage): data is WsEventMessage {
return data.type === "event" && supportedEventNames.has((data as WsEventMessage).name)
export function isSupportedEvent(msg: ServerWebsocketMessage): msg is WsEventMessage {
return msg.type === "event" && supportedEventNames.has((msg as WsEventMessage).name)
}

/**
* Type guard to check whether the websocket event is for a task state change that is handled
* by the Dashboard.
*/
export function isTaskStateChangeEvent(msg: WsEventMessage): msg is TaskStateChangeEventMessage {
return taskStates.includes(msg.name)
}

export function initWebSocket(dispatch: React.Dispatch<Action>) {
Expand Down Expand Up @@ -58,14 +74,14 @@ export function initWebSocket(dispatch: React.Dispatch<Action>) {

// Process the graph response and return a normalized store
function processWebSocketMessage(store: Entities, message: WsEventMessage) {
const taskType = message.payload["type"] === "task" ? "run" : message.payload["type"] // convert "task" to "run"
const taskState = message.name
const entityName = message.payload["name"]
return produce(store, draft => {
// We don't handle taskGraphComplete events
if (taskType && taskState !== "taskGraphComplete") {
if (isTaskStateChangeEvent(message)) {
const taskState = message.name
const payload = message.payload
const entityName = payload.name

draft.project.taskGraphProcessing = true
switch (taskType) {
switch (payload.type) {
case "publish":
break
case "deploy":
Expand All @@ -87,6 +103,10 @@ function processWebSocketMessage(store: Entities, message: WsEventMessage) {
}
break
case "test":
// Note that the task payload name for tests has the same format that we use in the
// store. So there's no need to use getTestKey here.
// FIXME: We need to make this more robust, although it will resolve itself when we implement
// https://github.com/garden-io/garden/issues/1177.
draft.tests[entityName] = {
...store.tests[entityName],
taskState,
Expand All @@ -95,8 +115,7 @@ function processWebSocketMessage(store: Entities, message: WsEventMessage) {
}
}

// add to requestState graph whenever its taskGraphComplete
if (taskState === "taskGraphComplete") {
if (message.name === "taskGraphComplete") {
draft.project.taskGraphProcessing = false
}
})
Expand Down
17 changes: 10 additions & 7 deletions dashboard/src/containers/entity-result.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,28 @@

import React, { useEffect } from "react"
import { useApi } from "../contexts/api"
import { getDuration } from "../util/helpers"
import { getDuration, getTestKey } from "../util/helpers"
import EntityResult from "../components/entity-result"
import { TaskResultOutput } from "garden-service/build/src/commands/get/get-task-result"
import { TestResultOutput } from "garden-service/build/src/commands/get/get-test-result"
import { ErrorNotification } from "../components/notifications"
import { EntityResultSupportedTypes } from "../contexts/ui"
import { loadTestResult, loadTaskResult } from "../api/actions"
import { RunResult } from "garden-service/build/src/types/plugin/base"

const ErrorMsg = ({ error, type }) => (
<ErrorNotification>
Error occured while trying to get {type} result: {error.message}
</ErrorNotification>
)

function prepareData(data: TestResultOutput | TaskResultOutput) {
function prepareData(data: RunResult) {
const startedAt = data.startedAt
const completedAt = data.completedAt
const duration =
startedAt &&
completedAt &&
getDuration(startedAt, completedAt)

const output = data.output
const output = data.log
return { duration, startedAt, completedAt, output }
}

Expand All @@ -50,11 +49,13 @@ export default ({ name, moduleName, type, onClose }: Props) => {
const {
dispatch,
store: {
entities: { tasks, tests },
entities,
requestStates,
},
} = useApi()

const { tasks, tests } = entities

const loadResults = () => {
if (type === "test") {
loadTestResult({ dispatch, name, moduleName })
Expand All @@ -66,7 +67,9 @@ export default ({ name, moduleName, type, onClose }: Props) => {
useEffect(loadResults, [name, moduleName])

if (type === "test") {
const testResult = tests && tests[name] && tests[name].result
const testKey = getTestKey({ moduleName, testName: name })

const testResult = tests && tests[testKey] && tests[testKey].result

if (requestStates.testResult.error) {
return <ErrorMsg error={requestStates.testResult.error} type={type} />
Expand Down
8 changes: 6 additions & 2 deletions dashboard/src/containers/graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { RenderedNode } from "garden-service/build/src/config-graph"
import { GraphOutput } from "garden-service/build/src/commands/get/get-graph"
import { loadGraph } from "../api/actions"
import { useConfig } from "../util/hooks"
import { getTestKey } from "../util/helpers"

const Wrapper = styled.div`
padding-left: .75rem;
Expand All @@ -40,11 +41,13 @@ export default () => {
const {
dispatch,
store: {
entities: { project, modules, services, tests, tasks, graph },
entities,
requestStates,
},
} = useApi()

const { project, modules, services, tests, tasks, graph } = entities

const {
actions: { selectGraphNode, stackGraphToggleItemsView, clearGraphNodeSelection },
state: { selectedGraphNode, isSidebarOpen, stackGraph: { filters } },
Expand Down Expand Up @@ -83,7 +86,8 @@ export default () => {
taskState = (tasks[node.name] && tasks[node.name].taskState) || taskState
break
case "test":
taskState = (tests[node.name] && tests[node.name].taskState) || taskState
const testKey = getTestKey({ testName: node.name, moduleName: node.moduleName })
taskState = (tests[testKey] && tests[testKey].taskState) || taskState
break
}
return { ...node, status: taskState }
Expand Down
16 changes: 12 additions & 4 deletions dashboard/src/contexts/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import { PickFromUnion } from "garden-service/build/src/util/util"
import { ServiceConfig } from "garden-service/build/src/config/service"
import { RunStatus } from "garden-service/build/src/commands/get/get-status"
import { TaskConfig } from "garden-service/build/src/config/task"
import { TaskResultOutput } from "garden-service/build/src/commands/get/get-task-result"
import { TestResultOutput } from "garden-service/build/src/commands/get/get-test-result"
import { GetTaskResultCommandResult } from "garden-service/build/src/commands/get/get-task-result"
import { GetTestResultCommandResult } from "garden-service/build/src/commands/get/get-test-result"
import { TestConfig } from "garden-service/build/src/config/test"
import { EventName } from "garden-service/build/src/events"
import { EnvironmentStatusMap } from "garden-service/build/src/types/plugin/provider/getEnvironmentStatus"
Expand Down Expand Up @@ -52,17 +52,25 @@ export type TaskState = PickFromUnion<SupportedEventName,
"taskCancelled"
>

export const taskStates = [
"taskComplete",
"taskError",
"taskPending",
"taskProcessing",
"taskCancelled",
]

export interface Test {
config: TestConfig,
status: RunStatus,
result: TestResultOutput,
result: GetTestResultCommandResult,
taskState: TaskState, // State of the test task for the module
}

export interface Task {
config: TaskConfig,
status: RunStatus,
result: TaskResultOutput,
result: GetTaskResultCommandResult,
taskState: TaskState, // State of the task task for the module
}

Expand Down
7 changes: 7 additions & 0 deletions dashboard/src/util/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,10 @@ export function getLinkUrl(ingress: ServiceIngress) {
pathname: ingress.path,
}))
}

/**
* Test names are not unique so we construct a unique key from the module name and the test name.
*/
export function getTestKey({ testName, moduleName }: { testName: string, moduleName: string }) {
return `${moduleName}.${testName}`
}
Loading

0 comments on commit 71e204d

Please sign in to comment.