Wednesday, 22 February 2017
Suddenly
Follow me on https://dracoater.github.io
Saturday, 14 December 2013
Testing Chef Cookbooks. Part 2.5. Speeding Up ChefSpec Run
Last time we were speaking about testing Chef recipes, I introduced to you ChefSpec as a very good tool for running unit tests on your cookbooks. But lately I encountered a problem with it. I have over 800 unit tests (aka examples in RSpec world) and now it takes about 20 minutes to run. 20 minutes!!! That's a extremely long time for this kind of task. So I decided to delve, what exactly is responsible for taking so much time.
My examples look like that (many recipes have similar example groups for windows and mac_os_x):
describe "example::default" do
context 'ubuntu' do
subject { ChefSpec::ChefRunner.new( :platform => 'ubuntu', :version => '12.04' ).converge described_recipe }
let( :node ) { subject.node }
it { should do_something }
it 'does some other thing' do
should do_another_thing
end
it { should do_much_more }
end
endI put some printouts inside describe, context, subject and let blocks, as well as read RSpec documentation about let and subject. Turned out, that subject and let blocks are called for every test, i.e. they are cached when accessed inside 1 test (it block), but not across tests inside test group (in our case ubuntu context). So for these tests subject is actually calculated 3 times. That is not a problem for ordinary RSpec tests, where subject most of the time is an object returned by constructor, e.g.
User.new. But in ChefSpec case we have a converge operation as Subject under Test (SuT), which is more costly and takes more time to calculate. Another difference is that, opposing to ordinary RSpec tests we do not change the SuT in ChefSpec, but just make sure that it has right resources with right actions. So running converge for every example is a huge overhead.How can we fix that? Well, obviously we should somehow save the value across the examples. I tried different approaches, some of them worked partially, some didn't at all. The simplest thing was to use before :all block.
describe "example::default" do
context 'ubuntu' do
before :all { @chef_run = ChefSpec::ChefRunner.new( :platform => 'ubuntu', :version => '12.04' ).converge described_recipe }
subject { @chef_run }
[...]
end
endIt does not require any more than small change in spec files, but the drawback of this approach is no mocking is supported in before :all block. So if you have to mock for example file existence, it would not work:
describe "example::default" do
context 'ubuntu' do
before :all do
::File.stub( :exists? ).with( '/some/path/' ).and_return false
@chef_run = ChefSpec::ChefRunner.new( :platform => 'ubuntu', :version => '12.04' ).converge described_recipe
end
subject { @chef_run }
[...]
end
endRSpec allows to extend modules with your own methods and the idea was to write method similar to let, but which will cache the results across examples too. Create a spec_helper.rb file somewhere in your Chef project and add the following lines there:
module SpecHelper
@@cache = {}
FINALIZER = lambda {|id| @@cache.delete id }
def shared( name, &block )
location = ancestors.first.metadata[:example_group][:location]
define_method( name ) do
unless @@cache.has_key? Thread.current.object_id
ObjectSpace.define_finalizer Thread.current, FINALIZER
end
@@cache[Thread.current.object_id] ||= {}
@@cache[Thread.current.object_id][location + name.to_s] ||= instance_eval( &block )
end
end
def shared!( name, &block )
shared name, &block
before { __send__ name }
end
end
RSpec.configure do |config|
config.extend SpecHelper
endValues from @@cache are never deleted, and you can use same names with this block, so I also use location of the usage, which looks like that: "./cookbooks/my_cookbook/spec/default_spec.rb:3". Now change subject into shared( :subject ) in your specs:
describe "example::default" do
context 'ubuntu' do
shared( :subject ) { ChefSpec::ChefRunner.new( :platform => 'ubuntu', :version => '12.04' ).converge described_recipe }
[...]
end
endAnd when running the tests you will now have to include the spec_helper.rb too:
rspec --include ./relative/path/spec_helper.rb cookbooks/*/spec/*_spec.rbIf you use the rake task I introduced in previous post, add the following line to it.
desc 'Runs specs with chefspec.'
RSpec::Core::RakeTask.new :spec, [:cookbook, :recipe, :output_file] do |t, args|
[...]
t.rspec_opts += ' --require ./relative/path/spec_helper.rb'
[...]
endAnd that's all! Now tests run in 2 minutes. 10 times faster!
Wednesday, 2 October 2013
Extracting Files From tar.gz With Ruby
././@LongLink. Shortly speaking, if you stumble upon an entry in tar archive which path equals to above mentioned ././@LongLink, that means that the following entry path is longer than 100 chars and is truncated. The full path of the following entry is actually the value of the current entry. So when extracting files from tar we also must have in mind this possibility.require 'rubygems/package'
require 'zlib'
TAR_LONGLINK = '././@LongLink'
tar_gz_archive = '/path/to/archive.tar.gz'
destination = '/where/extract/to'
Gem::Package::TarReader.new( Zlib::GzipReader.open tar_gz_archive ) do |tar|
dest = nil
tar.each do |entry|
if entry.full_name == TAR_LONGLINK
dest = File.join destination, entry.read.strip
next
end
dest ||= File.join destination, entry.full_name
if entry.directory?
FileUtils.rm_rf dest unless File.directory? dest
FileUtils.mkdir_p dest, :mode => entry.header.mode, :verbose => false
elsif entry.file?
FileUtils.rm_rf dest unless File.file? dest
File.open dest, "wb" do |f|
f.print entry.read
end
FileUtils.chmod entry.header.mode, dest, :verbose => false
elsif entry.header.typeflag == '2' #Symlink!
File.symlink entry.header.linkname, dest
end
dest = nil
end
endMonday, 23 September 2013
Testing Chef Cookbooks. Part 2. Chefspec.
Ruby has already a great spec library useful for unit testing every kind of project - it's called rspec. Many specialized unit test libraries are based on it and so is chefspec - the gem to write unit tests for your cookbooks.
Chefspec makes it easy to write unit tests for Chef recipes, get feedback fast on changes in cookbooks. So first let's install it.
sudo gem install rake chefspec --no-ri --no-rdocThis will also add
create_specs command to knife, which creates specs for particular existing cookbook:knife cookbook create_specs my_cookbookAfter this you will get a separate
*_spec.rb file in my_cookbook/specs/ for every recipe file. Chefspec readme has very good examples teaching how to write tests. A couple of things I personally do different is I use subject and should instead of let(:chef_run) and expect(chef_run).to, because it allows to omit subject in some cases: (Read why RSpec developers actually recommend using expect_to syntax)#Chefspec recommendations
describe "example::default" do
let( :chef_run ){ ChefSpec::ChefRunner.new.converge described_recipe }
it { expect(chef_run).to do_something }
it 'does some other thing' do
expect(chef_run).to do_another_thing
end
end
#My typical specs
describe "example::default" do
subject { ChefSpec::ChefRunner.new.converge described_recipe }
it { should do_something }
it 'does some other thing' do
should do_another_thing
end
endWe can also integrate it with Jenkins by making rspec output results in JUnit xml format that Jenkins understands. We need another gem for that:
sudo gem install rake rspec_junit_formatter --no-ri --no-rdocNow we can run rspec with the following parameters and it will output test results into test-results.xml: rspec my_cookbook --format RspecJunitFormatter --out test-results.xmlRspec also supports rake, so it may be more convenient to use it to run specs on your cookbooks: desc 'Runs specs with chefspec.'
RSpec::Core::RakeTask.new :spec, [:cookbook, :recipe, :output_file] do |t, args|
args.with_defaults( :cookbook => '*', :recipe => '*', :output_file => nil )
t.verbose = false
t.fail_on_error = false
t.rspec_opts = args.output_file.nil? ? '--format d' : "--format RspecJunitFormatter --out #{args.output_file}"
t.ruby_opts = '-W0' #it supports ruby options too
t.pattern = "cookbooks/#{args.cookbook}/spec/#{args.recipe}_spec.rb"
endTuesday, 17 September 2013
Testing Chef Cookbooks. Part 1. Foodcritic.
A couple of years ago we have adopted automating our server configuration through chef recipes. In the beginning we didn't have many cookbooks and all the recipes were more or less simple. But as time passed new applications had to be installed and configured, including some not so simple scenarios. Turned out that "hit and miss" method wasn't too good. We came across a lot of errors, such as:
- typo: simple as that. Although knife makes a syntax check on uploading cookbooks to server, but many times it was a wrong path or something like that, which could be revealed only after we tried to provision a node.
- missed dependencies: we ran our scripts on ec2 instances, and to save time on bootstrapping the new instance, we didn't do it every time we changed something in our scripts, but only the first time. When we finally got the recipe working on this node, sometimes it turned out that the recipe will not be working on another clean node, because we forgot some dependencies, that were somehow already installed on our test node.
- interfering applications: some recipes were used for configuring several applications. Although they were very similar, they were not identical, and sometimes changing the recipe for installing one application broke installation of the other one.
At last we came to the idea, that infrastructure code as any other code should be tested. Currently we have built a pipeline using Jenkins that first runs syntax check, then coding conventions tests, then unit tests and finally integration tests on cookbooks. And only if all the tests are passing, Jenkins runs
knife cookbook upload, publishing the cookbooks on chef-server.In my following posts I will share with you how we established this testing architecture for our chef recipes. There will 3 parts in the tutorial, we will start from the easiest checks that only make sure that your ruby code can be parsed and follows some code conventions.
First of all make sure you are running ruby 1.9.2 or newer. (We use Ubuntu on our linux servers, so all the code I provide is tested in Ubuntu 12.04 LTS.)
sudo aptitude install ruby1.9.3Now we need rake for building our project and foodcritic for testing.sudo gem install rake foodcritic --no-ri --no-rdocChef cookbook repository has a Rakefile in it. Now when we have rake installed, we can try and run rake inside the folder Rakefile is in.rakeThis should run syntax check on your recipes, templates and files inside cookbooks. Next we can try to run foodcritic tests on your cookbooks. Typefoodcritic cookbooksand hit enter (assuming that "cookbooks" is the folder your cookbooks are in). If it founds some warnings, it will print them out, otherwise an empty string will be printed.Of course you may not agree with some of the rules and would like to ignore them. This could be achieved by providing additional options to
foodcritic command. You can also write your own rules and add them into checks. For example, there was a FC001 rule, which stated "Use strings in preference to symbols to access node attributes". I actually preferred vice versa using symbols to strings. So I created a new rule:rule "JT001", "Use symbols in preference to strings to access node attributes" do
tags %w{style attributes jt}
recipe do |ast|
attribute_access( ast, :type => :string )
end
end
and saved it into foodcritic-rules.rb file. Then it was easy to disable the existing FC001 rule and enable mine with:foodcritic cookbooks --include foodcritic-rules.rb --tags ~FC001There are also some 3rd party rules available, so you have something to start with.Now we will join rake and foodcritic together by creating a rake task that runs foodcritic tests. Add a new rake task similar to:
desc "Runs foodcritic linter"
task :foodcritic do
if Gem::Version.new("1.9.2") <= Gem::Version.new(RUBY_VERSION.dup)
sh "foodcritic cookbooks --epic-fail correctness"
else
puts "WARN: foodcritic run is skipped as Ruby #{RUBY_VERSION} is < 1.9.2."
end
end
task :default => 'foodcritic'Now when you run rake it should run both syntax and code conventions tests.Next post will be about unit tests using chefspec.
Monday, 8 April 2013
Wednesday, 3 April 2013
Jenkins Plugins. Again.
Monday, 10 September 2012
How to Run Dynamic Cloud Tests with 800 Tomcats, Amazon EC2, Jenkins and LiveRebel
I was brainstorming in the shower the other day, and I thought "Eureka!" - I need to bootstrap and test my Java app on a dynamic cluster with 800 Tomcat servers right now! Then, breakfast.
Obviously, every now and then you need to build a dynamic cluster of 800 Tomcat machines and then run some tests. Oh, wait, you don’t? Well, lets say you do. Provisioning your machines on the cloud for testing is a great way to "exercise" your app and work on:
- Warming up: Bootstrap a clean slate, install the software, run your tests
- Checking your Processes: Smoke testing for deploying the app to production
- Ensuring success: Checking load handling before launching the application to real clientelle
- Leaving nothing behind: After you've got all green lights, shut it all down and watch it disappear
At ZeroTurnaround, we need this for testing LiveRebel with larger deployments. LiveRebel is a tool to manage JEE production and QA deployments and online updates. It is crucial that we support large clusters of machines. Testing such environments is not an easy task but luckily in 2012 it is not about buying 800 machines but only provisioning them in the cloud for some limited time. In this article I will walk you through setting up a dynamic Tomcat cluster and running some simple tests on them. (Quick note: When I started writing this article, we had only tested this out with 100 Tomcat machines, but since then we grew to be able to support 800 instances with LiveRebel and the other tools).
Technical Requirements
Let me define a bunch of non-functional requirements that I've thought up. The end result should have 800 Tomcat nodes, each configured with LiveRebel. A load balancer should sit in front of the nodes and provide a single URL for tests, and we'll use the LiveRebel Command Center to manage our deployments.Naturally, this is all easier said than done. The hurdles that we will need to overcome to achieve this are:
- Provisioning all the nodes - starting/stopping Amazon EC2 instances
- Installing required software - Java, Tomcat, LiveRebel
- Configuring Tomcat cluster - (think jvmRoute param in
conf/server.xml) - Configuring a load balancer (Apache) with all the provisioned IP addresses
- Automation - one-click provision/start/stop/terminate on the cluster using Jenkins
Tools
Architecture
Loadbalancer
- Install Apache
- Install/enable Apache loadbalancer module
- Update Apache configuration
- Install LiveRebel Command Center and start it (could be a separate machine but we’ll use this instance for 2 services)
The load balancer should check in with chef-server and provide his own IP address. LiveRebel Command Center should be running and accepting incoming requests on default port (9001).
LiveRebel node(s)
- Install a Tomcat instance
- Figure out the IP of the load balancer
- Download lr-agent-installer.jar from the LiveRebel CC
- Run it (
java -jar lr-agent-installer.jar) - Start Tomcat
After all nodes are ready we must update the Apache load balancer configuration and provide all the IP addresses of the nodes. This is because of the architecture of the load balancer. It needs to know the IP addresses of the machines it balances.
Code (The Fun Part)
knife ec2 server create --run-list role[lr-loadbalancer] --node-name ‘loadbalancer’
When the process finishes successfully you can go to https://your-server-address:9001/ and check if the LiveRebel is running. It should be, but you will have to register or provide a license file. If you already have a license file you can automate the registration step by copying the license into LiveRebel home folder in your cookbook. Another thing to check is - if the load balancer has registered with chef-server.
for i in {1..800} ; do
knife ec2 server create --run-list role[lr-node] --node-name ‘lr-node-$i’
done
Everything is almost ready! All we need now is to create Jenkins jobs. The first one - we’ll name it lr-cluster-create - should run these 2 commands and start the cluster. And the other one lr-cluster-delete - stops it with these commands:
ids=`knife ec2 server list | grep "lr-node|loadbalancer" | awk {'print $1'} | tr 'n' ' '`
knife ec2 server delete $ids --yes
knife node bulk delete "lr-node-.*" --yes
knife client bulk delete "lr-node-.*" --yes
knife node delete "loadbalancer" --yes
knife client delete "loadbalancer" --yes
Conclusions
At this point, you should be well on your way towards bootstrapping a clean environment, installing, running your tests, checking load handling, and then you can shut it all down once you've seen everything working to your satisfaction.Your two Jenkins jobs are now able to spawn a dynamic Tomcat cluster. You can even parameterize your job and supply a number of nodes that you are interested in for a really dynamic cluster.
Tuesday, 27 March 2012
GeekOut 2012 14-15 June
Thursday, 22 December 2011
Stanford AI Class Finished
Stanford AI class is over. I was very interesting and I learned a lot new things. Unfortunately I sucked at the first 2 questions of final exam and my score is not so high as I would like it to be. But there will be new interesting courses in spring - I will take my "revenge" there. So far I have signed up to Machine Learning, Game Theory and Design and Analysis of Algorithms courses and I hope I will have enough time for that. :)
Monday, 14 November 2011
Java: Save InputStream Into File
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}Seriously, guys, don't you think there is something wrong here? Even in C++ people do not copy streams by operating bytes anymore! There should be a lot better way :) (I am not considering now usage of any additional libraries that require some additional jar files).
import sun.misc.IOUtils;
new FileOutputStream("tmp.txt").write(IOUtils.readFully(inputStream, -1, false));
Wednesday, 24 August 2011
Top 10 Jenkins Must-Have Plugins
Friday, 10 June 2011
Ruby Pack/Unpack
Having a party in ZeroTurnaround new office in Tartu. There is a mat on the floor near the entrance door that says:
01010111011001010110110001100011011011110110110101100101
Using ruby, we can quickly figure out, what that actually means:
["01010111011001010110110001100011011011110110110101100101"].pack('B*') #==> Welcome
Thursday, 9 June 2011
GeekOut: The First Java Conference In Estonia
Today I have attended the first Java conference in Estonia: GeekOut. That is also my first conference at all, as I have never participated earlier in such an event. Nipping on ahead I could say, that the activity was a success. It was good organized, informative, interesting, with great food and beer (although I do not drink alcohol :) ).
The day started with small introduction from Jevgeni Kabanov, the founder and CTO of ZeroTurnaround, the organizers of the GeekOut. After that the main part began.
The first talk was about Java 7 by Martijn Verburg. It was about the new features that are coming in JDK 7. Project Coin announced:
- Strings in switch
- Automatic Resource Management (such as c#
usingconstruction) - Numeric literals with underscores. (Like in ruby: 3_456_789)
- Improved Type Inference for Generic Instance Creation
We can skip generics on the right side:Map<String, List<String>> anagrams = new HashMap<>(); - New file handling mechanism, which "is finally done right, I hope" (M.V.)
- Nonblocking I/O for sockets and files, new Files and Paths classes that provide some util functions to work with filelike objects, that are quicker than in JDK 6, multicatch and some others...
Next speech was about "Riding the data tsunami and coming out on top" by Alex Snaps. He introduced Terracotta - an open source solution for application scalability, availability and performance.
After a coffee break Joonas Lehtinen told us about Vaadin}> - the web framework for java, that allows creating rich internet applications fast and without a line in javascript. Interesting fact is that Vaadin is actually "10 years old, but 21 months young" - as the framework exists already for a long time, but only recently it became popular. You can write everything in java, no javascript debugging, no html, and if you are writing in some other jvm language, then you don't need java too! Scala, Groovy, Jruby ... are all good. Also a nice coding session, where Joonas wrote a nice web application in 15 minutes! I liked it, very impressive.
John Davies talked about integration of applications. Banking realities: FpML, 100-100000 messages/sec, latency critical - 10ms, xml is evil - no time for <>, network cards process the messages, not cpu - how the time is critical, 30PB of cache?! We also learned, why common message mapping is bad, when you have huge amount of data. That is converting to common message format and from it, when we can actually convert straight. What we need actually is to know how to convert each field of the message between POJO and particular format. XPath using in objects... and so on.
After the lunch noSql databases, particularly GraphDB called Neo4j was covered by Peter Neubauer. It was a kind of introductory presentation, showing the concepts of the database, with examples of searching and storing the data and also conditions in which GraphDBs can and should be used instead of Sql databases.
Jevgeni Kabanov showed problems that one may face doing the update of web application. For instance, the out of memory error problem arises because of previous version of application not being garbage collected, if there is a not matter how small leak, because it has the link to the classloader and it has the link to the previous version of application.
The last talk, presented once again by Martijn Verburg, was a relaxing one. Very funny, but at the same time serious. Have to figure out yourself, what qualities of a Diabolic Programmer are good, what not, and what good to some extent.
The closing of the GeekOut conference was in cafe in the same building. Free pizza and some drinks - nice ending of the good day. Next time I definitely will attend GeekOut again!
The Slides:
- Back To The Future With Java 7 ~ Martijn Verburg
- Vaadin, Rich Web Apps in Server-Side Java without Plug-ins or JavaScript ~ Joonas Lehtinen
- Architecting For Enterprise Scale ~ John T. Davies (Filmed on QCon)
- Neo4j For the Rescue ~ Peter Neubauer
PS. I will list all the slides of the presentations here as soon as they appear.
Wednesday, 11 May 2011
Google Code Jam 2011 Qualification Round
This Saturday Google Code Jam 2011 Qualification Round took place. I didn't have much time to spend on the problems, but still have solved a couple and proceeded to Round 1.
The ones that I solved are Magicka and Candy Splitting.
Magicka
First I tried to solve it with some cunning string substitution involving regular expressions. But in the end the simple simulation did the trick. I actually was a little bit disappointed after the official solutions were announced, because I thought that there should be some trick in here.
#!/usr/bin/ruby
lines = ARGF.readlines
t = lines.first.to_i
(1..t).each do |test_id|
arr = lines[test_id].split " "
c = arr[0].to_i
combines = arr[1..c].inject({}){|memo, e| memo[e[0..1]]=e[2]; memo[e[1]+e[0]]=e[2]; memo }
d = arr[c+1].to_i
opposed = arr[c+2..c+1+d]
n = arr[c+2+d].to_i
elems = arr[c+3+d] #.split("").collect {|i| i.to_sym }
result = []
elems.split("").each do |elem|
result << elem
if result.length > 1
last2 = result[-2..-1].join
if combines.key?(last2)
result.pop(2)
result = result << combines[last2]
end
opposed.each do |o|
if result.include?(o[0]) && result.include?(o[1])
result = []
break
end
end
end
end
puts "Case ##{test_id}: [#{result.join(", ")}]"
end
Candy Splitting
This one was a little bit more tricky and the author's solution is much more simpler and clear than mine. I made it using old school brute force, just like Goro (strength is my strength :) )
#!/usr/bin/ruby
def s( candies, pile1, pile2 )
#p "c:#{candies}, 1:#{pile1}, 2:#{pile2}"
if candies.empty?
if !pile1.empty? && !pile2.empty? && pile1.inject(0){|memo, i| memo ^ i} == pile2.inject(0){|memo, i| memo ^ i}
return pile1
else
return false
end
end
x = candies.shift
p1 = pile1.clone
return s( candies, p1 << x, pile2) || s( candies, pile1, pile2 << x)
end
lines = ARGF.readlines
t = lines.first.to_i
(1..t).each do |test_id|
n_candies = lines[test_id*2-1]
candies = lines[test_id*2].split(" ").collect{|i| i.to_i }
r = s( candies.sort.reverse, [], [] )
r = !r ? "NO" : r.inject(:+)
puts "Case ##{test_id}: #{r}"
end
Thursday, 21 April 2011
Mercurial In Ubuntu
Since I have moved to ZeroTurnaround I had to learn a lot of new and interesting things. Most of them are very simple to write about, but as time passes I finally thought up the things, I could share with you.
We use Mercurial as SCM. So here is a small tip for ubuntu users how to configure hg.
Mercurial is available to install through repository
$ sudo aptitude install mercurial
So now as it is installed, we can configure it. Mercurial reads configuration data from several files, if they exist. To list them use:
$ hg help config
Now we will edit the $HOME/.hgrc file to add there some user information, authentication and enable plugins. A configuration file consists of sections, led by a [section] header and followed by name = value entries (sometimes called configuration keys)
[ui]
username = Firstname Lastname <firstname.lastname@example.net>
Here we introduced ourselves. The section is [ui] and ui.username is typically a person's name and email address. If this field is not declared in hgrc, you will have to enter it manually every time you commit.
[auth]
foo.prefix=*
foo.username=firstname.lastname@example.net
foo.password=SecretPassword123
The [auth] section allows you to store credentials for http authentication, I hate entering username and password every time I pull or push. You can store several different credentials for different servers here. They will be grouped by the part before the . (full stop, foo - in my example). And the auth.prefix will determine, which credentials should be used for what http address. It should be either * or a URI with or without the scheme part. In my example 1 and the same credentials are used for all addresses.
[extensions]
fetch =
color =
#this extension will get loaded from the file specified
myfeature = ~/.hgext/myfeature.py
Mercurial has an extension mechanism for adding new features. To enable an extension, create an entry for it in [extensions] section. There is a list of extensions for Mercurial and you can write one yourself. Extensions bundled with Mercurial does not need anything after the equals sign, but you need to provide the full path to others.
Now that we have configured it a little bit, we can start using. Mercurial tutorial by Joel Spolsky will teach you, how.
Friday, 14 January 2011
Hello, ZeroTurnaround!
A week ago I have left Axinom. Now I work in ZeroTurnaround - the famous home of JRebel. I don't want to write about the causes that made me to do it. (Those who interested may ask in private.) The only thing I can say, that I am definitely glad :) I did it.
This job switch also means change of technologies I will be working with. During this week I recalled a little bit of Java and got acquainted with Maven, Ant, Hudson and Selenium (not java specific, but still something new). So look for Java related posts in the near future.
Friday, 31 December 2010
Monday, 20 December 2010
Automatic Update Of Moles References To Other Solution Projects
The situation: I have a solution with several projects in it. One of them is UnitTest project, that uses Moles for mocking. And it has referenses to other projecs in solution as well as to their moled dlls. Every time I change code in my projects and rebuild them, the UnitTest project loses the references to moled dlls, as they allready have other versions. I see that Moles builds new versions of projects' dlls, but it does not update references. Why?
RTFM, Juri.
From the Microsoft Moles Reference Manual (page 12)
The Moles framework for Visual Studio monitors build events and automatically forces the regeneration of stub types for projects that have been updated. For efficiency
reasons, this automatic update only works for .moles files that are in the top level
folder of the project, to avoid walking large nested project structures. This automatic
update creates a smooth experience when writing code in a test-driven development
style.
So the automatic update of references works only for .moles files that are in the same folder with the project file. But I have moved all the .moles files into separate folder.
Now that I moved all the .moles files back, it is working.
Friday, 17 December 2010
Solution: Eee Pc Ubuntu 10.10 Wireless Connection Fail After Resume From Hibernate
After upgrading your Ubuntu to Maverick, you may have experienced some problems using wireless networks. That is when your computer resumes from hibernate, it is no longer able to connect to any wireless network and only a restart will make it do it again. Also some random disconnects from wireless occur. That concerns not only Eee Pc (I have a 1000h), but I believe every computer that uses RaLink network controller. First, check if it is you :)
$ lspci -k|grep -i network --after-context 3
03:00.0 Network controller: RaLink RT2860
Subsystem: Foxconn International, Inc. Device e002
Kernel driver in use: rt2800pci
Kernel modules: rt2800pci, rt2860sta
With Ubuntu 10.10 some hardware that was previously driven by the rt2860sta driver is now driven by default by the rt2800pci driver. Sometimes the new rt2800pci does not work as well as the rt2860sta. In that case it is often possible to switch back by blacklisting. As we already saw, we have both drivers installed and the pci one in use. Now we will create a text file that will allow us to easily switch between the drivers.
sudo gedit /etc/modprobe.d/blacklist-wlan.conf
Copy these 2 lines into the newly created file.
blacklist rt2800pci
#install rt2860sta /bin/false
And save. After the reboot your computer will use the rt2860sta driver. If you want to switch back to the rt2800pci driver, just comment the first line, uncomment the second and reboot.
PS. Solution was found here

