MuranoCLI 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +28 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +21 -0
  5. data/Gemfile +27 -0
  6. data/LICENSE.txt +19 -0
  7. data/MuranoCLI.gemspec +50 -0
  8. data/MuranoCLI.iss +50 -0
  9. data/README.markdown +208 -0
  10. data/Rakefile +188 -0
  11. data/TODO.taskpaper +122 -0
  12. data/bin/mr +8 -0
  13. data/bin/murano +84 -0
  14. data/docs/demo.md +109 -0
  15. data/lib/MrMurano/Account.rb +211 -0
  16. data/lib/MrMurano/Config-Migrate.rb +47 -0
  17. data/lib/MrMurano/Config.rb +286 -0
  18. data/lib/MrMurano/Mock.rb +63 -0
  19. data/lib/MrMurano/Product-1P-Device.rb +145 -0
  20. data/lib/MrMurano/Product-Resources.rb +195 -0
  21. data/lib/MrMurano/Product.rb +358 -0
  22. data/lib/MrMurano/ProjectFile.rb +349 -0
  23. data/lib/MrMurano/Solution-Cors.rb +46 -0
  24. data/lib/MrMurano/Solution-Endpoint.rb +177 -0
  25. data/lib/MrMurano/Solution-File.rb +150 -0
  26. data/lib/MrMurano/Solution-ServiceConfig.rb +140 -0
  27. data/lib/MrMurano/Solution-Services.rb +326 -0
  28. data/lib/MrMurano/Solution-Users.rb +129 -0
  29. data/lib/MrMurano/Solution.rb +59 -0
  30. data/lib/MrMurano/SubCmdGroupContext.rb +49 -0
  31. data/lib/MrMurano/SyncUpDown.rb +565 -0
  32. data/lib/MrMurano/commands/assign.rb +57 -0
  33. data/lib/MrMurano/commands/businessList.rb +45 -0
  34. data/lib/MrMurano/commands/completion.rb +152 -0
  35. data/lib/MrMurano/commands/config.rb +67 -0
  36. data/lib/MrMurano/commands/content.rb +130 -0
  37. data/lib/MrMurano/commands/cors.rb +30 -0
  38. data/lib/MrMurano/commands/domain.rb +17 -0
  39. data/lib/MrMurano/commands/gb.rb +33 -0
  40. data/lib/MrMurano/commands/init.rb +138 -0
  41. data/lib/MrMurano/commands/keystore.rb +157 -0
  42. data/lib/MrMurano/commands/logs.rb +78 -0
  43. data/lib/MrMurano/commands/mock.rb +63 -0
  44. data/lib/MrMurano/commands/password.rb +88 -0
  45. data/lib/MrMurano/commands/postgresql.rb +41 -0
  46. data/lib/MrMurano/commands/product.rb +14 -0
  47. data/lib/MrMurano/commands/productCreate.rb +39 -0
  48. data/lib/MrMurano/commands/productDelete.rb +33 -0
  49. data/lib/MrMurano/commands/productDevice.rb +84 -0
  50. data/lib/MrMurano/commands/productDeviceIdCmds.rb +86 -0
  51. data/lib/MrMurano/commands/productList.rb +45 -0
  52. data/lib/MrMurano/commands/productWrite.rb +27 -0
  53. data/lib/MrMurano/commands/show.rb +80 -0
  54. data/lib/MrMurano/commands/solution.rb +14 -0
  55. data/lib/MrMurano/commands/solutionCreate.rb +39 -0
  56. data/lib/MrMurano/commands/solutionDelete.rb +34 -0
  57. data/lib/MrMurano/commands/solutionList.rb +45 -0
  58. data/lib/MrMurano/commands/status.rb +92 -0
  59. data/lib/MrMurano/commands/sync.rb +60 -0
  60. data/lib/MrMurano/commands/timeseries.rb +115 -0
  61. data/lib/MrMurano/commands/tsdb.rb +271 -0
  62. data/lib/MrMurano/commands/usage.rb +23 -0
  63. data/lib/MrMurano/commands/zshcomplete.erb +112 -0
  64. data/lib/MrMurano/commands.rb +32 -0
  65. data/lib/MrMurano/hash.rb +20 -0
  66. data/lib/MrMurano/http.rb +153 -0
  67. data/lib/MrMurano/makePretty.rb +75 -0
  68. data/lib/MrMurano/schema/pf-v1.0.0.yaml +114 -0
  69. data/lib/MrMurano/schema/sf-v0.2.0.yaml +77 -0
  70. data/lib/MrMurano/schema/sf-v0.3.0.yaml +78 -0
  71. data/lib/MrMurano/template/mock.erb +9 -0
  72. data/lib/MrMurano/template/projectFile.murano.erb +81 -0
  73. data/lib/MrMurano/verbosing.rb +99 -0
  74. data/lib/MrMurano/version.rb +4 -0
  75. data/lib/MrMurano.rb +20 -0
  76. data/spec/Account-Passwords_spec.rb +242 -0
  77. data/spec/Account_spec.rb +272 -0
  78. data/spec/ConfigFile_spec.rb +50 -0
  79. data/spec/ConfigMigrate_spec.rb +89 -0
  80. data/spec/Config_spec.rb +409 -0
  81. data/spec/Http_spec.rb +204 -0
  82. data/spec/MakePretties_spec.rb +118 -0
  83. data/spec/Mock_spec.rb +53 -0
  84. data/spec/ProductBase_spec.rb +113 -0
  85. data/spec/ProductContent_spec.rb +162 -0
  86. data/spec/ProductResources_spec.rb +329 -0
  87. data/spec/Product_1P_Device_spec.rb +202 -0
  88. data/spec/Product_1P_RPC_spec.rb +175 -0
  89. data/spec/Product_spec.rb +153 -0
  90. data/spec/ProjectFile_spec.rb +324 -0
  91. data/spec/Solution-Cors_spec.rb +164 -0
  92. data/spec/Solution-Endpoint_spec.rb +581 -0
  93. data/spec/Solution-File_spec.rb +212 -0
  94. data/spec/Solution-ServiceConfig_spec.rb +202 -0
  95. data/spec/Solution-ServiceDevice_spec.rb +176 -0
  96. data/spec/Solution-ServiceEventHandler_spec.rb +385 -0
  97. data/spec/Solution-ServiceModules_spec.rb +465 -0
  98. data/spec/Solution-UsersRoles_spec.rb +207 -0
  99. data/spec/Solution_spec.rb +92 -0
  100. data/spec/SyncRoot_spec.rb +83 -0
  101. data/spec/SyncUpDown_spec.rb +495 -0
  102. data/spec/Verbosing_spec.rb +279 -0
  103. data/spec/_workspace.rb +27 -0
  104. data/spec/cmd_assign_spec.rb +51 -0
  105. data/spec/cmd_business_spec.rb +59 -0
  106. data/spec/cmd_common.rb +72 -0
  107. data/spec/cmd_config_spec.rb +68 -0
  108. data/spec/cmd_content_spec.rb +71 -0
  109. data/spec/cmd_cors_spec.rb +50 -0
  110. data/spec/cmd_device_spec.rb +96 -0
  111. data/spec/cmd_domain_spec.rb +32 -0
  112. data/spec/cmd_init_spec.rb +30 -0
  113. data/spec/cmd_keystore_spec.rb +97 -0
  114. data/spec/cmd_password_spec.rb +62 -0
  115. data/spec/cmd_status_spec.rb +239 -0
  116. data/spec/cmd_syncdown_spec.rb +86 -0
  117. data/spec/cmd_syncup_spec.rb +62 -0
  118. data/spec/cmd_usage_spec.rb +36 -0
  119. data/spec/fixtures/.mrmuranorc +9 -0
  120. data/spec/fixtures/ProjectFiles/invalid.yaml +9 -0
  121. data/spec/fixtures/ProjectFiles/only_meta.yaml +24 -0
  122. data/spec/fixtures/ProjectFiles/with_routes.yaml +27 -0
  123. data/spec/fixtures/SolutionFiles/0.2.0.json +20 -0
  124. data/spec/fixtures/SolutionFiles/0.2.0_invalid.json +18 -0
  125. data/spec/fixtures/SolutionFiles/0.2.json +21 -0
  126. data/spec/fixtures/SolutionFiles/0.3.0.json +20 -0
  127. data/spec/fixtures/SolutionFiles/0.3.0_invalid.json +19 -0
  128. data/spec/fixtures/SolutionFiles/0.3.json +20 -0
  129. data/spec/fixtures/SolutionFiles/basic.json +20 -0
  130. data/spec/fixtures/SolutionFiles/secret.json +6 -0
  131. data/spec/fixtures/configfile +9 -0
  132. data/spec/fixtures/dumped_config +42 -0
  133. data/spec/fixtures/mrmuranorc_deleted_bob +8 -0
  134. data/spec/fixtures/mrmuranorc_tool_bob +3 -0
  135. data/spec/fixtures/product_spec_files/example.exoline.spec.yaml +116 -0
  136. data/spec/fixtures/product_spec_files/example.murano.spec.yaml +14 -0
  137. data/spec/fixtures/product_spec_files/gwe.exoline.spec.yaml +21 -0
  138. data/spec/fixtures/product_spec_files/gwe.murano.spec.yaml +16 -0
  139. data/spec/fixtures/product_spec_files/lightbulb-no-state.yaml +11 -0
  140. data/spec/fixtures/product_spec_files/lightbulb.yaml +14 -0
  141. data/spec/fixtures/roles-three.yaml +11 -0
  142. data/spec/fixtures/syncable_content/assets/icon.png +0 -0
  143. data/spec/fixtures/syncable_content/assets/index.html +0 -0
  144. data/spec/fixtures/syncable_content/assets/js/script.js +0 -0
  145. data/spec/fixtures/syncable_content/modules/table_util.lua +58 -0
  146. data/spec/fixtures/syncable_content/routes/manyRoutes.lua +11 -0
  147. data/spec/fixtures/syncable_content/routes/singleRoute.lua +5 -0
  148. data/spec/fixtures/syncable_content/services/devdata.lua +18 -0
  149. data/spec/fixtures/syncable_content/services/timers.lua +4 -0
  150. data/spec/spec_helper.rb +119 -0
  151. metadata +498 -0
