├── .env.sample ├── .gitignore ├── .pkgr.yml ├── .rspec ├── .ruby-version ├── .travis.yml ├── Berksfile ├── Berksfile.lock ├── CHANGELOG.md ├── Gemfile ├── Gemfile.lock ├── Guardfile ├── LICENSE ├── Makefile ├── Procfile ├── README.md ├── Rakefile ├── Vagrantfile ├── app ├── assets │ ├── font │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff │ ├── images │ │ ├── bg.png │ │ ├── blue.png │ │ ├── blue@2x.png │ │ ├── core_admin.png │ │ ├── core_admin_small.png │ │ ├── groups.png │ │ ├── ie-spacer.gif │ │ ├── loading.gif │ │ ├── logo.png │ │ ├── noise-blue-repeat.png │ │ └── rails.png │ ├── javascripts │ │ ├── application.js │ │ ├── d3.v3.js │ │ ├── datatabler.js │ │ ├── graphing.js │ │ ├── jquery.countdown.js │ │ ├── navbar.js │ │ ├── nv.d3.js │ │ ├── scenarios.js.coffee │ │ ├── shC.js │ │ ├── shXml.js │ │ ├── test_runs.js.coffee.erb │ │ └── theme.js │ └── stylesheets │ │ ├── application.css.scss │ │ ├── custom.css.scss │ │ ├── datatables.css.scss │ │ ├── font-awesome.css │ │ ├── nv.d3.css │ │ ├── scenarios.css.scss │ │ ├── shCore.css │ │ ├── shThemeDefault.css │ │ ├── test_runs.css.scss │ │ └── theme.css ├── controllers │ ├── application_controller.rb │ ├── home_controller.rb │ ├── profiles_controller.rb │ ├── scenarios_controller.rb │ ├── targets_controller.rb │ ├── test_runs_controller.rb │ ├── users │ │ └── omniauth_callbacks_controller.rb │ └── users_controller.rb ├── enums │ └── transport_type.rb ├── helpers │ ├── application_helper.rb │ └── home_helper.rb ├── mailers │ └── .gitkeep ├── models │ ├── .gitkeep │ ├── ability.rb │ ├── profile.rb │ ├── rtcp_data.rb │ ├── scenario.rb │ ├── sipp_data.rb │ ├── system_load_datum.rb │ ├── target.rb │ ├── test_run.rb │ └── user.rb ├── services │ ├── rtcp_parser.rb │ ├── rtcp_tools.rb │ ├── rtcp_tools │ │ └── listener.rb │ ├── runner.rb │ ├── sipp_parser.rb │ ├── stats_collector.rb │ ├── test_runner.rb │ └── vmstat_parser.rb ├── uploaders │ ├── errors_report_file_uploader.rb │ ├── pcap_audio_uploader.rb │ └── stats_file_uploader.rb ├── views │ ├── home │ │ └── index.html.haml │ ├── kaminari │ │ ├── list │ │ │ ├── _first_page.html.haml │ │ │ ├── _gap.html.haml │ │ │ ├── _last_page.html.haml │ │ │ ├── _next_page.html.haml │ │ │ ├── _page.html.haml │ │ │ ├── _paginator.html.haml │ │ │ └── _prev_page.html.haml │ │ └── table │ │ │ ├── _first_page.html.haml │ │ │ ├── _gap.html.haml │ │ │ ├── _last_page.html.haml │ │ │ ├── _next_page.html.haml │ │ │ ├── _page.html.haml │ │ │ ├── _paginator.html.haml │ │ │ └── _prev_page.html.haml │ ├── layouts │ │ ├── _blue_strip.html.haml │ │ ├── _footer.html.haml │ │ ├── _head.html.haml │ │ ├── _messages.html.haml │ │ ├── _page_header.html.haml │ │ ├── _sidebar.html.haml │ │ ├── _top_navigation.html.haml │ │ └── application.html.haml │ ├── partials │ │ └── _bool_badge.html.haml │ ├── profiles │ │ ├── _form.html.haml │ │ ├── edit.html.haml │ │ ├── index.html.haml │ │ ├── new.html.haml │ │ └── show.html.haml │ ├── scenarios │ │ ├── _form.html.haml │ │ ├── edit.html.haml │ │ ├── index.html.haml │ │ ├── new.html.haml │ │ └── show.html.haml │ ├── targets │ │ ├── _form.html.haml │ │ ├── edit.html.haml │ │ ├── index.html.haml │ │ ├── new.html.haml │ │ └── show.html.haml │ ├── test_runs │ │ ├── _form.html.haml │ │ ├── edit.html.haml │ │ ├── index.html.haml │ │ ├── new.html.haml │ │ └── show.html.haml │ └── users │ │ ├── edit.html.haml │ │ ├── index.html.haml │ │ └── show.html.haml └── workers │ └── test_run_worker.rb ├── config.ru ├── config ├── application.rb ├── boot.rb ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── fog_credentials.yml ├── initializers │ ├── 01_parse_vcap.rb │ ├── airbrake.rb │ ├── backtrace_silencers.rb │ ├── carrierwave.rb │ ├── devise.rb │ ├── inflections.rb │ ├── kaminari.rb │ ├── mime_types.rb │ ├── omniauth.rb │ ├── secret_token.rb │ ├── session_store.rb │ ├── sidekiq.rb │ ├── simple_form.rb │ ├── simple_form_bootstrap.rb │ └── wrap_parameters.rb ├── locales │ ├── devise.en.yml │ ├── en.yml │ └── simple_form.en.yml └── routes.rb ├── db ├── migrate │ ├── 20130718193845_create_users.rb │ ├── 20130718231537_create_scenarios.rb │ ├── 20130719001047_create_profiles.rb │ ├── 20130719004508_create_targets.rb │ ├── 20130719005907_remove_scenario_id_from_profiles.rb │ ├── 20130719010213_create_test_runs.rb │ ├── 20130719011059_add_user_id_to_test_run.rb │ ├── 20130813165413_create_rtcp_data.rb │ ├── 20130813171603_create_sipp_data.rb │ ├── 20130815073021_add_run_status_to_test_run.rb │ ├── 20130816153851_add_response_time_to_sipp_data.rb │ ├── 20130820123419_add_jid_to_test_run.rb │ ├── 20130823181127_add_sippy_cup_scenario_to_scenario.rb │ ├── 20130829131123_add_enqueued_at_started_at_completed_at_state_to_test_runs.rb │ ├── 20130829163022_remove_run_status_from_test_runs.rb │ ├── 20130903162859_add_csv_data_to_scenario.rb │ ├── 20130904085924_add_receiver_to_scenarios.rb │ ├── 20130904090726_add_receiver_scenario_id_to_test_run.rb │ ├── 20130904155102_add_user_id_to_targets.rb │ ├── 20130904161150_add_user_id_to_profiles.rb │ ├── 20130904161817_add_user_id_to_scenarios.rb │ ├── 20130904201939_add_admin_fields_to_users.rb │ ├── 20130905160536_remove_perma_admin_from_users.rb │ ├── 20130905234209_add_registration_scenario_id_to_test_run.rb │ ├── 20130906154523_add_registration_scenario_to_scenario.rb │ ├── 20130906193214_remove_registration_scenario_id_from_test_run.rb │ ├── 20130908161710_add_error_logging_columns_to_test_runs.rb │ ├── 20130913155706_add_description_to_scenario.rb │ ├── 20130913164234_add_transport_type_to_profile.rb │ ├── 20130916205553_update_transport_on_profiles.rb │ ├── 20130916211948_add_username_to_target.rb │ ├── 20130917163559_create_system_load_data.rb │ ├── 20130930174850_change_error_message_to_text.rb │ ├── 20131023225343_add_authentication_token_to_user.rb │ ├── 20140101171241_add_name_to_user.rb │ ├── 20141005150720_add_reports_to_test_run.rb │ ├── 20141006032516_add_rate_scaling_to_profile.rb │ ├── 20141018225244_add_to_user_to_test_runs.rb │ ├── 20150202215251_add_params_to_test_run.rb │ ├── 20150216173416_allow_multiline_sipp_options_on_test_runs.rb │ └── 20150414001332_add_cumulative_to_sipp_data.rb ├── schema.rb └── seeds.rb ├── lib ├── assets │ └── .gitkeep ├── tasks │ └── .gitkeep └── templates │ └── erb │ └── scaffold │ └── _form.html.erb ├── packaging └── wizards │ └── siptreadmill │ ├── bin │ ├── compile │ ├── configure │ ├── postinstall │ └── preinstall │ └── templates ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico └── robots.txt ├── script └── rails ├── sipp ├── files │ └── default │ │ └── sipp_dyn_pcap.diff ├── metadata.rb └── recipes │ └── default.rb ├── spec ├── assets │ ├── rtcp.json │ └── sipp.csv ├── controllers │ └── test_run_controller_spec.rb ├── factories │ ├── profile.rb │ ├── rtcp_data.rb │ ├── scenario.rb │ ├── sipp_data.rb │ ├── system_load_data.rb │ ├── target.rb │ ├── test_run.rb │ └── user.rb ├── features │ └── test_runs_spec.rb ├── fixtures │ ├── audio.pcap │ ├── dtmf_2833_1.pcap │ ├── errors.txt │ └── vmstat_fixture.log ├── helpers │ └── home_helper_spec.rb ├── models │ ├── profile_spec.rb │ ├── rtcp_data_spec.rb │ ├── scenario_spec.rb │ ├── sipp_data_spec.rb │ ├── system_load_data_spec.rb │ ├── target_spec.rb │ ├── test_run_spec.rb │ └── user_spec.rb ├── requests │ ├── scenarios_spec.rb │ └── test_runs_spec.rb ├── services │ ├── rtcp_tools │ │ └── listener_spec.rb │ ├── rtcp_tools_spec.rb │ ├── runner_spec.rb │ ├── sipp_parser_spec.rb │ ├── stats_collector_spec.rb │ ├── test_runner_spec.rb │ └── vmstat_parser_spec.rb ├── spec_helper.rb ├── support │ └── helpers.rb └── workers │ └── test_run_worker_spec.rb ├── treadmill ├── metadata.rb └── recipes │ ├── app.rb │ └── database.rb └── vendor ├── assets ├── javascripts │ └── .gitkeep └── stylesheets │ └── .gitkeep └── cache ├── actionmailer-3.2.19.gem ├── actionpack-3.2.19.gem ├── activemodel-3.2.19.gem ├── activerecord-3.2.19.gem ├── activeresource-3.2.19.gem ├── activesupport-3.2.19.gem ├── addressable-2.3.5.gem ├── airbrake-4.1.0.gem ├── arel-3.0.3.gem ├── bcrypt-ruby-3.1.1.gem ├── better_errors-0.9.0.gem ├── binding_of_caller-0.7.2.gem ├── bourbon-3.1.8.gem ├── builder-3.0.4.gem ├── cancan-1.6.10.gem ├── capybara-2.1.0.gem ├── carrierwave-0.10.0.gem ├── celluloid-0.14.1.gem ├── classy_enum-3.3.1.gem ├── cliver-0.2.1.gem ├── coderay-1.0.9.gem ├── coffee-rails-3.2.2.gem ├── coffee-script-2.2.0.gem ├── coffee-script-source-1.6.3.gem ├── connection_pool-1.1.0.gem ├── countdownlatch-1.0.0.gem ├── crack-0.4.1.gem ├── daemons-1.1.9.gem ├── database_cleaner-1.0.1.gem ├── debug_inspector-0.0.2.gem ├── devise-3.0.2.gem ├── diff-lcs-1.2.5.gem ├── dotenv-0.9.0.gem ├── erubis-2.7.0.gem ├── eventmachine-1.0.7.gem ├── excon-0.25.3.gem ├── execjs-1.4.0.gem ├── factory_girl-4.5.0.gem ├── factory_girl_rails-4.5.0.gem ├── fakefs-0.4.2.gem ├── faraday-0.8.8.gem ├── ffi-1.9.0.gem ├── fog-1.14.0.gem ├── foreman-0.63.0.gem ├── formatador-0.2.4.gem ├── guard-1.8.2.gem ├── guard-rspec-3.0.2.gem ├── haml-4.0.3.gem ├── hashie-2.0.5.gem ├── hike-1.2.3.gem ├── httpauth-0.2.0.gem ├── i18n-0.7.0.gem ├── journey-1.0.4.gem ├── jquery-datatables-rails-1.11.2.gem ├── jquery-rails-3.0.4.gem ├── json-1.8.2.gem ├── jwt-0.1.8.gem ├── kaminari-0.14.1.gem ├── libv8-3.16.14.7-x86_64-darwin-13.gem ├── libv8-3.16.14.7-x86_64-linux.gem ├── listen-1.2.3.gem ├── lumberjack-1.0.4.gem ├── mail-2.5.4.gem ├── method_source-0.8.2.gem ├── mime-types-1.25.1.gem ├── mini_portile-0.6.0.gem ├── minitest-5.4.3.gem ├── multi_json-1.11.0.gem ├── multipart-post-1.2.0.gem ├── net-scp-1.1.2.gem ├── net-ssh-2.6.8.gem ├── nokogiri-1.6.3.1.gem ├── oauth2-0.8.1.gem ├── omniauth-1.1.4.gem ├── omniauth-github-1.1.2.gem ├── omniauth-oauth2-1.1.1.gem ├── orm_adapter-0.4.0.gem ├── packetfu-1.1.10.gem ├── pg-0.16.0.gem ├── poltergeist-1.4.1.gem ├── polyglot-0.3.5.gem ├── power_assert-0.2.2.gem ├── pry-0.9.12.2.gem ├── pry-rails-0.3.2.gem ├── psych-2.0.13.gem ├── quiet_assets-1.0.2.gem ├── rack-1.4.5.gem ├── rack-cache-1.2.gem ├── rack-protection-1.5.0.gem ├── rack-ssl-1.3.4.gem ├── rack-test-0.6.2.gem ├── rails-3.2.19.gem ├── rails_12factor-0.0.3.gem ├── rails_serve_static_assets-0.0.4.gem ├── rails_stdout_logging-0.0.3.gem ├── railties-3.2.19.gem ├── rake-10.3.2.gem ├── rb-fsevent-0.9.3.gem ├── rb-inotify-0.9.1.gem ├── rb-kqueue-0.2.0.gem ├── rdoc-3.12.2.gem ├── redis-3.0.4.gem ├── redis-namespace-1.3.1.gem ├── ref-1.0.5.gem ├── rspec-2.14.1.gem ├── rspec-core-2.14.8.gem ├── rspec-expectations-2.14.5.gem ├── rspec-mocks-2.14.6.gem ├── rspec-rails-2.14.0.gem ├── ruby-hmac-0.4.0.gem ├── safe_yaml-0.9.5.gem ├── sass-3.2.10.gem ├── sass-rails-3.2.6.gem ├── sidekiq-2.13.1.gem ├── simple_form-2.1.0.gem ├── sinatra-1.4.3.gem ├── sippy_cup-0.6.0.gem ├── slim-2.0.1.gem ├── slop-3.4.6.gem ├── sprockets-2.2.2.gem ├── state_machine-1.2.0.gem ├── temple-0.6.6.gem ├── test-unit-3.0.8.gem ├── therubyracer-0.12.0.gem ├── thin-1.5.1.gem ├── thor-0.19.1.gem ├── tilt-1.4.1.gem ├── timecop-0.6.3.gem ├── timers-1.1.0.gem ├── treetop-1.4.15.gem ├── turbo-sprockets-rails3-0.3.14.gem ├── tzinfo-0.3.41.gem ├── uglifier-2.1.2.gem ├── warden-1.2.3.gem ├── webmock-1.13.0.gem ├── websocket-driver-0.2.3.gem └── xpath-2.0.0.gem /.env.sample: -------------------------------------------------------------------------------- 1 | RACK_ENV=development 2 | COOKIE_SECRET='8rnvltcokysxzissqpyjkvb7rjjaujln8rnvltcokysxzissqpyjkvb7rjjaujln8rnvltcokysxzissqpyjkvb7rjjaujln8rnvltcokysxzissqpyjkvb7rjjaujln8rnvltcokysxzissqpyjkvb7rjjaujln8rnvltcokysxzissqpyjkvb7rjjaujln8rnvltcokysxzissqpyjkvb7rjjaujln8rnvltcokysxzissqpyjkvb7rjjaujln8rnvltcokysxzissqpyjkvb7rjjaujln' 3 | OMNIAUTH_TYPE=none 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile ~/.gitignore_global 6 | 7 | # Ignore bundler config 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | 13 | # Ignore all logfiles and tempfiles. 14 | /log/*.log 15 | /tmp 16 | 17 | # Editor temp files 18 | .*.sw* 19 | 20 | # Application configuration 21 | /.env 22 | 23 | .DS_Store 24 | 25 | public/uploads 26 | 27 | .ruby-gemset 28 | 29 | /public/assets 30 | 31 | # Development environment things 32 | .vagrant 33 | vagrant/ 34 | cookbooks 35 | -------------------------------------------------------------------------------- /.pkgr.yml: -------------------------------------------------------------------------------- 1 | description: Web application to faciliate benchmarking and testing SIP based services 2 | homepage: http://adhearsion.github.io/SIPtreadmill/ 3 | vendor: Adhearsion Foundation Inc 4 | maintainer: Adhearsion Foundation Inc 5 | license: MIT 6 | changelog: CHANGELOG.md 7 | targets: 8 | ubuntu-14.04: 9 | installer: https://github.com/pkgr/installer.git#master 10 | wizards: 11 | - https://github.com/pkgr/addon-apache2.git 12 | - ./packaging/wizards/siptreadmill 13 | after: 14 | - rm -rf .git app/assets packaging sipp treadmill tmp vendor/cache 15 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format documentation 3 | --profile 4 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.2.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.2.0 4 | before_script: 5 | - cp .env.sample .env 6 | - bundle exec rake db:create db:setup 7 | env: DATABASE_USERNAME=postgres DATABASE_PASSWORD='' 8 | cache: bundler 9 | script: bundle exec rspec spec 10 | sudo: false 11 | services: 12 | - redis-server 13 | -------------------------------------------------------------------------------- /Berksfile: -------------------------------------------------------------------------------- 1 | source "http://api.berkshelf.com" 2 | 3 | cookbook 'treadmill', path: 'treadmill' 4 | cookbook 'sipp', path: 'sipp' 5 | 6 | cookbook 'apt' 7 | cookbook 'freeswitch', git: 'https://github.com/benlangfeld/freeswitch-cookbook.git', ref: '50648a22478fee37f40d2793ae85910a3e47e234' 8 | cookbook 'rvm', git: 'https://github.com/fnichol/chef-rvm.git', ref: '7e1d452eeda083c1048ea94d513b58df78ad5350' 9 | cookbook 'sqlite' 10 | cookbook 'redis', git: 'https://github.com/phlipper/chef-redis.git', ref: '7476279fc9c8727f082b8d77b5e1922dc2ef437b' 11 | cookbook 'locale' 12 | cookbook 'phantomjs', '0.1.0' 13 | -------------------------------------------------------------------------------- /Berksfile.lock: -------------------------------------------------------------------------------- 1 | DEPENDENCIES 2 | apt 3 | freeswitch 4 | git: https://github.com/benlangfeld/freeswitch-cookbook.git 5 | revision: 50648a22478fee37f40d2793ae85910a3e47e234 6 | ref: 50648a2 7 | locale 8 | phantomjs (= 0.1.0) 9 | redis 10 | git: https://github.com/phlipper/chef-redis.git 11 | revision: 7476279fc9c8727f082b8d77b5e1922dc2ef437b 12 | ref: 7476279 13 | rvm 14 | git: https://github.com/fnichol/chef-rvm.git 15 | revision: 7e1d452eeda083c1048ea94d513b58df78ad5350 16 | ref: 7e1d452 17 | sipp 18 | path: sipp 19 | sqlite 20 | treadmill 21 | path: treadmill 22 | 23 | GRAPH 24 | apt (2.6.1) 25 | build-essential (2.1.3) 26 | chef-sugar (2.5.0) 27 | chef_gem (0.1.0) 28 | database (3.0.3) 29 | mysql2_chef_gem (~> 1.0) 30 | postgresql (>= 1.0.0) 31 | freeswitch (0.6.4) 32 | apt (~> 2.2) 33 | yum (~> 3.1) 34 | java (1.29.0) 35 | locale (1.0.2) 36 | mariadb (0.2.11) 37 | apt (>= 0.0.0) 38 | yum (>= 0.0.0) 39 | yum-epel (>= 0.0.0) 40 | mysql (6.0.10) 41 | smf (>= 0.0.0) 42 | yum-mysql-community (>= 0.0.0) 43 | mysql2_chef_gem (1.0.1) 44 | build-essential (>= 0.0.0) 45 | mariadb (>= 0.0.0) 46 | mysql (>= 0.0.0) 47 | openssl (2.0.2) 48 | chef-sugar (>= 0.0.0) 49 | phantomjs (0.1.0) 50 | postgresql (3.4.14) 51 | apt (>= 1.9.0) 52 | build-essential (>= 0.0.0) 53 | openssl (>= 0.0.0) 54 | rbac (1.0.2) 55 | redis (0.5.6) 56 | apt (>= 0.0.0) 57 | resource-control (0.1.1) 58 | rvm (0.10.1) 59 | chef_gem (>= 0.0.0) 60 | java (>= 0.0.0) 61 | sipp (0.0.0) 62 | smf (2.2.1) 63 | rbac (>= 1.0.1) 64 | resource-control (>= 0.0.0) 65 | sqlite (1.1.0) 66 | sudo (2.7.1) 67 | treadmill (0.0.0) 68 | database (>= 0.0.0) 69 | openssl (>= 0.0.0) 70 | postgresql (>= 0.0.0) 71 | redis (>= 0.0.0) 72 | rvm (>= 0.0.0) 73 | sipp (>= 0.0.0) 74 | sudo (>= 0.0.0) 75 | yum (3.5.2) 76 | yum-epel (0.6.0) 77 | yum (~> 3.0) 78 | yum-mysql-community (0.1.12) 79 | yum (>= 3.0) 80 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [develop](https://github.com/adhearsion/SIPtreadmill/compare/1.0.1...develop) 2 | * Feature: Allow and document fully configuring Airbrake for error notification 3 | * Bugfix: Properly log RTCP collection errors 4 | * Bugfix: Correct local file upload directory 5 | * Bugfix: Properly record final call counts for test runs 6 | 7 | # [1.0.1](https://github.com/adhearsion/SIPtreadmill/compare/1.0.0...1.0.1) 8 | * Allow running Rails console in production installed from packages. Minitest / TestUnit are required. 9 | 10 | # [1.0.0](https://github.com/adhearsion/SIPtreadmill/compare/0.1.1...1.0.0) 11 | * Authentication is now optional. When disabled, anonymous users have full administrative access. 12 | * AT&T APIMatrix authentication was removed, since the client library for this has been abandoned. 13 | * File storage may now be to local disk or S3 14 | * Profiles and targets may now be cloned similarly to test runs 15 | * Failures to gather info from the test target via SSH are now notified as exceptions 16 | * Test runs can be created and run via a REST API 17 | * Call rate differentials may now be more finely controlled 18 | * A Javascript error when rendering the test run listing was fixed 19 | * The application now runs on Ruby 2.2.0 20 | 21 | # [0.1.1](https://github.com/adhearsion/SIPtreadmill/compare/0.1.0...0.1.1) 22 | * Fix duplication of test run attributes 23 | 24 | # [0.1.0](https://github.com/adhearsion/SIPtreadmill/compare/5949933d1fe4940f1e401e86514c596104ff41eb...0.1.1) 25 | * First official release 26 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | ruby '2.2.0' 4 | 5 | gem 'rails', '3.2.19' 6 | gem 'devise' 7 | gem 'omniauth', '~> 1.0' 8 | gem 'omniauth-github', '~> 1.1' 9 | gem 'haml' 10 | gem 'simple_form' 11 | gem 'carrierwave' 12 | gem 'fog' 13 | gem 'airbrake' 14 | gem 'kaminari' 15 | gem 'bourbon' 16 | gem 'state_machine' 17 | gem 'cancan' 18 | 19 | # Sidekiq and monitoring 20 | gem 'sidekiq' 21 | gem 'slim', '>= 1.1.0' 22 | gem 'sinatra', '>= 1.3.0', :require => nil 23 | 24 | gem 'pg' 25 | 26 | group :assets do 27 | gem 'sass-rails', '~> 3.2.3' 28 | gem 'coffee-rails', '~> 3.2.1' 29 | 30 | # See https://github.com/sstephenson/execjs#readme for more supported runtimes 31 | gem 'therubyracer', :platforms => :ruby 32 | 33 | gem 'uglifier', '>= 1.0.3' 34 | 35 | gem 'turbo-sprockets-rails3' 36 | end 37 | 38 | gem 'jquery-rails' 39 | gem 'jquery-datatables-rails' 40 | gem 'classy_enum' 41 | 42 | gem 'thin' 43 | 44 | gem 'sippy_cup', '~> 0.6.0' 45 | gem 'net-ssh' 46 | 47 | gem 'rails_12factor' 48 | 49 | gem 'minitest' 50 | gem 'test-unit' 51 | 52 | group :development do 53 | gem 'pry-rails' 54 | gem 'better_errors' 55 | gem 'binding_of_caller' 56 | gem 'rspec-rails' 57 | gem 'guard-rspec' 58 | gem 'factory_girl_rails' 59 | gem 'database_cleaner', '1.0.1' 60 | gem 'capybara' 61 | gem 'poltergeist' 62 | gem 'fakefs', :require => 'fakefs/safe' 63 | gem 'quiet_assets' 64 | gem 'foreman' 65 | gem 'countdownlatch' 66 | end 67 | 68 | group :test do 69 | gem 'webmock' 70 | gem 'timecop' 71 | end 72 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | ENV['SKIP_RCOV'] = 'true' 2 | ENV['COOKIE_SECRET_TOKEN'] = "A" * 32 3 | 4 | guard 'rspec', all_after_pass: false, cli: '--format documentation' do 5 | watch(%r{^spec/.+_spec\.rb$}) 6 | watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } 7 | watch('spec/spec_helper.rb') { "spec/" } 8 | end 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 AT&T 4 | Copyright (c) 2014-2015 Mojo Lingo LLC 5 | Copyright (c) 2015 Adhearsion Foundation Inc 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ci: destroy_dev_env create_dev_env run_tests_in_dev_env 2 | 3 | destroy_dev_env: 4 | vagrant destroy -f 5 | 6 | create_dev_env: 7 | vagrant up dev 8 | 9 | run_tests_in_dev_env: 10 | vagrant ssh dev -c "cd /srv/treadmill/current && rake db\:test\:prepare spec" 11 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec rails server thin --port $PORT --env $RACK_ENV 2 | worker: bundle exec sidekiq -e $RACK_ENV 3 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | SIPTreadmill::Application.load_tasks 8 | -------------------------------------------------------------------------------- /app/assets/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/font/FontAwesome.otf -------------------------------------------------------------------------------- /app/assets/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /app/assets/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /app/assets/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /app/assets/images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/images/bg.png -------------------------------------------------------------------------------- /app/assets/images/blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/images/blue.png -------------------------------------------------------------------------------- /app/assets/images/blue@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/images/blue@2x.png -------------------------------------------------------------------------------- /app/assets/images/core_admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/images/core_admin.png -------------------------------------------------------------------------------- /app/assets/images/core_admin_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/images/core_admin_small.png -------------------------------------------------------------------------------- /app/assets/images/groups.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/images/groups.png -------------------------------------------------------------------------------- /app/assets/images/ie-spacer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/images/ie-spacer.gif -------------------------------------------------------------------------------- /app/assets/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/images/loading.gif -------------------------------------------------------------------------------- /app/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/images/logo.png -------------------------------------------------------------------------------- /app/assets/images/noise-blue-repeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/images/noise-blue-repeat.png -------------------------------------------------------------------------------- /app/assets/images/rails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/assets/images/rails.png -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require theme 14 | //= require jquery_ujs 15 | //= require dataTables/jquery.dataTables 16 | //= require dataTables/jquery.dataTables.bootstrap 17 | //= require navbar 18 | //= require_tree . 19 | -------------------------------------------------------------------------------- /app/assets/javascripts/datatabler.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $('.datatable').dataTable({ 3 | "sDom": "<'row-fluid'<'span6'l><'span6'f>r>t<'row-fluid'<'span6'i><'span6'p>>", 4 | "sPaginationType": "bootstrap", 5 | "bDestroy": true, 6 | "bAutoWidth": false 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /app/assets/javascripts/graphing.js: -------------------------------------------------------------------------------- 1 | function drawTotalCallsGraph(data, target) { 2 | nv.addGraph(function() { 3 | var chart = nv.models.stackedAreaChart() 4 | .x(function(d) { return d[0] }) 5 | .y(function(d) { return d[1] }) 6 | .color(['#55ff55','#ff2a2a', '#ffcc00']) 7 | .clipEdge(true); 8 | 9 | chart.xAxis 10 | .axisLabel('Time') 11 | .tickFormat(function(d) { return d3.time.format('%X')(new Date(d)) }); 12 | 13 | chart.yAxis 14 | .axisLabel('Number of Calls') 15 | .tickFormat(d3.format(',.0f')); 16 | 17 | d3.select(target + " svg") 18 | .datum(data).transition() 19 | .duration(500).call(chart); 20 | 21 | nv.utils.windowResize(chart.update); 22 | return chart; 23 | }); 24 | } 25 | 26 | function drawRunsCompleted(data, target) { 27 | nv.addGraph(function() { 28 | var chart = nv.models.discreteBarChart() 29 | .x(function(d) { return d[0] }) 30 | .y(function(d) { return d[1] }) 31 | .showValues(true).color(['#1f77b4']); 32 | 33 | chart.xAxis 34 | .axisLabel('Date') 35 | .tickFormat(function(d) { return d3.time.format('%x')(new Date(d) )}); 36 | 37 | chart.yAxis 38 | .axisLabel('Test Runs') 39 | .tickFormat(d3.format(',.0f')); 40 | 41 | d3.select(target + " svg") 42 | .datum(data).transition() 43 | .duration(500).call(chart); 44 | 45 | nv.utils.windowResize(chart.update); 46 | return chart; 47 | }); 48 | } 49 | 50 | function drawLineGraph(data, options){ 51 | nv.addGraph(function() { 52 | var chart = nv.models.lineChart() 53 | .x(function(d) { return d[0] }) 54 | .y(function(d) { return d[1] }) 55 | .clipEdge(true); 56 | 57 | chart.xAxis 58 | .axisLabel(options.xAxis) 59 | .tickFormat(function(d) { return d3.time.format('%X')(new Date(d) )}); 60 | 61 | chart.yAxis 62 | .axisLabel(options.yAxis) 63 | .tickFormat(d3.format(',.2f')); 64 | 65 | d3.select(options.target + " svg") 66 | .datum(data).transition() 67 | .duration(500).call(chart); 68 | 69 | nv.utils.windowResize(chart.update); 70 | return chart; 71 | }); 72 | } 73 | -------------------------------------------------------------------------------- /app/assets/javascripts/navbar.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | navResponse(); 3 | }) 4 | 5 | $(window).resize(function() { 6 | navResponse(); 7 | }) 8 | 9 | function navResponse() { 10 | if ($(window).width() < 980) { 11 | // Display sidebar along the top. 12 | $('ul.nav-collapse-primary').css('height','auto'); 13 | $('ul.nav-collapse-primary li').css('display', 'inline-block'); 14 | $('ul.nav-collapse-primary li > span.glow').css('display', 'none'); 15 | $('ul.nav-collapse-primary li.active a').css('color', '#ccc'); 16 | } else { 17 | // Put it back the way it was. 18 | $('ul.nav-collapse-primary').css('height','inherit'); 19 | $('ul.nav-collapse-primary li > span.glow').css('display', 'block'); 20 | $('ul.nav-collapse-primary li').css('display', 'inherit'); 21 | $('ul.nav-collapse-primary li.active a').css('color', '#939ea4'); 22 | } 23 | } -------------------------------------------------------------------------------- /app/assets/javascripts/shXml.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SyntaxHighlighter 3 | * http://alexgorbatchev.com/SyntaxHighlighter 4 | * 5 | * SyntaxHighlighter is donationware. If you are using it, please donate. 6 | * http://alexgorbatchev.com/SyntaxHighlighter/donate.html 7 | * 8 | * @version 9 | * 3.0.83 (July 02 2010) 10 | * 11 | * @copyright 12 | * Copyright (C) 2004-2010 Alex Gorbatchev. 13 | * 14 | * @license 15 | * Dual licensed under the MIT and GPL licenses. 16 | */ 17 | ;(function() 18 | { 19 | // CommonJS 20 | typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; 21 | 22 | function Brush() 23 | { 24 | function process(match, regexInfo) 25 | { 26 | var constructor = SyntaxHighlighter.Match, 27 | code = match[0], 28 | tag = new XRegExp('(<|<)[\\s\\/\\?]*(?[:\\w-\\.]+)', 'xg').exec(code), 29 | result = [] 30 | ; 31 | if (match.attributes != null) 32 | { 33 | var attributes, 34 | regex = new XRegExp('(? [\\w:\\-\\.]+)' + 35 | '\\s*=\\s*' + 36 | '(? ".*?"|\'.*?\'|\\w+)', 37 | 'xg'); 38 | 39 | while ((attributes = regex.exec(code)) != null) 40 | { 41 | result.push(new constructor(attributes.name, match.index + attributes.index, 'color1')); 42 | result.push(new constructor(attributes.value, match.index + attributes.index + attributes[0].indexOf(attributes.value), 'string')); 43 | } 44 | } 45 | 46 | if (tag != null) 47 | result.push( 48 | new constructor(tag.name, match.index + tag[0].indexOf(tag.name), 'keyword') 49 | ); 50 | 51 | return result; 52 | } 53 | 54 | this.regexList = [ 55 | { regex: new XRegExp('(\\<|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\>|>)', 'gm'), css: 'color2' }, // 56 | { regex: SyntaxHighlighter.regexLib.xmlComments, css: 'comments' }, // 57 | { regex: new XRegExp('(<|<)[\\s\\/\\?]*(\\w+)(?.*?)[\\s\\/\\?]*(>|>)', 'sg'), func: process } 58 | ]; 59 | }; 60 | 61 | Brush.prototype = new SyntaxHighlighter.Highlighter(); 62 | Brush.aliases = ['xml', 'xhtml', 'xslt', 'html']; 63 | 64 | SyntaxHighlighter.brushes.Xml = Brush; 65 | 66 | // CommonJS 67 | typeof(exports) != 'undefined' ? exports.Brush = Brush : null; 68 | })(); 69 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | */ 12 | 13 | @import "bourbon"; 14 | @import "nv.d3"; 15 | @import "theme"; 16 | @import "font-awesome"; 17 | @import "custom"; 18 | @import "shCore"; 19 | @import "shThemeDefault"; 20 | @import "test_runs"; 21 | 22 | @import "datatables"; 23 | @import "dataTables/jquery.dataTables.bootstrap"; 24 | -------------------------------------------------------------------------------- /app/assets/stylesheets/custom.css.scss: -------------------------------------------------------------------------------- 1 | $attblue: #22a9d5; 2 | 3 | body .modal { 4 | width: 700px; 5 | margin-left: -350px; 6 | } 7 | 8 | .blue_strip { 9 | @include linear-gradient(lighten($attblue, 10%), darken($attblue, 10%)); 10 | color: #fff; 11 | height: 31px; 12 | padding-top: 10px; 13 | position: relative; 14 | border-bottom: 1px solid darken($attblue, 50%); 15 | } 16 | 17 | .blue_strip h1 { 18 | position: relative; 19 | margin-left: 20px; 20 | font-size: 30px; 21 | line-height: 1em; 22 | padding: 0; 23 | top: -15px; 24 | color: #fff; 25 | } 26 | .blue_strip i.header-icon{ 27 | font-size: 30px; 28 | line-height: 1em; 29 | color: #fff; 30 | } 31 | 32 | form .instructions { 33 | font-style: italic; 34 | color: #666; 35 | } 36 | 37 | .hidden { 38 | visibility: visible; 39 | } 40 | 41 | .dashboard-stats .glyph-red { 42 | border: 1px solid #de7e6d; 43 | color: #7d2a1c; 44 | background: #e8a397; 45 | } 46 | 47 | .dashboard-stats .glyph-green { 48 | border: 1px solid #97cc2e; 49 | color: #2b3a0d; 50 | background: #acd954; 51 | } 52 | 53 | .action-header { 54 | width: 130px; 55 | } 56 | 57 | .padded-top { 58 | padding-top: 20px; 59 | } 60 | 61 | div.uploader { 62 | width: 300px; 63 | } 64 | 65 | .centered { 66 | text-align: center; 67 | } 68 | 69 | .color-ok { 70 | color: #0c0; 71 | } 72 | 73 | .color-ko { 74 | color: #c00; 75 | } 76 | 77 | .help-inline.instructions { 78 | vertical-align: top; 79 | } 80 | 81 | .ajax_display_data h6, .ajax_display_data p { 82 | display: inline-block; 83 | margin: 0; 84 | } 85 | 86 | .loggedinas p { 87 | text-align: right; 88 | a { 89 | font-size: 1.2em; 90 | color: $attblue; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/assets/stylesheets/datatables.css.scss: -------------------------------------------------------------------------------- 1 | .table thead:first-child tr:first-child td { 2 | border-top: 1px solid #d0d0d0; 3 | text-align: center; 4 | vertical-align: middle; 5 | font-weight: bold; 6 | line-height: 1.4em; 7 | position: relative; 8 | padding-right: 20px; 9 | } 10 | 11 | table.table.table-normal tbody td { 12 | text-align: center; 13 | } 14 | 15 | table.table.table-normal tbody tr td:nth-child(1) { 16 | font-weight: bold; 17 | } 18 | 19 | table.table.table-normal tbody tr td:nth-child(2) { 20 | text-align: left; 21 | } 22 | 23 | table.table.table-normal tbody tr td:nth-child(8) a, table.table.table-normal tbody tr td:nth-child(9) a { 24 | font-style: oblique; 25 | } 26 | 27 | table.table.table-normal tbody tr:last-child { 28 | border-bottom: 1px solid #eee; 29 | } 30 | 31 | .dataTables_info { 32 | padding-left: 10px; 33 | } 34 | 35 | .dataTables_paginate { 36 | padding-right: 10px; 37 | } 38 | 39 | .btn-group { 40 | height: 15px; 41 | } 42 | 43 | .dataTables_length, .dataTables_filter { 44 | width: 100%; 45 | } 46 | 47 | .dataTables_length > label { 48 | margin-left: 10px; 49 | } 50 | 51 | .dataTables_filter > label { 52 | margin-right: 10px; 53 | } 54 | 55 | .box-content.data-grid { 56 | overflow-x: scroll; 57 | } -------------------------------------------------------------------------------- /app/assets/stylesheets/scenarios.css.scss: -------------------------------------------------------------------------------- 1 | #page_scenarios { 2 | .type-control { 3 | margin-bottom: 10px; 4 | border-bottom: 1px solid #ccc; 5 | padding-bottom: 10px; 6 | } 7 | } -------------------------------------------------------------------------------- /app/assets/stylesheets/test_runs.css.scss: -------------------------------------------------------------------------------- 1 | #page_test_run { 2 | form.test-run-form label { 3 | padding-right: 20px; 4 | } 5 | 6 | form.test-run-form .instructions { 7 | width: 49%; 8 | } 9 | 10 | form.test-run-form .row { 11 | margin-left: 0; 12 | .help-inline.instructions { 13 | vertical-align: top; 14 | } 15 | } 16 | 17 | .ajax_display_data h6, .ajax_display_data p { 18 | display: inline-block; 19 | margin: 0; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | before_filter :load_stats, :guest_user_auth 4 | 5 | def load_stats 6 | @stats = Sidekiq::Stats.new 7 | end 8 | 9 | def guest_user_auth 10 | if ENV['OMNIAUTH_TYPE'] == 'none' 11 | sign_in(User.where(admin: true).first) 12 | end 13 | end 14 | 15 | rescue_from CanCan::AccessDenied do |exception| 16 | redirect_to root_url, alert: exception.message 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | def index 3 | @omniauth_type = (ENV['OMNIAUTH_TYPE'] || 'none').to_sym 4 | end 5 | 6 | def toggle_admin 7 | authorize! :toggle_admin_mode, :current_user 8 | 9 | current_user.admin_mode = !current_user.admin_mode 10 | current_user.save 11 | 12 | redirect_to :back 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/controllers/profiles_controller.rb: -------------------------------------------------------------------------------- 1 | class ProfilesController < ApplicationController 2 | before_filter :authenticate_user! 3 | load_and_authorize_resource 4 | 5 | # GET /profiles 6 | # GET /profiles.json 7 | def index 8 | @profiles = Profile.accessible_by(current_ability).page(params[:page]) 9 | 10 | respond_to do |format| 11 | format.html # index.html.erb 12 | format.json { render json: @profiles } 13 | end 14 | end 15 | 16 | # GET /profiles/1 17 | # GET /profiles/1.json 18 | def show 19 | @profile = Profile.accessible_by(current_ability).find(params[:id]) 20 | 21 | respond_to do |format| 22 | format.html # show.html.erb 23 | format.json { render json: @profile } 24 | end 25 | end 26 | 27 | # GET /profiles/new 28 | # GET /profiles/new.json 29 | def new 30 | @profile = current_user.profiles.new 31 | 32 | respond_to do |format| 33 | format.html # new.html.erb 34 | format.json { render json: @profile } 35 | end 36 | end 37 | 38 | # GET /profiles/1/edit 39 | def edit 40 | @profile = Profile.accessible_by(current_ability).find(params[:id]) 41 | unless @profile.writable? 42 | redirect_to @profile, alert: "Cannot edit a profile that has already been used in a Test Run" 43 | end 44 | end 45 | 46 | # POST /profiles 47 | # POST /profiles.json 48 | def create 49 | @profile = current_user.profiles.new(params[:profile]) 50 | 51 | respond_to do |format| 52 | if @profile.save 53 | format.html { redirect_to @profile, notice: 'Profile was successfully created.' } 54 | format.json { render json: @profile, status: 201, location: @profile } 55 | else 56 | format.html { render action: "new" } 57 | format.json { render json: @profile.errors, status: 422 } 58 | end 59 | end 60 | end 61 | 62 | # PUT /profiles/1 63 | # PUT /profiles/1.json 64 | def update 65 | @profile = Profile.accessible_by(current_ability).find(params[:id]) 66 | 67 | respond_to do |format| 68 | if @profile.update_attributes(params[:profile]) 69 | format.html { redirect_to @profile, notice: 'Profile was successfully updated.' } 70 | format.json { head :no_content } 71 | else 72 | format.html { render action: "edit" } 73 | format.json { render json: @profile.errors, status: :unprocessable_entity } 74 | end 75 | end 76 | end 77 | 78 | def copy 79 | @profile = Profile.find(params[:profile_id]) 80 | new_profile = @profile.duplicate current_user 81 | if new_profile 82 | redirect_to new_profile 83 | else 84 | redirect_to @profile, alert: "Could not copy the selected profile" 85 | end 86 | end 87 | 88 | # DELETE /profiles/1 89 | # DELETE /profiles/1.json 90 | def destroy 91 | @profile = Profile.accessible_by(current_ability).find(params[:id]) 92 | @profile.destroy 93 | 94 | respond_to do |format| 95 | format.html { redirect_to profiles_url } 96 | format.json { head :no_content } 97 | end 98 | end 99 | end 100 | -------------------------------------------------------------------------------- /app/controllers/targets_controller.rb: -------------------------------------------------------------------------------- 1 | class TargetsController < ApplicationController 2 | before_filter :authenticate_user! 3 | load_and_authorize_resource 4 | 5 | # GET /targets 6 | # GET /targets.json 7 | def index 8 | @targets = Target.accessible_by(current_ability).page(params[:page]) 9 | 10 | respond_to do |format| 11 | format.html # index.html.erb 12 | format.json { render json: @targets } 13 | end 14 | end 15 | 16 | # GET /targets/1 17 | # GET /targets/1.json 18 | def show 19 | @target = Target.accessible_by(current_ability).find(params[:id]) 20 | 21 | respond_to do |format| 22 | format.html # show.html.erb 23 | format.json { render json: @target } 24 | end 25 | end 26 | 27 | # GET /targets/new 28 | # GET /targets/new.json 29 | def new 30 | @target = current_user.targets.new 31 | 32 | respond_to do |format| 33 | format.html # new.html.erb 34 | format.json { render json: @target } 35 | end 36 | end 37 | 38 | # GET /targets/1/edit 39 | def edit 40 | @target = Target.accessible_by(current_ability).find(params[:id]) 41 | end 42 | 43 | # POST /targets 44 | # POST /targets.json 45 | def create 46 | @target = current_user.targets.new(params[:target]) 47 | 48 | respond_to do |format| 49 | if @target.save 50 | format.html { redirect_to @target, notice: 'Target was successfully created.' } 51 | format.json { render json: @target, status: 201, location: @target } 52 | else 53 | format.html { render action: "new" } 54 | format.json { render json: @target.errors, status: 422 } 55 | end 56 | end 57 | end 58 | 59 | # PUT /targets/1 60 | # PUT /targets/1.json 61 | def update 62 | @target = Target.accessible_by(current_ability).find(params[:id]) 63 | 64 | respond_to do |format| 65 | if @target.update_attributes(params[:target]) 66 | format.html { redirect_to @target, notice: 'Target was successfully updated.' } 67 | format.json { head :no_content } 68 | else 69 | format.html { render action: "edit" } 70 | format.json { render json: @target.errors, status: :unprocessable_entity } 71 | end 72 | end 73 | end 74 | 75 | # DELETE /targets/1 76 | # DELETE /targets/1.json 77 | def destroy 78 | @target = Target.accessible_by(current_ability).find(params[:id]) 79 | @target.destroy 80 | 81 | respond_to do |format| 82 | format.html { redirect_to targets_url } 83 | format.json { head :no_content } 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /app/controllers/users/omniauth_callbacks_controller.rb: -------------------------------------------------------------------------------- 1 | class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController 2 | def github 3 | @user = User.find_or_create_from_auth_hash :github, request.env["omniauth.auth"] 4 | 5 | if @user.persisted? 6 | sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated 7 | set_flash_message(:notice, :success, :kind => "GitHub") if is_navigational_format? 8 | end 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | before_filter :authenticate_user! 3 | load_and_authorize_resource 4 | 5 | def index 6 | @users = User.page(params[:page]) 7 | end 8 | 9 | def show 10 | @user = User.find params[:id] 11 | end 12 | 13 | def edit 14 | authorize! :make_others_admin, :current_user 15 | end 16 | 17 | def update 18 | authorize! :make_others_admin, :current_user 19 | @user.admin = params[:user][:admin] 20 | logger.info params 21 | 22 | if @user.save 23 | redirect_to @user, notice: 'User was successfully updated.' 24 | else 25 | render action: "edit" 26 | end 27 | end 28 | 29 | def generate_token 30 | @user = User.find params[:id] 31 | @user.new_auth_token! 32 | 33 | redirect_to @user, notice: 'Authentication Token successfully generated.' 34 | end 35 | end -------------------------------------------------------------------------------- /app/enums/transport_type.rb: -------------------------------------------------------------------------------- 1 | class TransportType < ClassyEnum::Base 2 | end 3 | 4 | class TransportType::U1 < TransportType 5 | def text 6 | 'UDP Mono' 7 | end 8 | end 9 | 10 | class TransportType::Un < TransportType 11 | def text 12 | 'UDP Multi' 13 | end 14 | end 15 | 16 | class TransportType::T1 < TransportType 17 | def text 18 | 'TCP Mono' 19 | end 20 | end 21 | 22 | class TransportType::Tn < TransportType 23 | def text 24 | 'TCP Multi' 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | def status_label(status) 3 | case status 4 | when 'pending' 5 | text = 'Pending' 6 | css = '' 7 | when 'queued' 8 | text = 'Queued' 9 | css = 'label-inverse' 10 | when 'running' 11 | text = 'Running' 12 | css = 'label-info' 13 | when 'complete' 14 | text = 'Complete' 15 | css = 'label-success' 16 | when 'complete_with_warnings' 17 | text = 'Warnings' 18 | css = 'label-warning' 19 | when 'complete_with_errors' 20 | text = 'Errors' 21 | css = 'label-important' 22 | end 23 | capture_haml do 24 | haml_tag :span, text, {class: "label #{css}"} 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/helpers/home_helper.rb: -------------------------------------------------------------------------------- 1 | module HomeHelper 2 | def get_completed_test_runs 3 | complete = TestRun.accessible_by(current_ability).where(state: "complete") 4 | [ 5 | { 6 | key: "Completed Successfully", 7 | values: complete.group("date(completed_at)").count(:id).to_a 8 | } 9 | ].to_json 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/mailers/.gitkeep -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/app/models/.gitkeep -------------------------------------------------------------------------------- /app/models/ability.rb: -------------------------------------------------------------------------------- 1 | class Ability 2 | include CanCan::Ability 3 | 4 | def initialize(user) 5 | if user.admin_mode 6 | can :manage, Target 7 | can :manage, Profile 8 | can :manage, Scenario 9 | can :manage, TestRun 10 | else 11 | can :manage, Target, user_id: user.id 12 | can :manage, Profile, user_id: user.id 13 | can :manage, Scenario, user_id: user.id 14 | can :manage, TestRun, user_id: user.id 15 | end 16 | 17 | # Profiles and Scenarios are shared by all 18 | can :read, Profile 19 | can :read, Scenario 20 | can :generate_auth_token, :current_user 21 | can :manage, user 22 | 23 | if user.admin 24 | can :manage, User 25 | can :toggle_admin_mode, :current_user 26 | can :make_others_admin, :current_user 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /app/models/profile.rb: -------------------------------------------------------------------------------- 1 | class Profile < ActiveRecord::Base 2 | classy_enum_attr :transport_type, default: 'u1' 3 | attr_accessible :calls_per_second, :max_calls, :max_concurrent, :calls_per_second_incr, :calls_per_second_max, :calls_per_second_interval, :name, :transport_type 4 | belongs_to :user 5 | has_many :test_runs 6 | 7 | validates_presence_of :name, :calls_per_second, :max_calls, :max_concurrent, :transport_type 8 | validates_uniqueness_of :name, scope: :user_id 9 | 10 | def writable? 11 | self.test_runs.count == 0 12 | end 13 | 14 | def duplicate(requesting_user) 15 | new_profile = Profile.new( 16 | name: "#{self.name} (Copy)", 17 | calls_per_second: self.calls_per_second, 18 | max_calls: self.max_calls, 19 | max_concurrent: self.max_concurrent, 20 | transport_type: self.transport_type, 21 | user: requesting_user 22 | ) 23 | new_profile.save ? new_profile : nil 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/models/rtcp_data.rb: -------------------------------------------------------------------------------- 1 | class RtcpData < ActiveRecord::Base 2 | attr_accessible :avg_jitter, :avg_packet_loss, :max_jitter, :max_packet_loss, :test_run, :time 3 | belongs_to :test_run 4 | end 5 | -------------------------------------------------------------------------------- /app/models/scenario.rb: -------------------------------------------------------------------------------- 1 | require 'open-uri' 2 | require 'sippy_cup' 3 | 4 | class Scenario < ActiveRecord::Base 5 | PCAP_PLACEHOLDER = '{{PCAP_AUDIO}}' 6 | 7 | attr_accessible :name, :sipp_xml, :pcap_audio, :pcap_audio_cache, :sippy_cup_scenario, :csv_data, :receiver, :description 8 | belongs_to :user 9 | has_many :test_runs 10 | has_one :registration_scenario, class_name: "Scenario" 11 | 12 | mount_uploader :pcap_audio, PcapAudioUploader 13 | 14 | validates_presence_of :name 15 | validates_uniqueness_of :name, scope: :user_id 16 | 17 | validate :sippy_cup_scenario_must_be_valid 18 | 19 | def to_sippycup_scenario(opts = {}) 20 | if sippy_cup_scenario.present? 21 | scenario = SippyCup::Scenario.new name, opts 22 | scenario.build sippy_cup_scenario_steps 23 | scenario 24 | else 25 | SippyCup::XMLScenario.new name, sipp_xml, pcap_data, opts 26 | end 27 | end 28 | 29 | def sippy_cup_scenario_steps 30 | sippy_cup_scenario.split("\n").map(&:chomp) 31 | end 32 | 33 | def duplicate(requesting_user) 34 | new_scenario = Scenario.new( 35 | name: "#{self.name} (Copy)", 36 | description: self.description, 37 | user: requesting_user, 38 | ) 39 | if sippy_cup_scenario.present? 40 | new_scenario.sippy_cup_scenario = self.sippy_cup_scenario 41 | else 42 | new_scenario.pcap_audio = self.pcap_audio 43 | new_scenario.sipp_xml = self.sipp_xml 44 | new_scenario.csv_data = self.csv_data 45 | end 46 | new_scenario.save ? new_scenario : nil 47 | end 48 | 49 | def writable? 50 | !(self.test_runs.count > 0) 51 | end 52 | 53 | def sippy_cup_scenario_must_be_valid 54 | if sippy_cup_scenario.present? 55 | scenario = SippyCup::Scenario.new(name, source: '127.0.0.1', destination: '127.0.0.1') 56 | scenario.build sippy_cup_scenario_steps 57 | unless scenario.valid? 58 | scenario.errors.each do |err| 59 | errors.add(:sippy_cup_scenario, "#{err[:message]} (Step #{err[:step]})") 60 | end 61 | end 62 | end 63 | end 64 | 65 | private 66 | 67 | def pcap_data 68 | File.read(pcap_audio.url) if pcap_audio.url 69 | end 70 | 71 | end 72 | -------------------------------------------------------------------------------- /app/models/sipp_data.rb: -------------------------------------------------------------------------------- 1 | class SippData < ActiveRecord::Base 2 | attr_accessible :avg_call_duration, :avg_call_duration_cumulative, :concurrent_calls, :cps, :failed_calls, :failed_calls_cumulative, :response_time, :successful_calls, :successful_calls_cumulative, :test_run, :time, :total_calls 3 | belongs_to :test_run 4 | end 5 | -------------------------------------------------------------------------------- /app/models/system_load_datum.rb: -------------------------------------------------------------------------------- 1 | class SystemLoadDatum < ActiveRecord::Base 2 | attr_accessible :cpu, :memory, :test_run_id, :logged_at 3 | belongs_to :test_run 4 | end 5 | -------------------------------------------------------------------------------- /app/models/target.rb: -------------------------------------------------------------------------------- 1 | class Target < ActiveRecord::Base 2 | attr_accessible :address, :name, :ssh_username 3 | belongs_to :user 4 | has_many :test_runs 5 | 6 | validates_presence_of :name, :address 7 | validates_uniqueness_of :name, scope: :user_id 8 | end 9 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | attr_accessible :email, :first_name, :last_name, :phone_number, :provider, :uid, :name, :authentication_token 3 | devise :omniauthable, :omniauth_providers => [:att, :github] 4 | 5 | has_many :targets 6 | has_many :profiles 7 | has_many :scenarios 8 | has_many :test_runs 9 | 10 | before_update do 11 | self.admin_mode = self.admin if self.admin_changed? 12 | true 13 | end 14 | 15 | def self.find_or_create_from_auth_hash(type, auth_hash) 16 | user_info = auth_hash.info 17 | user = self.where(uid: auth_hash.uid).first 18 | unless user 19 | case type 20 | when :att 21 | user = new( 22 | first_name: user_info.first_name, 23 | last_name: user_info.last_name, 24 | email: user_info.email, 25 | phone_number: user_info.phone_number, 26 | provider: auth_hash.provider, 27 | uid: auth_hash.uid 28 | ) 29 | user.save! 30 | when :github 31 | user = new( 32 | name: user_info.name, 33 | email: user_info.email, 34 | uid: auth_hash.uid 35 | ) 36 | user.save! 37 | end 38 | end 39 | user 40 | end 41 | 42 | def full_name 43 | return self.name || "#{self.first_name} #{self.last_name}" 44 | end 45 | 46 | def ensure_authentication_token 47 | unless self.authentication_token.present? 48 | self.new_auth_token! 49 | end 50 | end 51 | 52 | def new_auth_token! 53 | self.authentication_token = generate_authentication_token 54 | self.save 55 | end 56 | 57 | private 58 | 59 | def generate_authentication_token 60 | loop do 61 | token = Devise.friendly_token 62 | break token unless User.where(authentication_token: token).first 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /app/services/rtcp_parser.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | class RtcpParser 4 | def initialize(data, test_run_instance) 5 | @data, @test_run = data, test_run_instance 6 | end 7 | 8 | def run 9 | @data.each { |d| @test_run.rtcp_data.create d } 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/services/rtcp_tools.rb: -------------------------------------------------------------------------------- 1 | module RTCPTools 2 | class << self 3 | def parse(packet) 4 | headers, @packet = packet.unpack "B8 A*" 5 | headers = parse_headers headers 6 | return nil unless headers[:version] == 2 7 | 8 | type, @packet = @packet.unpack "C1 A*" 9 | return nil unless type.to_i == 200 10 | 11 | length, @packet = @packet.unpack "S>1 A*" 12 | 13 | ssrc, @packet = @packet.unpack "H8 A*" 14 | ts_seconds, @packet = @packet.unpack "L>1 A*" 15 | time = convert_ntp_epoch ts_seconds 16 | ts_fraction, @packet = @packet.unpack "L>1 A*" 17 | 18 | rtp_timestamp, @packet = @packet.unpack "L>1 A*" 19 | packet_count, octet_count, @packet = @packet.unpack "L>1 L>1 A*" 20 | 21 | source_ssrc, @packet = @packet.unpack "H8 A*" 22 | floss, @packet = @packet.unpack "C1 A*" 23 | fraction_loss = calc_fraction_loss floss 24 | 25 | tloss, @packet = @packet.unpack "B24 A*" 26 | total_loss = calc_total_loss tloss 27 | 28 | sequence, @packet = @packet.unpack "L>1 A*" 29 | jitter, @packet = @packet.unpack "L>1 A*" 30 | 31 | { time: time, fractional_loss: fraction_loss, total_loss: total_loss, jitter: jitter } 32 | end 33 | 34 | def parse_headers(headers) 35 | version = headers.slice(0,2).to_i(2) 36 | padding = headers.slice(2,1).to_i == 1 37 | report_count = headers.slice(3,5).to_i(2) 38 | {version: version, padding: padding, report_count: report_count} 39 | end 40 | 41 | def convert_ntp_epoch(seconds) 42 | diff = Time.at(0) - Time.utc(1900) 43 | seconds -= diff 44 | Time.at seconds 45 | end 46 | 47 | def calc_fraction_loss(loss) 48 | loss.to_f / 256 49 | end 50 | 51 | def calc_total_loss(loss) 52 | zero_byte = "0" * 8 53 | total_loss = zero_byte << loss 54 | total_loss.to_i(2) 55 | end 56 | 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /app/services/rtcp_tools/listener.rb: -------------------------------------------------------------------------------- 1 | require 'socket' 2 | 3 | module RTCPTools 4 | class Listener 5 | attr_reader :data 6 | attr_accessor :running 7 | def initialize(port) 8 | @socket = UDPSocket.new 9 | @socket.bind('', port) 10 | @data = { } 11 | @running = true 12 | end 13 | 14 | def run 15 | while running? 16 | socket_set = IO.select [@socket], [], [], 3 17 | next unless socket_set 18 | socket = socket_set.first.first 19 | packet = socket.recvfrom_nonblock(1024).first 20 | if new_data = RTCPTools.parse(packet) 21 | t = new_data[:time] 22 | @data[t] ||= { } 23 | [:fractional_loss, :jitter].each do |k| 24 | @data[t][k] ||= [] 25 | @data[t][k] << new_data[k] 26 | end 27 | end 28 | end 29 | end 30 | 31 | def organize_data 32 | organized_data = [] 33 | @data.each do |time, stats| 34 | max_jitter = stats[:jitter].max 35 | avg_jitter = average stats[:jitter] 36 | max_loss = stats[:fractional_loss].max 37 | avg_loss = average stats[:fractional_loss] 38 | organized_data << { time: time, avg_jitter: avg_jitter, max_jitter: max_jitter, 39 | avg_packet_loss: avg_loss, max_packet_loss: max_loss } 40 | end 41 | organized_data 42 | end 43 | 44 | def average(arr) 45 | arr.inject(:+).to_f / arr.length 46 | end 47 | 48 | def stop 49 | @running = false 50 | @socket.close 51 | end 52 | 53 | def running? 54 | @running 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /app/services/runner.rb: -------------------------------------------------------------------------------- 1 | require 'sippy_cup/runner' 2 | require 'json' 3 | require 'tempfile' 4 | 5 | class Runner 6 | attr_accessor :sipp_file, :rtcp_data 7 | def initialize(name, scenario, opts = {}) 8 | @name = name 9 | @scenario = scenario 10 | @stats_file = Tempfile.new('stats') 11 | @errors_report_file = Tempfile.new('errors_report') 12 | @summary_report_file = Tempfile.new('summary_report') 13 | @opts = { 14 | stats_file: @stats_file.path, 15 | errors_report_file: @errors_report_file.path, 16 | summary_report_file: @summary_report_file.path, 17 | media_port: Kernel.rand(16384..32767) 18 | } 19 | @opts.merge! opts 20 | @stopped = false 21 | 22 | @stats_collector = StatsCollector.new host: @opts[:destination], vm_buffer: @opts.delete(:vmstat_buffer), interval: 1, name: @name, user: @opts[:username], password: @opts[:password] if @opts[:password] 23 | @rtcp_listener = RTCPTools::Listener.new(@opts[:media_port] + 1) 24 | 25 | @sipp_file = nil 26 | @rtcp_data = nil 27 | @ssh_error = nil 28 | rescue 29 | clean_up_handlers 30 | raise 31 | end 32 | 33 | def run 34 | if @stats_collector 35 | run_and_catch_errors mode: :error do 36 | @stats_collector.run 37 | end 38 | end 39 | 40 | run_and_catch_errors mode: :notify do 41 | @rtcp_listener.run 42 | end 43 | 44 | begin 45 | @sippy_runner = SippyCup::Runner.new @scenario.to_sippycup_scenario(@opts), full_sipp_output: false 46 | @sippy_runner.run 47 | check_ssh_errors 48 | ensure 49 | @rtcp_listener.stop 50 | @stats_collector.stop if @stats_collector 51 | end 52 | 53 | unless @stopped 54 | rtcp_data = @rtcp_listener.organize_data 55 | @stats_file.rewind 56 | stats_data = @stats_file.read 57 | end 58 | 59 | @summary_report_file.rewind 60 | summary_report = @summary_report_file.read 61 | 62 | { 63 | stats_data: stats_data, 64 | stats_file: @stats_file, 65 | rtcp_data: rtcp_data, 66 | summary_report: summary_report, 67 | errors_report_file: @errors_report_file 68 | } 69 | end 70 | 71 | def stop 72 | @stopped = true 73 | @sippy_runner.stop 74 | end 75 | 76 | def run_and_catch_errors(opts = {}) 77 | Thread.new do 78 | begin 79 | yield 80 | rescue => e 81 | case opts[:mode] 82 | when :notify 83 | Airbrake.notify e 84 | raise 85 | when :error 86 | @ssh_error = e 87 | end 88 | end 89 | end 90 | end 91 | 92 | def check_ssh_errors 93 | raise @ssh_error if @ssh_error 94 | end 95 | 96 | def clean_up_handlers 97 | if @stats_file 98 | @stats_file.close 99 | @stats_file.unlink 100 | end 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /app/services/sipp_parser.rb: -------------------------------------------------------------------------------- 1 | require 'csv' 2 | 3 | class SippParser 4 | def initialize(data, test_run_instance) 5 | @test_run = test_run_instance 6 | @data = data 7 | end 8 | 9 | def run 10 | CSV.parse(@data, headers: true, col_sep: ";").each do |row| 11 | data = { 12 | time: DateTime.parse(row['CurrentTime']), 13 | test_run: @test_run, 14 | total_calls: row['TotalCallCreated'], 15 | successful_calls: row['SuccessfulCall(P)'], 16 | successful_calls_cumulative: row['SuccessfulCall(C)'], 17 | failed_calls: row['FailedCall(P)'], 18 | failed_calls_cumulative: row['FailedCall(C)'], 19 | concurrent_calls: row['CurrentCall'], 20 | avg_call_duration: row['CallLength(P)'], 21 | avg_call_duration_cumulative: row['CallLength(C)'], 22 | response_time: row['ResponseTime1(P)'], 23 | cps: row['CallRate(P)'] 24 | } 25 | SippData.create data 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/services/stats_collector.rb: -------------------------------------------------------------------------------- 1 | require 'net/ssh' 2 | 3 | class StatsCollector 4 | attr_accessor :running 5 | def initialize(opts={}) 6 | [:host, :user, :password, :interval, :vm_buffer].each do |option| 7 | raise ArgumentError, "Must provide #{option}!" unless opts.keys.include? option 8 | end 9 | @opts = opts 10 | end 11 | 12 | def run 13 | @running = true 14 | Net::SSH.start(@opts[:host], @opts[:user], password: @opts[:password]) do |ssh| 15 | ssh.open_channel do |channel| 16 | channel.exec "vmstat -S M -a #{@opts[:interval]}" do |ch, success| 17 | unless success 18 | raise "CPU/Memory profiling failed!" 19 | end 20 | ch.on_data do |c, data| 21 | @opts[:vm_buffer] << "#{data}|#{Time.now.to_i}" 22 | unless @running 23 | c.close 24 | end 25 | end 26 | end 27 | end 28 | end 29 | end 30 | 31 | def stop 32 | @running = false 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /app/services/vmstat_parser.rb: -------------------------------------------------------------------------------- 1 | class VMStatParser 2 | def initialize(buffer, test_run_instance) 3 | columns = ['pwait', 'psleep', 'swpd', 'free', 'inact', 'active', 'swpin', 'swpout', 'blocksin', 4 | 'blocksout', 'interrupts', 'cs', 'user_cpu', 'sys_cpu', 'idle_cpu', 'wait_cpu'] 5 | @columns = columns 6 | @test_run = test_run_instance 7 | @buffer = buffer 8 | end 9 | 10 | def parse 11 | @buffer.each {|l| parse_line l} 12 | end 13 | 14 | def parse_line(line) 15 | unless line =~ /^\s+r/ || line =~ /---/ 16 | data = {} 17 | line, timestamp_part = line.split('|') 18 | timestamp = Time.at(timestamp_part.to_i) 19 | fields = line.split(/\s+/) 20 | fields.shift if fields[0].empty? 21 | @columns.each do |c| 22 | data[c] = fields.shift 23 | end 24 | cpu = data['user_cpu'].to_f + data['sys_cpu'].to_f + data['wait_cpu'].to_f 25 | memory = 100.0 - (data['free'].to_f / (data['free'].to_f + data['inact'].to_f + data['active'].to_f) * 100) 26 | 27 | params = { cpu: cpu, memory: memory.round(1), test_run_id: @test_run.id, logged_at: timestamp} 28 | SystemLoadDatum.create params 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /app/uploaders/errors_report_file_uploader.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | class ErrorsReportFileUploader < CarrierWave::Uploader::Base 4 | end 5 | -------------------------------------------------------------------------------- /app/uploaders/pcap_audio_uploader.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | class PcapAudioUploader < CarrierWave::Uploader::Base 4 | end 5 | -------------------------------------------------------------------------------- /app/uploaders/stats_file_uploader.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | class StatsFileUploader < CarrierWave::Uploader::Base 4 | end 5 | -------------------------------------------------------------------------------- /app/views/home/index.html.haml: -------------------------------------------------------------------------------- 1 | - if user_signed_in? 2 | - content_for(:page_title) { "Dashboard" } 3 | - content_for(:page_icon) { "icon-dashboard" } 4 | - content_for(:page_subtitle) { "Welcome, #{current_user.full_name}"} 5 | - else 6 | - content_for(:page_title) { "Authentication required" } 7 | - content_for(:page_icon) { "icon-lock" } 8 | = render "layouts/page_header" 9 | - if user_signed_in? 10 | .container-fluid.padded 11 | .row-fluid 12 | .span6 13 | .box 14 | .box-header 15 | %span.title= "Queue summary" 16 | .box-content.padded 17 | .row-fluid 18 | .span12.separate-sections{:style => "margin-top: 5px;"} 19 | .row-fluid 20 | .span12 21 | .dashboard-stats 22 | %ul.inline 23 | %li.glyph 24 | %i.icon-bolt.icon-2x 25 | %li.count= @stats.enqueued 26 | .stats-label Queued jobs 27 | .row-fluid{:style => "margin-top:30px;"} 28 | .span4 29 | .dashboard-stats.small 30 | %ul.inline 31 | %li.glyph 32 | %i.icon-list 33 | %li.count= @stats.processed 34 | .stats-label Processed jobs 35 | .span4 36 | .dashboard-stats.small 37 | %ul.inline 38 | %li.glyph.glyph-green 39 | %i.icon-ok 40 | %li.count= @stats.processed - @stats.failed 41 | .stats-label Successful jobs 42 | .span4 43 | .dashboard-stats.small 44 | %ul.inline 45 | %li.glyph.glyph-red 46 | %i.icon-remove 47 | %li.count= @stats.failed 48 | .stats-label Failed Jobs 49 | .row-fluid 50 | .span6 51 | .box 52 | .box-header 53 | %span.title= "Completed Test Runs by Day" 54 | .box-content.padded{:style => "margin-top: 12px"} 55 | #testRunGraph 56 | %svg 57 | :javascript 58 | $(function() { 59 | drawRunsCompleted(#{get_completed_test_runs}, '#testRunGraph'); 60 | }); 61 | 62 | - else 63 | .container-fluid.padded 64 | .row-fluid 65 | .span12 66 | %p= link_to 'Log In', user_omniauth_authorize_path(@omniauth_type), class: "btn btn-success" 67 | -------------------------------------------------------------------------------- /app/views/kaminari/list/_first_page.html.haml: -------------------------------------------------------------------------------- 1 | %li 2 | = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote 3 | -------------------------------------------------------------------------------- /app/views/kaminari/list/_gap.html.haml: -------------------------------------------------------------------------------- 1 | %li.disabled 2 | = link_to raw(t 'views.pagination.truncate'), '#' 3 | -------------------------------------------------------------------------------- /app/views/kaminari/list/_last_page.html.haml: -------------------------------------------------------------------------------- 1 | %li 2 | = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote} 3 | -------------------------------------------------------------------------------- /app/views/kaminari/list/_next_page.html.haml: -------------------------------------------------------------------------------- 1 | %li 2 | = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote 3 | -------------------------------------------------------------------------------- /app/views/kaminari/list/_page.html.haml: -------------------------------------------------------------------------------- 1 | %li{class: "#{'active' if page.current?}"} 2 | = link_to page, page.current? ? '#' : url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} 3 | -------------------------------------------------------------------------------- /app/views/kaminari/list/_paginator.html.haml: -------------------------------------------------------------------------------- 1 | = paginator.render do 2 | .pagination 3 | %ul 4 | = first_page_tag unless current_page.first? 5 | = prev_page_tag unless current_page.first? 6 | - each_page do |page| 7 | - if page.left_outer? || page.right_outer? || page.inside_window? 8 | = page_tag page 9 | - elsif !page.was_truncated? 10 | = gap_tag 11 | = next_page_tag unless current_page.last? 12 | = last_page_tag unless current_page.last? 13 | -------------------------------------------------------------------------------- /app/views/kaminari/list/_prev_page.html.haml: -------------------------------------------------------------------------------- 1 | %li 2 | = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote 3 | -------------------------------------------------------------------------------- /app/views/kaminari/table/_first_page.html.haml: -------------------------------------------------------------------------------- 1 | = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote, :class => "first paginate_button" 2 | -------------------------------------------------------------------------------- /app/views/kaminari/table/_gap.html.haml: -------------------------------------------------------------------------------- 1 | = link_to raw(t 'views.pagination.truncate'), '#' 2 | -------------------------------------------------------------------------------- /app/views/kaminari/table/_last_page.html.haml: -------------------------------------------------------------------------------- 1 | = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, :remote => remote, :class => "last paginate_button" 2 | -------------------------------------------------------------------------------- /app/views/kaminari/table/_next_page.html.haml: -------------------------------------------------------------------------------- 1 | = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote, :class => "next paginate_button" 2 | -------------------------------------------------------------------------------- /app/views/kaminari/table/_page.html.haml: -------------------------------------------------------------------------------- 1 | = link_to page, page.current? ? '#' : url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil, :class => page.current? ? 'paginate_active' : 'paginate_button'} -------------------------------------------------------------------------------- /app/views/kaminari/table/_paginator.html.haml: -------------------------------------------------------------------------------- 1 | = paginator.render do 2 | .dataTables_paginate.paging_full_numbers 3 | = first_page_tag unless current_page.first? 4 | = prev_page_tag unless current_page.first? 5 | - each_page do |page| 6 | - if page.left_outer? || page.right_outer? || page.inside_window? 7 | = page_tag page 8 | - elsif !page.was_truncated? 9 | = gap_tag 10 | = next_page_tag unless current_page.last? 11 | = last_page_tag unless current_page.last? 12 | -------------------------------------------------------------------------------- /app/views/kaminari/table/_prev_page.html.haml: -------------------------------------------------------------------------------- 1 | = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote, :class => "previous paginate_button" 2 | -------------------------------------------------------------------------------- /app/views/layouts/_blue_strip.html.haml: -------------------------------------------------------------------------------- 1 | .blue_strip 2 | /%img{src: asset_path('logo.png'), style: 'float: right'} 3 | %h1 4 | %i.icon-wrench.header-icon 5 | SIP Treadmill 6 | -------------------------------------------------------------------------------- /app/views/layouts/_footer.html.haml: -------------------------------------------------------------------------------- 1 | %footer 2 | = yield :scripts -------------------------------------------------------------------------------- /app/views/layouts/_head.html.haml: -------------------------------------------------------------------------------- 1 | %meta{:charset => "utf-8"} 2 | %meta{:name => "viewport", :content => "width=device-width, initial-scale=1.0"} 3 | %title= content_for?(:title) ? yield(:title) : "SIP Treadmill" 4 | %meta{:content => "", :name => "description"} 5 | %meta{:content => "", :name => "author"} 6 | = stylesheet_link_tag "application", :media => "all" 7 | = javascript_include_tag "application" 8 | = csrf_meta_tags 9 | = yield(:head) 10 | -------------------------------------------------------------------------------- /app/views/layouts/_messages.html.haml: -------------------------------------------------------------------------------- 1 | - flash.each do |name, msg| 2 | - if msg.is_a?(String) 3 | %div{:class => "alert alert-#{name == :notice ? "success" : "error"}"} 4 | %a.close{"data-dismiss" => "alert"} × 5 | = content_tag :div, msg, :id => "flash_#{name}" 6 | -------------------------------------------------------------------------------- /app/views/layouts/_page_header.html.haml: -------------------------------------------------------------------------------- 1 | .row-fluid 2 | .area-top.clearfix 3 | .pull-left.header 4 | %h3.title 5 | %i{class: content_for?(:page_icon) ? content_for(:page_icon) : 'icon-table'} 6 | - if content_for?(:page_title) 7 | = yield(:page_title) 8 | - else 9 | Page title 10 | - if content_for?(:page_subtitle) 11 | %h5 12 | = yield(:page_subtitle) 13 | .pull-right.inline.loggedinas 14 | - if user_signed_in? 15 | %p 16 | Logged in as 17 | %strong= "#{current_user.full_name}" 18 | - if current_user.admin 19 | -if current_user.admin_mode 20 | %p= link_to 'Disable admin mode', home_toggle_admin_path, class: 'btn btn-mini btn-danger', method: :post 21 | -else 22 | %p= link_to 'Enable admin mode', home_toggle_admin_path, class: 'btn btn-mini btn-success', method: :post 23 | %p 24 | =link_to 'Logout', destroy_user_session_path, :method => :delete, data: { confirm: "Are you sure you want to logout? You may lose unsaved data." } 25 | .row-fluid 26 | .padded 27 | = render 'layouts/messages' 28 | -------------------------------------------------------------------------------- /app/views/layouts/_sidebar.html.haml: -------------------------------------------------------------------------------- 1 | .sidebar-background 2 | .primary-sidebar-background 3 | .primary-sidebar 4 | / Main nav 5 | %ul.nav.nav-collapse.collapse.nav-collapse-primary 6 | - if user_signed_in? 7 | %li{class: controller.controller_name == 'home' ? 'active' : ''} 8 | %span.glow 9 | %a{href: root_path} 10 | %i.icon-dashboard.icon-2x 11 | %span Dashboard 12 | 13 | %li{class: controller.controller_name == 'test_runs' ? 'active' : ''} 14 | %span.glow 15 | %a{href: test_runs_path} 16 | %i.icon-rocket.icon-2x 17 | %span Test Runs 18 | %li{class: controller.controller_name == 'scenarios' ? 'active' : ''} 19 | %span.glow 20 | %a{href: scenarios_path} 21 | %i.icon-list.icon-2x 22 | %span Scenarios 23 | %li{class: controller.controller_name == 'profiles' ? 'active' : ''} 24 | %span.glow 25 | %a{href: profiles_path} 26 | %i.icon-bar-chart.icon-2x 27 | %span Profiles 28 | %li{class: controller.controller_name == 'targets' ? 'active' : ''} 29 | %span.glow 30 | %a{href: targets_path} 31 | %i.icon-bullseye.icon-2x 32 | %span Targets 33 | %li{class: controller.controller_name == 'users' ? 'active' : ''} 34 | %span.glow 35 | %a{href: "/users/#{current_user.id}" } 36 | %i.icon-user.icon-2x 37 | %span User 38 | - if current_user.admin 39 | %li{class: controller.controller_name == 'users' ? 'active' : ''} 40 | %span.glow 41 | %a{href: users_path} 42 | %i.icon-group.icon-2x 43 | %span Users -------------------------------------------------------------------------------- /app/views/layouts/_top_navigation.html.haml: -------------------------------------------------------------------------------- 1 | %header.navbar.navbar-top.navbar-inverse 2 | %nav.navbar-inner 3 | .container-fluid 4 | - if user_signed_in? 5 | %ul.nav.pull-right 6 | %li= link_to "Logged in as #{current_user.first_name} #{current_user.last_name}", '#' -------------------------------------------------------------------------------- /app/views/layouts/application.html.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %head 4 | = render 'layouts/head' 5 | %body 6 | = render 'layouts/blue_strip' 7 | = render 'layouts/sidebar' 8 | .main-content 9 | = yield 10 | = render 'layouts/footer' 11 | -------------------------------------------------------------------------------- /app/views/partials/_bool_badge.html.haml: -------------------------------------------------------------------------------- 1 | - if check_val 2 | %i.icon-check-sign.color-ok 3 | -else 4 | %i.icon-remove-sign.color-ko -------------------------------------------------------------------------------- /app/views/profiles/_form.html.haml: -------------------------------------------------------------------------------- 1 | = simple_form_for(@profile, html: {class: 'form-horizontal'}, remote: local_assigns[:remote], format: local_assigns[:use_json] ? :json : :html) do |f| 2 | = f.error_notification 3 | .form-inputs.container-fluid.padded 4 | .row-fluid 5 | .span12 6 | = f.input :name, hint: 'Give your new profile a name so you can refer to it in the future.' 7 | .row-fluid 8 | .span12 9 | = f.input :max_calls 10 | = f.input :calls_per_second 11 | = f.input :max_concurrent 12 | = f.input :transport_type, collection: TransportType.select_options 13 | %hr 14 | %p Optional: increase the calls-per-second rate linearly 15 | = f.input :calls_per_second_incr, label: 'Increment (per Interval)' 16 | = f.input :calls_per_second_interval, label: 'Interval (seconds)', hint: 'The CPS will be increased by the Increment each Interval' 17 | = f.input :calls_per_second_max, label: 'Maximum CPS' 18 | .form-actions 19 | = f.button :submit, class: 'btn-default' 20 | -------------------------------------------------------------------------------- /app/views/profiles/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-bar-chart" } 2 | - content_for(:page_title) { "Editing Profile" } 3 | = render "layouts/page_header" 4 | .container-fluid.padded 5 | .row-fluid 6 | .span12 7 | .box 8 | .box-header 9 | %span.title Edit Profile 10 | %ul.box-toolbar 11 | %li= link_to '', :back, class: 'btn btn-primary icon-arrow-left', title: 'Back' 12 | %li= link_to '', @profile, class:'btn btn-info icon-eye-open', title: 'Show' 13 | .box-content.padded-top 14 | = render 'form' 15 | 16 | -------------------------------------------------------------------------------- /app/views/profiles/index.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-bar-chart" } 2 | - content_for(:page_title) { "Listing Profiles" } 3 | = render "layouts/page_header" 4 | .container-fluid.padded 5 | .row-fluid 6 | .span12 7 | .box 8 | .box-header 9 | %span.title Profiles 10 | %ul.box-toolbar 11 | %li= link_to "", new_profile_path, class: 'btn btn-success icon-plus', title: 'Create new' 12 | .box-content.data-grid 13 | %table.table.datatable.table-normal 14 | %thead 15 | %tr 16 | %td Name 17 | %td Max calls 18 | %td Calls per second Initial 19 | %td Calls per second Max 20 | %td Calls per second Increment/Interval 21 | %td Max concurrent 22 | - if current_user.admin_mode 23 | %td Owned by 24 | %td Transport type 25 | %td.action-header 26 | 27 | %tbody 28 | - @profiles.each do |profile| 29 | %tr 30 | %td= profile.name 31 | %td= profile.max_calls 32 | %td= profile.calls_per_second 33 | %td= profile.calls_per_second_max 34 | %td 35 | - if profile.calls_per_second_incr 36 | = profile.calls_per_second_incr 37 | \/ 38 | = profile.calls_per_second_interval 39 | %td= profile.max_concurrent 40 | - if current_user.admin_mode 41 | %td= profile.user.full_name if profile.user 42 | - if profile.transport_type.blank? 43 | %td No transport type specified. 44 | - else 45 | %td= profile.transport_type.text 46 | %td 47 | .btn-group 48 | = link_to '', profile, class: 'btn btn-info icon-eye-open', title: 'Show' 49 | - if profile.writable? 50 | = link_to '', edit_profile_path(profile), class: 'btn btn-warning icon-edit', title: 'Edit' 51 | - else 52 | %a{"data-original-title" => "Read-only: in use by #{pluralize(profile.test_runs.count, 'test run')}", "data-placement" => "bottom", "data-toggle" => "tooltip", :href => "#", :title => ""} 53 | %span{class: 'btn btn- icon-edit', disabled: "disabled"} 54 | = link_to '', "/profiles/#{profile.id}/copy", class: 'btn alert-info icon-copy', title: "Clone" 55 | = link_to '', profile, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger icon-trash', title: 'Delete' 56 | .table-footer 57 | = paginate @profiles, theme: 'table' 58 | 59 | :javascript 60 | $(function() { 61 | $('.datatable').dataTable({ 62 | "sDom": "<'row-fluid'<'span6'l><'span6'f>r>t<'row-fluid'<'span6'i><'span6'p>>", 63 | "sPaginationType": "bootstrap", 64 | "bDestroy": true, 65 | "bStateSave": true, 66 | "bAutoWidth": false, 67 | "aoColumns": [ 68 | {}, 69 | {}, 70 | {}, 71 | {}, 72 | {}, 73 | { "bSortable": false } 74 | ] 75 | }); 76 | }); 77 | $('[data-toggle=tooltip]').tooltip(); 78 | $('span[disabled=disabled]').css('cursor','help'); 79 | -------------------------------------------------------------------------------- /app/views/profiles/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-bar-chart" } 2 | - content_for(:page_title) { "Creating New Profile" } 3 | = render "layouts/page_header" 4 | .container-fluid.padded 5 | .row-fluid 6 | .span12 7 | .box 8 | .box-header 9 | %span.title New Profile 10 | %ul.box-toolbar 11 | %li= link_to '', :back, class: 'btn btn-primary icon-arrow-left', title: 'Back' 12 | .box-content.padded-top 13 | = render 'form' 14 | -------------------------------------------------------------------------------- /app/views/profiles/show.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-bar-chart" } 2 | - content_for(:page_title) { "Showing Profile" } 3 | - content_for(:page_subtitle) { "#{@profile.name}"} 4 | = render "layouts/page_header" 5 | .container-fluid.padded 6 | .row-fluid 7 | .span6 8 | .box 9 | .box-header 10 | %span.title= @profile.name 11 | %ul.box-toolbar 12 | %li= link_to '', profiles_path, class: 'btn btn-primary icon-list', title: 'List' 13 | %li= link_to '', edit_profile_path(@profile), class: 'btn btn-warning icon-edit', title: 'Edit' 14 | %li= link_to '', "/profiles/#{@profile.id}/copy", class: 'btn alert-info icon-copy', title: 'Clone' 15 | %li= link_to '', @profile, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger icon-trash', title: 'Delete' 16 | .box-content.padded 17 | %dl 18 | %dt Name 19 | %dd= @profile.name 20 | %dt Max calls 21 | %dd= @profile.max_calls 22 | %dt Calls per second 23 | %dd= @profile.calls_per_second 24 | %dt Max concurrent 25 | %dd= @profile.max_concurrent 26 | %dt Transport type 27 | %dd= @profile.transport_type.text 28 | %dt Calls Per Second Increment 29 | %dd= @profile.calls_per_second_incr 30 | %dt Calls Per Second Interval 31 | %dd= @profile.calls_per_second_interval 32 | %dt Calls Per Second Maximum 33 | %dd= @profile.calls_per_second_max 34 | - if current_user.admin_mode 35 | %hr 36 | %dt Owned by 37 | %dd= @profile.user.full_name if @profile.user 38 | -------------------------------------------------------------------------------- /app/views/scenarios/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-list" } 2 | - content_for(:page_title) { "Editing Scenario" } 3 | = render "layouts/page_header" 4 | .container-fluid.padded 5 | .row-fluid 6 | .span12 7 | .box 8 | .box-header 9 | %span.title Edit Scenario 10 | %ul.box-toolbar 11 | %li= link_to '', :back, class: 'btn btn-primary icon-arrow-left', title: 'Back' 12 | %li= link_to '', @profile, class:'btn btn-info icon-eye-open', title: 'Show' 13 | .box-content.padded-top 14 | = render 'form' 15 | 16 | -------------------------------------------------------------------------------- /app/views/scenarios/index.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-list" } 2 | - content_for(:page_title) { "Listing Scenarios" } 3 | = render "layouts/page_header" 4 | #page_scenarios.container-fluid.padded 5 | .row-fluid 6 | .span12 7 | .box 8 | .box-header 9 | %span.title Scenarios 10 | %ul.box-toolbar 11 | %li= link_to "", new_scenario_path, class: 'btn btn-success icon-plus', title: 'Create new' 12 | .box-content.data-grid 13 | %table.table.datatable.table-normal 14 | %thead 15 | %tr 16 | %td Name 17 | %td Type 18 | - if current_user.admin_mode 19 | %td Owned by 20 | %td.action-header 21 | %tbody 22 | - @scenarios.each do |scenario| 23 | %tr 24 | %td= scenario.name 25 | %td= scenario.receiver ? 'Receiver' : 'Sender' 26 | - if current_user.admin_mode 27 | %td= scenario.user.full_name if scenario.user 28 | %td 29 | .btn-group 30 | = link_to '', scenario, class: 'btn btn-info icon-eye-open', title: 'Show' 31 | - if scenario.writable? 32 | = link_to '', edit_scenario_path(scenario), class: 'btn btn-warning icon-edit', title: 'Edit' 33 | - else 34 | %a{"data-original-title" => "Read-only: in use by #{pluralize(scenario.test_runs.count, 'test run')}", "data-placement" => "bottom", "data-toggle" => "tooltip", :href => "#", :title => ""} 35 | %span{class: 'btn btn- icon-edit', disabled: "disabled"} 36 | = link_to '', "/scenarios/#{scenario.id}/copy", class: 'btn alert-info icon-copy', title: "Clone" 37 | = link_to '', scenario, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger icon-trash', title: 'Delete' 38 | .table-footer 39 | = paginate @scenarios, theme: 'table' 40 | 41 | :javascript 42 | $(function() { 43 | $('.datatable').dataTable({ 44 | "sDom": "<'row-fluid'<'span6'l><'span6'f>r>t<'row-fluid'<'span6'i><'span6'p>>", 45 | "sPaginationType": "bootstrap", 46 | "bDestroy": true, 47 | "bStateSave": true, 48 | "bAutoWidth": false, 49 | "aoColumns": [ 50 | {}, 51 | {}, 52 | { "bSortable": false } 53 | ] 54 | }); 55 | }); 56 | $('[data-toggle=tooltip]').tooltip(); 57 | $('span[disabled=disabled]').css('cursor','help'); 58 | -------------------------------------------------------------------------------- /app/views/scenarios/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-list" } 2 | - content_for(:page_title) { "Creating New Scenario" } 3 | = render "layouts/page_header" 4 | .container-fluid.padded 5 | .row-fluid 6 | .span12 7 | .box 8 | .box-header 9 | %span.title New Scenario 10 | %ul.box-toolbar 11 | %li= link_to '', :back, class: 'btn btn-primary icon-arrow-left', title: 'Back' 12 | .box-content.padded-top 13 | = render 'form' 14 | 15 | -------------------------------------------------------------------------------- /app/views/scenarios/show.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-list" } 2 | - content_for(:page_title) { "Showing Scenario" } 3 | - content_for(:page_subtitle) { "#{@scenario.name}"} 4 | = render "layouts/page_header" 5 | :javascript 6 | SyntaxHighlighter.all(); 7 | .container-fluid.padded 8 | .row-fluid 9 | .span6 10 | .box 11 | .box-header 12 | %span.title= @scenario.name 13 | %ul.box-toolbar 14 | %li= link_to '', scenarios_path, class: 'btn btn-primary icon-list', title: 'List' 15 | %li= link_to '', edit_scenario_path(@scenario), class: 'btn btn-warning icon-edit', title: 'Edit' 16 | %li= link_to '', "/scenarios/#{@scenario.id}/copy", class: 'btn alert-info icon-copy', title: 'Clone' 17 | %li= link_to '', @scenario, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger icon-trash', title: 'Delete' 18 | .box-content.padded 19 | %dl 20 | %dt Name 21 | %dd= @scenario.name 22 | %dt Type 23 | %dd= @scenario.receiver ? 'Receiver' : 'Sender' 24 | - if @scenario.sippy_cup_scenario.nil? || @scenario.sippy_cup_scenario.empty? 25 | %dt SIPp XML 26 | %dd 27 | - if @scenario.sipp_xml.nil? || @scenario.sipp_xml.empty? 28 | None supplied. 29 | - else 30 | %pre{class: "brush:xml;"}= @scenario.sipp_xml 31 | %dt CSV Data 32 | %dd 33 | - if @scenario.csv_data.nil? || @scenario.csv_data.empty? 34 | None supplied. 35 | - else 36 | %pre= @scenario.csv_data 37 | - else 38 | %dt SippyCup Scenario 39 | %pre 40 | %dd= @scenario.sippy_cup_scenario 41 | - if current_user.admin_mode 42 | %dt Owned by 43 | %dd= @scenario.user.full_name if @scenario.user 44 | -------------------------------------------------------------------------------- /app/views/targets/_form.html.haml: -------------------------------------------------------------------------------- 1 | = simple_form_for(@target, remote: local_assigns[:remote], format: local_assigns[:use_json] ? :json : :html) do |f| 2 | = f.error_notification 3 | .form-inputs 4 | = f.input :name 5 | = f.input :address 6 | = f.input :ssh_username, label: "SSH Username" 7 | .form-actions 8 | = f.button :submit, class: 'btn-default' 9 | -------------------------------------------------------------------------------- /app/views/targets/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-bullseye" } 2 | - content_for(:page_title) { "Editing Target" } 3 | = render "layouts/page_header" 4 | .container-fluid.padded 5 | .row-fluid 6 | .span12 7 | .box 8 | .box-header 9 | %span.title Edit Target 10 | %ul.box-toolbar 11 | %li= link_to '', :back, class: 'btn btn-primary icon-arrow-left', title: 'Back' 12 | %li= link_to '', @profile, class:'btn btn-info icon-eye-open', title: 'Show' 13 | .box-content.padded-top 14 | = render 'form' 15 | 16 | -------------------------------------------------------------------------------- /app/views/targets/index.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-bullseye" } 2 | - content_for(:page_title) { "Listing Targets" } 3 | = render "layouts/page_header" 4 | .container-fluid.padded 5 | .row-fluid 6 | .span12 7 | .box 8 | .box-header 9 | %span.title Targets 10 | %ul.box-toolbar 11 | %li= link_to "", new_target_path, class: 'btn btn-success icon-plus', title: 'Create new' 12 | .box-content.data-grid 13 | %table.table.datatable.table-normal 14 | %thead 15 | %tr 16 | %td Name 17 | %td Address 18 | %td SSH Username 19 | - if current_user.admin_mode 20 | %td Owned by 21 | %td.action-header 22 | 23 | %tbody 24 | - @targets.each do |target| 25 | %tr 26 | %td= target.name 27 | %td= target.address 28 | %td= target.ssh_username 29 | - if current_user.admin_mode 30 | %td= target.user.full_name if target.user 31 | %td 32 | .btn-group 33 | = link_to '', target, class: 'btn btn-info icon-eye-open', title: 'Show' 34 | = link_to '', edit_target_path(target), class: 'btn btn-warning icon-edit', title: 'Edit' 35 | = link_to '', target, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger icon-trash', title: 'Delete' 36 | .table-footer 37 | 38 | :javascript 39 | $(function() { 40 | $('.datatable').dataTable({ 41 | "sDom": "<'row-fluid'<'span6'l><'span6'f>r>t<'row-fluid'<'span6'i><'span6'p>>", 42 | "sPaginationType": "bootstrap", 43 | "bDestroy": true, 44 | "bStateSave": true, 45 | "bAutoWidth": false, 46 | "aoColumns": [ 47 | {}, 48 | {}, 49 | { "bSortable": false } 50 | ] 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /app/views/targets/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-bullseye" } 2 | - content_for(:page_title) { "Creating New Target" } 3 | = render "layouts/page_header" 4 | .container-fluid.padded 5 | .row-fluid 6 | .span12 7 | .box 8 | .box-header 9 | %span.title New Target 10 | %ul.box-toolbar 11 | %li= link_to '', :back, class: 'btn btn-primary icon-arrow-left', title: 'Back' 12 | .box-content.padded-top 13 | = render 'form' 14 | -------------------------------------------------------------------------------- /app/views/targets/show.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-bullseye" } 2 | - content_for(:page_title) { "Showing Target" } 3 | - content_for(:page_subtitle) { "#{@target.name}"} 4 | = render "layouts/page_header" 5 | .container-fluid.padded 6 | .row-fluid 7 | .span6 8 | .box 9 | .box-header 10 | %span.title= @target.name 11 | %ul.box-toolbar 12 | %li= link_to '', targets_path, class: 'btn btn-primary icon-list', title: 'List' 13 | %li= link_to '', edit_target_path(@target), class: 'btn btn-warning icon-edit', title: 'Edit' 14 | %li= link_to '', @target, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger icon-trash', title: 'Delete' 15 | .box-content.padded 16 | %dl 17 | %dt Name 18 | %dd= @target.name 19 | %dt Address 20 | %dd= @target.address 21 | %dt SSH Username 22 | %dd= @target.ssh_username 23 | - if current_user.admin_mode 24 | %dt Owned by 25 | %dd= @target.user.full_name if @target.user 26 | 27 | -------------------------------------------------------------------------------- /app/views/test_runs/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-rocket" } 2 | - content_for(:page_title) { "Editing Test Run" } 3 | = render "layouts/page_header" 4 | #page_test_run.container-fluid.padded 5 | .row-fluid 6 | .span12 7 | .box 8 | .box-header 9 | %span.title Edit Test Run 10 | %ul.box-toolbar 11 | %li= link_to '', :back, class: 'btn btn-primary icon-arrow-left', title: 'Back' 12 | %li= link_to '', @test_run, class:'btn btn-info icon-eye-open', title: 'Show' 13 | .box-content.padded-top 14 | = render 'form' 15 | 16 | -------------------------------------------------------------------------------- /app/views/test_runs/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-rocket" } 2 | - content_for(:page_title) { "Creating New Test Run" } 3 | = render "layouts/page_header" 4 | #page_test_run.container-fluid.padded 5 | .row-fluid 6 | .span12 7 | .box 8 | .box-header 9 | %span.title New Test Run 10 | %ul.box-toolbar 11 | %li= link_to '', :back, class: 'btn btn-primary icon-arrow-left', title: 'Back' 12 | .box-content.padded-top 13 | = render 'form' 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/views/users/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-group" } 2 | - content_for(:page_title) { "Editing User" } 3 | - content_for(:page_subtitle) { "#{@user.first_name} #{@user.last_name}"} 4 | = render "layouts/page_header" 5 | .container-fluid.padded 6 | .row-fluid 7 | .span12 8 | .box 9 | .box-header 10 | %span.title= "#{@user.first_name} #{@user.last_name}" 11 | %ul.box-toolbar 12 | %li= link_to '', :back, class: 'btn btn-primary icon-arrow-left', title: 'Back' 13 | %li= link_to '', @user, class: 'btn btn-info icon-eye-open', title: 'Show' 14 | .box-content.padded-top 15 | = simple_form_for(@user, :html => {:class => 'form-horizontal' }) do |f| 16 | = f.error_notification 17 | .form-inputs 18 | = f.input :admin 19 | .form-actions 20 | = f.button :submit, class: 'btn-default' 21 | 22 | -------------------------------------------------------------------------------- /app/views/users/index.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-group" } 2 | - content_for(:page_title) { "Listing Users" } 3 | = render "layouts/page_header" 4 | .container-fluid.padded 5 | .row-fluid 6 | .span12 7 | .box 8 | .box-header 9 | %span.title Users 10 | .box-content 11 | %table.table.table-normal 12 | %thead 13 | %tr 14 | %td First Name 15 | %td Last Name 16 | %td Email 17 | %td Phone Number 18 | %td Admin? 19 | %td.action-header 20 | 21 | %tbody 22 | - @users.each do |user| 23 | %tr 24 | %td= user.first_name 25 | %td= user.last_name 26 | %td= user.email 27 | %td= user.phone_number 28 | %td.centered= render "partials/bool_badge", :check_val => user.admin 29 | %td 30 | .btn-group 31 | = link_to '', user, class: 'btn btn-info icon-eye-open', title: 'Show' 32 | = link_to '', edit_user_path(user), class: 'btn btn-warning icon-edit', title: 'Edit' 33 | .table-footer 34 | = paginate @users, theme: 'table' -------------------------------------------------------------------------------- /app/views/users/show.html.haml: -------------------------------------------------------------------------------- 1 | - content_for(:page_icon) { "icon-group" } 2 | - content_for(:page_title) { "Showing User" } 3 | - content_for(:page_subtitle) { "#{@user.first_name} #{@user.last_name}"} 4 | = render "layouts/page_header" 5 | .container-fluid.padded 6 | .row-fluid 7 | .span6 8 | .box 9 | .box-header 10 | %span.title= "#{@user.first_name} #{@user.last_name}" 11 | %ul.box-toolbar 12 | %li= link_to '', users_path, class: 'btn btn-primary icon-list', title: 'List' 13 | %li= link_to '', edit_user_path(@user), class: 'btn btn-warning icon-edit', title: 'Edit' 14 | .box-content.padded 15 | %dl 16 | %dt First Name 17 | %dd= @user.first_name 18 | %dt Last name 19 | %dd= @user.last_name 20 | %dt Email 21 | %dd= @user.email 22 | %dt Phone number 23 | %dd= @user.phone_number 24 | %dt Authentication Token 25 | %dd In order to make calls from Continuous Integration or other automated script, include an auth_token parameter with the following authentication token in each request made to Treadmill 26 | %dd 27 | %pre= @user.authentication_token 28 | %dd= link_to 'Generate', "/users/#{@user.id}/generate_token", class: 'btn btn-primary' 29 | %dt Admin? 30 | %dd= render "partials/bool_badge", :check_val => @user.admin 31 | .span6 32 | .box 33 | .box-header 34 | %span.title Statistics 35 | .box-content.padded 36 | %dl 37 | %dt Test Runs 38 | %dd= @user.test_runs.count 39 | %dt Scenarios 40 | %dd= @user.scenarios.count 41 | %dt Profiles 42 | %dd= @user.profiles.count 43 | %dt Targets 44 | %dd= @user.targets.count -------------------------------------------------------------------------------- /app/workers/test_run_worker.rb: -------------------------------------------------------------------------------- 1 | class TestRunWorker 2 | include Sidekiq::Worker 3 | sidekiq_options :retry => false 4 | 5 | def perform(test_run_id, password = nil) 6 | test_run = nil 7 | return if check_for_stop_signal 8 | 9 | test_run = TestRun.find test_run_id 10 | test_run.start! 11 | 12 | @test_runner = TestRunner.new test_run, jid, password 13 | 14 | @listener_running = true 15 | stop_signal_listener 16 | 17 | @test_runner.run 18 | 19 | if @test_runner.stopped 20 | test_run.stop! 21 | else 22 | test_run.complete! 23 | end 24 | rescue => e 25 | test_run.error_name = e.class.to_s 26 | test_run.error_message = e.message 27 | test_run.complete_with_errors if test_run 28 | raise 29 | ensure 30 | @listener_running = false 31 | end 32 | 33 | def check_for_stop_signal 34 | Sidekiq.redis do |r| 35 | result = r.srem(TestRun::STOP_JOBS_NAMESPACE, jid) 36 | return result 37 | end 38 | rescue 39 | false 40 | end 41 | 42 | def stop_signal_listener 43 | Thread.new do 44 | while @listener_running do 45 | sleep(1) 46 | if check_for_stop_signal 47 | @test_runner.stop 48 | @listener_running = false 49 | end 50 | end 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run SIPTreadmill::Application 5 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | if defined?(Bundler) 6 | # If you precompile assets before deploying to production, use this line 7 | Bundler.require(*Rails.groups(:assets => %w(development test))) 8 | # If you want your assets lazily compiled in production, use this line 9 | # Bundler.require(:default, :assets, Rails.env) 10 | end 11 | 12 | module SIPTreadmill 13 | class Application < Rails::Application 14 | # Settings in config/environments/* take precedence over those specified here. 15 | # Application configuration should go into files in config/initializers 16 | # -- all .rb files in that directory are automatically loaded. 17 | 18 | # Custom directories with classes and modules you want to be autoloadable. 19 | # config.autoload_paths += %W(#{config.root}/extras) 20 | 21 | # Only load the plugins named here, in the order given (default is alphabetical). 22 | # :all can be used as a placeholder for all plugins not explicitly named. 23 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 24 | 25 | # Activate observers that should always be running. 26 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 27 | 28 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 29 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 30 | # config.time_zone = 'Central Time (US & Canada)' 31 | 32 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 33 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 34 | # config.i18n.default_locale = :de 35 | 36 | # Configure the default encoding used in templates for Ruby 1.9. 37 | config.encoding = "utf-8" 38 | 39 | # Configure sensitive parameters which will be filtered from the log file. 40 | config.filter_parameters += [:password] 41 | 42 | # Enable escaping HTML in JSON. 43 | config.active_support.escape_html_entities_in_json = true 44 | 45 | # Use SQL instead of Active Record's schema dumper when creating the database. 46 | # This is necessary if your schema can't be completely dumped by the schema dumper, 47 | # like if you have constraints or database-specific column types 48 | # config.active_record.schema_format = :sql 49 | 50 | # Enforce whitelist mode for mass assignment. 51 | # This will create an empty whitelist of attributes available for mass-assignment for all models 52 | # in your app. As such, your models will need to explicitly whitelist or blacklist accessible 53 | # parameters by using an attr_accessible or attr_protected declaration. 54 | config.active_record.whitelist_attributes = true 55 | 56 | # Enable the asset pipeline 57 | config.assets.enabled = true 58 | 59 | # Version of your assets, change this if you want to expire all your assets 60 | config.assets.version = '1.0' 61 | 62 | # Avoid initializing the database connection when precompiling assets 63 | config.assets.initialize_on_precompile = false 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | common: &common 2 | adapter: postgresql 3 | username: <%= ENV['DATABASE_USERNAME'] || 'sip_treadmill' %> 4 | password: <%= ENV['DATABASE_PASSWORD'] || 'super_secret' %> 5 | host: <%= ENV['DATABASE_HOST'] || '127.0.0.1' %> 6 | port: <%= ENV['DATABASE_PORT'] ? ENV['DATABASE_PORT'].to_i : 5432 %> 7 | template: template0 8 | 9 | production: 10 | <<: *common 11 | database: <%= ENV['DATABASE_NAME'] || 'treadmill' %> 12 | 13 | development: 14 | <<: *common 15 | database: <%= ENV['DATABASE_NAME'] || 'treadmill_dev' %> 16 | 17 | test: 18 | <<: *common 19 | database: <%= ENV['DATABASE_NAME'] || 'treadmill_test' %> 20 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | SIPTreadmill::Application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | $stdout.sync = true 2 | 3 | SIPTreadmill::Application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb 5 | 6 | # In the development environment your application's code is reloaded on 7 | # every request. This slows down response time but is perfect for development 8 | # since you don't have to restart the web server when you make code changes. 9 | config.cache_classes = false 10 | 11 | # Log error messages when you accidentally call methods on nil. 12 | config.whiny_nils = true 13 | 14 | # Show full error reports and disable caching 15 | config.consider_all_requests_local = true 16 | config.action_controller.perform_caching = false 17 | 18 | # Don't care if the mailer can't send 19 | config.action_mailer.raise_delivery_errors = false 20 | 21 | # Print deprecation notices to the Rails logger 22 | config.active_support.deprecation = :log 23 | 24 | # Only use best-standards-support built into browsers 25 | config.action_dispatch.best_standards_support = :builtin 26 | 27 | # Raise exception on mass assignment protection for Active Record models 28 | config.active_record.mass_assignment_sanitizer = :strict 29 | 30 | # Log the query plan for queries taking more than this (works 31 | # with SQLite, MySQL, and PostgreSQL) 32 | config.active_record.auto_explain_threshold_in_seconds = 0.5 33 | 34 | # Do not compress assets 35 | config.assets.compress = false 36 | 37 | # Expands the lines which load the assets 38 | config.assets.debug = true 39 | end 40 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | SIPTreadmill::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = true 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = false 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to nil and saved in location specified by config.assets.prefix 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | # config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Prepend all log lines with the following tags 37 | # config.log_tags = [ :subdomain, :uuid ] 38 | 39 | # Use a different logger for distributed setups 40 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 41 | 42 | # Use a different cache store in production 43 | #config.cache_store = :dalli_store 44 | #config.assets.cache_store = :dalli_store 45 | 46 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 47 | # config.action_controller.asset_host = "http://assets.example.com" 48 | 49 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 50 | # config.assets.precompile += %w( ) 51 | 52 | # Disable delivery errors, bad email addresses will be ignored 53 | # config.action_mailer.raise_delivery_errors = false 54 | 55 | # Enable threaded mode 56 | # config.threadsafe! 57 | 58 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 59 | # the I18n.default_locale when a translation can not be found) 60 | config.i18n.fallbacks = true 61 | 62 | # Send deprecation notices to registered listeners 63 | config.active_support.deprecation = :notify 64 | 65 | # Log the query plan for queries taking more than this (works 66 | # with SQLite, MySQL, and PostgreSQL) 67 | # config.active_record.auto_explain_threshold_in_seconds = 0.5 68 | end 69 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | SIPTreadmill::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = "public, max-age=3600" 13 | 14 | # Log error messages when you accidentally call methods on nil 15 | config.whiny_nils = true 16 | 17 | # Show full error reports and disable caching 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Raise exception on mass assignment protection for Active Record models 33 | config.active_record.mass_assignment_sanitizer = :strict 34 | 35 | # Print deprecation notices to the stderr 36 | config.active_support.deprecation = :stderr 37 | end 38 | -------------------------------------------------------------------------------- /config/fog_credentials.yml: -------------------------------------------------------------------------------- 1 | default: 2 | aws_access_key_id: 'test' 3 | aws_secret_access_key: 'test' 4 | -------------------------------------------------------------------------------- /config/initializers/01_parse_vcap.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | if ENV.has_key? 'VCAP_SERVICES' 4 | Rails.logger.info "CloudFoundry environment detected." 5 | 6 | begin 7 | vcap = JSON.parse ENV['VCAP_SERVICES'] 8 | 9 | # Redis 10 | if vcap.has_key? 'redis-2.6' 11 | redis = vcap['redis-2.6'].first['credentials'] 12 | ENV['REDIS_URL'] = "redis://#{redis['name']}:#{redis['password']}@#{redis['host']}:#{redis['port']}/" 13 | end 14 | 15 | rescue => e 16 | Rails.logger.warn "Failed to parse CloudFoundry environment: #{e.message}" 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /config/initializers/airbrake.rb: -------------------------------------------------------------------------------- 1 | Airbrake.configure do |config| 2 | config.api_key = ENV['AIRBRAKE_TOKEN'] 3 | config.host = ENV['AIRBRAKE_HOST'] || "api.airbrake.io" 4 | config.port = 80 5 | config.secure = config.port == 443 6 | end 7 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/carrierwave.rb: -------------------------------------------------------------------------------- 1 | CarrierWave.configure do |config| 2 | if ENV['STORAGE_TYPE'] == 's3' 3 | config.storage = :fog 4 | config.fog_credentials = { 5 | :provider => 'AWS', 6 | :aws_access_key_id => ENV['AWS_ACCESS_KEY_ID'] || 'test', 7 | :aws_secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'] || 'test', 8 | } 9 | config.fog_directory = ENV['AWS_S3_BUCKET'] || "sip-treadmill-#{Rails.env}" 10 | else 11 | config.storage = :file 12 | config.root = ENV['FILE_PATH'] || File.expand_path("../../public", File.dirname(__FILE__)) 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format 4 | # (all these examples are active by default): 5 | ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | inflect.uncountable %w( rtcp_data ) 10 | end 11 | # 12 | # These inflection rules are supported but not enabled by default: 13 | # ActiveSupport::Inflector.inflections do |inflect| 14 | # inflect.acronym 'RESTful' 15 | # end 16 | -------------------------------------------------------------------------------- /config/initializers/kaminari.rb: -------------------------------------------------------------------------------- 1 | Kaminari.configure do |config| 2 | # config.default_per_page = 25 3 | # config.max_per_page = nil 4 | # config.window = 4 5 | # config.outer_window = 0 6 | # config.left = 0 7 | # config.right = 0 8 | # config.page_method_name = :page 9 | # config.param_name = :page 10 | end 11 | 12 | module Kaminari 13 | module Helpers 14 | class Paginator 15 | def render(&block) 16 | instance_eval(&block) if @options[:total_pages] >= 1 17 | @output_buffer 18 | end 19 | end 20 | end 21 | end -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /config/initializers/omniauth.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/config/initializers/omniauth.rb -------------------------------------------------------------------------------- /config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | SIPTreadmill::Application.config.secret_token = ENV['COOKIE_SECRET'] 8 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | SIPTreadmill::Application.config.session_store :cookie_store, key: '_sip_treadmill_session' 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # SIPTreadmill::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /config/initializers/sidekiq.rb: -------------------------------------------------------------------------------- 1 | Sidekiq.configure_server do |config| 2 | config.options[:concurrency] = 1 3 | end 4 | -------------------------------------------------------------------------------- /config/initializers/simple_form_bootstrap.rb: -------------------------------------------------------------------------------- 1 | # Use this setup block to configure all options available in SimpleForm. 2 | SimpleForm.setup do |config| 3 | config.wrappers :bootstrap, :tag => 'div', :class => 'control-group', :error_class => 'error' do |b| 4 | b.use :html5 5 | b.use :placeholder 6 | b.use :label 7 | b.wrapper :tag => 'div', :class => 'controls' do |ba| 8 | ba.use :input 9 | ba.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' } 10 | ba.use :hint, :wrap_with => { :tag => 'p', :class => 'help-block' } 11 | end 12 | end 13 | 14 | config.wrappers :prepend, :tag => 'div', :class => "control-group", :error_class => 'error' do |b| 15 | b.use :html5 16 | b.use :placeholder 17 | b.use :label 18 | b.wrapper :tag => 'div', :class => 'controls' do |input| 19 | input.wrapper :tag => 'div', :class => 'input-prepend' do |prepend| 20 | prepend.use :input 21 | end 22 | input.use :hint, :wrap_with => { :tag => 'span', :class => 'help-block' } 23 | input.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' } 24 | end 25 | end 26 | 27 | config.wrappers :append, :tag => 'div', :class => "control-group", :error_class => 'error' do |b| 28 | b.use :html5 29 | b.use :placeholder 30 | b.use :label 31 | b.wrapper :tag => 'div', :class => 'controls' do |input| 32 | input.wrapper :tag => 'div', :class => 'input-append' do |append| 33 | append.use :input 34 | end 35 | input.use :hint, :wrap_with => { :tag => 'span', :class => 'help-block' } 36 | input.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' } 37 | end 38 | end 39 | 40 | # Wrappers for forms and inputs using the Twitter Bootstrap toolkit. 41 | # Check the Bootstrap docs (http://twitter.github.com/bootstrap) 42 | # to learn about the different styles for forms and inputs, 43 | # buttons and other elements. 44 | config.default_wrapper = :bootstrap 45 | end 46 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # Disable root element in JSON by default. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /config/locales/simple_form.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | simple_form: 3 | "yes": 'Yes' 4 | "no": 'No' 5 | required: 6 | text: 'required' 7 | mark: '*' 8 | # You can uncomment the line below if you need to overwrite the whole required html. 9 | # When using html, text and mark won't be used. 10 | # html: '*' 11 | error_notification: 12 | default_message: "Please review the problems below:" 13 | # Labels and hints examples 14 | # labels: 15 | # defaults: 16 | # password: 'Password' 17 | # user: 18 | # new: 19 | # email: 'E-mail to sign in.' 20 | # edit: 21 | # email: 'E-mail.' 22 | # hints: 23 | # defaults: 24 | # username: 'User name to sign in.' 25 | # password: 'No special characters, please.' 26 | 27 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | require 'sidekiq/web' 2 | SIPTreadmill::Application.routes.draw do 3 | resources :test_runs do 4 | member do 5 | post 'enqueue' 6 | post 'cancel' 7 | post 'stop' 8 | get 'copy' 9 | end 10 | end 11 | resources :targets 12 | resources :profiles do 13 | get 'copy' 14 | end 15 | resources :scenarios do 16 | get 'copy' 17 | end 18 | 19 | resources :users, only: [:index, :show, :edit, :update, :copy] 20 | resources :users do 21 | member do 22 | get 'generate_token' 23 | end 24 | end 25 | 26 | post '/home/toggle_admin' 27 | 28 | authenticate :user do 29 | mount Sidekiq::Web => '/sidekiq' 30 | end 31 | 32 | devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" } 33 | 34 | devise_scope :user do 35 | delete "logout" => "devise/sessions#destroy", :as => :destroy_user_session 36 | end 37 | 38 | root to: "home#index" 39 | end 40 | -------------------------------------------------------------------------------- /db/migrate/20130718193845_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration 2 | def change 3 | create_table :users do |t| 4 | t.string :first_name 5 | t.string :last_name 6 | t.string :email 7 | t.string :phone_number 8 | t.string :provider 9 | t.string :uid 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20130718231537_create_scenarios.rb: -------------------------------------------------------------------------------- 1 | class CreateScenarios < ActiveRecord::Migration 2 | def change 3 | create_table :scenarios do |t| 4 | t.string :name 5 | t.text :sipp_xml 6 | t.string :pcap_audio 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20130719001047_create_profiles.rb: -------------------------------------------------------------------------------- 1 | class CreateProfiles < ActiveRecord::Migration 2 | def change 3 | create_table :profiles do |t| 4 | t.string :name 5 | t.integer :scenario_id 6 | t.integer :max_calls 7 | t.integer :calls_per_second 8 | t.integer :max_concurrent 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20130719004508_create_targets.rb: -------------------------------------------------------------------------------- 1 | class CreateTargets < ActiveRecord::Migration 2 | def change 3 | create_table :targets do |t| 4 | t.string :name 5 | t.string :address 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130719005907_remove_scenario_id_from_profiles.rb: -------------------------------------------------------------------------------- 1 | class RemoveScenarioIdFromProfiles < ActiveRecord::Migration 2 | def up 3 | remove_column :profiles, :scenario_id 4 | end 5 | 6 | def down 7 | add_column :profiles, :scenario_id, :integer 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20130719010213_create_test_runs.rb: -------------------------------------------------------------------------------- 1 | class CreateTestRuns < ActiveRecord::Migration 2 | def change 3 | create_table :test_runs do |t| 4 | t.string :name 5 | t.text :description 6 | t.integer :scenario_id 7 | t.integer :profile_id 8 | t.integer :target_id 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20130719011059_add_user_id_to_test_run.rb: -------------------------------------------------------------------------------- 1 | class AddUserIdToTestRun < ActiveRecord::Migration 2 | def change 3 | add_column :test_runs, :user_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130813165413_create_rtcp_data.rb: -------------------------------------------------------------------------------- 1 | class CreateRtcpData < ActiveRecord::Migration 2 | def change 3 | create_table :rtcp_data do |t| 4 | t.integer :test_run_id 5 | t.time :time 6 | t.float :max_packet_loss 7 | t.float :avg_packet_loss 8 | t.float :max_jitter 9 | t.float :avg_jitter 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20130813171603_create_sipp_data.rb: -------------------------------------------------------------------------------- 1 | class CreateSippData < ActiveRecord::Migration 2 | def change 3 | create_table :sipp_data do |t| 4 | t.integer :test_run_id 5 | t.time :time 6 | t.integer :successful_calls 7 | t.integer :failed_calls 8 | t.integer :total_calls 9 | t.float :cps 10 | t.integer :concurrent_calls 11 | t.float :avg_call_duration 12 | 13 | t.timestamps 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20130815073021_add_run_status_to_test_run.rb: -------------------------------------------------------------------------------- 1 | class AddRunStatusToTestRun < ActiveRecord::Migration 2 | def change 3 | add_column :test_runs, :run_status, :string, :default => :pending 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130816153851_add_response_time_to_sipp_data.rb: -------------------------------------------------------------------------------- 1 | class AddResponseTimeToSippData < ActiveRecord::Migration 2 | def change 3 | add_column :sipp_data, :response_time, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130820123419_add_jid_to_test_run.rb: -------------------------------------------------------------------------------- 1 | class AddJidToTestRun < ActiveRecord::Migration 2 | def change 3 | add_column :test_runs, :jid, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130823181127_add_sippy_cup_scenario_to_scenario.rb: -------------------------------------------------------------------------------- 1 | class AddSippyCupScenarioToScenario < ActiveRecord::Migration 2 | def change 3 | add_column :scenarios, :sippy_cup_scenario, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130829131123_add_enqueued_at_started_at_completed_at_state_to_test_runs.rb: -------------------------------------------------------------------------------- 1 | class AddEnqueuedAtStartedAtCompletedAtStateToTestRuns < ActiveRecord::Migration 2 | def change 3 | add_column :test_runs, :state, :string 4 | add_column :test_runs, :enqueued_at, :timestamp 5 | add_column :test_runs, :started_at, :timestamp 6 | add_column :test_runs, :completed_at, :timestamp 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20130829163022_remove_run_status_from_test_runs.rb: -------------------------------------------------------------------------------- 1 | class RemoveRunStatusFromTestRuns < ActiveRecord::Migration 2 | def up 3 | remove_column :test_runs, :run_status 4 | end 5 | 6 | def down 7 | add_column :test_runs, :run_status, :integer 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20130903162859_add_csv_data_to_scenario.rb: -------------------------------------------------------------------------------- 1 | class AddCsvDataToScenario < ActiveRecord::Migration 2 | def change 3 | add_column :scenarios, :csv_data, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130904085924_add_receiver_to_scenarios.rb: -------------------------------------------------------------------------------- 1 | class AddReceiverToScenarios < ActiveRecord::Migration 2 | def change 3 | add_column :scenarios, :receiver, :boolean, :default => false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130904090726_add_receiver_scenario_id_to_test_run.rb: -------------------------------------------------------------------------------- 1 | class AddReceiverScenarioIdToTestRun < ActiveRecord::Migration 2 | def change 3 | add_column :test_runs, :receiver_scenario_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130904155102_add_user_id_to_targets.rb: -------------------------------------------------------------------------------- 1 | class AddUserIdToTargets < ActiveRecord::Migration 2 | def change 3 | add_column :targets, :user_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130904161150_add_user_id_to_profiles.rb: -------------------------------------------------------------------------------- 1 | class AddUserIdToProfiles < ActiveRecord::Migration 2 | def change 3 | add_column :profiles, :user_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130904161817_add_user_id_to_scenarios.rb: -------------------------------------------------------------------------------- 1 | class AddUserIdToScenarios < ActiveRecord::Migration 2 | def change 3 | add_column :scenarios, :user_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130904201939_add_admin_fields_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddAdminFieldsToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :admin, :boolean, default: false 4 | add_column :users, :admin_mode, :boolean, default: false 5 | add_column :users, :perma_admin, :boolean, default: false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130905160536_remove_perma_admin_from_users.rb: -------------------------------------------------------------------------------- 1 | class RemovePermaAdminFromUsers < ActiveRecord::Migration 2 | def up 3 | remove_column :users, :perma_admin 4 | end 5 | 6 | def down 7 | add_column :users, :perma_admin, :boolean, default: false 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20130905234209_add_registration_scenario_id_to_test_run.rb: -------------------------------------------------------------------------------- 1 | class AddRegistrationScenarioIdToTestRun < ActiveRecord::Migration 2 | def change 3 | add_column :test_runs, :registration_scenario_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130906154523_add_registration_scenario_to_scenario.rb: -------------------------------------------------------------------------------- 1 | class AddRegistrationScenarioToScenario < ActiveRecord::Migration 2 | def change 3 | add_column :scenarios, :scenario_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130906193214_remove_registration_scenario_id_from_test_run.rb: -------------------------------------------------------------------------------- 1 | class RemoveRegistrationScenarioIdFromTestRun < ActiveRecord::Migration 2 | def up 3 | remove_column :test_runs, :registration_scenario_id 4 | end 5 | 6 | def down 7 | add_column :test_runs, :registration_scenario_id, :integer 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20130908161710_add_error_logging_columns_to_test_runs.rb: -------------------------------------------------------------------------------- 1 | class AddErrorLoggingColumnsToTestRuns < ActiveRecord::Migration 2 | def change 3 | add_column :test_runs, :error_name, :string 4 | add_column :test_runs, :error_message, :string 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20130913155706_add_description_to_scenario.rb: -------------------------------------------------------------------------------- 1 | class AddDescriptionToScenario < ActiveRecord::Migration 2 | def change 3 | add_column :scenarios, :description, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130913164234_add_transport_type_to_profile.rb: -------------------------------------------------------------------------------- 1 | class AddTransportTypeToProfile < ActiveRecord::Migration 2 | def change 3 | add_column :profiles, :transport_type, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130916205553_update_transport_on_profiles.rb: -------------------------------------------------------------------------------- 1 | class UpdateTransportOnProfiles < ActiveRecord::Migration 2 | def up 3 | Profile.all.each do |profile| 4 | # ||= doesn't work anymore because of the default value 5 | profile.transport_type = profile.transport_type 6 | profile.save! 7 | end 8 | end 9 | 10 | def down 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20130916211948_add_username_to_target.rb: -------------------------------------------------------------------------------- 1 | class AddUsernameToTarget < ActiveRecord::Migration 2 | def change 3 | add_column :targets, :ssh_username, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130917163559_create_system_load_data.rb: -------------------------------------------------------------------------------- 1 | class CreateSystemLoadData < ActiveRecord::Migration 2 | def change 3 | create_table :system_load_data do |t| 4 | t.integer :test_run_id 5 | t.float :cpu 6 | t.float :memory 7 | t.datetime :logged_at 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20130930174850_change_error_message_to_text.rb: -------------------------------------------------------------------------------- 1 | class ChangeErrorMessageToText < ActiveRecord::Migration 2 | def up 3 | change_column :test_runs, :error_message, :text 4 | end 5 | 6 | def down 7 | change_column :test_runs, :error_message, :string, limit: 255 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20131023225343_add_authentication_token_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddAuthenticationTokenToUser < ActiveRecord::Migration 2 | def change 3 | add_column :users, :authentication_token, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20140101171241_add_name_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddNameToUser < ActiveRecord::Migration 2 | def change 3 | add_column :users, :name, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20141005150720_add_reports_to_test_run.rb: -------------------------------------------------------------------------------- 1 | class AddReportsToTestRun < ActiveRecord::Migration 2 | def change 3 | add_column :test_runs, :summary_report, :text 4 | add_column :test_runs, :errors_report_file, :string 5 | add_column :test_runs, :stats_file, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141006032516_add_rate_scaling_to_profile.rb: -------------------------------------------------------------------------------- 1 | class AddRateScalingToProfile < ActiveRecord::Migration 2 | def change 3 | add_column :profiles, :calls_per_second_incr, :integer 4 | add_column :profiles, :calls_per_second_interval, :integer 5 | add_column :profiles, :calls_per_second_max, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141018225244_add_to_user_to_test_runs.rb: -------------------------------------------------------------------------------- 1 | class AddToUserToTestRuns < ActiveRecord::Migration 2 | def change 3 | add_column :test_runs, :to_user, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20150202215251_add_params_to_test_run.rb: -------------------------------------------------------------------------------- 1 | class AddParamsToTestRun < ActiveRecord::Migration 2 | def change 3 | add_column :test_runs, :from_user, :string 4 | add_column :test_runs, :advertise_address, :string 5 | add_column :test_runs, :sipp_options, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150216173416_allow_multiline_sipp_options_on_test_runs.rb: -------------------------------------------------------------------------------- 1 | class AllowMultilineSippOptionsOnTestRuns < ActiveRecord::Migration 2 | def up 3 | change_column :test_runs, :sipp_options, :text 4 | end 5 | 6 | def down 7 | change_column :test_runs, :sipp_options, :string 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20150414001332_add_cumulative_to_sipp_data.rb: -------------------------------------------------------------------------------- 1 | class AddCumulativeToSippData < ActiveRecord::Migration 2 | def change 3 | add_column :sipp_data, :successful_calls_cumulative, :integer 4 | add_column :sipp_data, :failed_calls_cumulative, :integer 5 | add_column :sipp_data, :avg_call_duration_cumulative, :float 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/lib/assets/.gitkeep -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/lib/tasks/.gitkeep -------------------------------------------------------------------------------- /lib/templates/erb/scaffold/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%%= simple_form_for(@<%= singular_table_name %>) do |f| %> 2 | <%%= f.error_notification %> 3 | 4 |
5 | <%- attributes.each do |attribute| -%> 6 | <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %> 7 | <%- end -%> 8 |
9 | 10 |
11 | <%%= f.button :submit %> 12 |
13 | <%% end %> 14 | -------------------------------------------------------------------------------- /packaging/wizards/siptreadmill/bin/compile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | ROOT_DIR=$(dirname $(dirname $0)) 6 | APP_NAME="$1" 7 | APP_VERSION="$2" 8 | APP_ITERATION="$3" 9 | APP_DIR="$4" 10 | APP_SAFE_NAME=${APP_NAME//-/_} 11 | 12 | find ${ROOT_DIR}/debian -type f -print0 | xargs -0 sed -i "s/_APP_NAME_/${APP_NAME}/g" 13 | find ${ROOT_DIR}/debian -type f -print0 | xargs -0 sed -i "s/_APP_VERSION_/${APP_VERSION}/g" 14 | find ${ROOT_DIR}/debian -type f -print0 | xargs -0 sed -i "s/_APP_ITERATION_/${APP_ITERATION}/g" 15 | find ${ROOT_DIR}/debian -type f -print0 | xargs -0 sed -i "s/_APP_SAFE_NAME_/${APP_SAFE_NAME}/g" 16 | -------------------------------------------------------------------------------- /packaging/wizards/siptreadmill/bin/configure: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | . "${INSTALLER_DIR}/wizard" 6 | 7 | input_start() { 8 | wiz_put "siptreadmill/authentication/provider" 9 | if wiz_ask ; then 10 | if [ $(wiz_get "siptreadmill/authentication/provider") == "none" ]; then 11 | STATE="storage" 12 | else 13 | STATE="auth_creds" 14 | fi 15 | else 16 | STATE="done" 17 | echo "Authentication configuration canceled." 18 | exit 1 19 | fi 20 | } 21 | 22 | input_auth_creds() { 23 | wiz_put "siptreadmill/authentication/key" 24 | wiz_put "siptreadmill/authentication/token" 25 | 26 | if wiz_ask ; then 27 | STATE="storage" 28 | else 29 | STATE="start" 30 | fi 31 | } 32 | 33 | input_storage() { 34 | wiz_put "siptreadmill/storage/type" 35 | 36 | if wiz_ask ; then 37 | if [ $(wiz_get "siptreadmill/storage/type") == "s3" ]; then 38 | STATE="s3" 39 | else 40 | STATE="filepath" 41 | fi 42 | else 43 | STATE="start" 44 | fi 45 | } 46 | 47 | input_filepath() { 48 | wiz_put "siptreadmill/storage/directory" 49 | 50 | if wiz_ask ; then 51 | STATE="airbrake" 52 | else 53 | STATE="start" 54 | fi 55 | } 56 | 57 | input_s3() { 58 | wiz_put "siptreadmill/s3/bucket" 59 | wiz_put "siptreadmill/s3/key" 60 | wiz_put "siptreadmill/s3/token" 61 | 62 | if wiz_ask ; then 63 | STATE="airbrake" 64 | else 65 | STATE="start" 66 | fi 67 | } 68 | 69 | input_airbrake() { 70 | wiz_put "siptreadmill/airbrake/token" 71 | wiz_put "siptreadmill/airbrake/host" 72 | 73 | if wiz_ask ; then 74 | STATE="done" 75 | else 76 | STATE="start" 77 | fi 78 | } 79 | 80 | state_machine() { 81 | case "$1" in 82 | "start") 83 | input_start 84 | ;; 85 | "auth_creds") 86 | input_auth_creds 87 | ;; 88 | "storage") 89 | input_storage 90 | ;; 91 | "filepath") 92 | input_filepath 93 | ;; 94 | "s3") 95 | input_s3 96 | ;; 97 | "airbrake") 98 | input_airbrake 99 | ;; 100 | "done") 101 | echo "DONE" 102 | break 103 | ;; 104 | *) 105 | echo "invalid state ${STATE}" 106 | break 107 | ;; 108 | esac 109 | } 110 | 111 | wizard "start" 112 | -------------------------------------------------------------------------------- /packaging/wizards/siptreadmill/bin/postinstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | . ${INSTALLER_DIR}/wizard 6 | 7 | CLI="${APP_NAME}" 8 | 9 | # set cookie secret token 10 | cookie_secret=$(${CLI} config:get COOKIE_SECRET || ${CLI} run rake -s secret | tail -1) 11 | ${CLI} config:set COOKIE_SECRET="$cookie_secret" 12 | 13 | # Create database 14 | sudo -u postgres psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='${APP_NAME}'" | grep -q 1 || sudo -u postgres createuser -D -A ${APP_NAME} 15 | database_password=$(${CLI} config:get DATABASE_PASSWORD || ${CLI} run rake -s secret | tail -1) 16 | sudo -u postgres psql -c "alter user ${APP_NAME} with password '$database_password';" 17 | sudo -u postgres psql -lqt | cut -d \| -f 1 | grep -w ${APP_NAME} | wc -l || sudo -u postgres createdb -O ${APP_NAME} ${APP_NAME} 18 | ${CLI} config:set DATABASE_URL="postgres://${APP_NAME}:$database_password@localhost/${APP_NAME}" 19 | ${CLI} config:set DATABASE_PASSWORD="$database_password" 20 | 21 | # prepare database 22 | ${CLI} run rake db:migrate db:seed || true 23 | 24 | # Configure third-party auth provider 25 | auth_provider=$(wiz_get "siptreadmill/authentication/provider") 26 | ${CLI} config:set OMNIAUTH_TYPE=${auth_provider} 27 | case "${auth_provider}" in 28 | "github") 29 | ${CLI} config:set GITHUB_KEY=$(wiz_get "siptreadmill/authentication/key") 30 | ${CLI} config:set GITHUB_SECRET=$(wiz_get "siptreadmill/authentication/token") 31 | ;; 32 | "none") 33 | ;; 34 | "skip") 35 | ;; 36 | *) 37 | echo "Unknown value for siptreadmill/authentication/provider" 38 | ;; 39 | esac 40 | 41 | # Configure Amazon S3 credentials 42 | if [ $(wiz_get "siptreadmill/storage/type") == "s3" ]; then 43 | ${CLI} config:set STORAGE_TYPE=$(wiz_get "siptreadmill/storage/type") 44 | ${CLI} config:set AWS_S3_BUCKET=$(wiz_get "siptreadmill/s3/bucket") 45 | ${CLI} config:set AWS_ACCESS_KEY_ID=$(wiz_get "siptreadmill/s3/key") 46 | ${CLI} config:set AWS_SECRET_ACCESS_KEY=$(wiz_get "siptreadmill/s3/token") 47 | else 48 | ${CLI} config:set STORAGE_TYPE=$(wiz_get "siptreadmill/storage/type") 49 | ${CLI} config:set FILE_PATH=$(wiz_get "siptreadmill/storage/directory") 50 | fi 51 | 52 | ${CLI} config:set AIRBRAKE_TOKEN=$(wiz_get "siptreadmill/airbrake/token") 53 | ${CLI} config:set AIRBRAKE_HOST=$(wiz_get "siptreadmill/airbrake/host") 54 | 55 | # scale 56 | ${CLI} scale web=1 worker=1 || true 57 | 58 | # restart 59 | service ${APP_NAME} restart 60 | 61 | exit 0 62 | -------------------------------------------------------------------------------- /packaging/wizards/siptreadmill/bin/preinstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | . "${INSTALLER_DIR}/wizard" 6 | 7 | # Install datastores 8 | apt-get -y install postgresql redis-server 9 | 10 | # Install SIPp & setup sudo 11 | echo "deb http://ppa.launchpad.net/taisph/sipp/ubuntu trusty main" | tee /etc/apt/sources.list.d/taisph-sipp.list 12 | apt-get -y update 13 | apt-get -y install sipp --force-yes 14 | echo "${APP_NAME} ALL=(ALL) NOPASSWD: /usr/bin/sipp" | tee /etc/sudoers.d/siptreadmill 15 | chmod 0440 /etc/sudoers.d/siptreadmill 16 | 17 | exit 0 18 | -------------------------------------------------------------------------------- /packaging/wizards/siptreadmill/templates: -------------------------------------------------------------------------------- 1 | Template: siptreadmill/authentication/provider 2 | Type: select 3 | Choices: github, none 4 | Translations: Github, Guest Mode 5 | Default: github 6 | Description: Which authentication provider do you want to use for $APP_NAME? 7 | Chose the authentication provider you have setup $APP_NAME. 8 | 9 | Template: siptreadmill/authentication/key 10 | Type: string 11 | Description: Authentication provider API key 12 | The API key provided to you by your authentication provider 13 | 14 | Template: siptreadmill/authentication/token 15 | Type: string 16 | Description: Authentication provider API token 17 | The API token/secret provided to you by your authentication provider 18 | 19 | Template: siptreadmill/storage/type 20 | Type: select 21 | Choices: file, s3 22 | Translations: Local Filesystem, AWS S3 23 | Default: file 24 | Description: Where do you want to store uploaded files for $APP_NAME? 25 | Chose where you store uploaded files for $APP_NAME. 26 | 27 | Template: siptreadmill/storage/directory 28 | Type: string 29 | Default: $APP_HOME/public 30 | Description: Directory to store uploaded files in 31 | Chose a directory to store uploaded files in. 32 | 33 | Template: siptreadmill/s3/bucket 34 | Type: string 35 | Default: siptreadmill 36 | Description: AWS S3 bucket 37 | The S3 bucket name you want to use for storing files 38 | 39 | Template: siptreadmill/s3/key 40 | Type: string 41 | Description: AWS S3 key 42 | The API token/secret provided to you by your authentication provider 43 | 44 | Template: siptreadmill/s3/token 45 | Type: string 46 | Description: AWS S3 authentication token 47 | The token/secret provided to you by Amazon. 48 | 49 | Template: siptreadmill/airbrake/token 50 | Type: string 51 | Description: Airbrake authentication token for error notification 52 | The token/secret provided to you by Airbrake for error notification. 53 | 54 | Template: siptreadmill/airbrake/host 55 | Type: string 56 | Default: api.airbrake.io 57 | Description: Airbrake host for error notification 58 | The host provided to you by Airbrake for error notification. 59 | -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-Agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /sipp/metadata.rb: -------------------------------------------------------------------------------- 1 | name "sipp" 2 | maintainer "Adhearsion Foundation Inc" 3 | maintainer_email "info@adhearsion.com" 4 | license "MIT" 5 | description "Patches and Installs the SIPp load testing tool" 6 | recipe "sipp", "Fetches, patches, and installs SIPp" 7 | 8 | %w{ ubuntu debian }.each do |os| 9 | supports os 10 | end 11 | -------------------------------------------------------------------------------- /sipp/recipes/default.rb: -------------------------------------------------------------------------------- 1 | %w{build-essential openssl libssl-dev libpcap-dev libncurses5-dev}.each { |p| package p } 2 | 3 | remote_file '/tmp/sipp-3.3.tar.gz' do 4 | source "http://downloads.sourceforge.net/project/sipp/sipp/3.3/sipp-3.3.tar.gz" 5 | checksum "17fd02e6aa71d44a90c65e84a1aa39d3aa329990d4aa48e4fb4b895304dbc920" 6 | end 7 | 8 | cookbook_file '/tmp/sipp_dyn_pcap.diff' do 9 | source 'sipp_dyn_pcap.diff' 10 | end 11 | 12 | script "compile sipp" do 13 | interpreter "/bin/bash" 14 | cwd "/tmp" 15 | code <<-EOF 16 | tar -xf sipp-3.3.tar.gz 17 | cd sipp-3.3 18 | patch < ../sipp_dyn_pcap.diff 19 | make pcapplay 20 | cp sipp /usr/local/bin 21 | EOF 22 | not_if do 23 | system 'sipp' 24 | $?.exitstatus == 99 25 | end 26 | end 27 | 28 | script "copy pcap files to home directory" do 29 | interpreter "/bin/bash" 30 | cwd "/home/vagrant" 31 | code <<-EOF 32 | cp -rp /tmp/sipp-3.3/pcap . 33 | chown -R vagrant:vagrant pcap/ 34 | EOF 35 | end -------------------------------------------------------------------------------- /spec/assets/rtcp.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /spec/controllers/test_run_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe TestRunsController do 4 | it %q{should associate a test run with the creating user when creating a new TestRun} 5 | end 6 | -------------------------------------------------------------------------------- /spec/factories/profile.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :profile do 3 | name "My first profile" 4 | calls_per_second 5 5 | max_calls 100 6 | max_concurrent 10 7 | transport_type "u1" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/factories/rtcp_data.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :rtcp_datum, :class => 'RtcpData' do 5 | time "2013-08-13 12:54:13" 6 | max_packet_loss 1.5 7 | avg_packet_loss 1.5 8 | max_jitter 1.5 9 | avg_jitter 1.5 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/factories/scenario.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :scenario do 3 | name "My first scenario" 4 | sipp_xml " {{PCAP_AUDIO}}" 5 | end 6 | 7 | factory :sipp_scenario, parent: :scenario do 8 | sipp_xml "" 9 | sippy_cup_scenario nil 10 | end 11 | 12 | factory :sipp_scenario_with_pcap, parent: :sipp_scenario do 13 | pcap_audio { File.open(File.join(Rails.root, 'spec', 'fixtures', 'dtmf_2833_1.pcap')) } 14 | end 15 | 16 | factory :sippy_cup_scenario, parent: :scenario do 17 | sipp_xml nil 18 | sippy_cup_scenario "invite" 19 | end 20 | 21 | factory :sippy_cup_scenario_with_complete_manifest, parent: :scenario do 22 | sipp_xml nil 23 | sippy_cup_scenario "---\nsource: 18341:23492\ndestination: 180348:2390480\nname: SIPPY CUP\nsteps: \n - invite" 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/factories/sipp_data.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :sipp_datum, :class => 'SippData' do 5 | time "2013-08-13 13:16:03" 6 | successful_calls 1 7 | failed_calls 1 8 | total_calls 1 9 | cps 1.5 10 | concurrent_calls 1 11 | avg_call_duration 1.5 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/factories/system_load_data.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :system_load_datum, :class => 'SystemLoadDatum' do 5 | cpu 1.5 6 | memory 1 7 | logged_at "2013-08-13 13:16:03" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/factories/target.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :target do 3 | name "My first target" 4 | address "127.0.0.1" 5 | end 6 | end -------------------------------------------------------------------------------- /spec/factories/test_run.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :test_run do 3 | name "My first test_run" 4 | user { FactoryGirl.build(:user) } 5 | scenario { FactoryGirl.build(:scenario) } 6 | profile { FactoryGirl.build(:profile) } 7 | target { FactoryGirl.build(:target) } 8 | to_user '+14044754840' 9 | from_user 'sippppp' 10 | advertise_address '10.5.5.1' 11 | sipp_options 'p: "101"' 12 | errors_report_file { File.open(File.join(Rails.root, 'spec', 'fixtures', 'errors.txt')) } 13 | state 'pending' 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/factories/user.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :user do 3 | first_name "Wanna" 4 | last_name "Be" 5 | email "wanna@be.com" 6 | phone_number "12125556789" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/features/test_runs_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | WebMock.allow_net_connect! 4 | 5 | describe "Test runs", :js => true do 6 | # Wait for form-submission JS to load. 7 | # AJAX forms submitted before this loads will cause tests to fail for odd reasons. 8 | # This mostly impacts forms not present on the page at initial load - those in modals. 9 | def prepare_for_form_submission 10 | sleep 1 11 | end 12 | 13 | describe "GET /test_runs/new" do 14 | before do 15 | login_with_oauth 16 | visit new_test_run_path 17 | end 18 | 19 | it "show the new test run form" do 20 | page.should have_content("New Test Run") 21 | end 22 | 23 | context "choosing to create a new scenario" do 24 | before { select "Create new...", from: :test_run_scenario_id } 25 | 26 | it "opens the new scenario form" do 27 | page.should have_content("New Scenario") 28 | end 29 | 30 | describe "submitting the form empty" do 31 | before do 32 | prepare_for_form_submission 33 | click_button "Create Scenario" 34 | end 35 | 36 | it "has an error" do 37 | page.should have_content("Please review the problems below") 38 | end 39 | 40 | it "has an error for the blank field" do 41 | pending "Why is this failing? It tests OK in the browser" 42 | page.should have_content("can't be blank") 43 | end 44 | end 45 | end 46 | 47 | context "choosing to create a new profile" do 48 | before { select "Create new...", from: :test_run_profile_id } 49 | 50 | it "opens the new profile form" do 51 | page.should have_content("New Profile") 52 | end 53 | 54 | it "has an error if submitted as empty" do 55 | prepare_for_form_submission 56 | click_button "Create Profile" 57 | page.should have_content("Please review the problems below") 58 | end 59 | end 60 | 61 | context "choosing to create a new target" do 62 | before { select "Create new...", from: :test_run_target_id } 63 | 64 | it "opens the new target form" do 65 | page.should have_content("New Target") 66 | end 67 | 68 | it "has an error if submitted as empty" do 69 | prepare_for_form_submission 70 | click_button "Create Target" 71 | page.should have_content("Please review the problems below") 72 | end 73 | end 74 | 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/fixtures/audio.pcap: -------------------------------------------------------------------------------- 1 | fooobar 2 | -------------------------------------------------------------------------------- /spec/fixtures/dtmf_2833_1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/spec/fixtures/dtmf_2833_1.pcap -------------------------------------------------------------------------------- /spec/fixtures/errors.txt: -------------------------------------------------------------------------------- 1 | errors 2 | errors 3 | errors 4 | -------------------------------------------------------------------------------- /spec/fixtures/vmstat_fixture.log: -------------------------------------------------------------------------------- 1 | procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----|1380060000 2 | r b swpd free inact active si so bi bo in cs us sy id wa|1380060001 3 | 1 0 46 321 12 0 9686 10577 12800 10581 4126 1730 1 25 54 20|1380060002 4 | 0 0 46 320 12 0 0 0 0 36 110 182 0 0 100 0|1380060003 5 | 0 0 46 320 12 0 0 0 0 0 97 155 0 1 100 0|1380060004 6 | 3 0 49 4 52 275 160 2664 612 2700 3469 412 1 11 88 0|1380060005 7 | 3 1 252 5 164 163 18932 213724 60732 213724 24644 6049 1 61 3 35|1380060006 8 | 9 6 310 3 163 162 51188 58228 64800 58228 15050 7927 0 42 3 55|1380060007 9 | 0 0 55 316 16 0 4440 2080 10220 2080 1731 1408 0 6 87 7|1380060008 10 | 0 0 55 316 16 0 0 0 0 0 111 164 0 1 99 0|1380060009 11 | -------------------------------------------------------------------------------- /spec/helpers/home_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | class HomeClass 4 | include HomeHelper 5 | end 6 | describe HomeHelper do 7 | context "Included in a class" do 8 | subject { HomeClass.new } 9 | 10 | describe "#get_completed_test_runs" do 11 | before do 12 | ability = Object.new 13 | ability.extend(CanCan::Ability) 14 | ability.can :read, TestRun 15 | subject.stub(:current_ability) { ability } 16 | 17 | [ 18 | Time.new(2012,12,21,5,12,21), 19 | Time.new(2012,12,21,1,12,21), 20 | Time.new(2012,12,22,1,12,22), 21 | ].each { |time| FactoryGirl.create :test_run, completed_at: time, state: "complete" } 22 | end 23 | 24 | it "should return the proper data structure" do 25 | subject.get_completed_test_runs.should == [ 26 | { 27 | key: "Completed Successfully", 28 | values: [ 29 | ["2012-12-21", 2], 30 | ["2012-12-22", 1], 31 | ] 32 | } 33 | ].to_json 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/models/profile_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Profile do 4 | context "validations" do 5 | it "should not accept a profile without a name" do 6 | FactoryGirl.build(:profile, name: nil).should_not be_valid 7 | end 8 | 9 | it "should not accept a profile without a calls_per_second" do 10 | FactoryGirl.build(:profile, calls_per_second: nil).should_not be_valid 11 | end 12 | 13 | it "should not accept a profile without a max_calls" do 14 | FactoryGirl.build(:profile, max_calls: nil).should_not be_valid 15 | end 16 | 17 | it "should not accept a profile without a max_concurrent" do 18 | FactoryGirl.build(:profile, max_concurrent: nil).should_not be_valid 19 | end 20 | 21 | it "should not accept the same name twice" do 22 | FactoryGirl.create(:profile) 23 | FactoryGirl.build(:profile).should_not be_valid 24 | end 25 | end 26 | end -------------------------------------------------------------------------------- /spec/models/rtcp_data_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe RtcpData do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/scenario_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Scenario do 4 | context "validations" do 5 | it "should not accept a scenario without a name" do 6 | FactoryGirl.build(:scenario, name: nil).should_not be_valid 7 | end 8 | 9 | it "should not accept the same name twice" do 10 | FactoryGirl.create(:scenario) 11 | FactoryGirl.build(:scenario).should_not be_valid 12 | end 13 | 14 | it "should not accept an invalid SippyCup scenario" do 15 | scenario = FactoryGirl.build :sippy_cup_scenario, sippy_cup_scenario: "send_digits 'abc'" 16 | scenario.should_not be_valid 17 | scenario.errors.messages[:sippy_cup_scenario].should == ["send_digits 'abc': Media not started (Step 1)"] 18 | end 19 | 20 | it "should accept a valid SippyCup scenario" do 21 | scenario = FactoryGirl.build :sippy_cup_scenario 22 | scenario.should be_valid 23 | end 24 | end 25 | 26 | context '#to_sippycup_scenario' do 27 | context 'XML Scenario' do 28 | let(:scenario) { FactoryGirl.build :sipp_scenario } 29 | let(:options) do 30 | { 31 | source: "127.0.0.1", 32 | destination: "127.0.0.1" 33 | } 34 | end 35 | it 'should return a SippyCup::XMLScenario object' do 36 | object = scenario.to_sippycup_scenario options 37 | object.should be_a(SippyCup::XMLScenario) 38 | end 39 | end 40 | 41 | context 'SippyCup Scenario' do 42 | let(:scenario) { FactoryGirl.build :sippy_cup_scenario } 43 | let(:options) do 44 | { 45 | source: "127.0.0.1", 46 | destination: "127.0.0.1" 47 | } 48 | end 49 | it 'should return a SippyCup::Scenario object' do 50 | object = scenario.to_sippycup_scenario options 51 | object.should be_a(SippyCup::Scenario) 52 | object.to_xml.should match(%r{INVITE}) 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/models/sipp_data_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SippData do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/system_load_data_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SystemLoadDatum do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/target_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Target do 4 | context "validations" do 5 | it "should not accept a target without a name" do 6 | FactoryGirl.build(:target, name: nil).should_not be_valid 7 | end 8 | 9 | it "should not accept a target without an address" do 10 | FactoryGirl.build(:target, address: nil).should_not be_valid 11 | end 12 | 13 | it "should not accept the same name twice" do 14 | FactoryGirl.create(:target) 15 | FactoryGirl.build(:target).should_not be_valid 16 | end 17 | end 18 | end -------------------------------------------------------------------------------- /spec/models/user_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'ostruct' 3 | 4 | describe User do 5 | describe "using AT&T auth" do 6 | let(:auth) do 7 | OpenStruct.new( 8 | uid: 'att-abcd1234', 9 | provider: 'att', 10 | credentials: OpenStruct.new(token: 'zyxwvut4321'), 11 | info: OpenStruct.new( 12 | first_name: 'Test', 13 | last_name: 'User', 14 | email: 'test@example.com', 15 | phone_number: '14045551234' 16 | ) 17 | ) 18 | end 19 | 20 | it %q{should find a user who has previously logged in via AT&T} do 21 | user = FactoryGirl.build(:user) 22 | user.uid = auth.uid 23 | user.provider = auth.provider 24 | user.save! 25 | User.find_or_create_from_auth_hash(:att, auth).should == user 26 | end 27 | 28 | it %q{should create a new user when no previous AT&T login and no matching email address} do 29 | found_user = User.find_or_create_from_auth_hash(:att, auth) 30 | found_user.first_name.should == 'Test' 31 | found_user.last_name.should == 'User' 32 | found_user.email.should == 'test@example.com' 33 | found_user.persisted?.should be true 34 | end 35 | 36 | end 37 | 38 | describe '#admin' do 39 | it "should not be possible to mass assign :admin" do 40 | user = FactoryGirl.build(:user) 41 | expect { user.update_attributes({admin: true}) }.to raise_error 42 | end 43 | 44 | it %q{should disable admin_mode when removing admin bit} do 45 | user = FactoryGirl.build :user 46 | user.admin = true 47 | user.admin_mode = true 48 | user.save! 49 | 50 | user.reload 51 | user.admin.should be true 52 | user.admin_mode.should be true 53 | user.admin = false 54 | 55 | user.save! 56 | user.reload 57 | user.admin_mode.should be false 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /spec/requests/scenarios_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Scenarios" do 4 | describe "GET /test_runs" do 5 | it "has the placeholder text" do 6 | login_user 7 | get new_scenario_path 8 | response.status.should be(200) 9 | response.body.should match("Use {{PCAP_AUDIO}} as a placeholder for the PCAP file path in the XML.") 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/requests/test_runs_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Test runs" do 4 | describe "GET /test_runs" do 5 | it "lists test_runs" do 6 | login_user 7 | get test_runs_path 8 | response.status.should be(200) 9 | end 10 | 11 | it "is unaccessible as a guest" do 12 | get test_runs_path 13 | response.status.should be(302) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/services/rtcp_tools/listener_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'socket' 3 | require 'countdownlatch' 4 | 5 | describe RTCPTools::Listener do 6 | let(:packet) { "\x81\xC8\x00\f\x18\x1D\xC0\x1C\xD5\xE6\xE4F\xA5\xEA\x06\xED\x00\x00\x9C@\x00\x00\x00\xFA\x00\x00\x9C@\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\xC6\xA5\xE3\x81\xCA\x00\x02\x18\x1D\xC0\x1C\x01\x00\x00\x00" } 7 | let(:time) { Time.new(2013,9,20,11,12,06,"-04:00") } 8 | context '#run' do 9 | 10 | it 'should read from the socket and parse data' do 11 | listener = RTCPTools::Listener.new 6000 12 | Thread.new { listener.run } 13 | UDPSocket.new.send packet, 0, 'localhost', 6000 14 | sleep 1 15 | listener.stop 16 | listener.data.should == { time => { jitter: [0], fractional_loss: [0.0] } } 17 | listener.organize_data.should == [{ time: time, avg_jitter: 0, max_jitter: 0, avg_packet_loss: 0.0, max_packet_loss: 0.0 }] 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/services/rtcp_tools_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe RTCPTools do 4 | subject { RTCPTools } 5 | 6 | describe "#parse" do 7 | # Use a real RTCP packet to test 8 | let(:packet) { "\x81\xc8\x00\x0c\x42\x69\xc7\xa9\xd5\xa3\xd1\x94\x2a\x85\x77\xbf\x00\x00\x9c\x40\x00\x00\x00\xfa\x00\x00\x9c\x40\x40\xc1\x11\x06\x00\x00\x00\x00\x00\x00\x00\xfd\x00\x00\x00\x01\x00\x00\x00\x00\x53\x14\x2a\x7e\x81\xca\x00\x02\x42\x69\xc7\xa9\x01\x00\x00\x00" } 9 | it "should return the proper data" do 10 | subject.parse(packet).should == {time: Time.new(2013,07,31,14,10,28,"-04:00"), fractional_loss: 0.0, total_loss: 0, jitter: 1} 11 | end 12 | end 13 | 14 | describe "#parse_headers" do 15 | context "No padding, one repoort" do 16 | let(:headers) { "\x81".unpack("B8").first } 17 | it "should return proper values for version, padding, and number of reports" do 18 | subject.parse_headers(headers).should == { version: 2, padding: false, report_count: 1 } 19 | end 20 | end 21 | 22 | context "Padding, two reports" do 23 | let(:headers) { "\xA2".unpack("B8").first } 24 | it "should return proper values for version, padding, and number of reports" do 25 | subject.parse_headers(headers).should == { version: 2, padding: true, report_count: 2 } 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/services/runner_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'countdownlatch' 3 | 4 | describe Runner do 5 | let(:rtcp_listener) { double :rtcp_listener } 6 | let(:sippy_cup_runner) { double :sippy_cup_runner } 7 | let(:e) { StandardError.new } 8 | let(:scenario) { double } 9 | 10 | subject(:runner) do 11 | Runner.new 'larry', scenario, my: :options 12 | end 13 | 14 | context '#run_and_catch_errors' do 15 | it 'should run the block passed to it' do 16 | mock_obj = double 'mock object' 17 | mock_obj.should_receive(:mock_method).once 18 | runner.run_and_catch_errors do 19 | mock_obj.mock_method 20 | end 21 | end 22 | 23 | it 'should report exceptions to Airbrake if mode airbrake is specified' do 24 | canary = double 'canary' 25 | latch = CountDownLatch.new 1 26 | canary.should_receive(:bang!).and_raise e 27 | Airbrake.should_receive(:notify).with e 28 | runner.run_and_catch_errors mode: :notify do 29 | canary.bang! 30 | latch.countdown! 31 | end 32 | latch.wait 2 33 | lambda { runner.check_ssh_errors }.should_not raise_error 34 | end 35 | 36 | it 'should not raise an SSH error if there were no problems with SSH' do 37 | mock_obj = double 'mock obj' 38 | latch = CountDownLatch.new 1 39 | mock_obj.should_receive(:mock_method).once 40 | runner.run_and_catch_errors mode: :error do 41 | mock_obj.mock_method 42 | latch.countdown! 43 | end 44 | latch.wait 2 45 | lambda { runner.check_ssh_errors }.should_not raise_error 46 | end 47 | 48 | it 'should raise an error if there were problems with SSH' do 49 | canary = double 'canary' 50 | latch = CountDownLatch.new 1 51 | canary.should_receive(:bang!).and_raise e 52 | runner.run_and_catch_errors mode: :error do 53 | canary.bang! 54 | latch.countdown! 55 | end 56 | latch.wait 2 57 | lambda { runner.check_ssh_errors }.should raise_error e 58 | end 59 | end 60 | 61 | describe "#run" do 62 | let(:rtcp_port){ 17000 } 63 | 64 | it "passes the same port to Listener and SippyCup" do 65 | Kernel.should_receive(:rand).and_return(rtcp_port) 66 | RTCPTools::Listener.should_receive(:new).with(rtcp_port+1).and_return rtcp_listener 67 | scenario.should_receive(:to_sippycup_scenario).and_return scenario 68 | rtcp_listener.stub(:run) 69 | rtcp_listener.stub(:stop) 70 | rtcp_listener.stub(:organize_data) 71 | SippyCup::Runner.should_receive(:new).with(scenario, full_sipp_output: false).and_return sippy_cup_runner 72 | sippy_cup_runner.should_receive(:run) 73 | subject.run 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/services/stats_collector_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe StatsCollector do 4 | let(:vm_buffer) { [] } 5 | let(:opts) do 6 | { 7 | host: '127.0.0.1', 8 | user: 'vagrant', 9 | password: 'vagrant', 10 | interval: 1, 11 | vm_buffer: vm_buffer 12 | } 13 | end 14 | 15 | describe '#initialize' do 16 | it 'raises if the host required option is missing' do 17 | opts.delete(:host) 18 | expect { StatsCollector.new opts }.to raise_error ArgumentError, 'Must provide host!' 19 | end 20 | end 21 | 22 | describe '#run' do 23 | subject { StatsCollector.new opts } 24 | let(:test_run) { FactoryGirl.create :test_run } 25 | 26 | it "collects data" do 27 | pending "Need to make this test not rely on a Vagrant VM just to collect stats" 28 | Thread.new do 29 | sleep 3 30 | subject.stop 31 | end 32 | subject.run 33 | 34 | parser = VMStatParser.new vm_buffer, test_run 35 | parser.parse 36 | test_run.system_load_data.count.should > 0 37 | 38 | first_data = test_run.system_load_data.first 39 | first_data.memory.should > 0 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/services/vmstat_parser_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe VMStatParser do 4 | let(:test_run) { FactoryGirl.create :test_run } 5 | let(:vmstat_buffer) { File.read(File.join(Rails.root,'spec/fixtures/vmstat_fixture.log')).split("\n") } 6 | 7 | subject { VMStatParser.new vmstat_buffer, test_run } 8 | 9 | it "should parse the data and save it to the test run" do 10 | subject.parse 11 | first_data = test_run.system_load_data.first 12 | first_data.cpu.should == 46.0 13 | first_data.memory.should == 3.6 14 | first_data.logged_at.should == Time.at(1380060002) 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV["RAILS_ENV"] ||= 'test' 3 | ENV['COOKIE_SECRET'] = 'ABCD' * 15 4 | require File.expand_path("../../config/environment", __FILE__) 5 | require 'rspec/rails' 6 | require 'rspec/autorun' 7 | require 'factory_girl' 8 | require 'database_cleaner' 9 | require 'capybara/rspec' 10 | require 'fakefs/spec_helpers' 11 | require 'webmock/rspec' 12 | 13 | require 'support/helpers' 14 | include HelperMethods 15 | 16 | include Warden::Test::Helpers 17 | Warden.test_mode! 18 | 19 | # Requires supporting ruby files with custom matchers and macros, etc, 20 | # in spec/support/ and its subdirectories. 21 | Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} 22 | 23 | RSpec.configure do |config| 24 | # ## Mock Framework 25 | # 26 | # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: 27 | # 28 | # config.mock_with :mocha 29 | # config.mock_with :flexmock 30 | # config.mock_with :rr 31 | 32 | config.treat_symbols_as_metadata_keys_with_true_values = true 33 | config.filter_run focus: true 34 | config.run_all_when_everything_filtered = true 35 | 36 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 37 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 38 | 39 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 40 | # examples within a transaction, remove the following line or assign false 41 | # instead of true. 42 | config.use_transactional_fixtures = true 43 | 44 | # If true, the base class of anonymous controllers will be inferred 45 | # automatically. This will be the default behavior in future versions of 46 | # rspec-rails. 47 | config.infer_base_class_for_anonymous_controllers = false 48 | 49 | config.include Devise::TestHelpers, :type => :controller 50 | 51 | # Run specs in random order to surface order dependencies. If you find an 52 | # order dependency and want to debug it, you can fix the order by providing 53 | # the seed, which is printed after each run. 54 | # --seed 1234 55 | config.order = "random" 56 | 57 | config.before(:suite) do 58 | DatabaseCleaner.strategy = :truncation 59 | end 60 | 61 | config.before(:each) do 62 | DatabaseCleaner.start 63 | end 64 | 65 | config.after(:each) do 66 | DatabaseCleaner.clean 67 | end 68 | end 69 | 70 | Fog.mock! 71 | Fog.credentials_path = Rails.root.join('config/fog_credentials.yml') 72 | connection = Fog::Storage.new(provider: 'AWS') 73 | connection.directories.create(key: "sip-treadmill-#{Rails.env}") # This should not be duplicated from the CarrierWave initializer 74 | 75 | FactoryGirl.find_definitions 76 | 77 | require 'capybara/poltergeist' 78 | Capybara.register_driver :poltergeist do |app| 79 | Capybara::Poltergeist::Driver.new app, js_errors: true 80 | end 81 | Capybara.javascript_driver = :poltergeist 82 | Capybara.default_wait_time = 10 83 | 84 | if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION >= "1.9" 85 | module Kernel 86 | alias :__at_exit :at_exit 87 | def at_exit(&block) 88 | __at_exit do 89 | exit_status = $!.status if $!.is_a?(SystemExit) 90 | block.call 91 | exit exit_status if exit_status 92 | end 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /spec/support/helpers.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module HelperMethods 4 | def login_user 5 | user = FactoryGirl.create(:user) 6 | login_as(user, :scope => :user) 7 | end 8 | 9 | def set_omniauth(opts = {}) 10 | default = { 11 | uid: 'att-abcd1234', 12 | provider: 'github', 13 | credentials: {token: 'zyxwvut4321'}, 14 | info: { 15 | first_name: 'Test', 16 | last_name: 'User', 17 | email: 'test@example.com', 18 | phone_number: '14045551234' 19 | } 20 | } 21 | 22 | credentials = default.merge(opts) 23 | provider = credentials[:provider] 24 | user_hash = credentials[provider] 25 | 26 | OmniAuth.config.test_mode = true 27 | 28 | OmniAuth.config.mock_auth[provider] = { 29 | 'uid' => credentials[:uid] 30 | } 31 | end 32 | 33 | def set_invalid_omniauth(opts = {}) 34 | credentials = { :provider => :facebook, 35 | :invalid => :invalid_crendentials 36 | }.merge(opts) 37 | 38 | OmniAuth.config.test_mode = true 39 | OmniAuth.config.mock_auth[credentials[:provider]] = credentials[:invalid] 40 | end 41 | 42 | def login_with_oauth 43 | set_omniauth 44 | visit user_omniauth_authorize_path :github 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /treadmill/metadata.rb: -------------------------------------------------------------------------------- 1 | name "treadmill" 2 | maintainer "Adhearsion Foundation Inc" 3 | maintainer_email "info@adhearsion.com" 4 | license "MIT" 5 | description "Sets up treadmill dev environment" 6 | recipe "database", "Sets up a database for Treadmill dev" 7 | depends "openssl" 8 | depends "postgresql" 9 | depends "database" 10 | depends "rvm" 11 | depends "redis" 12 | depends "sudo" 13 | depends "sipp" 14 | 15 | %w{ ubuntu debian }.each do |os| 16 | supports os 17 | end 18 | -------------------------------------------------------------------------------- /treadmill/recipes/app.rb: -------------------------------------------------------------------------------- 1 | include_recipe "sudo" 2 | include_recipe "sipp" 3 | 4 | rvm_user = 'vagrant' 5 | 6 | gnupg_dir = "/home/#{rvm_user}/.gnupg" 7 | gnupg_dir_user = "chown -R #{rvm_user}:#{rvm_user} #{gnupg_dir};" 8 | gnupg_dir_root = "if [ -d #{gnupg_dir} ]; then chown -R root:root #{gnupg_dir}; fi;" 9 | gnupg_cmd = "`which gpg2 || which gpg` --keyserver hkp://keys.gnupg.net --recv-keys #{node['rvm']['gpg_key']};" 10 | 11 | execute "Adding gpg key to #{rvm_user}" do 12 | environment ({"HOME" => "/home/#{rvm_user}"}) 13 | command "#{gnupg_dir_root} #{gnupg_cmd} #{gnupg_dir_user}" 14 | not_if { node['rvm']['gpg_key'].empty? } 15 | returns 0 16 | end 17 | 18 | include_recipe "rvm::user" 19 | include_recipe "redis::server" 20 | include_recipe "postgresql::client" 21 | 22 | rvm_shell "install gem deps" do 23 | code "bundle install" 24 | cwd "/srv/treadmill/current" 25 | user 'vagrant' 26 | environment 'NOKOGIRI_USE_SYSTEM_LIBRARIES' => 'true' 27 | action :run 28 | end 29 | 30 | rvm_shell "setup database" do 31 | code "rake db:setup" 32 | cwd "/srv/treadmill/current" 33 | user 'vagrant' 34 | action :run 35 | end 36 | -------------------------------------------------------------------------------- /treadmill/recipes/database.rb: -------------------------------------------------------------------------------- 1 | ENV['LANGUAGE'] = ENV['LANG'] = ENV['LC_ALL'] = "en_US.UTF-8" 2 | include_recipe "openssl" 3 | include_recipe "postgresql::server" 4 | include_recipe "database::postgresql" 5 | 6 | connection_info = { 7 | :host => "127.0.0.1", 8 | :port => 5432, 9 | :username => 'postgres', 10 | :password => node['postgresql']['password']['postgres'] 11 | } 12 | 13 | postgresql_database_user 'sip_treadmill' do 14 | connection connection_info 15 | password 'super_secret' 16 | action :create 17 | end 18 | 19 | postgresql_database "template1" do 20 | connection connection_info 21 | sql "ALTER USER sip_treadmill CREATEDB;" 22 | action :query 23 | end 24 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/assets/javascripts/.gitkeep -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/assets/stylesheets/.gitkeep -------------------------------------------------------------------------------- /vendor/cache/actionmailer-3.2.19.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/actionmailer-3.2.19.gem -------------------------------------------------------------------------------- /vendor/cache/actionpack-3.2.19.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/actionpack-3.2.19.gem -------------------------------------------------------------------------------- /vendor/cache/activemodel-3.2.19.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/activemodel-3.2.19.gem -------------------------------------------------------------------------------- /vendor/cache/activerecord-3.2.19.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/activerecord-3.2.19.gem -------------------------------------------------------------------------------- /vendor/cache/activeresource-3.2.19.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/activeresource-3.2.19.gem -------------------------------------------------------------------------------- /vendor/cache/activesupport-3.2.19.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/activesupport-3.2.19.gem -------------------------------------------------------------------------------- /vendor/cache/addressable-2.3.5.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/addressable-2.3.5.gem -------------------------------------------------------------------------------- /vendor/cache/airbrake-4.1.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/airbrake-4.1.0.gem -------------------------------------------------------------------------------- /vendor/cache/arel-3.0.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/arel-3.0.3.gem -------------------------------------------------------------------------------- /vendor/cache/bcrypt-ruby-3.1.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/bcrypt-ruby-3.1.1.gem -------------------------------------------------------------------------------- /vendor/cache/better_errors-0.9.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/better_errors-0.9.0.gem -------------------------------------------------------------------------------- /vendor/cache/binding_of_caller-0.7.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/binding_of_caller-0.7.2.gem -------------------------------------------------------------------------------- /vendor/cache/bourbon-3.1.8.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/bourbon-3.1.8.gem -------------------------------------------------------------------------------- /vendor/cache/builder-3.0.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/builder-3.0.4.gem -------------------------------------------------------------------------------- /vendor/cache/cancan-1.6.10.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/cancan-1.6.10.gem -------------------------------------------------------------------------------- /vendor/cache/capybara-2.1.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/capybara-2.1.0.gem -------------------------------------------------------------------------------- /vendor/cache/carrierwave-0.10.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/carrierwave-0.10.0.gem -------------------------------------------------------------------------------- /vendor/cache/celluloid-0.14.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/celluloid-0.14.1.gem -------------------------------------------------------------------------------- /vendor/cache/classy_enum-3.3.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/classy_enum-3.3.1.gem -------------------------------------------------------------------------------- /vendor/cache/cliver-0.2.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/cliver-0.2.1.gem -------------------------------------------------------------------------------- /vendor/cache/coderay-1.0.9.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/coderay-1.0.9.gem -------------------------------------------------------------------------------- /vendor/cache/coffee-rails-3.2.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/coffee-rails-3.2.2.gem -------------------------------------------------------------------------------- /vendor/cache/coffee-script-2.2.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/coffee-script-2.2.0.gem -------------------------------------------------------------------------------- /vendor/cache/coffee-script-source-1.6.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/coffee-script-source-1.6.3.gem -------------------------------------------------------------------------------- /vendor/cache/connection_pool-1.1.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/connection_pool-1.1.0.gem -------------------------------------------------------------------------------- /vendor/cache/countdownlatch-1.0.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/countdownlatch-1.0.0.gem -------------------------------------------------------------------------------- /vendor/cache/crack-0.4.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/crack-0.4.1.gem -------------------------------------------------------------------------------- /vendor/cache/daemons-1.1.9.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/daemons-1.1.9.gem -------------------------------------------------------------------------------- /vendor/cache/database_cleaner-1.0.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/database_cleaner-1.0.1.gem -------------------------------------------------------------------------------- /vendor/cache/debug_inspector-0.0.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/debug_inspector-0.0.2.gem -------------------------------------------------------------------------------- /vendor/cache/devise-3.0.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/devise-3.0.2.gem -------------------------------------------------------------------------------- /vendor/cache/diff-lcs-1.2.5.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/diff-lcs-1.2.5.gem -------------------------------------------------------------------------------- /vendor/cache/dotenv-0.9.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/dotenv-0.9.0.gem -------------------------------------------------------------------------------- /vendor/cache/erubis-2.7.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/erubis-2.7.0.gem -------------------------------------------------------------------------------- /vendor/cache/eventmachine-1.0.7.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/eventmachine-1.0.7.gem -------------------------------------------------------------------------------- /vendor/cache/excon-0.25.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/excon-0.25.3.gem -------------------------------------------------------------------------------- /vendor/cache/execjs-1.4.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/execjs-1.4.0.gem -------------------------------------------------------------------------------- /vendor/cache/factory_girl-4.5.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/factory_girl-4.5.0.gem -------------------------------------------------------------------------------- /vendor/cache/factory_girl_rails-4.5.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/factory_girl_rails-4.5.0.gem -------------------------------------------------------------------------------- /vendor/cache/fakefs-0.4.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/fakefs-0.4.2.gem -------------------------------------------------------------------------------- /vendor/cache/faraday-0.8.8.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/faraday-0.8.8.gem -------------------------------------------------------------------------------- /vendor/cache/ffi-1.9.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/ffi-1.9.0.gem -------------------------------------------------------------------------------- /vendor/cache/fog-1.14.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/fog-1.14.0.gem -------------------------------------------------------------------------------- /vendor/cache/foreman-0.63.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/foreman-0.63.0.gem -------------------------------------------------------------------------------- /vendor/cache/formatador-0.2.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/formatador-0.2.4.gem -------------------------------------------------------------------------------- /vendor/cache/guard-1.8.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/guard-1.8.2.gem -------------------------------------------------------------------------------- /vendor/cache/guard-rspec-3.0.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/guard-rspec-3.0.2.gem -------------------------------------------------------------------------------- /vendor/cache/haml-4.0.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/haml-4.0.3.gem -------------------------------------------------------------------------------- /vendor/cache/hashie-2.0.5.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/hashie-2.0.5.gem -------------------------------------------------------------------------------- /vendor/cache/hike-1.2.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/hike-1.2.3.gem -------------------------------------------------------------------------------- /vendor/cache/httpauth-0.2.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/httpauth-0.2.0.gem -------------------------------------------------------------------------------- /vendor/cache/i18n-0.7.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/i18n-0.7.0.gem -------------------------------------------------------------------------------- /vendor/cache/journey-1.0.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/journey-1.0.4.gem -------------------------------------------------------------------------------- /vendor/cache/jquery-datatables-rails-1.11.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/jquery-datatables-rails-1.11.2.gem -------------------------------------------------------------------------------- /vendor/cache/jquery-rails-3.0.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/jquery-rails-3.0.4.gem -------------------------------------------------------------------------------- /vendor/cache/json-1.8.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/json-1.8.2.gem -------------------------------------------------------------------------------- /vendor/cache/jwt-0.1.8.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/jwt-0.1.8.gem -------------------------------------------------------------------------------- /vendor/cache/kaminari-0.14.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/kaminari-0.14.1.gem -------------------------------------------------------------------------------- /vendor/cache/libv8-3.16.14.7-x86_64-darwin-13.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/libv8-3.16.14.7-x86_64-darwin-13.gem -------------------------------------------------------------------------------- /vendor/cache/libv8-3.16.14.7-x86_64-linux.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/libv8-3.16.14.7-x86_64-linux.gem -------------------------------------------------------------------------------- /vendor/cache/listen-1.2.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/listen-1.2.3.gem -------------------------------------------------------------------------------- /vendor/cache/lumberjack-1.0.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/lumberjack-1.0.4.gem -------------------------------------------------------------------------------- /vendor/cache/mail-2.5.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/mail-2.5.4.gem -------------------------------------------------------------------------------- /vendor/cache/method_source-0.8.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/method_source-0.8.2.gem -------------------------------------------------------------------------------- /vendor/cache/mime-types-1.25.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/mime-types-1.25.1.gem -------------------------------------------------------------------------------- /vendor/cache/mini_portile-0.6.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/mini_portile-0.6.0.gem -------------------------------------------------------------------------------- /vendor/cache/minitest-5.4.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/minitest-5.4.3.gem -------------------------------------------------------------------------------- /vendor/cache/multi_json-1.11.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/multi_json-1.11.0.gem -------------------------------------------------------------------------------- /vendor/cache/multipart-post-1.2.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/multipart-post-1.2.0.gem -------------------------------------------------------------------------------- /vendor/cache/net-scp-1.1.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/net-scp-1.1.2.gem -------------------------------------------------------------------------------- /vendor/cache/net-ssh-2.6.8.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/net-ssh-2.6.8.gem -------------------------------------------------------------------------------- /vendor/cache/nokogiri-1.6.3.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/nokogiri-1.6.3.1.gem -------------------------------------------------------------------------------- /vendor/cache/oauth2-0.8.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/oauth2-0.8.1.gem -------------------------------------------------------------------------------- /vendor/cache/omniauth-1.1.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/omniauth-1.1.4.gem -------------------------------------------------------------------------------- /vendor/cache/omniauth-github-1.1.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/omniauth-github-1.1.2.gem -------------------------------------------------------------------------------- /vendor/cache/omniauth-oauth2-1.1.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/omniauth-oauth2-1.1.1.gem -------------------------------------------------------------------------------- /vendor/cache/orm_adapter-0.4.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/orm_adapter-0.4.0.gem -------------------------------------------------------------------------------- /vendor/cache/packetfu-1.1.10.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/packetfu-1.1.10.gem -------------------------------------------------------------------------------- /vendor/cache/pg-0.16.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/pg-0.16.0.gem -------------------------------------------------------------------------------- /vendor/cache/poltergeist-1.4.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/poltergeist-1.4.1.gem -------------------------------------------------------------------------------- /vendor/cache/polyglot-0.3.5.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/polyglot-0.3.5.gem -------------------------------------------------------------------------------- /vendor/cache/power_assert-0.2.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/power_assert-0.2.2.gem -------------------------------------------------------------------------------- /vendor/cache/pry-0.9.12.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/pry-0.9.12.2.gem -------------------------------------------------------------------------------- /vendor/cache/pry-rails-0.3.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/pry-rails-0.3.2.gem -------------------------------------------------------------------------------- /vendor/cache/psych-2.0.13.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/psych-2.0.13.gem -------------------------------------------------------------------------------- /vendor/cache/quiet_assets-1.0.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/quiet_assets-1.0.2.gem -------------------------------------------------------------------------------- /vendor/cache/rack-1.4.5.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rack-1.4.5.gem -------------------------------------------------------------------------------- /vendor/cache/rack-cache-1.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rack-cache-1.2.gem -------------------------------------------------------------------------------- /vendor/cache/rack-protection-1.5.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rack-protection-1.5.0.gem -------------------------------------------------------------------------------- /vendor/cache/rack-ssl-1.3.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rack-ssl-1.3.4.gem -------------------------------------------------------------------------------- /vendor/cache/rack-test-0.6.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rack-test-0.6.2.gem -------------------------------------------------------------------------------- /vendor/cache/rails-3.2.19.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rails-3.2.19.gem -------------------------------------------------------------------------------- /vendor/cache/rails_12factor-0.0.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rails_12factor-0.0.3.gem -------------------------------------------------------------------------------- /vendor/cache/rails_serve_static_assets-0.0.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rails_serve_static_assets-0.0.4.gem -------------------------------------------------------------------------------- /vendor/cache/rails_stdout_logging-0.0.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rails_stdout_logging-0.0.3.gem -------------------------------------------------------------------------------- /vendor/cache/railties-3.2.19.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/railties-3.2.19.gem -------------------------------------------------------------------------------- /vendor/cache/rake-10.3.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rake-10.3.2.gem -------------------------------------------------------------------------------- /vendor/cache/rb-fsevent-0.9.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rb-fsevent-0.9.3.gem -------------------------------------------------------------------------------- /vendor/cache/rb-inotify-0.9.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rb-inotify-0.9.1.gem -------------------------------------------------------------------------------- /vendor/cache/rb-kqueue-0.2.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rb-kqueue-0.2.0.gem -------------------------------------------------------------------------------- /vendor/cache/rdoc-3.12.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rdoc-3.12.2.gem -------------------------------------------------------------------------------- /vendor/cache/redis-3.0.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/redis-3.0.4.gem -------------------------------------------------------------------------------- /vendor/cache/redis-namespace-1.3.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/redis-namespace-1.3.1.gem -------------------------------------------------------------------------------- /vendor/cache/ref-1.0.5.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/ref-1.0.5.gem -------------------------------------------------------------------------------- /vendor/cache/rspec-2.14.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rspec-2.14.1.gem -------------------------------------------------------------------------------- /vendor/cache/rspec-core-2.14.8.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rspec-core-2.14.8.gem -------------------------------------------------------------------------------- /vendor/cache/rspec-expectations-2.14.5.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rspec-expectations-2.14.5.gem -------------------------------------------------------------------------------- /vendor/cache/rspec-mocks-2.14.6.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rspec-mocks-2.14.6.gem -------------------------------------------------------------------------------- /vendor/cache/rspec-rails-2.14.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/rspec-rails-2.14.0.gem -------------------------------------------------------------------------------- /vendor/cache/ruby-hmac-0.4.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/ruby-hmac-0.4.0.gem -------------------------------------------------------------------------------- /vendor/cache/safe_yaml-0.9.5.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/safe_yaml-0.9.5.gem -------------------------------------------------------------------------------- /vendor/cache/sass-3.2.10.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/sass-3.2.10.gem -------------------------------------------------------------------------------- /vendor/cache/sass-rails-3.2.6.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/sass-rails-3.2.6.gem -------------------------------------------------------------------------------- /vendor/cache/sidekiq-2.13.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/sidekiq-2.13.1.gem -------------------------------------------------------------------------------- /vendor/cache/simple_form-2.1.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/simple_form-2.1.0.gem -------------------------------------------------------------------------------- /vendor/cache/sinatra-1.4.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/sinatra-1.4.3.gem -------------------------------------------------------------------------------- /vendor/cache/sippy_cup-0.6.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/sippy_cup-0.6.0.gem -------------------------------------------------------------------------------- /vendor/cache/slim-2.0.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/slim-2.0.1.gem -------------------------------------------------------------------------------- /vendor/cache/slop-3.4.6.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/slop-3.4.6.gem -------------------------------------------------------------------------------- /vendor/cache/sprockets-2.2.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/sprockets-2.2.2.gem -------------------------------------------------------------------------------- /vendor/cache/state_machine-1.2.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/state_machine-1.2.0.gem -------------------------------------------------------------------------------- /vendor/cache/temple-0.6.6.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/temple-0.6.6.gem -------------------------------------------------------------------------------- /vendor/cache/test-unit-3.0.8.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/test-unit-3.0.8.gem -------------------------------------------------------------------------------- /vendor/cache/therubyracer-0.12.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/therubyracer-0.12.0.gem -------------------------------------------------------------------------------- /vendor/cache/thin-1.5.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/thin-1.5.1.gem -------------------------------------------------------------------------------- /vendor/cache/thor-0.19.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/thor-0.19.1.gem -------------------------------------------------------------------------------- /vendor/cache/tilt-1.4.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/tilt-1.4.1.gem -------------------------------------------------------------------------------- /vendor/cache/timecop-0.6.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/timecop-0.6.3.gem -------------------------------------------------------------------------------- /vendor/cache/timers-1.1.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/timers-1.1.0.gem -------------------------------------------------------------------------------- /vendor/cache/treetop-1.4.15.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/treetop-1.4.15.gem -------------------------------------------------------------------------------- /vendor/cache/turbo-sprockets-rails3-0.3.14.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/turbo-sprockets-rails3-0.3.14.gem -------------------------------------------------------------------------------- /vendor/cache/tzinfo-0.3.41.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/tzinfo-0.3.41.gem -------------------------------------------------------------------------------- /vendor/cache/uglifier-2.1.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/uglifier-2.1.2.gem -------------------------------------------------------------------------------- /vendor/cache/warden-1.2.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/warden-1.2.3.gem -------------------------------------------------------------------------------- /vendor/cache/webmock-1.13.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/webmock-1.13.0.gem -------------------------------------------------------------------------------- /vendor/cache/websocket-driver-0.2.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/websocket-driver-0.2.3.gem -------------------------------------------------------------------------------- /vendor/cache/xpath-2.0.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adhearsion/SIPtreadmill/e5d2234434fa5a7a89fe6ce37f0da4e976ffa80b/vendor/cache/xpath-2.0.0.gem --------------------------------------------------------------------------------