asautotest 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +674 -0
- data/README.rdoc +182 -0
- data/bin/asautotest +437 -0
- data/bin/flash-policy-server +88 -0
- data/lib/asautotest/compilation-output-parser.rb +115 -0
- data/lib/asautotest/compilation-result.rb +102 -0
- data/lib/asautotest/compilation-runner.rb +135 -0
- data/lib/asautotest/compiler-shell.rb +78 -0
- data/lib/asautotest/logging.rb +124 -0
- data/lib/asautotest/problematic-file.rb +526 -0
- data/lib/asautotest/stopwatch.rb +50 -0
- data/lib/asautotest/test-runner.rb +424 -0
- data/lib/asautotest/utilities.rb +62 -0
- metadata +78 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# flash-policy-server --- simple Flash security policy file server
|
4
|
+
# Copyright (C) 2010 Go Interactive
|
5
|
+
|
6
|
+
# This file is part of ASAutotest.
|
7
|
+
|
8
|
+
# ASAutotest is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
|
13
|
+
# ASAutotest is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with ASAutotest. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
|
21
|
+
require "socket"
|
22
|
+
require "timeout"
|
23
|
+
|
24
|
+
class PolicyServer
|
25
|
+
PORT = 843
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@server = TCPServer.new(PORT)
|
29
|
+
@server.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
|
30
|
+
|
31
|
+
info "Listening to localhost:#{PORT}."
|
32
|
+
end
|
33
|
+
|
34
|
+
def run
|
35
|
+
loop { accept }
|
36
|
+
end
|
37
|
+
|
38
|
+
def accept
|
39
|
+
handle_socket(@server.accept)
|
40
|
+
end
|
41
|
+
|
42
|
+
def info(message)
|
43
|
+
puts info_string(message)
|
44
|
+
end
|
45
|
+
|
46
|
+
def info_string(message)
|
47
|
+
"policy-server: #{message}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def begin_info(message)
|
51
|
+
STDOUT.print info_string("#{message}...")
|
52
|
+
STDOUT.flush
|
53
|
+
end
|
54
|
+
|
55
|
+
def end_info(message)
|
56
|
+
STDOUT.puts " #{message}."
|
57
|
+
end
|
58
|
+
|
59
|
+
EXPECTED_REQUEST = "<policy-file-request/>\0"
|
60
|
+
|
61
|
+
def handle_socket(socket)
|
62
|
+
source = "#{socket.peeraddr[2]}:#{socket.peeraddr[1]}"
|
63
|
+
begin_info "Serving #{source}"
|
64
|
+
request = Timeout.timeout(3) { socket.read(EXPECTED_REQUEST.size) }
|
65
|
+
if request == EXPECTED_REQUEST
|
66
|
+
socket.print(policy_xml)
|
67
|
+
socket.print("\0")
|
68
|
+
end_info "ok"
|
69
|
+
else
|
70
|
+
end_info "recieved garbage: #{request.inspect}"
|
71
|
+
end
|
72
|
+
rescue Timeout::Error
|
73
|
+
end_info "timeout"
|
74
|
+
ensure
|
75
|
+
socket.close
|
76
|
+
end
|
77
|
+
|
78
|
+
def policy_xml
|
79
|
+
<<-end_xml
|
80
|
+
<cross-domain-policy>
|
81
|
+
<site-control permitted-cross-domain-policies="master-only"/>
|
82
|
+
<allow-access-from domain="*" to-ports="*"/>
|
83
|
+
</cross-domain-policy>
|
84
|
+
end_xml
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
PolicyServer.new.run
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# compilation-output-parser.rb --- parse the output of one compilation
|
3
|
+
# Copyright (C) 2010 Go Interactive
|
4
|
+
|
5
|
+
# This file is part of ASAutotest.
|
6
|
+
|
7
|
+
# ASAutotest is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
|
12
|
+
# ASAutotest is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with ASAutotest. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
module ASAutotest
|
21
|
+
class OutputParser
|
22
|
+
def initialize(output, request, stopwatch, result)
|
23
|
+
@output = output
|
24
|
+
@request = request
|
25
|
+
@stopwatch = stopwatch
|
26
|
+
@result = result
|
27
|
+
|
28
|
+
@problematic_file_names = Set.new
|
29
|
+
@n_problems = 0
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.parse(*arguments)
|
33
|
+
new(*arguments).run
|
34
|
+
end
|
35
|
+
|
36
|
+
def run
|
37
|
+
parse_lines
|
38
|
+
add_summary
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse_lines
|
42
|
+
@result.source_directories = @request.source_directories
|
43
|
+
|
44
|
+
while has_more_lines?
|
45
|
+
line = read_line
|
46
|
+
puts ">> #{line}" if Logging.verbose?
|
47
|
+
parse_line(line)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def parse_line(line)
|
52
|
+
case line
|
53
|
+
when /^Loading configuration file /
|
54
|
+
when /^fcsh: Assigned (\d+) as the compile target id/
|
55
|
+
@request.compile_id = $1
|
56
|
+
when /^Recompile: /
|
57
|
+
when /^Reason: /
|
58
|
+
when /^\s*$/
|
59
|
+
when /\(\d+ bytes\)$/
|
60
|
+
@successful = true
|
61
|
+
when /^Nothing has changed /
|
62
|
+
@n_recompiled_files = 0
|
63
|
+
when /^Files changed: (\d+) Files affected: (\d+)/
|
64
|
+
@n_recompiled_files = $1.to_i + $2.to_i
|
65
|
+
when /^(.*?)\((\d+)\): col: (\d+) (.*)/
|
66
|
+
file_name = $1
|
67
|
+
line_number = $2.to_i
|
68
|
+
column_number = $3.to_i - 1
|
69
|
+
message = $4
|
70
|
+
source_line = read_lines(4)[1]
|
71
|
+
|
72
|
+
location = Location[line_number, column_number, source_line]
|
73
|
+
problem = Problem[message, location]
|
74
|
+
|
75
|
+
add_problem(file_name, problem)
|
76
|
+
when /^Error: (.*)/
|
77
|
+
add_problem(nil, Problem[$1, nil])
|
78
|
+
when /^(.*?): (.*)/
|
79
|
+
add_problem($1, Problem[$2, nil])
|
80
|
+
else
|
81
|
+
@result.add_unrecognized_line(line)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def add_problem(file_name, problem)
|
86
|
+
@first_problem ||= problem
|
87
|
+
@problematic_file_names << file_name
|
88
|
+
@n_problems += 1
|
89
|
+
@result.add_problem(file_name, problem)
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_summary
|
93
|
+
@result.add_summary \
|
94
|
+
:request => @request,
|
95
|
+
:successful? => @successful,
|
96
|
+
:n_recompiled_files => @n_recompiled_files,
|
97
|
+
:n_problematic_files => @problematic_file_names.size,
|
98
|
+
:n_problems => @n_problems,
|
99
|
+
:first_problem => @first_problem,
|
100
|
+
:compilation_time => @stopwatch
|
101
|
+
end
|
102
|
+
|
103
|
+
def has_more_lines?
|
104
|
+
not @output.empty?
|
105
|
+
end
|
106
|
+
|
107
|
+
def read_lines(n)
|
108
|
+
@output.shift(n).map(&:chomp)
|
109
|
+
end
|
110
|
+
|
111
|
+
def read_line
|
112
|
+
@output.shift.chomp
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# compilation-result.rb --- collect the results of a compilation
|
3
|
+
# Copyright (C) 2010 Go Interactive
|
4
|
+
|
5
|
+
# This file is part of ASAutotest.
|
6
|
+
|
7
|
+
# ASAutotest is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
|
12
|
+
# ASAutotest is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with ASAutotest. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
module ASAutotest
|
21
|
+
class CompilationResult
|
22
|
+
attr_reader :n_recompiled_files
|
23
|
+
attr_reader :problematic_files
|
24
|
+
attr_reader :unrecognized_lines
|
25
|
+
attr_reader :summaries
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@problematic_files = {}
|
29
|
+
@n_recompiled_files = nil
|
30
|
+
@unrecognized_lines = []
|
31
|
+
@summaries = []
|
32
|
+
end
|
33
|
+
|
34
|
+
# ----------------------------------------------------
|
35
|
+
|
36
|
+
def source_directories= value
|
37
|
+
@source_directories = value
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_problem(file_name, problem)
|
41
|
+
get_problematic_file(file_name) << problem unless
|
42
|
+
@typing == :dynamic and problem.type_warning?
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_problematic_file(file_name)
|
46
|
+
if @problematic_files.include? file_name
|
47
|
+
@problematic_files[file_name]
|
48
|
+
else
|
49
|
+
@problematic_files[file_name] =
|
50
|
+
ProblematicFile.new(file_name, @source_directories)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# ----------------------------------------------------
|
55
|
+
|
56
|
+
def add_unrecognized_line(line)
|
57
|
+
@unrecognized_lines << line
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_summary(summary)
|
61
|
+
@summaries << summary
|
62
|
+
end
|
63
|
+
|
64
|
+
# ----------------------------------------------------
|
65
|
+
|
66
|
+
def any_type_warnings?
|
67
|
+
@problematic_files.values.any? &:any_type_warnings?
|
68
|
+
end
|
69
|
+
|
70
|
+
def successful?
|
71
|
+
@summaries.all? { |x| x[:successful?] }
|
72
|
+
end
|
73
|
+
|
74
|
+
def n_problematic_files
|
75
|
+
@problematic_files.values.size
|
76
|
+
end
|
77
|
+
|
78
|
+
def n_problems
|
79
|
+
@problematic_files.values.inject(0) { |a, x| a + x.n_problems }
|
80
|
+
end
|
81
|
+
|
82
|
+
def failed?
|
83
|
+
not successful?
|
84
|
+
end
|
85
|
+
|
86
|
+
def bootstrap?
|
87
|
+
@summaries.all? { |x| x[:n_recompiled_files] == nil }
|
88
|
+
end
|
89
|
+
|
90
|
+
def n_recompiled_files
|
91
|
+
@summaries.inject(0) { |a, x| a + x[:n_recompiled_files] }
|
92
|
+
end
|
93
|
+
|
94
|
+
def recompilation?
|
95
|
+
not bootstrap?
|
96
|
+
end
|
97
|
+
|
98
|
+
def did_anything?
|
99
|
+
bootstrap? or n_recompiled_files > 0
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# compilation-runner.rb --- run compilations and report the results
|
3
|
+
# Copyright (C) 2010 Go Interactive
|
4
|
+
|
5
|
+
# This file is part of ASAutotest.
|
6
|
+
|
7
|
+
# ASAutotest is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
|
12
|
+
# ASAutotest is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with ASAutotest. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require "asautotest/logging"
|
21
|
+
|
22
|
+
module ASAutotest
|
23
|
+
class CompilationRunner
|
24
|
+
class CompilationFailure < Exception ; end
|
25
|
+
|
26
|
+
include Logging
|
27
|
+
|
28
|
+
attr_reader :result
|
29
|
+
|
30
|
+
def initialize(shell, options)
|
31
|
+
@shell = shell
|
32
|
+
@typing = options[:typing]
|
33
|
+
@result = CompilationResult.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def run
|
37
|
+
@stopwatch = Stopwatch.new
|
38
|
+
whisper_commands
|
39
|
+
compile
|
40
|
+
@stopwatch.stop
|
41
|
+
print_report
|
42
|
+
end
|
43
|
+
|
44
|
+
def whisper_commands
|
45
|
+
for command in @shell.compilation_commands
|
46
|
+
whisper "$ #{command}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def compile
|
51
|
+
say("Compiling") do |status|
|
52
|
+
@shell.run_compilations(@result)
|
53
|
+
|
54
|
+
if @result.failed?
|
55
|
+
status << "failed"
|
56
|
+
elsif @result.did_anything?
|
57
|
+
files = if @result.bootstrap?
|
58
|
+
"everything"
|
59
|
+
else
|
60
|
+
n_x(@result.n_recompiled_files, "file")
|
61
|
+
end
|
62
|
+
status << "recompiled #{files} in #{compilation_time}"
|
63
|
+
else
|
64
|
+
status << "nothing changed"
|
65
|
+
end
|
66
|
+
|
67
|
+
if @result.successful?
|
68
|
+
for summary in @result.summaries
|
69
|
+
title = File.basename(summary[:request].source_file_name)
|
70
|
+
if summary[:successful?] and summary[:n_recompiled_files] != 0
|
71
|
+
files = if summary[:n_recompiled_files]
|
72
|
+
n_x(summary[:n_recompiled_files], "file")
|
73
|
+
else
|
74
|
+
"everything"
|
75
|
+
end
|
76
|
+
time = "#{summary[:compilation_time].to_s(1)}s"
|
77
|
+
growl_success title, "Compiled #{files} in #{time}."
|
78
|
+
end
|
79
|
+
end
|
80
|
+
else
|
81
|
+
summary = @result.summaries.find { |x| not x[:successful?] }
|
82
|
+
file_name = summary[:first_problem].file.basename
|
83
|
+
line_number = summary[:first_problem].line_number
|
84
|
+
message = summary[:first_problem].plain_message
|
85
|
+
growl_error "#{file_name}, line #{line_number}", message
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def n_x(n, x)
|
91
|
+
"#{n} #{x}#{n == 1 ? "" : "s"}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def growl_success(title, message)
|
95
|
+
if ASAutotest::growl_enabled
|
96
|
+
options = { :title => title, :icon => "as" }
|
97
|
+
if ASAutotest::displaying_growl_error
|
98
|
+
options[:identifier] = GROWL_ERROR_TOKEN
|
99
|
+
ASAutotest::displaying_growl_error = false
|
100
|
+
end
|
101
|
+
Growl.notify(message, options)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def growl_error(title, message)
|
106
|
+
if ASAutotest::growl_enabled
|
107
|
+
Growl.notify_error message,
|
108
|
+
:title => title, :sticky => true,
|
109
|
+
:identifier => GROWL_ERROR_TOKEN
|
110
|
+
ASAutotest::displaying_growl_error = true
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def compilation_time
|
115
|
+
"~#{@stopwatch.to_s(1)} seconds"
|
116
|
+
end
|
117
|
+
|
118
|
+
def print_report
|
119
|
+
for line in @result.unrecognized_lines
|
120
|
+
barf line
|
121
|
+
end
|
122
|
+
|
123
|
+
for name, file in @result.problematic_files
|
124
|
+
file.print_report
|
125
|
+
end
|
126
|
+
|
127
|
+
puts unless @result.problematic_files.empty?
|
128
|
+
|
129
|
+
if @typing == nil and @result.any_type_warnings?
|
130
|
+
hint "Use --dynamic-typing to disable type declaration warnings,"
|
131
|
+
hint "or --static-typing to disable this hint."
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# compiler-shell.rb --- wrapper around the fcsh executable
|
3
|
+
# Copyright (C) 2010 Go Interactive
|
4
|
+
|
5
|
+
# This file is part of ASAutotest.
|
6
|
+
|
7
|
+
# ASAutotest is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
|
12
|
+
# ASAutotest is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with ASAutotest. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
module ASAutotest
|
21
|
+
class CompilerShell
|
22
|
+
PROMPT = "\n(fcsh) "
|
23
|
+
|
24
|
+
class PromptNotFound < Exception ; end
|
25
|
+
|
26
|
+
include Logging
|
27
|
+
|
28
|
+
attr_reader :compilation_requests
|
29
|
+
|
30
|
+
def initialize(options)
|
31
|
+
@compilation_requests = options[:compilation_requests]
|
32
|
+
end
|
33
|
+
|
34
|
+
def start
|
35
|
+
say "Starting compiler shell" do
|
36
|
+
@process = IO.popen("#{FCSH} 2>&1", "r+")
|
37
|
+
read_until_prompt
|
38
|
+
end
|
39
|
+
rescue PromptNotFound => error
|
40
|
+
shout "Could not find FCSH prompt:"
|
41
|
+
for line in error.message.lines do
|
42
|
+
barf line.chomp
|
43
|
+
end
|
44
|
+
if error.message.include? "command not found"
|
45
|
+
shout "Please make sure that fcsh is in your PATH."
|
46
|
+
shout "Alternatively, set the ‘FCSH’ environment variable."
|
47
|
+
end
|
48
|
+
exit -1
|
49
|
+
end
|
50
|
+
|
51
|
+
def run_compilations(result)
|
52
|
+
for request in @compilation_requests
|
53
|
+
run_compilation(request, result)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def compilation_commands
|
58
|
+
@compilation_requests.map { |x| x.compilation_command }
|
59
|
+
end
|
60
|
+
|
61
|
+
def run_compilation(request, result)
|
62
|
+
stopwatch = Stopwatch.new
|
63
|
+
@process.puts(request.compilation_command)
|
64
|
+
OutputParser.parse(read_until_prompt, request, stopwatch, result)
|
65
|
+
stopwatch.stop
|
66
|
+
end
|
67
|
+
|
68
|
+
def read_until_prompt
|
69
|
+
result = ""
|
70
|
+
until result.include? PROMPT
|
71
|
+
result << @process.readpartial(100)
|
72
|
+
end
|
73
|
+
result.lines.entries[0 .. -2]
|
74
|
+
rescue EOFError
|
75
|
+
raise PromptNotFound, result
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|