From debff96552ee21a29c28bd77e696e457d6280729 Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Tue, 14 Nov 2017 11:37:11 +0100 Subject: [PATCH] Add Parser implementation with tests ParserImpl implements parsing phase of Job handling. It saves yaml file in ArtifactDB, parses it and sets up config. Change-Id: Icb52b7c1943c29744f82532877aade2bb085c345 Signed-off-by: Lukasz Wojciechowski --- controller/parserimpl.go | 97 +++++++++++++++++++++ controller/parserimpl_test.go | 190 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 controller/parserimpl.go create mode 100644 controller/parserimpl_test.go diff --git a/controller/parserimpl.go b/controller/parserimpl.go new file mode 100644 index 0000000..8fb2a87 --- /dev/null +++ b/controller/parserimpl.go @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ + +// File controller/parserimpl.go implements Parser. + +package controller + +import ( + "fmt" + "io/ioutil" + + . "git.tizen.org/tools/weles" + "git.tizen.org/tools/weles/controller/notifier" +) + +// ParserImpl implements Parser for Controller. +type ParserImpl struct { + // Notifier provides channel for communication with Controller. + notifier.Notifier + // jobs references module implementing Jobs management. + jobs JobsController + // artifacts references Weles module implementing ArtifactManager for + // managing ArtifactsDB. + artifacts ArtifactManager + // parser references Weles module implementing YamlParser for unmarshaling + // yaml Job recipe. + parser YamlParser +} + +// NewParser creates a new ParserImpl structure setting up references +// to used Weles modules. +func NewParser(j JobsController, a ArtifactManager, p YamlParser) Parser { + return &ParserImpl{ + Notifier: notifier.NewNotifier(), + jobs: j, + artifacts: a, + parser: p, + } +} + +// Parse prepares new Job to be processed by saving yaml file in ArtifactDB, +// parsing yaml and preparing Job's configuration. +func (h *ParserImpl) Parse(j JobID) { + err := h.jobs.SetStatusAndInfo(j, JOB_PARSING, "") + if err != nil { + h.SendFail(j, fmt.Sprintf("Internal Weles error while changing Job status : %s", err.Error())) + return + } + + yaml, err := h.jobs.GetYaml(j) + if err != nil { + h.SendFail(j, fmt.Sprintf("Internal Weles error while getting yaml description : %s", err.Error())) + return + } + + path, err := h.artifacts.CreateArtifact(ArtifactDescription{ + JobID: j, + Type: AM_YAMLFILE, + }) + if err != nil { + h.SendFail(j, fmt.Sprintf("Internal Weles error while creating file path in ArtifactDB : %s", err.Error())) + return + } + + err = ioutil.WriteFile(string(path), yaml, 0644) + if err != nil { + h.SendFail(j, fmt.Sprintf("Internal Weles error while saving file in ArtifactDB : %s", err.Error())) + return + } + + conf, err := h.parser.ParseYaml(yaml) + if err != nil { + h.SendFail(j, fmt.Sprintf("Error parsing yaml file : %s", err.Error())) + return + } + + err = h.jobs.SetConfig(j, conf) + if err != nil { + h.SendFail(j, fmt.Sprintf("Internal Weles error while setting config : %s", err.Error())) + return + } + + h.SendOK(j) +} diff --git a/controller/parserimpl_test.go b/controller/parserimpl_test.go new file mode 100644 index 0000000..cec0724 --- /dev/null +++ b/controller/parserimpl_test.go @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ + +package controller + +import ( + "errors" + + . "git.tizen.org/tools/weles" + cmock "git.tizen.org/tools/weles/controller/mock" + . "git.tizen.org/tools/weles/controller/notifier" + mock "git.tizen.org/tools/weles/mock" + gomock "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("ParserImpl", func() { + var r <-chan Notification + var jc *cmock.MockJobsController + var am *mock.MockArtifactManager + var yp *mock.MockYamlParser + var h Parser + var ctrl *gomock.Controller + j := JobID(0xCAFE) + goodpath := ArtifactPath("/tmp/weles_test") + badpath := ArtifactPath("/such/path/does/not/exist") + config := Config{JobName: "Test name"} + yaml := []byte("test yaml") + err := errors.New("test error") + + BeforeEach(func() { + ctrl = gomock.NewController(GinkgoT()) + + jc = cmock.NewMockJobsController(ctrl) + am = mock.NewMockArtifactManager(ctrl) + yp = mock.NewMockYamlParser(ctrl) + + h = NewParser(jc, am, yp) + r = h.Listen() + }) + AfterEach(func() { + ctrl.Finish() + }) + Describe("NewParser", func() { + It("should create a new object", func() { + Expect(h).NotTo(BeNil()) + Expect(h.(*ParserImpl).jobs).To(Equal(jc)) + Expect(h.(*ParserImpl).artifacts).To(Equal(am)) + Expect(h.(*ParserImpl).parser).To(Equal(yp)) + }) + }) + Describe("Parse", func() { + It("should handle job successfully", func() { + gomock.InOrder( + jc.EXPECT().SetStatusAndInfo(j, JOB_PARSING, ""), + jc.EXPECT().GetYaml(j).Return(yaml, nil), + am.EXPECT().CreateArtifact(ArtifactDescription{JobID: j, Type: AM_YAMLFILE}).Return(goodpath, nil), + yp.EXPECT().ParseYaml(yaml).Return(config, nil), + jc.EXPECT().SetConfig(j, config), + ) + + h.Parse(j) + + Eventually(r).Should(Receive(Equal(Notification{ + JobID: j, + OK: true, + }))) + }) + It("should fail when unable to set config", func() { + gomock.InOrder( + jc.EXPECT().SetStatusAndInfo(j, JOB_PARSING, ""), + jc.EXPECT().GetYaml(j).Return(yaml, nil), + am.EXPECT().CreateArtifact(ArtifactDescription{JobID: j, Type: AM_YAMLFILE}).Return(goodpath, nil), + yp.EXPECT().ParseYaml(yaml).Return(config, nil), + jc.EXPECT().SetConfig(j, config).Return(err), + ) + + h.Parse(j) + + notification := Notification{} + expectedNotification := Notification{ + JobID: j, + OK: false, + Msg: "Internal Weles error while setting config : " + err.Error(), + } + Eventually(r).Should(Receive(¬ification)) + Expect(notification).To(Equal(expectedNotification)) + }) + It("should fail when unable to parse yaml", func() { + gomock.InOrder( + jc.EXPECT().SetStatusAndInfo(j, JOB_PARSING, ""), + jc.EXPECT().GetYaml(j).Return(yaml, nil), + am.EXPECT().CreateArtifact(ArtifactDescription{JobID: j, Type: AM_YAMLFILE}).Return(goodpath, nil), + yp.EXPECT().ParseYaml(yaml).Return(Config{}, err), + ) + + h.Parse(j) + + notification := Notification{} + expectedNotification := Notification{ + JobID: j, + OK: false, + Msg: "Error parsing yaml file : " + err.Error(), + } + Eventually(r).Should(Receive(¬ification)) + Expect(notification).To(Equal(expectedNotification)) + }) + It("should fail when unable to write yaml file", func() { + gomock.InOrder( + jc.EXPECT().SetStatusAndInfo(j, JOB_PARSING, ""), + jc.EXPECT().GetYaml(j).Return(yaml, nil), + am.EXPECT().CreateArtifact(ArtifactDescription{JobID: j, Type: AM_YAMLFILE}).Return(badpath, nil), + ) + + h.Parse(j) + + notification := Notification{} + expectedNotification := Notification{ + JobID: j, + OK: false, + Msg: "Internal Weles error while saving file in ArtifactDB : " + "open " + string(badpath) + ": no such file or directory", + } + Eventually(r).Should(Receive(¬ification)) + Expect(notification).To(Equal(expectedNotification)) + }) + It("should fail when unable to create path in ArtifactDB", func() { + gomock.InOrder( + jc.EXPECT().SetStatusAndInfo(j, JOB_PARSING, ""), + jc.EXPECT().GetYaml(j).Return(yaml, nil), + am.EXPECT().CreateArtifact(ArtifactDescription{JobID: j, Type: AM_YAMLFILE}).Return(ArtifactPath(""), err), + ) + + h.Parse(j) + + notification := Notification{} + expectedNotification := Notification{ + JobID: j, + OK: false, + Msg: "Internal Weles error while creating file path in ArtifactDB : " + err.Error(), + } + Eventually(r).Should(Receive(¬ification)) + Expect(notification).To(Equal(expectedNotification)) + }) + It("should fail when unable to get yaml", func() { + gomock.InOrder( + jc.EXPECT().SetStatusAndInfo(j, JOB_PARSING, ""), + jc.EXPECT().GetYaml(j).Return([]byte{}, err), + ) + + h.Parse(j) + + notification := Notification{} + expectedNotification := Notification{ + JobID: j, + OK: false, + Msg: "Internal Weles error while getting yaml description : " + err.Error(), + } + Eventually(r).Should(Receive(¬ification)) + Expect(notification).To(Equal(expectedNotification)) + }) + It("should fail when unable to change job status", func() { + jc.EXPECT().SetStatusAndInfo(j, JOB_PARSING, "").Return(err) + + h.Parse(j) + + notification := Notification{} + expectedNotification := Notification{ + JobID: j, + OK: false, + Msg: "Internal Weles error while changing Job status : " + err.Error(), + } + Eventually(r).Should(Receive(¬ification)) + Expect(notification).To(Equal(expectedNotification)) + }) + }) +}) -- 2.7.4