@@ -0,0 +1,78 @@
1
+ ---
2
+ type: object
3
+ description: |
4
+ A Solutionfile.json
5
+ This describes all of the bits and bobs that go into a Murano Solution.
6
+
7
+ properties:
8
+ version:
9
+ type: string
10
+ pattern: "0\\.3(\\.0)?"
11
+ description: Version format of the config
12
+
13
+ default_page:
14
+ type: string
15
+ description: The local file name to upload as /
16
+
17
+ assets:
18
+ type: string
19
+ description: Relative path to directory of static assets
20
+
21
+ routes:
22
+ type: string
23
+ description: Relative path of file containing endpoints (or routes)
24
+
25
+ routes_hook:
26
+ type: string
27
+ description: URL path to call at end of deploy
28
+
29
+ modules:
30
+ type: object
31
+ description: Additional lua chunks to load with endpoints and event handlers
32
+ patternProperties:
33
+ "[a-z]+":
34
+ type: string
35
+ description: Relative path to module script
36
+
37
+ services:
38
+ type: object
39
+ description: Event handler scripts
40
+ properties:
41
+ device:
42
+ type: object
43
+ description: Device (Product) event handlers
44
+ properties:
45
+ datapoint:
46
+ type: string
47
+ description: Relative path to device.datapoint event script
48
+ required: [datapoint]
49
+ timer:
50
+ type: object
51
+ description: Timer event handlers
52
+ properties:
53
+ timer:
54
+ type: string
55
+ description: Relative path to timer.timer event script
56
+ required: [timer]
57
+ additionalProperties: false
58
+
59
+ cors:
60
+ type: object
61
+ properties:
62
+ origin:
63
+ type: array
64
+ methods:
65
+ type: array
66
+ headers:
67
+ type: array
68
+ credentials:
69
+ type: boolean
70
+
71
+ required:
72
+ - default_page
73
+ - assets
74
+ - routes
75
+ - services
76
+ - version
77
+ additionalProperties: false
78
+
@@ -0,0 +1,9 @@
1
+ --#ENDPOINT POST /testpoint/{service}/{call}
2
+ -- this function allows remote calls to your services
3
+ if request.headers["authorization"] == "<%= uuid %>" then
4
+ local fn = _G[request.parameters.service][request.parameters.call]
5
+ response.message = fn(request.body)
6
+ else
7
+ response.code = 401
8
+ response.message = "invalid authorization header"
9
+ end
@@ -0,0 +1,81 @@
1
+ ---
2
+ # First up is some metadata about this project.
3
+ info:
4
+ # Nice short and easy. Also must be a valid domain name component.
5
+ name: <%= info.name %>
6
+
7
+ # Short one line summary of this project.
8
+ summary: <%= info.summary %>
9
+
10
+ # Longer, multiple paragraph explanation.
11
+ description: |
12
+ <%= info.description.gsub(/^/m, ' ') %>
13
+
14
+ # Who made this
15
+ authors: <%= info.authors.to_json %>
16
+
17
+ # The version of the Project
18
+ version: <%= info.version %>
19
+
20
+
21
+ ####
22
+ #
23
+ # The sections routes, assets, modules, and services are all optional.
24
+ #
25
+ # They all have defaults values that should work for a majority of the projects out
26
+ # there. But they are all fully configurable to fit the way you want your project
27
+ # to be.
28
+ #
29
+ # Examples follow.
30
+ #
31
+ #
32
+ #routes:
33
+ # #Start off with the directory name we want to keep everything in.
34
+ # location: routes
35
+ #
36
+ # #Then use globs to find all of the files that can contain route code.
37
+ # #If using single glob, then can be just the string.
38
+ # include: ['{,../endpoints}/*.lua', '{,../endpoints}/*/*.lua']
39
+ # #include: '**/*.lua'
40
+ #
41
+ # #Then remove all that match these globs. Again, if a single, can drop the array.
42
+ # #If not excluding, use empty array [], or empty node.
43
+ # exclude: ['*_test.lua', '*_spec.lua', '**/.*']
44
+ #
45
+ # #That leaves a list of files with API routes in them. Each Route file can
46
+ # #contain one or more actual routes that are synced with Murano.
47
+ #
48
+ #
49
+ # #If you are hosting your website somewhere other than on Murano, and you want to
50
+ # #tighten up what Cross Origin calls are allowed, you can set that here.
51
+ #
52
+ # #Either point to a YAML file
53
+ # cors: "cors.yaml"
54
+ # #Or include it directly
55
+ # cors: {"origin":true,"methods":["HEAD","GET","POST","PUT","DELETE","OPTIONS","PATCH"],"headers":["Content-Type","Cookie","Authorization"],"credentials":true}
56
+ #
57
+ #assets:
58
+ # location: assets
59
+ # include: '**/*'
60
+ # exclude:
61
+ # default_page: index.html
62
+ #
63
+ #modules:
64
+ # location: modules
65
+ # include: ['*.lua', '*/*.lua']
66
+ # exclude: ['*_test.lua', '*_spec.lua', '**/.*']
67
+ #
68
+ #services:
69
+ # location: services
70
+ # include:
71
+ # - '*.lua'
72
+ # - '*/*.lua'
73
+ # - '{../eventhandlers,../event_handler}/*.lua'
74
+ # - '{../eventhandlers,../event_handler}/*/*.lua'
75
+ # exclude: ['*_test.lua', '*_spec.lua', '**/.*']
76
+
77
+
78
+ # The format version of this file. This is required.
79
+ formatversion: 1.0.0
80
+
81
+ # vim: set et sw=2 ts=2 :
@@ -0,0 +1,99 @@
1
+ require 'highline'
2
+ require 'yaml'
3
+ require 'json'
4
+ require 'pp'
5
+ require 'csv'
6
+ require 'terminal-table'
7
+
8
+ module MrMurano
9
+ module Verbose
10
+ def verbose(msg)
11
+ if $cfg['tool.verbose'] then
12
+ say msg
13
+ end
14
+ end
15
+
16
+ def debug(msg)
17
+ if $cfg['tool.debug'] then
18
+ say msg
19
+ end
20
+ end
21
+
22
+ def warning(msg)
23
+ $stderr.puts HighLine.color(msg, :yellow)
24
+ end
25
+
26
+ def error(msg)
27
+ $stderr.puts HighLine.color(msg, :red)
28
+ end
29
+
30
+ ## Output tabular data
31
+ # +data+:: Data to write. Preferably a Hash with :headers and :rows
32
+ # +ios+:: Output stream to write to, if nil, then use $stdout
33
+ # Output is either a nice visual table or CSV.
34
+ def tabularize(data, ios=nil)
35
+ fmt = $cfg['tool.outformat']
36
+ ios = $stdout if ios.nil?
37
+ cols = nil
38
+ rows = nil
39
+ title = nil
40
+ if data.kind_of?(Hash) then
41
+ cols = data[:headers] if data.has_key?(:headers)
42
+ rows = data[:rows] if data.has_key?(:rows)
43
+ title = data[:title]
44
+ elsif data.kind_of?(Array) then
45
+ rows = data
46
+ elsif data.respond_to?(:to_a) then
47
+ rows = data.to_a
48
+ elsif data.respond_to?(:each) then
49
+ rows = []
50
+ data.each{|i| rows << i}
51
+ else
52
+ error "Don't know how to tabularize data."
53
+ return
54
+ end
55
+ if fmt =~ /csv/i then
56
+ cols = [] if cols.nil?
57
+ rows = [[]] if rows.nil?
58
+ CSV(ios, :headers=>cols, :write_headers=>(not cols.empty?)) do |csv|
59
+ rows.each{|v| csv << v}
60
+ end
61
+ else
62
+ # table.
63
+ table = Terminal::Table.new
64
+ table.title = title unless title.nil?
65
+ table.headings = cols unless cols.nil?
66
+ table.rows = rows unless rows.nil?
67
+ ios.puts table
68
+ end
69
+ end
70
+
71
+ ## Format and print the object
72
+ # Handles many of the raw 'unpolished' formats.
73
+ def outf(obj, ios=nil, &block)
74
+ fmt = $cfg['tool.outformat']
75
+ ios = $stdout if ios.nil?
76
+ case fmt
77
+ when /yaml/i
78
+ ios.puts Hash.transform_keys_to_strings(obj).to_yaml
79
+ when /pp/
80
+ pp obj
81
+ when /json/i
82
+ ios.puts obj.to_json
83
+ else # aka best.
84
+ # sometime ‘best’ is only know by the caller, so block.
85
+ if block_given? then
86
+ yield obj, ios
87
+ else
88
+ if obj.kind_of?(Array) then
89
+ obj.each {|i| ios.puts i.to_s}
90
+ else
91
+ ios.puts obj.to_s
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ end
98
+ end
99
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,4 @@
1
+ module MrMurano
2
+ VERSION = '2.0.0'.freeze
3
+ end
4
+
data/lib/MrMurano.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'MrMurano/version'
2
+ require 'MrMurano/verbosing'
3
+ require 'MrMurano/hash'
4
+ require 'MrMurano/http'
5
+
6
+ require 'MrMurano/Config'
7
+ require 'MrMurano/ProjectFile'
8
+
9
+ require 'MrMurano/Account'
10
+ require 'MrMurano/Solution'
11
+ require 'MrMurano/Solution-Endpoint'
12
+ require 'MrMurano/Solution-File'
13
+ require 'MrMurano/Solution-Services'
14
+ require 'MrMurano/Solution-Users'
15
+ require 'MrMurano/Solution-ServiceConfig'
16
+ require 'MrMurano/Product'
17
+ require 'MrMurano/Product-1P-Device'
18
+ require 'MrMurano/Product-Resources'
19
+
20
+ require 'MrMurano/commands'
@@ -0,0 +1,242 @@
1
+ require 'MrMurano/version'
2
+ require 'MrMurano/Account'
3
+ require 'tempfile'
4
+
5
+ RSpec.describe MrMurano::Passwords, "#pwd" do
6
+ before(:example) do
7
+ @saved_pwd = ENV['MURANO_PASSWORD']
8
+ ENV['MURANO_PASSWORD'] = nil
9
+ end
10
+ after(:example) do
11
+ ENV['MURANO_PASSWORD'] = @saved_pwd
12
+ end
13
+
14
+ it "Creates a file " do
15
+ tmpfile = Dir.tmpdir + '/pwtest' # This way because Tempfile.new creates.
16
+ begin
17
+ pwd = MrMurano::Passwords.new( tmpfile )
18
+ pwd.save
19
+
20
+ expect( FileTest.exist?(tmpfile) )
21
+ ensure
22
+ File.unlink(tmpfile) if File.exist? tmpfile
23
+ end
24
+ end
25
+
26
+ it "Creates a file in a directory that doesn't exist." do
27
+ tmpfile = Dir.tmpdir + '/deeper/pwtest' # This way because Tempfile.new creates.
28
+ begin
29
+ pwd = MrMurano::Passwords.new( tmpfile )
30
+ pwd.save
31
+
32
+ expect( FileTest.exist?(tmpfile) )
33
+ ensure
34
+ File.unlink(tmpfile) if File.exist? tmpfile
35
+ end
36
+ end
37
+
38
+ it "Loads a file" do
39
+ Tempfile.open('test') do |tf|
40
+ tf << %{---
41
+ this.is.a.host:
42
+ user: password
43
+ }
44
+ tf.close
45
+
46
+ pwd = MrMurano::Passwords.new( tf.path )
47
+ pwd.load
48
+ ps = pwd.get('this.is.a.host', 'user')
49
+ expect(ps).to eq('password')
50
+ end
51
+ end
52
+
53
+ it "Saves a file" do
54
+ Tempfile.open('pstest') do |tf|
55
+ tf.close
56
+
57
+ pwd = MrMurano::Passwords.new(tf.path)
58
+ pwd.set('this.is.a.host', 'user3', 'passwords4')
59
+ pwd.save
60
+
61
+ File.open(tf.path) do |io|
62
+ data = io.read
63
+ expect(data).to eq(%{---
64
+ this.is.a.host:
65
+ user3: passwords4
66
+ })
67
+ end
68
+ end
69
+ end
70
+
71
+ it "Writes multiple hosts" do
72
+ Tempfile.open('pwtest') do |tf|
73
+ tf.close
74
+
75
+ pwd = MrMurano::Passwords.new(tf.path)
76
+ pwd.set('this.is.a.host', 'user3', 'passwords4')
77
+ pwd.save
78
+ pwd = nil
79
+
80
+ pwd = MrMurano::Passwords.new(tf.path)
81
+ pwd.load
82
+ ps = pwd.get('this.is.a.host', 'user3')
83
+ expect(ps).to eq('passwords4')
84
+ pwd = nil
85
+
86
+ pwd = MrMurano::Passwords.new(tf.path)
87
+ pwd.load
88
+ pwd.set('another.host', 'user9', 'passwords2')
89
+ pwd.save
90
+ pwd = nil
91
+
92
+ pwd = MrMurano::Passwords.new(tf.path)
93
+ pwd.load
94
+ ps = pwd.get('this.is.a.host', 'user3')
95
+ expect(ps).to eq('passwords4')
96
+ ps = pwd.get('another.host', 'user9')
97
+ expect(ps).to eq('passwords2')
98
+ pwd = nil
99
+
100
+ end
101
+ end
102
+
103
+ it "Write multiple users to same host" do
104
+ Tempfile.open('pwstest') do |tf|
105
+ tf.close
106
+
107
+ pwd = MrMurano::Passwords.new(tf.path)
108
+ pwd.set('this.is.a.host', 'user3', 'passwords4')
109
+ pwd.save
110
+ pwd = nil
111
+
112
+ pwd = MrMurano::Passwords.new(tf.path)
113
+ pwd.load
114
+ pwd.set('this.is.a.host', 'user9', 'passwords2')
115
+ pwd.save
116
+ pwd = nil
117
+
118
+ pwd = MrMurano::Passwords.new(tf.path)
119
+ pwd.load
120
+ ps = pwd.get('this.is.a.host', 'user3')
121
+ expect(ps).to eq('passwords4')
122
+ ps = pwd.get('this.is.a.host', 'user9')
123
+ expect(ps).to eq('passwords2')
124
+ pwd = nil
125
+
126
+ end
127
+ end
128
+
129
+ it "lists usernames" do
130
+ Tempfile.open('pwstest') do |tf|
131
+ tf.close
132
+
133
+ pwd = MrMurano::Passwords.new(tf.path)
134
+ pwd.set('this.is.a.host', 'user3', 'passwords4')
135
+ pwd.save
136
+ pwd = nil
137
+
138
+ pwd = MrMurano::Passwords.new(tf.path)
139
+ pwd.load
140
+ pwd.set('this.is.a.host', 'user9', 'passwords2')
141
+ pwd.save
142
+ pwd = nil
143
+
144
+ pwd = MrMurano::Passwords.new(tf.path)
145
+ pwd.load
146
+ ret = pwd.list
147
+ expect(ret).to match({
148
+ "this.is.a.host"=>a_collection_containing_exactly("user9", "user3")
149
+ })
150
+ end
151
+ end
152
+
153
+
154
+ it "removes username" do
155
+ Tempfile.open('pwstest') do |tf|
156
+ tf.close
157
+
158
+ pwd = MrMurano::Passwords.new(tf.path)
159
+ pwd.set('this.is.a.host', 'user3', 'passwords4')
160
+ pwd.save
161
+ pwd = nil
162
+
163
+ pwd = MrMurano::Passwords.new(tf.path)
164
+ pwd.load
165
+ pwd.set('this.is.a.host', 'user9', 'passwords2')
166
+ pwd.save
167
+ pwd = nil
168
+
169
+ pwd = MrMurano::Passwords.new(tf.path)
170
+ pwd.load
171
+ pwd.remove('this.is.a.host', 'user3')
172
+ pwd.save
173
+ pwd = nil
174
+
175
+ pwd = MrMurano::Passwords.new(tf.path)
176
+ pwd.load
177
+ ret = pwd.list
178
+ expect(ret).to match({ "this.is.a.host"=>["user9"] })
179
+ end
180
+ end
181
+
182
+ context "Uses ENV" do
183
+ before(:example) do
184
+ ENV['MR_PASSWORD'] = nil
185
+ end
186
+ after(:example) do
187
+ ENV['MR_PASSWORD'] = nil
188
+ end
189
+
190
+ it "Uses ENV instead" do
191
+ Tempfile.open('test') do |tf|
192
+ tf << %{---
193
+ this.is.a.host:
194
+ user: password
195
+ }
196
+ tf.close
197
+
198
+ ENV['MURANO_PASSWORD'] = 'a test!'
199
+ pwd = MrMurano::Passwords.new( tf.path )
200
+ pwd.load
201
+ expect(pwd).not_to receive(:warning)
202
+ ps = pwd.get('this.is.a.host', 'user')
203
+ expect(ps).to eq('a test!')
204
+ ENV['MURANO_PASSWORD'] = nil
205
+ end
206
+ end
207
+
208
+ it "Uses ENV instead, even with empty file" do
209
+ Tempfile.open('test') do |tf|
210
+ tf.close
211
+
212
+ ENV['MURANO_PASSWORD'] = 'a test!'
213
+ pwd = MrMurano::Passwords.new( tf.path )
214
+ pwd.load
215
+ expect(pwd).not_to receive(:warning)
216
+ ps = pwd.get('this.is.a.host', 'user')
217
+ expect(ps).to eq('a test!')
218
+ ENV['MURANO_PASSWORD'] = nil
219
+
220
+ data = IO.read(tf.path)
221
+ expect(data).to eq('')
222
+ end
223
+ end
224
+
225
+ it "Warns about migrating" do
226
+ Tempfile.open('test') do |tf|
227
+ tf.close
228
+
229
+ ENV['MR_PASSWORD'] = 'a test!'
230
+ pwd = MrMurano::Passwords.new( tf.path )
231
+ pwd.load
232
+ expect(pwd).to receive(:warning).once
233
+ ps = pwd.get('this.is.a.host', 'user')
234
+ expect(ps).to eq('a test!')
235
+ end
236
+ end
237
+ end
238
+
239
+
240
+ end
241
+
242
+ # vim: set ai et sw=2 ts=2 :