Merge lp:~fginther/cupstream2distro-config/stack-lookup-3 into lp:cupstream2distro-config
- stack-lookup-3
- Merge into trunk
| Status: | Rejected |
|---|---|
| Rejected by: | Loïc Minier |
| Proposed branch: | lp:~fginther/cupstream2distro-config/stack-lookup-3 |
| Merge into: | lp:cupstream2distro-config |
| Diff against target: |
756 lines (+742/-0) 3 files modified
c2dconfigutils/cu2dStackLookup.py (+247/-0) ci/cu2d-stack-lookup (+40/-0) tests/test_cu2dStackLookup.py (+455/-0) |
| To merge this branch: | bzr merge lp:~fginther/cupstream2distro-config/stack-lookup-3 |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Chris Gagnon (community) | Needs Fixing | ||
| PS Jenkins bot | continuous-integration | Approve | |
|
Review via email:
|
|||
Commit message
Provides an API and a utility to query a stack for project, job names and attributes.
Description of the change
Provides an API and a utility to query a stack for project, job names and attributes.
This will be used by the dashboard (it's currently using an earlier version).
| PS Jenkins bot (ps-jenkins) wrote : | # |
| Chris Gagnon (chris.gagnon) wrote : | # |
the cli options -d and -b need tests
| Chris Gagnon (chris.gagnon) wrote : | # |
I am trying to lookup a children in a stack and get the following
./cu2d-stack-lookup -l -a -i ../stacks/
["qt-folks", "qtubuntu-gps"]
2013-06-19 17:07:21,049 ERROR Could not find None in stack configuration
| Chris Gagnon (chris.gagnon) wrote : | # |
I get the same error without the i
./cu2d-stack-lookup -l ../stacks/
["qt-folks", "qtubuntu-gps"]
2013-06-19 17:20:38,097 ERROR Could not find None in stack configuration
| Chris Gagnon (chris.gagnon) wrote : | # |
I get an error when using -t with -l
./cu2d-stack-lookup -t qt-folks -l ../stacks/
["qt-folks", "qtubuntu-gps"]
2013-06-19 17:24:58,095 ERROR Could not find qt-folks in stack configuration
| Chris Gagnon (chris.gagnon) : | # |
| Francis Ginther (fginther) wrote : | # |
I'm going to rework this due to a change in direction from the dashboard project. We can't install this in the production environment. My solution is to add a utility to post the information to a well known jenkins job so that the dashboard can consume the data directly from jenkins.
- 425. By Francis Ginther
-
Add option to choose output format (yaml or json) and an option to dump a stack summary (to be used by the dashboard tools).
- 426. By Francis Ginther
-
Changed project list to a dictionary and fixed error caused by an empty project list.
| Loïc Minier (lool) wrote : | # |
(Rejecting to drop out of active reviews)
Unmerged revisions
- 426. By Francis Ginther
-
Changed project list to a dictionary and fixed error caused by an empty project list.
- 425. By Francis Ginther
-
Add option to choose output format (yaml or json) and an option to dump a stack summary (to be used by the dashboard tools).
- 424. By Francis Ginther
-
Provides an API and a utility to query a stack for project, job names and attributes.
Preview Diff
| 1 | === added file 'c2dconfigutils/cu2dStackLookup.py' | |||
| 2 | --- c2dconfigutils/cu2dStackLookup.py 1970-01-01 00:00:00 +0000 | |||
| 3 | +++ c2dconfigutils/cu2dStackLookup.py 2013-07-16 19:36:23 +0000 | |||
| 4 | @@ -0,0 +1,247 @@ | |||
| 5 | 1 | """Supply information about projects and job names within a stack | ||
| 6 | 2 | |||
| 7 | 3 | - Reads stack configuration from YAML configuration file | ||
| 8 | 4 | - Returns list of projects within a stack, job names for a project or | ||
| 9 | 5 | specific attributes of a project | ||
| 10 | 6 | |||
| 11 | 7 | """ | ||
| 12 | 8 | # Copyright (C) 2013, Canonical Ltd (http://www.canonical.com/) | ||
| 13 | 9 | # | ||
| 14 | 10 | # Author: Francis Ginther <francis.ginther@canonical.com> | ||
| 15 | 11 | # | ||
| 16 | 12 | # This software is free software: you can redistribute it | ||
| 17 | 13 | # and/or modify it under the terms of the GNU General Public License | ||
| 18 | 14 | # as published by the Free Software Foundation, either version 3 of | ||
| 19 | 15 | # the License, or (at your option) any later version. | ||
| 20 | 16 | # | ||
| 21 | 17 | # This software is distributed in the hope that it will | ||
| 22 | 18 | # be useful, but WITHOUT ANY WARRANTY; without even the implied warranty | ||
| 23 | 19 | # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 24 | 20 | # GNU General Public License for more details. | ||
| 25 | 21 | # | ||
| 26 | 22 | # You should have received a copy of the GNU General Public License | ||
| 27 | 23 | # along with this software. If not, see <http://www.gnu.org/licenses/>. | ||
| 28 | 24 | |||
| 29 | 25 | import argparse | ||
| 30 | 26 | import copy | ||
| 31 | 27 | import logging | ||
| 32 | 28 | import json | ||
| 33 | 29 | import os.path | ||
| 34 | 30 | import yaml | ||
| 35 | 31 | |||
| 36 | 32 | from c2dconfigutils import ( | ||
| 37 | 33 | dict_union, load_default_cfg, load_stack_cfg, set_logging, | ||
| 38 | 34 | get_ci_base_job_name) | ||
| 39 | 35 | |||
| 40 | 36 | |||
| 41 | 37 | class StackLookup(object): | ||
| 42 | 38 | |||
| 43 | 39 | DEFAULT_BASE_PATH = '/usr/share/cupstream2distro-config/ci' | ||
| 44 | 40 | SUPPORTED_FORMATS = ['json', 'yaml'] | ||
| 45 | 41 | STACK_KEYS = ['name', 'series', 'ppa', 'dest'] | ||
| 46 | 42 | |||
| 47 | 43 | def parse_arguments(self, base_path): | ||
| 48 | 44 | """Parses the command line arguments | ||
| 49 | 45 | |||
| 50 | 46 | return args: the parsed arguments | ||
| 51 | 47 | """ | ||
| 52 | 48 | parser = argparse.ArgumentParser( | ||
| 53 | 49 | description='Generates jenkins job names from a stack') | ||
| 54 | 50 | parser.add_argument('-d', '--debug', action='store_true', | ||
| 55 | 51 | default=False, help='enable debug mode') | ||
| 56 | 52 | parser.add_argument('-b', '--base_path', | ||
| 57 | 53 | default=base_path, | ||
| 58 | 54 | help='path to the cupstream2distro-config ' | ||
| 59 | 55 | 'base directory (default: %s)' % base_path) | ||
| 60 | 56 | parser.add_argument('-o', '--output-format', | ||
| 61 | 57 | default='yaml', | ||
| 62 | 58 | help='Output format to use {}'.format( | ||
| 63 | 59 | self.SUPPORTED_FORMATS)) | ||
| 64 | 60 | parser.add_argument('-s', '--summary', action='store_true', | ||
| 65 | 61 | help='Return a stack dump summary') | ||
| 66 | 62 | parser.add_argument('-l', '--list-projects', action='store_true', | ||
| 67 | 63 | default=False, help='return a list of projects ' | ||
| 68 | 64 | 'defined within the stack.') | ||
| 69 | 65 | parser.add_argument('-p', '--project', | ||
| 70 | 66 | help='Reference the given project') | ||
| 71 | 67 | parser.add_argument('-a', '--autoland', action='store_true', | ||
| 72 | 68 | default=False, | ||
| 73 | 69 | help='Return the autolanding jobs for a project') | ||
| 74 | 70 | parser.add_argument('-c', '--ci', action='store_true', | ||
| 75 | 71 | default=False, | ||
| 76 | 72 | help='Return the ci jobs for a project') | ||
| 77 | 73 | parser.add_argument('-t', '--attribute', | ||
| 78 | 74 | help='Return the value of the given attribute') | ||
| 79 | 75 | parser.add_argument('-i', '--children', action='store_true', | ||
| 80 | 76 | default=False, | ||
| 81 | 77 | help='Return the child jobs for a project ' | ||
| 82 | 78 | '(requires -c/--ci or -a/--autolanding)') | ||
| 83 | 79 | parser.add_argument('stackcfg', | ||
| 84 | 80 | help='Path to a configuration file for the stack') | ||
| 85 | 81 | args = parser.parse_args() | ||
| 86 | 82 | if (not args.list_projects and args.project is None and | ||
| 87 | 83 | not args.summary): | ||
| 88 | 84 | parser.error('Must specify one of -l/--list-projects, ' | ||
| 89 | 85 | '-s/--summary or -p/--project') | ||
| 90 | 86 | return False | ||
| 91 | 87 | if (args.project and (args.attribute is None and not args.ci and | ||
| 92 | 88 | not args.autoland)): | ||
| 93 | 89 | parser.error('Must specify -a/--autolanding, -c/--ci or ' | ||
| 94 | 90 | '-t/--attribute with -p/--project') | ||
| 95 | 91 | return False | ||
| 96 | 92 | if (args.children and (not args.ci and not args.autoland)): | ||
| 97 | 93 | parser.error('Must specify -a/--autolanding or -c/--ci with ' | ||
| 98 | 94 | '-i/--children') | ||
| 99 | 95 | return False | ||
| 100 | 96 | if args.output_format not in self.SUPPORTED_FORMATS: | ||
| 101 | 97 | parser.error('Output format must be one of: {}'.format( | ||
| 102 | 98 | self.SUPPORTED_FORMATS)) | ||
| 103 | 99 | return args | ||
| 104 | 100 | |||
| 105 | 101 | def _generate_name(self, project_name, project_config, job_type, children): | ||
| 106 | 102 | job_base_name = get_ci_base_job_name(project_name, project_config) | ||
| 107 | 103 | if children and 'configurations' in project_config: | ||
| 108 | 104 | names = list() | ||
| 109 | 105 | configurations = project_config.pop('configurations') | ||
| 110 | 106 | for config_name in configurations: | ||
| 111 | 107 | if not configurations[config_name]: | ||
| 112 | 108 | # configuration is explicitly removed | ||
| 113 | 109 | continue | ||
| 114 | 110 | names.append('-'.join([job_base_name, config_name, job_type])) | ||
| 115 | 111 | return names | ||
| 116 | 112 | return ['-'.join([job_base_name, job_type])] | ||
| 117 | 113 | |||
| 118 | 114 | def _prepare_project(self, stack, project_name, job_type): | ||
| 119 | 115 | if project_name not in stack['projects']: | ||
| 120 | 116 | raise KeyError | ||
| 121 | 117 | project_config = copy.deepcopy(stack['ci_default']) | ||
| 122 | 118 | dict_union(project_config, stack['projects'][project_name]) | ||
| 123 | 119 | job_only_dict = dict() | ||
| 124 | 120 | if job_type in project_config: | ||
| 125 | 121 | job_only_dict = project_config.pop(job_type) | ||
| 126 | 122 | if project_config.get('%s_template' % (job_type), False): | ||
| 127 | 123 | job_dict = copy.deepcopy(project_config) | ||
| 128 | 124 | if job_only_dict is not None: | ||
| 129 | 125 | dict_union(job_dict, job_only_dict) | ||
| 130 | 126 | return job_dict | ||
| 131 | 127 | return None | ||
| 132 | 128 | |||
| 133 | 129 | def _get_name(self, stack, project_name, job_type, children): | ||
| 134 | 130 | try: | ||
| 135 | 131 | job_dict = self._prepare_project(stack, project_name, job_type) | ||
| 136 | 132 | except KeyError: | ||
| 137 | 133 | return False | ||
| 138 | 134 | if job_dict: | ||
| 139 | 135 | return self._generate_name(project_name, job_dict, job_type, children) | ||
| 140 | 136 | return list() | ||
| 141 | 137 | |||
| 142 | 138 | def get_projects(self, stack): | ||
| 143 | 139 | return sorted([project for project in stack['projects']]) | ||
| 144 | 140 | |||
| 145 | 141 | def get_ci_name(self, stack, project, children=False): | ||
| 146 | 142 | return self._get_name(stack, project, 'ci', children) | ||
| 147 | 143 | |||
| 148 | 144 | def get_autolanding_name(self, stack, project, children=False): | ||
| 149 | 145 | return self._get_name(stack, project, 'autolanding', children) | ||
| 150 | 146 | |||
| 151 | 147 | def get_attribute(self, stack, project_name, job_type, attribute): | ||
| 152 | 148 | try: | ||
| 153 | 149 | project = self._prepare_project(stack, project_name, job_type) | ||
| 154 | 150 | except KeyError: | ||
| 155 | 151 | return False | ||
| 156 | 152 | if attribute == 'target_branch' and 'target_branch' not in project: | ||
| 157 | 153 | value = "lp:" + project_name | ||
| 158 | 154 | else: | ||
| 159 | 155 | value = project[attribute] | ||
| 160 | 156 | return value | ||
| 161 | 157 | |||
| 162 | 158 | def dump_stack(self, file_name, stack): | ||
| 163 | 159 | out_data = {'projects': {}} | ||
| 164 | 160 | |||
| 165 | 161 | # Try to determine the following pieces from the file name | ||
| 166 | 162 | (head, out_data['file_name']) = os.path.split(file_name) | ||
| 167 | 163 | (head, out_data['release']) = os.path.split(head) | ||
| 168 | 164 | for key in stack: | ||
| 169 | 165 | data = stack[key] | ||
| 170 | 166 | if key in self.STACK_KEYS: | ||
| 171 | 167 | out_data[key] = data | ||
| 172 | 168 | |||
| 173 | 169 | if 'projects' in stack and stack['projects']: | ||
| 174 | 170 | for project in stack['projects']: | ||
| 175 | 171 | config = {} | ||
| 176 | 172 | config['target_branch'] = self.get_attribute(stack, project, | ||
| 177 | 173 | 'autolanding', | ||
| 178 | 174 | 'target_branch') | ||
| 179 | 175 | config['ci'] = self.get_ci_name(stack, project)[0] | ||
| 180 | 176 | config['autolanding'] = self.get_autolanding_name(stack, | ||
| 181 | 177 | project)[0] | ||
| 182 | 178 | out_data['projects'][project] = config | ||
| 183 | 179 | |||
| 184 | 180 | return out_data | ||
| 185 | 181 | |||
| 186 | 182 | def output(self, output_format, data): | ||
| 187 | 183 | if output_format == 'json': | ||
| 188 | 184 | return json.dumps(data) | ||
| 189 | 185 | if output_format == 'yaml': | ||
| 190 | 186 | return yaml.dump(data) | ||
| 191 | 187 | raise RuntimeError('Unknown output format') | ||
| 192 | 188 | |||
| 193 | 189 | def __call__(self, default_config_path): | ||
| 194 | 190 | """Entry point for cu2d-stack-info""" | ||
| 195 | 191 | args = self.parse_arguments(default_config_path) | ||
| 196 | 192 | if not args: | ||
| 197 | 193 | return 1 | ||
| 198 | 194 | |||
| 199 | 195 | set_logging(args.debug) | ||
| 200 | 196 | default_config = load_default_cfg(args.base_path) | ||
| 201 | 197 | stackcfg = load_stack_cfg(args.stackcfg, default_config) | ||
| 202 | 198 | if not stackcfg: | ||
| 203 | 199 | logging.error('Stack configuration failed to load. Aborting!') | ||
| 204 | 200 | return 1 | ||
| 205 | 201 | if 'projects' not in stackcfg: | ||
| 206 | 202 | logging.error('No projects found in stack configuration') | ||
| 207 | 203 | return 1 | ||
| 208 | 204 | |||
| 209 | 205 | if args.list_projects: | ||
| 210 | 206 | projects = self.get_projects(stackcfg) | ||
| 211 | 207 | if not projects: | ||
| 212 | 208 | return 1 | ||
| 213 | 209 | print(self.output(args.output_format, sorted(projects))) | ||
| 214 | 210 | |||
| 215 | 211 | if args.summary: | ||
| 216 | 212 | data_dump = self.dump_stack(args.stackcfg, stackcfg) | ||
| 217 | 213 | if not data_dump: | ||
| 218 | 214 | return 1 | ||
| 219 | 215 | print(self.output(args.output_format, data_dump)) | ||
| 220 | 216 | |||
| 221 | 217 | if args.attribute: | ||
| 222 | 218 | job_type = 'autolanding' | ||
| 223 | 219 | if args.ci: | ||
| 224 | 220 | job_type = 'ci' | ||
| 225 | 221 | value = self.get_attribute(stackcfg, args.project, job_type, | ||
| 226 | 222 | args.attribute) | ||
| 227 | 223 | if not value: | ||
| 228 | 224 | logging.error("Could not find %s in stack configuration" % | ||
| 229 | 225 | args.attribute) | ||
| 230 | 226 | return 1 | ||
| 231 | 227 | print(self.output(args.output_format, value)) | ||
| 232 | 228 | return 0 | ||
| 233 | 229 | |||
| 234 | 230 | if args.ci: | ||
| 235 | 231 | name = self.get_ci_name(stackcfg, args.project, args.children) | ||
| 236 | 232 | if not name: | ||
| 237 | 233 | logging.error("Could not find %s in stack configuration" % | ||
| 238 | 234 | args.project) | ||
| 239 | 235 | return 1 | ||
| 240 | 236 | print(self.output(args.output_format, name)) | ||
| 241 | 237 | return 0 | ||
| 242 | 238 | |||
| 243 | 239 | if args.autoland: | ||
| 244 | 240 | name = self.get_autolanding_name(stackcfg, args.project, | ||
| 245 | 241 | args.children) | ||
| 246 | 242 | if not name: | ||
| 247 | 243 | logging.error("Could not find %s in stack configuration" % | ||
| 248 | 244 | args.project) | ||
| 249 | 245 | return 1 | ||
| 250 | 246 | print(self.output(args.output_format, name)) | ||
| 251 | 247 | return 0 | ||
| 252 | 0 | 248 | ||
| 253 | === added file 'ci/cu2d-stack-lookup' | |||
| 254 | --- ci/cu2d-stack-lookup 1970-01-01 00:00:00 +0000 | |||
| 255 | +++ ci/cu2d-stack-lookup 2013-07-16 19:36:23 +0000 | |||
| 256 | @@ -0,0 +1,40 @@ | |||
| 257 | 1 | #!/usr/bin/env python | ||
| 258 | 2 | """Supply information about projects and job names within a stack | ||
| 259 | 3 | |||
| 260 | 4 | - Reads stack configuration from YAML configuration file | ||
| 261 | 5 | - Returns list of projects within a stack, jobs names for a project or | ||
| 262 | 6 | specific attributes of a project | ||
| 263 | 7 | |||
| 264 | 8 | """ | ||
| 265 | 9 | # Copyright (C) 2013, Canonical Ltd (http://www.canonical.com/) | ||
| 266 | 10 | # | ||
| 267 | 11 | # Author: Francis Ginther <francis.ginther@canonical.com> | ||
| 268 | 12 | # | ||
| 269 | 13 | # This software is free software: you can redistribute it | ||
| 270 | 14 | # and/or modify it under the terms of the GNU General Public License | ||
| 271 | 15 | # as published by the Free Software Foundation, either version 3 of | ||
| 272 | 16 | # the License, or (at your option) any later version. | ||
| 273 | 17 | # | ||
| 274 | 18 | # This software is distributed in the hope that it will | ||
| 275 | 19 | # be useful, but WITHOUT ANY WARRANTY; without even the implied warranty | ||
| 276 | 20 | # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 277 | 21 | # GNU General Public License for more details. | ||
| 278 | 22 | # | ||
| 279 | 23 | # You should have received a copy of the GNU General Public License | ||
| 280 | 24 | # along with this software. If not, see <http://www.gnu.org/licenses/>. | ||
| 281 | 25 | |||
| 282 | 26 | import sys | ||
| 283 | 27 | import os | ||
| 284 | 28 | |||
| 285 | 29 | BASEDIR = os.path.dirname(__file__) | ||
| 286 | 30 | |||
| 287 | 31 | # add local c2configutils | ||
| 288 | 32 | if os.path.isdir(os.path.join(BASEDIR, '../c2dconfigutils')): | ||
| 289 | 33 | sys.path.insert(0, os.path.join(BASEDIR, '..')) | ||
| 290 | 34 | |||
| 291 | 35 | from c2dconfigutils.cu2dStackLookup import StackLookup | ||
| 292 | 36 | |||
| 293 | 37 | |||
| 294 | 38 | if __name__ == "__main__": | ||
| 295 | 39 | command = StackLookup() | ||
| 296 | 40 | sys.exit(command(BASEDIR)) | ||
| 297 | 0 | 41 | ||
| 298 | === added file 'tests/test_cu2dStackLookup.py' | |||
| 299 | --- tests/test_cu2dStackLookup.py 1970-01-01 00:00:00 +0000 | |||
| 300 | +++ tests/test_cu2dStackLookup.py 2013-07-16 19:36:23 +0000 | |||
| 301 | @@ -0,0 +1,455 @@ | |||
| 302 | 1 | from unittest import TestCase | ||
| 303 | 2 | from mock import patch, MagicMock | ||
| 304 | 3 | from StringIO import StringIO | ||
| 305 | 4 | import sys | ||
| 306 | 5 | |||
| 307 | 6 | from c2dconfigutils.cu2dStackLookup import ( | ||
| 308 | 7 | StackLookup) | ||
| 309 | 8 | |||
| 310 | 9 | |||
| 311 | 10 | class Cu2dStackLookupTestsBase(TestCase): | ||
| 312 | 11 | |||
| 313 | 12 | def setUp(self): | ||
| 314 | 13 | self.stack = { | ||
| 315 | 14 | 'ci_default': { | ||
| 316 | 15 | 'ci_template': 'ci-config.xml.tmpl', | ||
| 317 | 16 | 'autolanding_template': 'autolanding-config.xml.tmpl', | ||
| 318 | 17 | 'build_template': 'pbuilder-config.xml.tmpl', | ||
| 319 | 18 | 'ci': { | ||
| 320 | 19 | 'configurations': { | ||
| 321 | 20 | 'raring-amd64': { | ||
| 322 | 21 | 'node_label': 'pbuilder'}, | ||
| 323 | 22 | 'raring-i386': { | ||
| 324 | 23 | 'node_label': 'pbuilder'}}}}, | ||
| 325 | 24 | 'projects': { | ||
| 326 | 25 | 'autopilot': { | ||
| 327 | 26 | 'autolanding': { | ||
| 328 | 27 | 'configurations': { | ||
| 329 | 28 | 'quantal-amd64': { | ||
| 330 | 29 | 'node_label': 'pbuilder'}, | ||
| 331 | 30 | 'quantal-i386': { | ||
| 332 | 31 | 'node_label': 'pbuilder'}}}}, | ||
| 333 | 32 | 'autopilot-qt': { | ||
| 334 | 33 | 'ci_template': False}, | ||
| 335 | 34 | 'autopilot-gtk': { | ||
| 336 | 35 | 'autolanding_template': False}, | ||
| 337 | 36 | 'xpathselect': { | ||
| 338 | 37 | 'target_branch': 'lp:xpathselect/feature', | ||
| 339 | 38 | 'ci': { | ||
| 340 | 39 | 'configurations': { | ||
| 341 | 40 | 'raring-amd64': False}}}}} | ||
| 342 | 41 | self.lookup = StackLookup() | ||
| 343 | 42 | |||
| 344 | 43 | |||
| 345 | 44 | class Cu2dStackLookupMethodTests(Cu2dStackLookupTestsBase): | ||
| 346 | 45 | |||
| 347 | 46 | def test_get_projects(self): | ||
| 348 | 47 | """Verifies all project names are returned""" | ||
| 349 | 48 | expected = ['autopilot', 'autopilot-gtk', 'autopilot-qt', | ||
| 350 | 49 | 'xpathselect'] | ||
| 351 | 50 | actual = self.lookup.get_projects(self.stack) | ||
| 352 | 51 | self.assertEqual(expected, actual) | ||
| 353 | 52 | |||
| 354 | 53 | def test_get_name_ci(self): | ||
| 355 | 54 | """Verifies a ci name is generated""" | ||
| 356 | 55 | expected = ['autopilot-ci'] | ||
| 357 | 56 | actual = self.lookup._get_name(self.stack, 'autopilot', 'ci', False) | ||
| 358 | 57 | self.assertEqual(expected, actual) | ||
| 359 | 58 | |||
| 360 | 59 | def test_get_name_autolanding(self): | ||
| 361 | 60 | """Verifies an autolanding name is generated""" | ||
| 362 | 61 | expected = ['autopilot-autolanding'] | ||
| 363 | 62 | actual = self.lookup._get_name(self.stack, 'autopilot', 'autolanding', | ||
| 364 | 63 | False) | ||
| 365 | 64 | self.assertEqual(expected, actual) | ||
| 366 | 65 | |||
| 367 | 66 | def test_get_name_target_branch(self): | ||
| 368 | 67 | """Verifies a name is generated based on the target branch""" | ||
| 369 | 68 | expected = ['xpathselect-feature-ci'] | ||
| 370 | 69 | actual = self.lookup._get_name(self.stack, 'xpathselect', 'ci', False) | ||
| 371 | 70 | self.assertEqual(expected, actual) | ||
| 372 | 71 | |||
| 373 | 72 | def test_get_name_no_template(self): | ||
| 374 | 73 | """Verifies that no names are returned from a False template""" | ||
| 375 | 74 | expected = [] | ||
| 376 | 75 | actual = self.lookup._get_name(self.stack, 'autopilot-qt', 'ci', False) | ||
| 377 | 76 | self.assertEqual(expected, actual) | ||
| 378 | 77 | |||
| 379 | 78 | def test_get_name_not_found(self): | ||
| 380 | 79 | """Verifies an invalid project returns no names""" | ||
| 381 | 80 | expected = False | ||
| 382 | 81 | actual = self.lookup._get_name(self.stack, 'not-found', 'ci', False) | ||
| 383 | 82 | self.assertEqual(expected, actual) | ||
| 384 | 83 | |||
| 385 | 84 | def test_get_ci_name(self): | ||
| 386 | 85 | """Verifies a ci job is returned for a valid project""" | ||
| 387 | 86 | expected = ['autopilot-gtk-ci'] | ||
| 388 | 87 | actual = self.lookup.get_ci_name(self.stack, 'autopilot-gtk') | ||
| 389 | 88 | self.assertEqual(expected, actual) | ||
| 390 | 89 | |||
| 391 | 90 | def test_get_ci_children(self): | ||
| 392 | 91 | """Verifies ci children jobs are returned for a valid project""" | ||
| 393 | 92 | expected = ['autopilot-raring-amd64-ci', | ||
| 394 | 93 | 'autopilot-raring-i386-ci'] | ||
| 395 | 94 | actual = self.lookup.get_ci_name(self.stack, 'autopilot', | ||
| 396 | 95 | children=True) | ||
| 397 | 96 | self.assertEqual(expected, actual) | ||
| 398 | 97 | |||
| 399 | 98 | def test_get_ci_children_default_removed(self): | ||
| 400 | 99 | """Verifies a project can overide a default configuration""" | ||
| 401 | 100 | expected = ['xpathselect-feature-raring-i386-ci'] | ||
| 402 | 101 | actual = self.lookup.get_ci_name(self.stack, 'xpathselect', | ||
| 403 | 102 | children=True) | ||
| 404 | 103 | self.assertEqual(expected, actual) | ||
| 405 | 104 | |||
| 406 | 105 | def test_get_autolanding_name(self): | ||
| 407 | 106 | """Verifies an autolanding job is returned for a valid project""" | ||
| 408 | 107 | expected = ['autopilot-autolanding'] | ||
| 409 | 108 | actual = self.lookup.get_autolanding_name(self.stack, 'autopilot') | ||
| 410 | 109 | self.assertEqual(expected, actual) | ||
| 411 | 110 | |||
| 412 | 111 | def test_get_autolanding_children(self): | ||
| 413 | 112 | """Verifies autolanding children are returned for a valid project""" | ||
| 414 | 113 | expected = ['autopilot-quantal-i386-autolanding', | ||
| 415 | 114 | 'autopilot-quantal-amd64-autolanding'] | ||
| 416 | 115 | actual = self.lookup.get_autolanding_name(self.stack, 'autopilot', | ||
| 417 | 116 | children=True) | ||
| 418 | 117 | self.assertEqual(expected, actual) | ||
| 419 | 118 | |||
| 420 | 119 | def test_get_autolanding_children_no_template(self): | ||
| 421 | 120 | """Verifies that no children are returned from a False template""" | ||
| 422 | 121 | expected = [] | ||
| 423 | 122 | actual = self.lookup.get_autolanding_name(self.stack, 'autopilot-gtk', | ||
| 424 | 123 | children=True) | ||
| 425 | 124 | self.assertEqual(expected, actual) | ||
| 426 | 125 | |||
| 427 | 126 | def test_get_attribute_default_target_branch(self): | ||
| 428 | 127 | """Verifies the default target branch is returned""" | ||
| 429 | 128 | expected = 'lp:autopilot' | ||
| 430 | 129 | actual = self.lookup.get_attribute(self.stack, 'autopilot', | ||
| 431 | 130 | 'autolanding', 'target_branch') | ||
| 432 | 131 | self.assertEqual(expected, actual) | ||
| 433 | 132 | |||
| 434 | 133 | def test_get_attribute_target_branch(self): | ||
| 435 | 134 | """Verifies the stack specified target branch is returned""" | ||
| 436 | 135 | expected = 'lp:xpathselect/feature' | ||
| 437 | 136 | actual = self.lookup.get_attribute(self.stack, 'xpathselect', 'ci', | ||
| 438 | 137 | 'target_branch') | ||
| 439 | 138 | self.assertEqual(expected, actual) | ||
| 440 | 139 | |||
| 441 | 140 | def test_get_attribute_autolanding_value(self): | ||
| 442 | 141 | """Verifies the autolanding attribute value is returned""" | ||
| 443 | 142 | expected = { | ||
| 444 | 143 | 'quantal-amd64': { | ||
| 445 | 144 | 'node_label': 'pbuilder'}, | ||
| 446 | 145 | 'quantal-i386': { | ||
| 447 | 146 | 'node_label': 'pbuilder'}} | ||
| 448 | 147 | actual = self.lookup.get_attribute(self.stack, 'autopilot', | ||
| 449 | 148 | 'autolanding', 'configurations') | ||
| 450 | 149 | self.assertEqual(expected, actual) | ||
| 451 | 150 | |||
| 452 | 151 | def test_get_attribute_ci_value(self): | ||
| 453 | 152 | """Verifies the ci attribute value is returned""" | ||
| 454 | 153 | expected = { | ||
| 455 | 154 | 'raring-amd64': { | ||
| 456 | 155 | 'node_label': 'pbuilder'}, | ||
| 457 | 156 | 'raring-i386': { | ||
| 458 | 157 | 'node_label': 'pbuilder'}} | ||
| 459 | 158 | actual = self.lookup.get_attribute(self.stack, 'autopilot', | ||
| 460 | 159 | 'ci', 'configurations') | ||
| 461 | 160 | self.assertEqual(expected, actual) | ||
| 462 | 161 | |||
| 463 | 162 | def test_get_attribute_bad_project(self): | ||
| 464 | 163 | """Verifies that a missing project returns False""" | ||
| 465 | 164 | expected = False | ||
| 466 | 165 | actual = self.lookup.get_attribute(self.stack, 'bad_project', | ||
| 467 | 166 | 'ci', 'bad_key') | ||
| 468 | 167 | self.assertEqual(expected, actual) | ||
| 469 | 168 | |||
| 470 | 169 | def test_get_attribute_bad_value(self): | ||
| 471 | 170 | """Verifies that a missing key raises a KeyError""" | ||
| 472 | 171 | with self.assertRaises(KeyError): | ||
| 473 | 172 | self.lookup.get_attribute(self.stack, 'autopilot', 'ci', | ||
| 474 | 173 | 'bad_key') | ||
| 475 | 174 | |||
| 476 | 175 | |||
| 477 | 176 | class Cu2dStackLookupCallTests(Cu2dStackLookupTestsBase): | ||
| 478 | 177 | |||
| 479 | 178 | def setUp(self): | ||
| 480 | 179 | super(Cu2dStackLookupCallTests, self).setUp() | ||
| 481 | 180 | self.args = type('Args', (object,), {'debug': False, | ||
| 482 | 181 | 'base_path': '/tmp', | ||
| 483 | 182 | 'list_projects': False, | ||
| 484 | 183 | 'project': None, | ||
| 485 | 184 | 'autoland': False, | ||
| 486 | 185 | 'ci': False, | ||
| 487 | 186 | 'attribute': None, | ||
| 488 | 187 | 'children': False, | ||
| 489 | 188 | 'stackcfg': 'stack.cfg'}) | ||
| 490 | 189 | self.lookup.parse_arguments = lambda x: self.args | ||
| 491 | 190 | self.saved_stdout = sys.stdout | ||
| 492 | 191 | self.stdout = StringIO() | ||
| 493 | 192 | sys.stdout = self.stdout | ||
| 494 | 193 | |||
| 495 | 194 | def tearDown(self): | ||
| 496 | 195 | sys.stdout = self.saved_stdout | ||
| 497 | 196 | |||
| 498 | 197 | def test_bad_args(self): | ||
| 499 | 198 | """Verifies error return for invalid arguments""" | ||
| 500 | 199 | expected = 1 | ||
| 501 | 200 | self.args = None | ||
| 502 | 201 | actual = self.lookup('/tmp') | ||
| 503 | 202 | self.assertEqual(expected, actual) | ||
| 504 | 203 | |||
| 505 | 204 | def test_no_stack(self): | ||
| 506 | 205 | """Verifies error return for an invalid stack file""" | ||
| 507 | 206 | expected = 1 | ||
| 508 | 207 | self.args.list_projects = True | ||
| 509 | 208 | with patch('c2dconfigutils.cu2dStackLookup.load_default_cfg', | ||
| 510 | 209 | new=lambda x: True), \ | ||
| 511 | 210 | patch('c2dconfigutils.cu2dStackLookup.load_stack_cfg', | ||
| 512 | 211 | new=lambda x, y: {}): | ||
| 513 | 212 | actual = self.lookup('/tmp') | ||
| 514 | 213 | self.assertEqual(expected, actual) | ||
| 515 | 214 | |||
| 516 | 215 | def test_no_projects(self): | ||
| 517 | 216 | """Verifies error return for a stack file with no projects""" | ||
| 518 | 217 | expected = 1 | ||
| 519 | 218 | self.args.list_projects = True | ||
| 520 | 219 | with patch('c2dconfigutils.cu2dStackLookup.load_default_cfg', | ||
| 521 | 220 | new=lambda x: True), \ | ||
| 522 | 221 | patch('c2dconfigutils.cu2dStackLookup.load_stack_cfg', | ||
| 523 | 222 | new=lambda x, y: {'ci_default': {}}): | ||
| 524 | 223 | actual = self.lookup('/tmp') | ||
| 525 | 224 | self.assertEqual(expected, actual) | ||
| 526 | 225 | |||
| 527 | 226 | def test_get_projects(self): | ||
| 528 | 227 | """Verifies output for a project list request""" | ||
| 529 | 228 | expected = 0 | ||
| 530 | 229 | self.args.list_projects = True | ||
| 531 | 230 | with patch('c2dconfigutils.cu2dStackLookup.load_default_cfg', | ||
| 532 | 231 | new=lambda x: True), \ | ||
| 533 | 232 | patch('c2dconfigutils.cu2dStackLookup.load_stack_cfg', | ||
| 534 | 233 | new=lambda x, y: self.stack): | ||
| 535 | 234 | actual = self.lookup('/tmp') | ||
| 536 | 235 | self.assertEqual(expected, actual) | ||
| 537 | 236 | output = '["autopilot", "autopilot-gtk", "autopilot-qt", ' \ | ||
| 538 | 237 | '"xpathselect"]' | ||
| 539 | 238 | self.assertEqual(output, self.stdout.getvalue().strip()) | ||
| 540 | 239 | |||
| 541 | 240 | def test_get_projects_none_found(self): | ||
| 542 | 241 | """Verifies error return when stack file contains no projects""" | ||
| 543 | 242 | expected = 1 | ||
| 544 | 243 | self.args.list_projects = True | ||
| 545 | 244 | with patch('c2dconfigutils.cu2dStackLookup.load_default_cfg', | ||
| 546 | 245 | new=lambda x: True), \ | ||
| 547 | 246 | patch('c2dconfigutils.cu2dStackLookup.load_stack_cfg', | ||
| 548 | 247 | new=lambda x, y: {'projects': {}}): | ||
| 549 | 248 | actual = self.lookup('/tmp') | ||
| 550 | 249 | self.assertEqual(expected, actual) | ||
| 551 | 250 | |||
| 552 | 251 | def test_get_attribute_ci(self): | ||
| 553 | 252 | """Verifies output for an attribute request""" | ||
| 554 | 253 | expected = 0 | ||
| 555 | 254 | self.args.attribute = 'target_branch' | ||
| 556 | 255 | self.args.ci = True | ||
| 557 | 256 | self.args.project = 'xpathselect' | ||
| 558 | 257 | with patch('c2dconfigutils.cu2dStackLookup.load_default_cfg', | ||
| 559 | 258 | new=lambda x: True), \ | ||
| 560 | 259 | patch('c2dconfigutils.cu2dStackLookup.load_stack_cfg', | ||
| 561 | 260 | new=lambda x, y: self.stack): | ||
| 562 | 261 | actual = self.lookup('/tmp') | ||
| 563 | 262 | self.assertEqual(expected, actual) | ||
| 564 | 263 | output = '"lp:xpathselect/feature"' | ||
| 565 | 264 | self.assertEqual(output, self.stdout.getvalue().strip()) | ||
| 566 | 265 | |||
| 567 | 266 | def test_get_attribute_autoland(self): | ||
| 568 | 267 | """Verifies out for an attribute request for an autolanding job""" | ||
| 569 | 268 | expected = 0 | ||
| 570 | 269 | self.args.attribute = 'target_branch' | ||
| 571 | 270 | self.args.project = 'xpathselect' | ||
| 572 | 271 | with patch('c2dconfigutils.cu2dStackLookup.load_default_cfg', | ||
| 573 | 272 | new=lambda x: True), \ | ||
| 574 | 273 | patch('c2dconfigutils.cu2dStackLookup.load_stack_cfg', | ||
| 575 | 274 | new=lambda x, y: self.stack): | ||
| 576 | 275 | actual = self.lookup('/tmp') | ||
| 577 | 276 | self.assertEqual(expected, actual) | ||
| 578 | 277 | output = '"lp:xpathselect/feature"' | ||
| 579 | 278 | self.assertEqual(output, self.stdout.getvalue().strip()) | ||
| 580 | 279 | |||
| 581 | 280 | def test_get_attribute_no_project(self): | ||
| 582 | 281 | """Verifies error return when the project is not found""" | ||
| 583 | 282 | expected = 1 | ||
| 584 | 283 | self.args.attribute = 'target_branch' | ||
| 585 | 284 | self.args.project = 'not-found' | ||
| 586 | 285 | with patch('c2dconfigutils.cu2dStackLookup.load_default_cfg', | ||
| 587 | 286 | new=lambda x: True), \ | ||
| 588 | 287 | patch('c2dconfigutils.cu2dStackLookup.load_stack_cfg', | ||
| 589 | 288 | new=lambda x, y: self.stack): | ||
| 590 | 289 | actual = self.lookup('/tmp') | ||
| 591 | 290 | self.assertEqual(expected, actual) | ||
| 592 | 291 | |||
| 593 | 292 | def test_get_ci_name(self): | ||
| 594 | 293 | """Verifies output for a ci job list request""" | ||
| 595 | 294 | expected = 0 | ||
| 596 | 295 | self.args.ci = True | ||
| 597 | 296 | self.args.project = 'autopilot' | ||
| 598 | 297 | with patch('c2dconfigutils.cu2dStackLookup.load_default_cfg', | ||
| 599 | 298 | new=lambda x: True), \ | ||
| 600 | 299 | patch('c2dconfigutils.cu2dStackLookup.load_stack_cfg', | ||
| 601 | 300 | new=lambda x, y: self.stack): | ||
| 602 | 301 | actual = self.lookup('/tmp') | ||
| 603 | 302 | self.assertEqual(expected, actual) | ||
| 604 | 303 | output = '["autopilot-ci"]' | ||
| 605 | 304 | self.assertEqual(output, self.stdout.getvalue().strip()) | ||
| 606 | 305 | |||
| 607 | 306 | def test_get_ci_name_no_project(self): | ||
| 608 | 307 | """Verifies error return when the project is not found""" | ||
| 609 | 308 | expected = 1 | ||
| 610 | 309 | self.args.ci = True | ||
| 611 | 310 | self.args.project = 'not-found' | ||
| 612 | 311 | with patch('c2dconfigutils.cu2dStackLookup.load_default_cfg', | ||
| 613 | 312 | new=lambda x: True), \ | ||
| 614 | 313 | patch('c2dconfigutils.cu2dStackLookup.load_stack_cfg', | ||
| 615 | 314 | new=lambda x, y: self.stack): | ||
| 616 | 315 | actual = self.lookup('/tmp') | ||
| 617 | 316 | self.assertEqual(expected, actual) | ||
| 618 | 317 | |||
| 619 | 318 | def test_get_autolanding_name(self): | ||
| 620 | 319 | """Verifies output for an autolanding job list request""" | ||
| 621 | 320 | expected = 0 | ||
| 622 | 321 | self.args.autoland = True | ||
| 623 | 322 | self.args.project = 'autopilot' | ||
| 624 | 323 | with patch('c2dconfigutils.cu2dStackLookup.load_default_cfg', | ||
| 625 | 324 | new=lambda x: True), \ | ||
| 626 | 325 | patch('c2dconfigutils.cu2dStackLookup.load_stack_cfg', | ||
| 627 | 326 | new=lambda x, y: self.stack): | ||
| 628 | 327 | actual = self.lookup('/tmp') | ||
| 629 | 328 | self.assertEqual(expected, actual) | ||
| 630 | 329 | output = '["autopilot-autolanding"]' | ||
| 631 | 330 | self.assertEqual(output, self.stdout.getvalue().strip()) | ||
| 632 | 331 | |||
| 633 | 332 | def test_get_autolanding_name_no_project(self): | ||
| 634 | 333 | """Verifies error return when the project is not found""" | ||
| 635 | 334 | expected = 1 | ||
| 636 | 335 | self.args.autoland = True | ||
| 637 | 336 | self.args.project = 'not-found' | ||
| 638 | 337 | with patch('c2dconfigutils.cu2dStackLookup.load_default_cfg', | ||
| 639 | 338 | new=lambda x: True), \ | ||
| 640 | 339 | patch('c2dconfigutils.cu2dStackLookup.load_stack_cfg', | ||
| 641 | 340 | new=lambda x, y: self.stack): | ||
| 642 | 341 | actual = self.lookup('/tmp') | ||
| 643 | 342 | self.assertEqual(expected, actual) | ||
| 644 | 343 | |||
| 645 | 344 | |||
| 646 | 345 | class TestParseArguments(TestCase): | ||
| 647 | 346 | def setUp(self): | ||
| 648 | 347 | self.error_mock = MagicMock() | ||
| 649 | 348 | |||
| 650 | 349 | def test_gibberish(self): | ||
| 651 | 350 | """Verifies invalid arguments returns an error""" | ||
| 652 | 351 | sys_argv = ['./command', '-oheck'] | ||
| 653 | 352 | with patch('sys.argv', sys_argv): | ||
| 654 | 353 | with patch('argparse.ArgumentParser.error', self.error_mock): | ||
| 655 | 354 | lookup = StackLookup() | ||
| 656 | 355 | lookup.parse_arguments('') | ||
| 657 | 356 | self.error_mock.assert_any_call( | ||
| 658 | 357 | 'too few arguments') | ||
| 659 | 358 | |||
| 660 | 359 | def test_noparams(self): | ||
| 661 | 360 | """Verifies no arguments returns a too few arguments error""" | ||
| 662 | 361 | sys_argv = ['./command'] | ||
| 663 | 362 | with patch('sys.argv', sys_argv): | ||
| 664 | 363 | with patch('argparse.ArgumentParser.error', self.error_mock): | ||
| 665 | 364 | lookup = StackLookup() | ||
| 666 | 365 | lookup.parse_arguments('') | ||
| 667 | 366 | self.error_mock.assert_any_call( | ||
| 668 | 367 | 'too few arguments') | ||
| 669 | 368 | |||
| 670 | 369 | def test_missing_main_option(self): | ||
| 671 | 370 | """Verify error is returned for a missing primary option""" | ||
| 672 | 371 | sys_argv = ['./command', 'stack.cfg'] | ||
| 673 | 372 | with patch('sys.argv', sys_argv): | ||
| 674 | 373 | with patch('argparse.ArgumentParser.error', self.error_mock): | ||
| 675 | 374 | lookup = StackLookup() | ||
| 676 | 375 | lookup.parse_arguments('') | ||
| 677 | 376 | self.error_mock.assert_called_with( | ||
| 678 | 377 | 'Must specify one of -l/--list-projects or -p/--project') | ||
| 679 | 378 | |||
| 680 | 379 | def test_missing_project_option(self): | ||
| 681 | 380 | """Verify error is returned for a missing project option""" | ||
| 682 | 381 | sys_argv = ['./command', '--project', 'foo', 'stack.cfg'] | ||
| 683 | 382 | with patch('sys.argv', sys_argv): | ||
| 684 | 383 | with patch('argparse.ArgumentParser.error', self.error_mock): | ||
| 685 | 384 | lookup = StackLookup() | ||
| 686 | 385 | lookup.parse_arguments('') | ||
| 687 | 386 | self.error_mock.assert_called_with( | ||
| 688 | 387 | 'Must specify -a/--autolanding, -c/--ci or ' | ||
| 689 | 388 | '-t/--attribute with -p/--project') | ||
| 690 | 389 | |||
| 691 | 390 | def test_missing_project_option_with_children(self): | ||
| 692 | 391 | """Verify error is returned for a missing project and children | ||
| 693 | 392 | option""" | ||
| 694 | 393 | sys_argv = ['./command', '--project', 'foo', '--attribute', | ||
| 695 | 394 | 'target_branch', '--children', 'stack.cfg'] | ||
| 696 | 395 | with patch('sys.argv', sys_argv): | ||
| 697 | 396 | with patch('argparse.ArgumentParser.error', self.error_mock): | ||
| 698 | 397 | lookup = StackLookup() | ||
| 699 | 398 | lookup.parse_arguments('') | ||
| 700 | 399 | self.error_mock.assert_called_with( | ||
| 701 | 400 | 'Must specify -a/--autolanding or -c/--ci with ' | ||
| 702 | 401 | '-i/--children') | ||
| 703 | 402 | |||
| 704 | 403 | def test_list_projects(self): | ||
| 705 | 404 | """Verify a list projects request""" | ||
| 706 | 405 | sys_argv = ['./command', '-l', 'stack.cfg'] | ||
| 707 | 406 | with patch('sys.argv', sys_argv): | ||
| 708 | 407 | lookup = StackLookup() | ||
| 709 | 408 | ret = lookup.parse_arguments('') | ||
| 710 | 409 | self.assertTrue(ret.list_projects) | ||
| 711 | 410 | |||
| 712 | 411 | def test_project_ci(self): | ||
| 713 | 412 | """Verify a ci job request""" | ||
| 714 | 413 | sys_argv = ['./command', '-p', 'project', '-c', 'stack.cfg'] | ||
| 715 | 414 | with patch('sys.argv', sys_argv): | ||
| 716 | 415 | lookup = StackLookup() | ||
| 717 | 416 | ret = lookup.parse_arguments('') | ||
| 718 | 417 | self.assertTrue(ret.ci) | ||
| 719 | 418 | self.assertEqual('project', ret.project) | ||
| 720 | 419 | |||
| 721 | 420 | def test_project_autoland(self): | ||
| 722 | 421 | """Verify a ci job request""" | ||
| 723 | 422 | sys_argv = ['./command', '-p', 'project', '-a', 'stack.cfg'] | ||
| 724 | 423 | with patch('sys.argv', sys_argv): | ||
| 725 | 424 | lookup = StackLookup() | ||
| 726 | 425 | ret = lookup.parse_arguments('') | ||
| 727 | 426 | self.assertTrue(ret.autoland) | ||
| 728 | 427 | self.assertEqual('project', ret.project) | ||
| 729 | 428 | |||
| 730 | 429 | def test_project_ci_children(self): | ||
| 731 | 430 | """Verify a ci job request""" | ||
| 732 | 431 | sys_argv = ['./command', '-p', 'project', '-c', '-i', 'stack.cfg'] | ||
| 733 | 432 | with patch('sys.argv', sys_argv): | ||
| 734 | 433 | lookup = StackLookup() | ||
| 735 | 434 | ret = lookup.parse_arguments('') | ||
| 736 | 435 | self.assertTrue(ret.ci) | ||
| 737 | 436 | self.assertTrue(ret.children) | ||
| 738 | 437 | |||
| 739 | 438 | def test_project_autoland_children(self): | ||
| 740 | 439 | """Verify a ci job request""" | ||
| 741 | 440 | sys_argv = ['./command', '-p', 'project', '-a', '-i', 'stack.cfg'] | ||
| 742 | 441 | with patch('sys.argv', sys_argv): | ||
| 743 | 442 | lookup = StackLookup() | ||
| 744 | 443 | ret = lookup.parse_arguments('') | ||
| 745 | 444 | self.assertTrue(ret.autoland) | ||
| 746 | 445 | self.assertTrue(ret.children) | ||
| 747 | 446 | |||
| 748 | 447 | def test_project_attribute(self): | ||
| 749 | 448 | """Verify a ci job request""" | ||
| 750 | 449 | sys_argv = ['./command', '-p', 'project', '-t', 'target_branch', | ||
| 751 | 450 | 'stack.cfg'] | ||
| 752 | 451 | with patch('sys.argv', sys_argv): | ||
| 753 | 452 | lookup = StackLookup() | ||
| 754 | 453 | ret = lookup.parse_arguments('') | ||
| 755 | 454 | self.assertEqual('project', ret.project) | ||
| 756 | 455 | self.assertEqual('target_branch', ret.attribute) | ||
PASSED: Continuous integration, rev:424 jenkins. qa.ubuntu. com/job/ cupstream2distr o-config- ci/305/ jenkins. qa.ubuntu. com/job/ cupstream2distr o-config- saucy-amd64- ci/103
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ cupstream2distr o-config- ci/305/ rebuild
http://