Repository: oozie Updated Branches: refs/heads/master 64459d01f -> c512332b0
OOZIE-3264 Flaky test TestCoordMaterializeTransitionXCommand#testLastOnlyMaterialization (asalamon74 via andras.piros) Project: http://git-wip-us.apache.org/repos/asf/oozie/repo Commit: http://git-wip-us.apache.org/repos/asf/oozie/commit/c512332b Tree: http://git-wip-us.apache.org/repos/asf/oozie/tree/c512332b Diff: http://git-wip-us.apache.org/repos/asf/oozie/diff/c512332b Branch: refs/heads/master Commit: c512332b0dc1d254ae7d25055d12086a4697029b Parents: 64459d0 Author: Andras Piros <[email protected]> Authored: Thu Aug 23 16:05:42 2018 +0200 Committer: Andras Piros <[email protected]> Committed: Thu Aug 23 16:05:42 2018 +0200 ---------------------------------------------------------------------- .../command/coord/TestCoordChangeXCommand.java | 24 ---- .../TestCoordMaterializeTransitionXCommand.java | 128 ++----------------- ...zeTransitionXCommandWithRunningServices.java | 99 ++++++++++++++ .../org/apache/oozie/test/XDataTestCase.java | 91 +++++++++++++ release-log.txt | 1 + 5 files changed, 199 insertions(+), 144 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/oozie/blob/c512332b/core/src/test/java/org/apache/oozie/command/coord/TestCoordChangeXCommand.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/oozie/command/coord/TestCoordChangeXCommand.java b/core/src/test/java/org/apache/oozie/command/coord/TestCoordChangeXCommand.java index b784093..2773bc7 100644 --- a/core/src/test/java/org/apache/oozie/command/coord/TestCoordChangeXCommand.java +++ b/core/src/test/java/org/apache/oozie/command/coord/TestCoordChangeXCommand.java @@ -19,10 +19,8 @@ package org.apache.oozie.command.coord; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; import java.util.List; -import java.util.Set; import org.apache.oozie.CoordinatorActionBean; import org.apache.oozie.CoordinatorJobBean; @@ -46,10 +44,8 @@ import org.apache.oozie.executor.jpa.SLARegistrationQueryExecutor; import org.apache.oozie.executor.jpa.SLARegistrationQueryExecutor.SLARegQuery; import org.apache.oozie.executor.jpa.SLASummaryQueryExecutor; import org.apache.oozie.executor.jpa.SLASummaryQueryExecutor.SLASummaryQuery; -import org.apache.oozie.service.CallableQueueService; import org.apache.oozie.service.JPAService; import org.apache.oozie.service.SchedulerService; -import org.apache.oozie.service.Service; import org.apache.oozie.service.Services; import org.apache.oozie.service.StatusTransitService; import org.apache.oozie.sla.SLARegistrationBean; @@ -57,7 +53,6 @@ import org.apache.oozie.sla.SLASummaryBean; import org.apache.oozie.store.StoreException; import org.apache.oozie.test.XDataTestCase; import org.apache.oozie.util.DateUtils; -import org.apache.oozie.util.XCallable; public class TestCoordChangeXCommand extends XDataTestCase { private Services services; @@ -74,25 +69,6 @@ public class TestCoordChangeXCommand extends XDataTestCase { return DateUtils.formatDateOozieTZ(new Date(timeStamp)); } - /** - * Class is used to change the queueservice, as that one meddles with the actions in the background. - */ - static class FakeCallableQueueService extends CallableQueueService implements Service { - @Override - public void init(Services services){} - - @Override - public void destroy(){} - - @Override - public synchronized boolean queueSerial(List<? extends XCallable<?>> callables, long delay){return false;} - - @Override - public Set<String> getInterruptTypes() { - return Collections.emptySet(); - } - } - @Override protected void setUp() throws Exception { super.setUp(); http://git-wip-us.apache.org/repos/asf/oozie/blob/c512332b/core/src/test/java/org/apache/oozie/command/coord/TestCoordMaterializeTransitionXCommand.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/oozie/command/coord/TestCoordMaterializeTransitionXCommand.java b/core/src/test/java/org/apache/oozie/command/coord/TestCoordMaterializeTransitionXCommand.java index 8189732..49b8732 100644 --- a/core/src/test/java/org/apache/oozie/command/coord/TestCoordMaterializeTransitionXCommand.java +++ b/core/src/test/java/org/apache/oozie/command/coord/TestCoordMaterializeTransitionXCommand.java @@ -28,7 +28,6 @@ import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.TimeZone; - import org.apache.hadoop.conf.Configuration; import org.apache.oozie.CoordinatorActionBean; import org.apache.oozie.CoordinatorJobBean; @@ -50,8 +49,8 @@ import org.apache.oozie.executor.jpa.CoordJobQueryExecutor.CoordJobQuery; import org.apache.oozie.executor.jpa.JPAExecutorException; import org.apache.oozie.executor.jpa.CoordJobGetActionsSubsetJPAExecutor; import org.apache.oozie.executor.jpa.SLAEventsGetForSeqIdJPAExecutor; -import org.apache.oozie.local.LocalOozie; import org.apache.oozie.service.JPAService; +import org.apache.oozie.service.SchedulerService; import org.apache.oozie.service.Services; import org.apache.oozie.test.XDataTestCase; import org.apache.oozie.util.DateUtils; @@ -62,18 +61,19 @@ import org.jdom.Element; @SuppressWarnings("deprecation") public class TestCoordMaterializeTransitionXCommand extends XDataTestCase { - private int oneHourInSeconds = (int) java.util.concurrent.TimeUnit.HOURS.toSeconds(1); - + private int oneHourInSeconds = hoursToSeconds(1); @Override protected void setUp() throws Exception { super.setUp(); - LocalOozie.start(); //LocalOozie does new Services().init(); + new Services().init(); + Services.get().setService(FakeCallableQueueService.class); + Services.get().get(SchedulerService.class).destroy(); } @Override protected void tearDown() throws Exception { - LocalOozie.stop(); + Services.get().destroy(); super.tearDown(); } @@ -85,10 +85,6 @@ public class TestCoordMaterializeTransitionXCommand extends XDataTestCase { checkCoordAction(job.getId() + "@1"); } - private int hoursToSeconds(final int hours) { - return new Long(java.util.concurrent.TimeUnit.HOURS.toSeconds(hours)).intValue(); - } - public void testActionMaterForHcatalog() throws Exception { Services.get().destroy(); Services services = super.setupServicesForHCatalog(); @@ -529,25 +525,6 @@ public class TestCoordMaterializeTransitionXCommand extends XDataTestCase { checkCoordActionsNominalTime(job.getId(), 2, nominalTimes); } - /** - * Job start time is after pause time, should pause the job. - * - * @throws Exception - */ - public void testActionMaterWithPauseTime3() throws Exception { - Date startTime = DateUtils.parseDateOozieTZ("2009-03-06T10:00Z"); - Date endTime = DateUtils.parseDateOozieTZ("2009-03-06T10:14Z"); - Date pauseTime = DateUtils.parseDateOozieTZ("2009-03-06T09:58Z"); - final CoordinatorJobBean job = addRecordToCoordJobTable(CoordinatorJob.Status.RUNNING, startTime, endTime, pauseTime, "5"); - new CoordMaterializeTransitionXCommand(job.getId(), hoursToSeconds(1)).call(); - waitFor(60_000, new Predicate() { - public boolean evaluate() throws Exception { - return (getStatus(job.getId()) == CoordinatorJob.Status.PAUSED); - } - }); - checkCoordActions(job.getId(), 0, CoordinatorJob.Status.PAUSED); - } - public void testGetDryrun() throws Exception { Date startTime = DateUtils.parseDateOozieTZ("2009-03-06T10:00Z"); Date endTime = DateUtils.parseDateOozieTZ("2009-03-06T10:14Z"); @@ -1096,10 +1073,9 @@ public class TestCoordMaterializeTransitionXCommand extends XDataTestCase { } public void testLastOnlyMaterialization() throws Exception { - long now = System.currentTimeMillis(); - Date startTime = DateUtils.toDate(new Timestamp(now - 180 * 60 * 1000)); // 3 secondsFromHours ago - Date endTime = DateUtils.toDate(new Timestamp(now + 180 * 60 * 1000)); // 3 secondsFromHours from now + Date startTime = DateUtils.toDate(new Timestamp(now - 180 * 60 * 1000)); // 3 hours ago + Date endTime = DateUtils.toDate(new Timestamp(now + 180 * 60 * 1000)); // 3 hours from now CoordinatorJobBean job = addRecordToCoordJobTable(CoordinatorJob.Status.RUNNING, startTime, endTime, null, -1, "10", CoordinatorJob.Execution.LAST_ONLY); // This would normally materialize the throttle amount and within a 1 hour window; however, with LAST_ONLY this should @@ -1250,61 +1226,6 @@ public class TestCoordMaterializeTransitionXCommand extends XDataTestCase { assertEquals(origStart.getTime(), job.getNextMaterializedTime()); } - protected CoordinatorJobBean addRecordToCoordJobTable(CoordinatorJob.Status status, Date startTime, Date endTime, - Date pauseTime, String freq) throws Exception { - return addRecordToCoordJobTable(status, startTime, endTime, pauseTime, -1, freq, Timeunit.MINUTE); - } - protected CoordinatorJobBean addRecordToCoordJobTable(CoordinatorJob.Status status, Date startTime, Date endTime, - Date pauseTime, String freq, Timeunit timeUnit) throws Exception { - return addRecordToCoordJobTable(status, startTime, endTime, pauseTime, -1, freq, timeUnit); - } - - protected CoordinatorJobBean addRecordToCoordJobTable(CoordinatorJob.Status status, Date startTime, Date endTime, - Date pauseTime, String freq, int matThrottling) throws Exception { - return addRecordToCoordJobTable(status, startTime, endTime, pauseTime, -1, freq, Timeunit.MINUTE, - CoordinatorJob.Execution.FIFO, matThrottling); - } - - protected CoordinatorJobBean addRecordToCoordJobTable(CoordinatorJob.Status status, Date startTime, Date endTime, - Date pauseTime, int timeout, String freq, Timeunit timeUnit) throws Exception { - return addRecordToCoordJobTable(status, startTime, endTime, pauseTime, timeout, freq, timeUnit, - CoordinatorJob.Execution.FIFO, 20); - } - - protected CoordinatorJobBean addRecordToCoordJobTable(CoordinatorJob.Status status, Date startTime, Date endTime, - Date pauseTime, int timeout, String freq, CoordinatorJob.Execution execution) throws Exception { - return addRecordToCoordJobTable(status, startTime, endTime, pauseTime, timeout, freq, Timeunit.MINUTE, execution, 20); - } - - protected CoordinatorJobBean addRecordToCoordJobTable(CoordinatorJob.Status status, Date startTime, Date endTime, - Date pauseTime, int timeout, String freq, Timeunit timeUnit, CoordinatorJob.Execution execution, int matThrottling) - throws Exception { - CoordinatorJobBean coordJob = createCoordJob(status, startTime, endTime, false, false, 0); - coordJob.setStartTime(startTime); - coordJob.setEndTime(endTime); - coordJob.setPauseTime(pauseTime); - coordJob.setFrequency(freq); - coordJob.setTimeUnit(timeUnit); - coordJob.setTimeout(timeout); - coordJob.setConcurrency(3); - coordJob.setMatThrottling(matThrottling); - coordJob.setExecutionOrder(execution); - - try { - JPAService jpaService = Services.get().get(JPAService.class); - assertNotNull(jpaService); - CoordJobInsertJPAExecutor coordInsertCmd = new CoordJobInsertJPAExecutor(coordJob); - jpaService.execute(coordInsertCmd); - } - catch (JPAExecutorException ex) { - ex.printStackTrace(); - fail("Unable to insert the test coord job record to table"); - throw ex; - } - - return coordJob; - } - private void checkCoordJobs(String jobId, CoordinatorJob.Status expectedStatus) { try { JPAService jpaService = Services.get().get(JPAService.class); @@ -1353,39 +1274,6 @@ public class TestCoordMaterializeTransitionXCommand extends XDataTestCase { return actionBean; } - private CoordinatorJob.Status getStatus(String jobId){ - CoordinatorJob job = null; - try { - JPAService jpaService = Services.get().get(JPAService.class); - job = jpaService.execute(new CoordJobGetJPAExecutor(jobId)); - } - catch (JPAExecutorException se) { - se.printStackTrace(); - } - return job.getStatus(); - } - - private void checkCoordActions(String jobId, int number, CoordinatorJob.Status status) { - try { - JPAService jpaService = Services.get().get(JPAService.class); - Integer actionsSize = jpaService.execute(new CoordJobGetActionsJPAExecutor(jobId)); - if (actionsSize != number) { - fail("Should have " + number + " actions created for job " + jobId + ", but has " + actionsSize + " actions."); - } - - if (status != null) { - CoordinatorJob job = jpaService.execute(new CoordJobGetJPAExecutor(jobId)); - if (job.getStatus() != status) { - fail("Job status " + job.getStatus() + " should be " + status); - } - } - } - catch (JPAExecutorException se) { - se.printStackTrace(); - fail("Job ID " + jobId + " was not stored properly in db"); - } - } - private void checkCoordActionsNominalTime(String jobId, int number, Date[] nominalTimes) { try { JPAService jpaService = Services.get().get(JPAService.class); http://git-wip-us.apache.org/repos/asf/oozie/blob/c512332b/core/src/test/java/org/apache/oozie/command/coord/TestCoordMaterializeTransitionXCommandWithRunningServices.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/oozie/command/coord/TestCoordMaterializeTransitionXCommandWithRunningServices.java b/core/src/test/java/org/apache/oozie/command/coord/TestCoordMaterializeTransitionXCommandWithRunningServices.java new file mode 100644 index 0000000..0a4c8e7 --- /dev/null +++ b/core/src/test/java/org/apache/oozie/command/coord/TestCoordMaterializeTransitionXCommandWithRunningServices.java @@ -0,0 +1,99 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.oozie.command.coord; + +import org.apache.oozie.CoordinatorJobBean; +import org.apache.oozie.client.CoordinatorJob; +import org.apache.oozie.executor.jpa.CoordJobGetActionsJPAExecutor; +import org.apache.oozie.executor.jpa.CoordJobGetJPAExecutor; +import org.apache.oozie.executor.jpa.JPAExecutorException; +import org.apache.oozie.service.JPAService; +import org.apache.oozie.service.Services; +import org.apache.oozie.test.XDataTestCase; +import org.apache.oozie.util.DateUtils; + +import java.util.Date; + +@SuppressWarnings("deprecation") +public class TestCoordMaterializeTransitionXCommandWithRunningServices extends XDataTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + new Services().init(); + } + + @Override + protected void tearDown() throws Exception { + Services.get().destroy(); + super.tearDown(); + } + + /** + * Job start time is after pause time, should pause the job. + * + * @throws Exception + */ + public void testActionMaterWithPauseTimeAfterStartTime() throws Exception { + Date startTime = DateUtils.parseDateOozieTZ("2009-03-06T10:00Z"); + Date endTime = DateUtils.parseDateOozieTZ("2009-03-06T10:14Z"); + Date pauseTime = DateUtils.parseDateOozieTZ("2009-03-06T09:58Z"); + final CoordinatorJobBean job = addRecordToCoordJobTable(CoordinatorJob.Status.RUNNING, startTime, endTime, pauseTime, "5"); + new CoordMaterializeTransitionXCommand(job.getId(), hoursToSeconds(1)).call(); + waitFor(60_000, new Predicate() { + public boolean evaluate() throws Exception { + return (getStatus(job.getId()) == CoordinatorJob.Status.PAUSED); + } + }); + checkCoordActions(job.getId(), 0, CoordinatorJob.Status.PAUSED); + } + + private CoordinatorJob.Status getStatus(String jobId){ + CoordinatorJob job = null; + try { + JPAService jpaService = Services.get().get(JPAService.class); + job = jpaService.execute(new CoordJobGetJPAExecutor(jobId)); + } + catch (JPAExecutorException se) { + se.printStackTrace(); + } + return job.getStatus(); + } + + private void checkCoordActions(String jobId, int number, CoordinatorJob.Status status) { + try { + JPAService jpaService = Services.get().get(JPAService.class); + Integer actionsSize = jpaService.execute(new CoordJobGetActionsJPAExecutor(jobId)); + if (actionsSize != number) { + fail("Should have " + number + " actions created for job " + jobId + ", but has " + actionsSize + " actions."); + } + + if (status != null) { + CoordinatorJob job = jpaService.execute(new CoordJobGetJPAExecutor(jobId)); + if (job.getStatus() != status) { + fail("Job status " + job.getStatus() + " should be " + status); + } + } + } + catch (JPAExecutorException se) { + se.printStackTrace(); + fail("Job ID " + jobId + " was not stored properly in db"); + } + } +} http://git-wip-us.apache.org/repos/asf/oozie/blob/c512332b/core/src/test/java/org/apache/oozie/test/XDataTestCase.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/oozie/test/XDataTestCase.java b/core/src/test/java/org/apache/oozie/test/XDataTestCase.java index a8fe703..20e1e82 100644 --- a/core/src/test/java/org/apache/oozie/test/XDataTestCase.java +++ b/core/src/test/java/org/apache/oozie/test/XDataTestCase.java @@ -29,7 +29,10 @@ import java.io.Reader; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.util.Calendar; +import java.util.Collections; import java.util.Date; +import java.util.List; +import java.util.Set; import java.util.regex.Matcher; import org.apache.hadoop.conf.Configuration; @@ -75,8 +78,10 @@ import org.apache.oozie.executor.jpa.WorkflowJobGetJPAExecutor; import org.apache.oozie.executor.jpa.WorkflowJobInsertJPAExecutor; import org.apache.oozie.executor.jpa.WorkflowJobQueryExecutor; import org.apache.oozie.executor.jpa.WorkflowJobQueryExecutor.WorkflowJobQuery; +import org.apache.oozie.service.CallableQueueService; import org.apache.oozie.service.JPAService; import org.apache.oozie.service.LiteWorkflowStoreService; +import org.apache.oozie.service.Service; import org.apache.oozie.service.Services; import org.apache.oozie.service.UUIDService; import org.apache.oozie.service.UUIDService.ApplicationType; @@ -86,6 +91,7 @@ import org.apache.oozie.sla.SLARegistrationBean; import org.apache.oozie.sla.SLASummaryBean; import org.apache.oozie.util.DateUtils; import org.apache.oozie.util.IOUtils; +import org.apache.oozie.util.XCallable; import org.apache.oozie.util.XConfiguration; import org.apache.oozie.util.XLog; import org.apache.oozie.util.XmlUtils; @@ -117,6 +123,29 @@ public abstract class XDataTestCase extends XHCatTestCase { protected String bundleId; protected String CREATE_TIME = "2012-07-22T00:00Z"; + /** + * Class is used to change the queueservice, as that one meddles with the actions in the background. + */ + protected static class FakeCallableQueueService extends CallableQueueService implements Service { + @Override + public void init(Services services) { + } + + @Override + public void destroy() { + } + + @Override + public synchronized boolean queueSerial(List<? extends XCallable<?>> callables, long delay) { + return false; + } + + @Override + public Set<String> getInterruptTypes() { + return Collections.emptySet(); + } + } + public XDataTestCase() { } @@ -135,6 +164,11 @@ public abstract class XDataTestCase extends XHCatTestCase { tearDown(); } + protected int hoursToSeconds(final int hours) { + return new Long(java.util.concurrent.TimeUnit.HOURS.toSeconds(hours)).intValue(); + } + + /** * Inserts the passed coord job * @param coord job bean @@ -154,6 +188,34 @@ public abstract class XDataTestCase extends XHCatTestCase { } } + protected CoordinatorJobBean addRecordToCoordJobTable(CoordinatorJob.Status status, Date startTime, Date endTime, + Date pauseTime, String freq) throws Exception { + return addRecordToCoordJobTable(status, startTime, endTime, pauseTime, -1, freq, Timeunit.MINUTE); + } + protected CoordinatorJobBean addRecordToCoordJobTable(CoordinatorJob.Status status, Date startTime, Date endTime, + Date pauseTime, String freq, Timeunit timeUnit) throws Exception { + return addRecordToCoordJobTable(status, startTime, endTime, pauseTime, -1, freq, timeUnit); + } + + protected CoordinatorJobBean addRecordToCoordJobTable(CoordinatorJob.Status status, Date startTime, Date endTime, + Date pauseTime, String freq, int matThrottling) throws Exception { + return addRecordToCoordJobTable(status, startTime, endTime, pauseTime, -1, freq, Timeunit.MINUTE, + CoordinatorJob.Execution.FIFO, matThrottling); + } + + protected CoordinatorJobBean addRecordToCoordJobTable(CoordinatorJob.Status status, Date startTime, Date endTime, + Date pauseTime, int timeout, String freq, Timeunit timeUnit) + throws Exception { + return addRecordToCoordJobTable(status, startTime, endTime, pauseTime, timeout, freq, timeUnit, + CoordinatorJob.Execution.FIFO, 20); + } + + protected CoordinatorJobBean addRecordToCoordJobTable(CoordinatorJob.Status status, Date startTime, Date endTime, + Date pauseTime, int timeout, String freq, + CoordinatorJob.Execution execution) throws Exception { + return addRecordToCoordJobTable(status, startTime, endTime, pauseTime, timeout, freq, Timeunit.MINUTE, execution, 20); + } + /** * Insert coord job for testing. * @@ -363,6 +425,35 @@ public abstract class XDataTestCase extends XHCatTestCase { return coordJob; } + protected CoordinatorJobBean addRecordToCoordJobTable(CoordinatorJob.Status status, Date startTime, Date endTime, + Date pauseTime, int timeout, String freq, Timeunit timeUnit, + CoordinatorJob.Execution execution, int matThrottling) + throws Exception { + CoordinatorJobBean coordJob = createCoordJob(status, startTime, endTime, false, false, 0); + coordJob.setStartTime(startTime); + coordJob.setEndTime(endTime); + coordJob.setPauseTime(pauseTime); + coordJob.setFrequency(freq); + coordJob.setTimeUnit(timeUnit); + coordJob.setTimeout(timeout); + coordJob.setConcurrency(3); + coordJob.setMatThrottling(matThrottling); + coordJob.setExecutionOrder(execution); + + try { + JPAService jpaService = Services.get().get(JPAService.class); + assertNotNull(jpaService); + CoordJobInsertJPAExecutor coordInsertCmd = new CoordJobInsertJPAExecutor(coordJob); + jpaService.execute(coordInsertCmd); + } catch (JPAExecutorException ex) { + ex.printStackTrace(); + fail("Unable to insert the test coord job record to table"); + throw ex; + } + + return coordJob; + } + /** * Create coord job bean * http://git-wip-us.apache.org/repos/asf/oozie/blob/c512332b/release-log.txt ---------------------------------------------------------------------- diff --git a/release-log.txt b/release-log.txt index d651ac9..70cbf47 100644 --- a/release-log.txt +++ b/release-log.txt @@ -1,5 +1,6 @@ -- Oozie 5.1.0 release (trunk - unreleased) +OOZIE-3264 Flaky test TestCoordMaterializeTransitionXCommand#testLastOnlyMaterialization (asalamon74 via andras.piros) OOZIE-3331 [spark-action] Inconsistency while parsing quoted Spark options (asalamon74 via andras.piros) OOZIE-3330 [spark-action] Remove double quotes inside plain option values (asalamon74 via andras.piros) OOZIE-3329 [build] test-patch-30-distro improvement (asalamon74 via andras.piros)
